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

龙哥盟 / 2024-10-23 / 原文

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

原文:TowardsDataScience

协议:CC BY-NC-SA 4.0

用屏幕录制 DIY 你自己的视频编辑器

原文:https://towardsdatascience.com/diy-your-own-video-editor-with-screen-recording-eb6046f5cea7

简化屏幕录制、视频编辑和格式转换的简单 Python 解决方案

我们中的许多人使用记录器软件来捕捉屏幕活动作为视频文件。不同的录像机可能支持不同的视频格式,如 AVIMP4GIF 等。输出的视频通常不是我们想要的。也许我们需要另一个编辑器来裁剪和修剪视频,或者将它们转换成我们需要的格式。

和平:作者的形象

为了简化这个过程,本文介绍了一个简单的 Python 解决方案,它是一个高度可定制的 DIY 工具,具有所有这些功能,即屏幕录制、简单的视频编辑和格式转换。

在接下来的几节中,作者将带您了解如何创建这样的工具。本文中的所有代码都可以在我的 git 库中找到。

屏幕录制

python 库,即 PynputPyAutoGUIOpenCV 用于记录屏幕活动。

选择要录制的区域

这里使用的 Pynput 是帮助用户通过鼠标点击(左键)选择屏幕上的一个区域。它记录鼠标点击事件中的鼠标位置。

可以使用左上角点( xy )、宽度 w 和高度 *h、*定义一个选中的矩形区域,如下图所示。

选定的矩形区域(图片由作者提供)

给定按下和释放事件上的鼠标位置,下面的函数返回所选区域的参数,即 xywh

如果您需要捕获整个屏幕,您可以使用下面的 PyAutoGui 命令来获取该区域。

wh = pyautogui.size()
region = [0, 0, wh.width, wh.height]

记录该地区的屏幕活动

PyAutoGUI 是一个跨平台的鼠标键盘控件和一个简单的 API。PyAutoGUI 获取单独的截图或帧,其中区域是上面选择的矩形。

然后用 OpenCV 将连续截图保存为视频。它支持不同的视频格式,如 AVI 和 *MP4。*也可以设置其他参数,例如每秒帧数(fps)。在 OpenCV 中,将图像从 BRG(蓝红绿)转换到 RGB(红绿蓝)颜色模型也是必要的。

该屏幕录制功能的代码如下:

下面显示了一个录制视频的示例。这个视频包含了该地区所有的荧屏活动。有必要移除不需要的片段。以下部分将介绍如何编辑该视频,即视频修剪和裁剪。

录制屏幕的示例视频

视频编辑

MoviePy 是一个流行的视频编辑 Python 模块。它支持基本操作(如修剪、裁剪、连接、标题插入)、视频处理或创建高级效果。它可以读写最常见的视频格式,包括 GIF

  • 视频修剪

我们可以使用以下命令来修剪上面视频中不想要的片段:

clips = [
    [(0, 2), (0, 8)], 
    [(0, 24), (0, 32)]
]
video = VideoFileClip("test_recording.mp4")
clipped = [video.subclip(*clip) for clip in clips]
final_clip = concatenate_videoclips(clipped)

其中 clips 是要保留在视频中的两个视频片段(0m2s-0m8s)和(0m24s,0m32s)。运行完这几行代码后,这两段之外的其他剪辑将被删除。

  • 视频裁剪

给定一个具有两个对角位置(即左上角和右下角)的矩形,可以使用下面的 MoviePy 命令来完成对视频的裁剪。

x1, y1 = (10, 240)
x2, y2 = (610, 680) 
cropped = vfx.crop(video, x1=x1, y1=y1, x2=x2, y2=y2)
  • 格式转换

MoviePy 可以将视频导出为 GIF 图片或 MP4 等文件格式,如下所示:

video.write_gif("saved.gif", fps=10)
video.write_videofile("saved.mp4", fps=10)

最后,经过修剪和裁剪后,视频如下图所示:

编辑后的视频:作者提供的图片

从图像创建视频

使用 MoviePy,我们还可以为一系列图像创建一个视频。

这里我们有 30 张同样大小的图片,名字分别是 img_0.pngimg_1.png 、…、 img_29.png 。要将这些图像连接成标题为 Peace 的顶部 GIF 图片,我们只需运行下面这段代码。

images = ["images/img_{}.png".format(i) for i in range(30)]
clips = [ImageClip(m).set_duration(1) for m in images]
concat_clip = concatenate_videoclips(clips, method="compose")
concat_clip.write_gif(out_filename, fps=1)

在上面的代码中,每个图像剪辑的持续时间设置为 1 秒,对应的 fps=1。

结论

本文介绍了一个简单的 DIY 视频编辑工具的解决方案,带有额外的屏幕录制功能。该工具基于开源 Python 库 Pynput、PyAutoGui、OpenCV 和 MoviePy 构建。你可以在方便的时候使用它。

为了进一步定制您的工具,更多的 MoviePy 或 OpenCV 功能,如对象检测和跟踪等。可能会添加。

感谢您的阅读。请随意发表评论。如果你喜欢这篇文章或这个 DIY 工具,请分享给你的朋友,并关注我。

参考

  1. https://pynput.readthedocs.io/en/latest/
  2. https://pyautogui.readthedocs.io/en/latest/
  3. https://opencv.org/
  4. https://zulko.github.io/moviepy/

Django 完全初学者的第一步:快速教程

原文:https://towardsdatascience.com/django-first-steps-for-the-total-beginners-a-quick-tutorial-5f1e5e7e9a8c

了解如何在 Django 应用程序中嵌入 Plotly 图形,以及其他主题

费萨尔在 Unsplash 上的照片

如果你喜欢用 Python 编程,并且想第一次进入 web 开发领域,我认为 Django 可能非常适合你。Django 是最受欢迎的 Python 框架之一,它为 web 开发中非常常见的任务提供了出色的内置解决方案,使快速高效地实现项目和编写代码成为可能。此外,Django 也被大公司用于制作,比如 Instagram 和 Spotify 。因此,这一出色的 Python 框架也很有可能满足您的项目需求。

我最近从 Coursera 的Django for Everybody Specialization毕业,我惊讶于使用 Django 内置视图类构建一个具有用户认证和登录功能的完整 CRUD 应用程序是如此的快速和简单。我将永远感谢来自密歇根大学的 Charles Severance 教授,因为他组织了这样一个令人惊叹和兴奋的课程,将我的 Django 技能提升到了一个完全不同的水平。

因此,我决定通过创建一个简单的 CRUD 应用程序来管理和显示我喜欢的电影中的数据,来实践我从这门课程中学到的东西。然而,在以后的文章中展示这种 CRUD 的代码之前,我想收集一些关于 Django 入门的介绍性信息。因此有了这个教程。

我希望这份材料能帮助一些人。至少,它帮助了我,因为这是一个回顾 Django 中一些基本概念和实践的机会。

我使用 Python 3.10.2 和 Django 4.0.2 开发了本教程。我还使用 Git Bash 作为我的终端,这是在 Windows 操作系统中运行 Linux 命令的好方法。

第 1 部分:第一步

  1. 创建一个名为films_project的项目文件夹并进入其中。
mkdir films_project
cd films_project

如果没有另外提到,本教程中的所有终端命令都应该在films_project目录中运行。

2.使用venv Python 模块创建一个新的虚拟环境。我将我的虚拟环境命名为.myenv,但是如果您愿意,也可以使用其他名称。

python -m venv .myenv

3.通过针对您选择的终端和操作系统运行正确的命令来激活虚拟环境。下面的命令在我的 Git Bash for Windows 中有效。如果你对用venv激活虚拟环境有疑问,请查阅 Python 文档。

source .myenv/Scripts/activate

激活它之后,您应该会在终端中看到您的虚拟环境名称,如下例所示:

作者图片

从现在开始,所有命令都必须在激活虚拟环境的情况下运行。

4.用 PIP 安装 Django:

pip install django

5.自己开始一个叫project的 Django 项目。

重要提示:不要忘记这个命令末尾的点。

django-admin startproject project .

运行这个命令将创建一个manage.py文件和一个名为project的文件夹,里面有五个文件(算上__init__.py一个)。因此,您的films_project目录树现在应该是这样的:

作者图片

请记住.myenv是我选择命名我的虚拟环境文件夹的方式,它在上面的图像中是折叠的(里面有一堆文件夹和文件,与我们的教程无关)。

6.启动名为films的 Django 应用程序:

python manage.py startapp films

Django 项目可以有一个或多个应用程序。您可以将 Django 中的应用程序视为在不同项目之间重用代码的一种方式。

这个命令python manage.py将在您的 Django 项目中频繁使用,所以请习惯它。另外,在终端中只运行python manage.py,不使用任何其他参数,将会显示所有可用选项的列表。

上面的startapp命令创建了一个名为films的新文件夹,里面有一些文件和一个文件夹。查看它们:

作者图片

films_project/films/migrations中唯一的文件是一个__init__.py文件,表明这个迁移目录将来应该作为一个模块使用。

7.每当我们创建一个新的应用程序时,我们必须将它添加到settings.py文件中的已安装应用程序列表中。我们现在就开始吧。打开project/settings.py,在INSTALLED_APPS变量中保存的列表末尾添加一个带有films应用的字符串。不要删除或更改列表中已有的任何其他字符串:

# inside project/settings.pyINSTALLED_APPS = [ 'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles', #new value below:
    'films.apps.FilmsConfig',
]

settings.py仍然打开时,您可以在LANGUAGE_CODETIME_ZONE变量中更改整个应用程序的默认语言和时区。

8.运行以下代码检查错误:

python manage.py check

如果您收到消息'系统检查未发现问题(0 沉默)',这意味着您的申请是好的。我们现在准备启动本地服务器,并第一次检查我们的 Django 网站。

9.运行以下命令,在默认端口(8000)启动本地服务器

python manage.py runserver

如果 8000 端口已被计算机中的另一个应用程序占用,请更改端口。只需在命令中添加新的端口号(例如 8050 ):

python manage.py runserver 8050

10.打开浏览器并转到以下地址之一:

[http://127.0.0.1:8000/](http://127.0.0.1:8000/)

或者

[http://localhost:8000/](http://localhost:8000/)

如有必要,用您的新端口号替换8000

通过访问这个运行在本地机器上的服务器,您将看到一个新项目的 Django 默认主页。

作者图片

11.注意,在films_project文件夹中创建了一个名为db.sqlite3的新文件。这是因为 sqlite3 是在project/settings.py文件中配置的默认数据库。然而,Django 允许与许多其他数据库连接;您只需要进行正确的配置。我们现在不会谈论这个话题,因为这个话题已经超出了我们当前基础教程的范围。

12.Django 已经为您创建了另一条路线。首先,确保您的本地服务器正在运行(也就是说,您在终端中执行了python manage.py runserver,并且那里没有错误消息)。然后转到管理页面查看:

[http://localhost:8000/admin/](http://localhost:8000/admin/)

当您尝试访问下面的链接时,您可能会看到一条非常难看的错误消息,在异常值字段中显示信息“no this table:django _ session”。我想让你看看那一页,因为我们可以从编程过程中出现的错误信息中学到很多。对此有一个非常简单的解决方法:我们只需要运行命令在数据库中创建管理应用程序使用的表。所以:

13.运行以下命令创建数据库表。

python manage.py migrate

大约十几条消息将显示在终端控制台中,表示迁移已被应用。这意味着 Django 为数据库中的默认应用程序创建了必要的表,比如 admin。实际上,如果您使用一个 sqlite3 服务连接到数据库并列出它的所有表,您将会看到这些由您刚才运行的migrate命令创建的新表。

14.您还需要创建一个超级用户来登录管理区。使用以下终端命令完成此操作:

python manage.py createsuperuser

告知用户名、电子邮件和密码。然后,使用python manage.py runserver重启服务器,并使用您的信息登录到管理区域。您将看到以下页面:

作者图片

这是 Django 从一开始就提供给开发人员的许多内置资源之一,我想让您知道它的存在,尽管我们现在不会在本教程中探究它。管理区是 Django 的强大特性之一,因此值得花时间学习如何使用它。

第二部分:我们的第一条路线和风景。

15.让我们创建我们的第一个新路由,它将替换我们刚刚访问的 Django 默认页面。我们将通过修改project/urls.py文件来实现。注意,我们还向它添加了一个新的 import 语句。

# inside project/urls.pyfrom django.contrib import admin
from django.urls import path
from films import views    # added 
urlpatterns = [
    path('', views.home, name='home'),    # added
    path('admin/', admin.site.urls),  
]

16.如果我们现在运行python manage.py check,它将返回一个错误,因为你的films/views.py是空的。让我们通过向该文件添加以下函数来纠正这一点:

# inside films/views.pyfrom django.shortcuts import render
from django.http import HttpResponse   # added def home(request):
    return HttpResponse('This is the home page.')

现在,再次访问http://localhost:8000,检查新修改的页面如何显示我们在home视图功能中设置的信息:

作者图片

干得好!它看起来一点也不花哨,但我们需要欣赏我们在这里取得的成就:我们使用 Django 和 Python 创建了我们的第一个网页,所有这些只需编写几行代码并在终端中运行几个命令。此外,所有这些知识将有助于我们在未来创建更加复杂和令人兴奋的网站,这一点可以肯定。如果我们现在建立了足够好的基础,将来我们可以成为非常熟练的 Django 开发人员,制作伟大而有用的 web 应用程序,同时享受用 Python 编程的乐趣。

在这一点上,对 Django 所认为的视图做一些简单的考虑是很有趣的。与大多数 MVC(模型-视图-控制器)框架不同,在 MVC 框架中,视图指的是应用程序的前端部分,Django 将视图称为配置应用程序逻辑和规则的代码。Django 中的接口部分被称为模板,这使得 Django 成为一个 MVT(模型-视图-模板)框架。

我再说一遍:Django 中的视图是我们创建控制器和应用程序逻辑的地方;不是前端的部分(这些在 Django 里叫模板)。我在这里提到它是因为这一点让许多人感到困惑,尤其是那些来自经典 MVC 模式的人。

从我们目前所做的可以看出,films/views.py中的home函数简洁明了;它只接受一个请求对象作为其参数,并返回一个响应对象,该对象在 DOM 中写入一个短语,并在所选的 URL 中显示它。但是我们也可以在视图函数中将 HTML 元素传递给响应对象,这样浏览器就可以用不同的字体大小和格式显示它们。

17.然后让我们修改films/views.py中的home函数如下:

# inside films/views.pyfrom django.shortcuts import render
from django.http import HttpResponse def home(request):
    # remove these print statements later
    print('\n\nRequest object:', request)
    print('Request object type:', type(request), '\n\n')

    html_tags = '''
    <h1>This is the Home Page</h1>
    <h3>Thanks for visiting us</h3>
    <p>MVT means:</p>
    <ul>
      <li>Model</li>
      <li>View</li>
      <li>Template</li>
    </ul>'''

    response = HttpResponse(html_tags) # remove these print statements later
    print('Response object:', response)
    print('Response object type:', type(response))
    print('\n\nUser-agent info :', end='')
    print(request.META['HTTP_USER_AGENT'], '\n\n')

    return response

如果你的 Django 本地服务器正在运行,用CTRL + C停止它,运行python manage.py check查看是否有错误,然后用python manage.py runserver再次启动服务器。接下来,进入http://localhost:8000查看新网页。每次刷新这个页面,都会向 Django 服务器发送一个 GET 请求,并执行home函数视图。您可以检查一些关于请求和响应对象的信息,我们要求在终端控制台中打印这些信息。

这里有一个重要的警告:我们永远不会在 Django 产品代码中使用带有 HTML 标签的字符串。否则,我们将把我们的申请提交给 XSS 恶意攻击。因此,在第一个例子中,我们将在 Django 视图中使用 HTML。稍后我将向您展示如何在 Django 中使用模板来呈现 HTML 页面。

我们现在将创建新的路线来巩固我们到目前为止所学的内容。

18.创建文件films/urls.py

touch films/urls.py

19.在project/urls.py中添加新路线。它将作为我们稍后为films应用创建的路线的入口点。

# inside projects/urls.pyfrom django.contrib import admin
from django.urls import path, include
from films import views urlpatterns = [
    path('', views.home, name='home'),
    path('admin/', admin.site.urls),
    path('films/', include('films.urls')),   # added
]

20.用新的路线信息填充films/urls.py文件。

# films/urls.pyfrom django.urls import path
from . import views app_name = 'films'urlpatterns = [
    path('', views.main, name='main'),
    path('user_info/', views.user_info, name='user_info'),
]

21.在films/views.py末尾增加新的视图功能:

# films/views.py(...)def main(request):
    message = '<h1>This is the films MAIN page.</h1>'
    return HttpResponse(message)def user_info(request):
    message = '<h1>This is the films USER_INFO page.</h1>'
    return HttpResponse(message)

22.现在访问创建的路由,检查它们是否显示正确的消息:

http://localhost:8000/films/
http://localhost:8000/films/user_info

第 3 部分:让视图呈现 HTML 模板文件

现在是时候开始使用 Django 模板了。现在,它们将是由视图函数呈现的简单 HTML 文件。

23.创建保存 HTML 文件的必要文件夹。

重要提示:请注意,这些新文件夹中有两个被命名为templates:一个在films中,另一个直接位于films_project的项目根目录中,与films处于同一层级。

mkdir templates
mkdir films/templates
mkdir films/templates/films

24.创建以下 HTML 文件:

touch templates/home.html
touch films/templates/films/main.html
touch films/templates/films/user_info.html

25.打开project/settings.py,导入os模块,在变量TEMPLATES中,用以下信息填充TEMPLATES['DIR']键中的空列表(只改变这一行,保留其他行):

TEMPLATES = [
{(...) 'DIRS': [os.path.join(BASE_DIR, 'templates')],(...)}
]

26.将以下信息放入相应的 HTML 文件中:

  • templates/home.html:
<h1>This is the Home Page</h1>
<h3>Thanks for visiting us</h3>
<p>MVT means:</p>
<ul>
  <li>Model</li>
  <li>View</li>
  <li>Template</li>
</ul>
<h3>Link to the website pages:</h3>
<ul>
  <li><a href="{% url 'home' %}">Home Page</a></li>
  <li><a href="{% url 'films:main' %}">Films Main Page</a></li>
  <li><a href="{% url 'films:user_info' %}">Films User_Info Page</a></li>
</ul>
  • films/templates/films/main.html
<h1>This is the films MAIN page.</h1>
<h3>Link to the website pages:</h3>
<ul>
  <li><a href="{% url 'home' %}">Home Page</a></li>
  <li><a href="{% url 'films:main' %}">Films Main Page</a></li>
  <li><a href="{% url 'films:user_info' %}">Films User_Info Page</a></li>
</ul>
  • films/templates/films/user_info.html
<h1>This is the films USER_INFO page.</h1>
<p>Username: Fabrício</p>
<h3>Link to the website pages:</h3>
<ul>
  <li><a href="{% url 'home' %}">Home Page</a></li>
  <li><a href="{% url 'films:main' %}">Films Main Page</a></li>
  <li><a href="{% url 'films:user_info' %}">Films User_Info Page</a></li>
</ul>

这里有一个重要的提示:如果你现在访问这些页面,你会发现什么都没有改变。这是因为我们没有在视图中进行任何更新。我们需要让每一个视图呈现正确的模板。

27.因此,将films/views.py中的所有内容替换为下面的新代码:

from django.shortcuts import render def home(request):
    return render(request, 'home.html')def main(request):
    return render(request, 'films/main.html')def user_info(request):
    return render(request, 'films/user_info.html')

现在访问网址并注意不同之处。浏览链接,在页面间快速移动。

第 4 部分:使用基础模板避免代码重复

我不知道你是否注意到了,HTML 文件中的代码有许多重复的行。这一点都不可取,因为它违反了 DRY ( 不要重复自己)原则,我们需要修正这一点。Django 允许使用模板标签,以一种非常简单的方式,将应该出现在多个页面中的 HTML 代码编写在一个 HTML 文件中。

28.创建一个templates/base.html文件。

touch templates/base.html 

我们现在将在我们的项目中使用一些来自 Bootstrap web 设计框架的代码。不幸的是,我不能在这里解释基本的 HTML、CSS 和引导代码是如何工作的。否则,本教程将会比现在更加广泛。然而,如果你想从事 web 开发,即使是在后端,这些都是很好的学习技巧。在我看来,新知识从来没有坏处。

所以,如果你想知道更多关于如何创建漂亮的网页界面,我建议你去看看丹尼尔·沃尔特·斯科特的名为响应式网页设计基础——html 5 CSS3 引导的伟大课程。这些视频信息量很大,练习也很棒,丹尼尔设法以一种非常有效和有趣的方式传播他的知识。

29.用下面的代码填充templates/base.html文件。这将是将在其他 HTML 页面中扩展的代码:

请注意base.html中出现的以下新结构:

  • {% block head %}{% endblock %}
  • {% block content %}{% endblock %}
  • {% if title %}{% else %}{% endif %}
  • {{title}}

符号{% %}在 Django 模板语言中被广泛使用。使用基本模板,{% block BLOCKNAME %}{% endblock %}标签用于标记我们应用程序中每个页面的特定代码块的插入点。

Django 模板语言使用了很多过滤器,这些过滤器允许它在模板中执行函数和方法。例如,我们已经看到了在我们代码的早期阶段使用的{% url %}过滤器:它接收一个字符串作为它的参数,以'app_name:route_name'的形式,并且它返回一个 web 资源的绝对路径。例如:{% url 'films:user_info %}将获得名为user_info的路线,在films应用程序中,它将以字符串形式返回其路径,并将其呈现在 HTML 页面上。

我们还可以注意到,Django 允许在模板中使用条件语句。正如我们将在后面看到的,循环的在这里也是可能的,这有助于创建更易维护的代码。

最后,注意{{title}}中的双花括号。这是 Django 呈现视图传递给模板的 Python 变量的方式。我们还没有做到这一点,但我们以后会的。

30.替换 HTML 文件的内容,如下所示:

  • templates/home.html:
{% extends 'base.html' %}{% block content %}<h1>This is the Home Page</h1>
<br>
<h3>Thanks for visiting us</h3>
<br>
<p>MVT means:</p>
<ul>
  <li>Model</li>
  <li>View</li>
  <li>Template</li>
</ul>{% endblock  %}
  • films/templates/films/main.html:
{% extends 'base.html' %}{% block content %}<h1>This is the films MAIN page</h1>
<br>
<h4>Some Pixar Movies:</h4><ul>
  {% for number in '012'|make_list %}
    <li>Toy Story {{forloop.counter}}</li>
  {% endfor %}
</ul>{% endblock  %}
  • films/templates/films/user_info.html:
{% extends 'base.html' %}{% block content %}<h1>This is the films USER_INFO page</h1>
<br>{% if userinfo %}
  <h4>username: {{userinfo.username}}</h4>
  <h4>country: {{userinfo.country}}</h4>
{% else %}
  <h4>username: not informed</h4>
  <h4>country: not informed</h4>
{% endif %}{% endblock  %}

注意这最后三个 HTML 文件是如何以{% extends 'base.html' %}开始的,这表明我们正在扩展来自base.html文件的模板信息。而且我们希望每个页面显示的 HTML 在{% block content %}……{% endblock %}标签之间,显示我们希望它从base.html插入到这些标签所在的地方。

现在用python manage.py check查找错误,然后用python manage.py runserver运行服务器。看看我们的页面现在有多像样。

作者图片

第 5 部分:将 PYTHON 变量传递给模板

31.现在打开films/views.py,为这个新版本替换旧代码。然后运行服务器,注意这一变化如何影响页面标题中显示的信息(浏览器选项卡中显示的文本元信息)和user_info页面中显示的用户信息。

正如我们所看到的,render()函数可以接收一个字典(通常命名为contextctx)作为它的第三个参数。然后,我们可以通过使用不带引号的键来访问这些字典值。

例如,注意title变量及其值如何出现在视图和base.html模板条件结构中。home视图函数不传递标题信息,因此title值将为None,并且将执行else子句,在主页上显示默认标题。另一方面,mainuser_info视图函数在上下文字典中都有一个键'title',所以它的值将是‘truthy’,并且将执行if子句,在呈现模板时在标签浏览器中显示title值。

类似的事情发生在由user_info视图函数传递给user_info.html模板的userinfo变量上。还要注意,我们将使用点符号来访问嵌套值,类似于 Javascript 对象中使用的符号。如果您尝试从 Python 中使用context[key]结构访问嵌套字典中的值,将无法工作,并且会出现错误。

第 6 部分:使用 DJANGO 模型创建自己的数据库表

32.打开films/models.py,插入下面的代码。我们将创建我们的第一个 Django 模型。

注意,Django 模型是作为继承自models.Model Django 类的类创建的。我们在这里创建两个表:genrefilm,实际上分别有 2 和 4 列。我们不必在代码中为每个模型添加id列,因为在project/settings.py文件中,变量DEFAULT_AUTO_FIELD被配置为为每个模型表创建一个具有自动递增整数值的id列。

还要注意的是,Film模型有一个名为genre的外键列,具有一对多关系。这两张表之间的关系并不完美。不过,出于教学目的,我们在这里使用一个更简化的模型,因为多对多模型更复杂,应该马上学习。

32.运行python manage.py makemigrations来创建迁移文件,这些文件将设置 Django 必须如何创建这两个新表filmgenre

33.现在运行python manage.py migrate命令,按照上次迁移中创建的指令,在db.sqlite3数据库中实际创建两个表。它们在数据库中的名称前面会有应用程序名称,所以实际的表名将是films_filmfilms_genre,如果您想运行一些 SQL 代码来检查它们的话。

现在,我们准备填充我们创建的这些新表。我将在这里展示两种不同的方法:

  • 使用管理区
  • 使用 Django shell

34.打开films/admin.py,添加以下代码:

from django.contrib import admin
from .models import Film, Genre admin.site.register(Film)
admin.site.register(Genre)

通过这样做,我们使得管理应用程序可以访问FilmGenre模型。

35.现在转到http://localhost:8000/admin/,输入你创建的超级用户的登录信息,检查两个新模型是如何出现在屏幕上的:

作者图片

36.点击Films链接,找到Add Film按钮,填写字段并保存信息。你可以点击旁边的绿色加号在这个页面上添加一个新的流派。这将在genre表中插入一个新行。至少保存三部新电影。我保存了四部《黑客帝国》电影,你可以看到它们的名字被很好地列在管理区。我可以点击他们中的任何一个,对他们的数据进行更改,然后按保存按钮。所有这些更改都会自动保存在 Django 应用程序的 sqlite3 数据库中。

作者图片

37.现在停止服务器并在终端中运行python manage.py shell。Django 解释器将会打开。这是另一个非常酷的特性:它不仅允许你用解释器运行 Python 代码,还可以加载你所有的项目文件。因此,您可以使用您的项目文件在这里运行 Django 命令,比如我们刚刚创建的模型。

我将使用 Django ORM 中的一些命令。它允许我们编写在数据库中运行查询的 Python 代码。使用 ORM 的优势在于,如果我们想要将数据库连接更改为 MySQL 或 PostgreSQL,我们只需要在project/settings.py中设置正确的数据库配置。所有使用 Django ORM(带有 Python 代码)的查询都将保持不变,这在我看来很棒。

38.在我们刚刚初始化的 Django shell 中键入以下命令。这将创建新的FilmGenre对象,将它们保存到各自的表中,并显示一个针对films_film表中所有电影的选择查询的快速示例。

作者图片

现在,我们将使用我们创建的这些新模型,并将它们连接到我们的视图,以便数据库数据可以从films应用程序显示在我们的主网页上。

39.在films/views.py内部,导入Film模型,改变main视图功能。保持其他视图不变:

40.打开films/main.html并将其内容更改为以下代码。请注意我们如何使用 for 循环来显示保存在数据库中的所有电影信息。

{% extends 'base.html' %}{% block content %}<h1>This is the films MAIN page</h1>
<br>
<h4>Films saved in our database:</h4><ul>
{% for film in films_list %}

  <li>{{film.title}} ({{film.year}}, genre: "{{film.genre}}")</li>{% endfor %}
</ul>{% endblock  %}

下面是我接入[http://localhost:8000/films](http://localhost:8000/main.)后的画面。它显示了我保存在数据库中的所有五部电影(四部黑客帝国电影和海底总动员)。

作者图片

这只是一个简单的例子,展示了我们如何显示数据库中的信息,并将其发送到我们的页面之一。实际上,Django 有一些定制的视图,以类的形式构建,我们可以用它们来完成一些最常见的任务,比如在网页上列出所有的观察结果(或者部分观察结果)。这是由**django.views.generic.list.ListView**类完成的。

在这个介绍性教程中,我们不会讨论更多关于视图类的内容。如果你想了解更多信息,请查看 Django 文档页面。

第 7 部分:查询参数

到目前为止,我们只处理了 GET 请求。当我们用 GET 方法发出请求时,我们可以传递直接附加到 URL 的参数,称为查询参数。我们将修改user_info视图函数,使用这些参数作为模板的输入。

41.在films/views.pyuser_info函数中进行以下修改,保留文件中的其他行。

在这个新版本中,我们使用了一个if / elif结构来检查请求方法。我们还不会访问elif部分,但是我已经选择将它写在代码中,这样您就可以看到我们如何根据请求方法是 GET 还是 POST 来让视图函数运行代码。例如,如果我们使用基于类的视图,我们将有两个类方法(.get().post()),每个方法处理各自的请求类型。

我还想提醒您注意重要的request.GET属性,它使用 URL 中使用的所有查询参数来访问字典。

42.现在,访问user_info URL 并添加必要的查询参数,如下例所示:

[http://localhost:8000/films/user_info/?username=Neo&country=USA](http://localhost:8000/films/user_info/?username=Novo&country=Sui%C3%A7a)

请注意问号是如何用于开始编写查询参数的。这里我们有两个(用户名和国家),值分别为“Neo”和“USA”。此外,我们可以观察到查询参数名称/值由等号分隔,而&符号用于分隔不同的参数。

继续更改参数值,按 enter 键,并查看页面上的值将如何变化。还可以查看控制台,了解查询参数字典的结构。您可以使用request.GET.get(KEY)代码获得它的任何值。

第 8 部分: HTML 表单和帖子请求

现在让我们用 POST 方法构建一个 HTML 表单。

43.创建films/templates/films/user_form.html文件,并将以下 HTML 代码放入其中:

44.在templates/base.html导航栏中做一个小改动,添加一个链接到新的user_form页面。我不会在这里重复所有的base.html代码;我将在结束的</ul>标签之前添加额外的<li>标签:

<li class="nav-item active">
  <a class="nav-link active" href="{% url 'films:user_form' %}">UserForm</a>
</li>

45.向films/urls.py添加新路线。

from django.urls import path
from . import viewsapp_name = 'films'urlpatterns = [
    path('', views.main, name='main'),
    path('user_info/', views.user_info, name='user_info'),

    ## new route below ##
    path('user_form/', views.user_form, name= 'user_form'),
]

46.在films/views.py中,一方面修改 imports 和user_info视图,另一方面创建user_form视图。由于这里做了很多修改,所以我给出了所有修改过的文件代码:

让我们更详细地评论一下这个新的films/views.py代码。当我们第一次访问http://localhost:8000/films/user_form时,这将是一个 GET 请求,因此视图中的if子句将被执行,只是加载各自的模板。但是当我们填写表单字段并按下 submit 按钮时,POST 方法被激活,并且运行elif子句中的代码。

正如我在 Charles Severance 教授的课程中所学到的,将 POST 请求中的数据发送到不同于表单所在的 URL 是一个很好的做法。当我们这样做时,一个 GET 请求将被调用到新的 URL,并且 POST 数据将会丢失。

因此,在我们进入下一页之前,我们需要保存表单中传递的数据。我们通过对每个输入字段使用request.POST.get(KEY)来做到这一点,其中KEY是来自相应的<input> HTML 标签的 name 属性的值,所以我们不能忘记设置它们。然后我们可以将这些值传递给位于request.session的另一个字典,这非常有帮助。它允许将数据存储在当前浏览器会话中,并在不同时刻由我们的代码检索。这就是为什么我们可以在user_info视图中使用保存在会话字典中的信息并显示它们。

第 9 部分:路线参数和详细页面

47.在films/urls.py创建新路线。我们将只在下面显示这一行,但是您已经知道如何将它插入到文件中。

(...)path('<int:id>/details', views.details, name='details')(...)

注意新的符号<int:id>。这里的< >符号显示我们正在处理一个新的参数类型,称为路由参数。int显示它是来自int类的一个对象,并且id告诉 Django 这里需要一个主键。

48.用以下内容创建films/templates/films/details.html模板。我们现在将使用一个带有一些引导类的 HTML 表结构。

{% extends 'base.html' %}{% block content %}<h1>Film details:</h1>
<br><table class="table" style="width: 30%">
  <thead>
    <tr>
      <th scope="col">Attribute</th>
      <th scope="col">Value</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td scope="row">Title:</td>
      <td class="text-dark">{{film.title}}</td>
    </tr>
    <tr>
      <td scope="row">Year:</td>
      <td>{{film.year}}</td>
    </tr>
    <tr>
      <td>Genre:</td>
      <td>{{film.genre}}</td>
    </tr>
  </tbody>
</table>{% endblock  %}

49.在films/views.py中添加新的details视图。我注释掉了一行代码,它也可以用于通过 id 查询单个元素。注意电影 id 是如何作为一个额外的参数传递给视图的。

def details(request, id):
    film = Film.objects.get(id=id)
    # other query option:
    # film = Film.objects.filter(id=id)[0]
    context = {'film': film}
    return render(request, 'films/details.html', context)

50.现在选择一条类似http://localhost:8000/films/1/details的路线,并查看这部电影的详细信息。手动更改 id 号,以便您可以查看其他影片的详细信息。如果选择了一个不存在的 id 号,视图将会产生一个错误,因为它没有针对这种情况的错误处理代码。所以,如果你觉得有趣,就去搜索处理这类问题的方法。

第 10 部分:在 DJANGO 中使用 PLOTLY 图

这一部分可能对那些想把这两个惊人的资源放在一起的人有用:Plotly graphs 和 Django。这里需要注意的最重要的事情如下:

  • 从一个 Plotly 图形对象使用.to_html()方法,并将其保存在一个上下文字典中,名称如fig
  • 在 Django 模板中,使用标签{{fig | safe}}来呈现图形。

我将在这里使用 Gapminder 数据集来加快速度。因为它与电影无关,所以创建另一个 Django 应用程序是正确的程序。但我不会那么做。相反,我将在films路径之外放置一条新路径,并借用films/views.py来存储显示图表所需的视图和辅助功能。我还将使用路线参数按年份过滤图表。

51.打开project/urls.py并添加新的 Gapminder 路线:

from django.contrib import admin
from django.urls import path, include
from films import views urlpatterns = [
    path('', views.home, name='home'),
    path('admin/', admin.site.urls),
    path('films/', include('films.urls')), # new route: 
    path('gapminder/<int:year>', views.gapminder, name='gapminder'),
]

films/views.py中,我们将添加两个不是 Django 视图的函数,因为它们不会处理 HTTP 请求。函数get_data()只从plotly.express获取 Gapminder 数据集作为 Pandas 数据帧。并且create_plot()会生成著名的 Gapminder 气泡图。这些函数在gapminder函数视图中被调用,year route 参数在这里用于在生成图表之前过滤数据集。

52.用 PIP 安装 Pandas 和 Plotly:

pip install pandas plotly

53.打开films/views.py,导入 Plotly Express,在最后一次导入后,定义get_data()create_plot()功能:

import plotly.express as px# keep the other imports(...)def get_data():
    df = px.data.gapminder()
    return dfdef create_plot(df, year):
    fig = px.scatter(
      data_frame = df.query(f'year=={year}'),
      x = 'gdpPercap',
      y = 'lifeExp',
      color = 'continent',
      size = 'pop',
      height = 500,
      log_x=True,
      size_max=60,
      hover_name="country")

    fig =  fig.to_html()
    return fig

54.在films/views.py结束时,创建gapminder视图:

def gapminder(request, year):
    df = get_data()
    fig = create_plot(df, year)
    context = {"plot": fig, "year": year}
    template = 'gapminder.html'
    return render(request, template, context)

55.创建文件templates/gapminder.html并在其中写入以下代码:

{% extends 'base.html' %}{% block content %}<h1 class="text-center">GAPMINDER (YEAR {{year}})</h1>
<div class="container-fluid d-flex justify-content-center">
  {{plot | safe}}
</div>{% endblock  %}

56.访问 Gapminder 数据集中的一个带有年份的 URL(比如http://localhost:8000/gapminder/2007)并播放您的网页及其漂亮的交互式图表。

作者图片

遗言

如果你到达这里并征服了这个教程,你就是一个真正的战士。恭喜你!Django 是一个完整的世界,还有很多需要了解的;只要坚持学习和练习,成功就会到来。

亲爱的读者,非常感谢你花时间和精力阅读我的文章。

快乐编码!

计算机如何看深度:基于深度学习的方法的最新进展

原文:https://towardsdatascience.com/dl-for-depth-estimation-p2-7cb2c9ff325d

第 2 部分:基于图像的立体视觉

立体 视觉 深度 学习。 输入是*一个立体图像对(即从左右摄像机捕捉的图像);输出是左图和两张照片中所有可见像素的深度图。*因此,现代端到端解决方案学会将两张 RGB 照片映射到深度图。目标是使用监督来最小化预测与实际之间的距离(或最大化相似性)。立体对(上面最左侧)是深度网络(中间)的输入,该深度网络将图像转换为相应的深度预测(右侧)。注意,物体离相机越近,视差越显著(即,深度越小)。输出是显示在右侧的密集视差图,暖色代表较大的深度值(和较小的视差)。作者创造了可视化。

我们对深度的感知对于创造我们周围的 3D 世界至关重要。这种知识已经流行了几个世纪,其中一个人就是列奥纳多·达·芬奇。他利用自己的专业知识帮助自己创作了一些艺术作品,这些作品将会名闻遐迩,如《最后的晚餐》或《萨尔瓦托勒·希泽拉》。从技术上讲,对双筒望远镜的理解可以追溯到公元 280 年,当时欧几里德意识到我们的深度知觉是人类用两只眼睛聚焦于同一物体。尽管如此,今天,立体视觉仍然是一个非常有趣的问题。随着我对话题的熟悉,一路上做的笔记,现在正在转化为一系列的博客,供其他人参考。

立体视觉是其他信息和多模态知识可以获得的基本任务。因此,立体视觉技术在现实世界的应用中有着广泛的实际用途,如机器人、自动驾驶汽车和大多数依赖于感知深度作为先验知识的任务!不足为奇的是,在过去的几十年里,这个话题已经被许多人所激发。有了现代的监督深度学习,问题的高度复杂性与高度复杂的网络更好地匹配。现在的需求很大,标记数据以适应这些受监督的深层网络的容量,这在获取和缓解条件以满足对数据的大量需求方面仍然是一个挑战。总之,我们正处于或接近深度感知可以在实践中自信地部署的边缘。但是,由于需要如此多的数据来训练深度网络,部署的模型需要大量的数据来学习将左/右对转换为其视差图的映射函数,如上图所示。

在本系列的第 2 部分中,我们将介绍几种基于图像的立体视觉监控方法。提供了动机、策略、结果(如在原始论文中发表的)、摘要、文档链接和源代码。这里的目的不是提供传统意义上的文献综述,而是充当监督立体视觉的深层方法的百科全书。该系列的未来部分将涵盖视频数据、自我监督和非监督、多任务学习,以及数据集和基准的更多细节和分析(即,比上一篇文章 第 1 部分 提供的更深入)。现在让我们回顾一下从 2015 年到 2020 年的几个 SOA 方法。未来的博客将涵盖最新的方法。然而,这里介绍的大部分材料都是初步的。

享受:)

目录

简介
背景信息
∘ 立体视觉
∘ 深度监督学习
∘ 深度监督学习用于立体视觉
MC-CNN
∘简介
∘ 方法
∘ 结果
∘ 总之【T28
∘ 总结
∘ 论文与代码
iresnet
∘动机
∘ 方法
∘ 结果
∘ 总结
∘ 论文与代码

金字塔立体匹配网络(PSMN)
∘ 动机
∘ 方法
∘ 结果
∘ 结果
∘ 总结
∘ 论文及代码
modulenet
∘动机
结果
∘ 总结
∘ 论文与代码
讨论
∘ 总结
∘ 未来工作
∘ 结论
附加资源

介绍

在立体视觉中,人类的大脑有一种奇妙的能力去看深度。我们使用我们的两只眼睛,它们彼此分开,位于头部的两侧,这使我们能够以三维方式感知世界:高度、宽度和深度(即,相对于周围环境的前后位置)。这项技能并不是人类独有的——正如在 第一部分 中强调和举例说明的那样;许多动物以各种方式使用立体声!尽管如此,建模立体计算已被证明是一个具有挑战性的壮举。从监督建模的角度来看,困难在于所需的数据集,这些数据集必须包含表示目标场景和组成深度网络的各种对象的信息。我们探讨了这些挑战以及研究人员旨在克服的基于深度学习的方法的最新进展。

从第 1 部分,让我们回忆一下极线假设:场景包含两个已知内在属性(即镜头的焦距 f 和外在属性(即左右摄像机的光学中心之间的距离称为基线 b )的摄像机。提供了预测的视差 D ,简单的几何图形被用来重建在捕获图像时丢失的深度尺寸(即 z )。

在这一部分(即第二部分)中,我们回顾了 2015-2020 年间基于深度学习的深度估计方法的进展。未来的部分(即 3、4 和 5)将涵盖最新和最大的(即 2021–2022),基于视频的深度立体方法(即多视图立体(MVS)),并在子像素级别产生相应的置信度。

背景资料

立体视觉

立体的基础——极线几何中更深的深度、图像校正和其他对初学者来说不太重要的数学细节(即,主题本身,如果需要,稍后再返回)将在本系列的第 1 部分中讨论。如果不理解下面的陈述,鼓励读者阅读前面的部分:

深度知觉的重要性及其古老起源视差的定义深度线索的概念以及人类如何自然感知 ( 提示: 两只【立体】眼睛);视差和深度之间的关系,以及如何从一个空间变换到另一个空间在两个(即,左和右)图像中提供了相应的像素;在之前假设了什么参数和条件(即,获得内部和外部参数,以及校正的立体图像对)。

深度监督学习

端到端有监督的深度学习在很多年前就已经成为主流*。它以之前无法想象的方式登上排行榜榜首。问题类型(即任务评估)的增长源于深度学习的成功,因此也是大数据时代的启动。也就是说,基于梯度的端到端深度学习概念可以追溯到 20 多年前[1]。然后,在 2012 年,辍学的概念遇到了大数据,缓解了过度拟合的问题,通用 GPU (GPGPU)的计算能力,允许矩阵数学在数千个内核上并行执行,为我们许多人在 2012 年提到的开创性工作铺平了道路[2]。然而,deep nets 又花了三年时间才在 2015 年提出用于补丁级别的深度重建[3],又花了一年时间提出图像级别的端到端系统[4]。*

在开始有监督的深度学习方法的旅程之前,让我们先定义一些重要的概念。非端到端端到端描述了最高级别的学习方法:端到端意味着输入直接映射到最终输出,这是一个通过反向传播从一个信号学习的权重函数,该信号从端到端回溯。端到端是当今首选的培训方式,因为目标指标中最令人兴奋的特性是通过优化获得的。相反,非端到端不学习从输入空间到输出的映射,而是依赖于中间步骤,这些中间步骤通常由人工设计来调整,因此可能不是最佳的。下图列出了两者的特征。

传统非端到端方法和现代端到端学习方法的特点。作者创造了可视化。

除了我们复习的第一种方法(即 MC CNN )之外,这部分涵盖的方法都是监督式端到端深度学习方法。尽管 MC CNN 是一个深度神经网络,我们很快就会知道,该模型将面片级输入对映射到视差空间,这意味着将视差面片估计融合到图像所需的额外步骤是不可学习的。因此, MC CNN 不是一个端到端方法。

**注意。**假设读者对深度学习概念有基本了解,主要是监督方法。最后的补充部分提供了由三部分组成的介绍性系列的链接。

立体视觉的深度监督学习

当设计用于深度估计的深度网络时,遵循两种一般的拓扑监督方法:编码器-解码器架构(图 1 )和在连体 CNN 之上使用成本体积正则化的方法(图 2 )。无论如何,输入空间是立体对(即,左和右 RGB 图像),并且输出是由最小和最大视差限定的相应视差 D :除非另有说明,否则视差等级的数量是离散的并且是已知的,因为假设图像对被校正。目标是最小化实际和预测视差映射之间的差异。

上面列出的假设应该是有意义的:视差Dserves 是在其 D 的空间中学习的(即,封闭形式的分类),而离散特征代表点从左到右沿水平方向移动的像素数量(即,整数个像素)。如何在亚像素级别获得鲁棒性:敬请关注,在本博客结束之前你将会有答案:)

***图一。*编码器-解码器拓扑的高级示意图,其中模型学习将立体对映射到相应的视差图。作者创造的人物。

***图二。*模型的典型视图的高级表示,通过融合左右图像的特征来调整以产生最佳视差图,从而形成成本体。作者创造的人物。

现在让我们开始具体方法的回顾。从 Zbontar 和 Lecun (2016)开始,我们将涵盖方法。

MC-CNN

Jure Zbontar 和 Yann LeCun。“通过训练卷积神经网络来比较图像块的立体匹配。”* J .马赫。学习。第 17.1 号决议 (2016 年)。*

介绍

第一个为深度估计提出的监督深度学习框架是 MC CNN 。由于学习从立体对到视差空间的逐像素(即密集)映射的巨大复杂性,作者使用了图像补片。尽管如此,MC CNN的概念对于后面介绍的端到端方法是必不可少的。换句话说, Jure Zbontar 和 Yann LeCun 推出了 MC CNN ,开始了我们即将走的路。很明显,MC CNN* 的部分内容启发了我们接下来的工作。*

学习从立体对到视差图的映射。请注意,最靠近相机的物体具有更大的差异:暖色的差异更大,因此深度更小——来源:原文。

方法

MC CNN 是将立体图像对映射到相应视差的面片级方案。如下图所示,该系统模拟了传统立体视觉技术的典型步骤。

用于生成视差图的管道。来自左和右图像的标记为红色和蓝色输入(最左侧)的小块被馈送到 CNN,为此产生具有**通道(每个视差值一个)的特征,表示在小块的相应位置处 d 的成本。来源:原创论文。

目标是为考虑中的所有差异 d 计算每个位置p的匹配成本。这样的成本可以简单地确定为关于点 p 的补片之间的绝对差。****

𝐼ᴸ和𝐼ᴿ是位置 p 处的图像强度。𝓝 是固定窗口中以p**—也就是p=(xy ),然后pd=(x-【t70)因此,下图描述了修补程序级别的连体网络。**

MC CNN 的连体架构(快)。注意,对于每个具有共享权重的相似性分数,处理一对 9x9 的面片(即,暹罗网络)。作者创造了可视化。

作者提出了快速(左)和精确(右)的变体。

MC CNN 的作者提出了两个变量,一个是速度(即快**),另一个是准确性(即):对于任何一个,网络拓扑都会产生相似性得分。快速变体完全独立地从左侧和右侧提取特征,允许一个面片的表示被转换一次,然后与其他面片比较几次以生成分数。同时,精确模型在共享分支之前融合特征,通过一系列附加层从连接的特征中学习度量。因此,精确方法必须在每次生成分数时处理两个补丁,而更快的版本可以存储补丁的特征,例如只需在补丁对之间进行点积。**

**作者还表明,像传统的立体匹配方案一样,最大化相关性是最佳的。**此外,相关性计算(即层)在模型的存储和速度方面花费较少。下图从不同的角度显示了管道。

他们采用了一个连体网络,提取每个像素所有可能差异的边缘分布,以学习信息丰富的图像补丁表示。

结果

在 KITTI 2012、KITTI 2015 和 Middlebury 数据集上,精确变体比其所有前辈产生了更低的错误率;快速版本的运行速度比精确架构快 90 倍,误差增加很少。

这些结果表明,CNN 在确定立体声对的匹配成本方面工作良好,甚至在需要实时性能的应用中也是如此。

因此,这个相对简单的 CNN 声称是最先进的(SOA),展示了现代深度学习方法解决经典立体视觉计算机视觉问题的巨大潜力。

概括起来

为了完整起见, MC CNN 被包含在这一部分中,关于用于立体视觉的第一批深度学习方法,因为它是一个开创性的解决方案。但是,它不是一个端到端的解决方案,因为它处理补丁,而不是在映像级别。因此,这种方法的覆盖面被设计得很小。更深入地讨论了处理方法。

赞成的意见

  • 首次尝试使用深度特征学习来解决立体深度估计
  • 一项广泛的研究显示了一种快速和一种精确变体
  • 补丁提供了大量的训练数据

骗局

  • 不是端到端的解决方案
  • 许多手工设计的步骤
  • 无法捕捉全局上下文,因此仍然无法捕捉不均匀和高度纹理化的区域。

纸张和代码

https://arxiv.org/abs/1510.05970

**https://github.com/jzbontar/mc-cnn

流动网络

*Dosovitskiy,Alexey,等人《流网:用卷积网络学习光流》*IEEE 计算机视觉国际会议 (2015)。

动机

当以端到端的方式训练时,深度神经网络学习感兴趣的任务知识的能力处于其最高潜力。虽然最初提出 FlowNet 是为了解决光流(即,本质上类似于根据视差进行深度估计的任务),但它是第一个端到端解决方案。因此,这里的许多概念将在以后直接应用于视差估计。

**注意:**光流是一个视频相邻帧中对应点之间的差值。正如我们所了解的,立体视觉中经常做出的一个假设是输入图像是经过校正的。差异是水平位移的函数。另一方面,光流考虑水平和垂直方向上像素位置的差异。因此,可以在描述由一对立体摄像机提供的场景流的两种类型的知识之间推断几何相似性。关于光流的细节超出了本博客的范围。感兴趣的读者可以在[5]中看到更多关于光流的内容,在[6]中可以看到更具描述性的场景流。最近,一项关于这两个主题的调查发表了[7]。

FlowNet 在空间上和网络的收缩部分压缩信息(即特征),然后在扩展部分细化这些特征。因此,将图像对直接映射到目标输出空间。论文中的下图描述了 FlowNet 的高级概念。

FlowNet 的结构类似于编码器-解码器网络。U-Net [4]计算大小为(1, nrowsncolumns )的正则化视差 d⋆。这种方法的主要缺点是归一化互相关层的计算成本。而且还会产生模糊的视差图:来源— 论文。

方法

如下图所示,Flownet 包括两种网络架构:FlowNetSimple (FlowNetS)和 FlowNetCorr (FlowNetC)。

FlowNetS 将两幅图像连接起来,并将其输入网络。

FlowNetC 是一种不太通用的网络结构,其中每个图像都被送入一个连体网络,其工作方式如下:

  • 分别学习有意义的表示(如边)。
  • 然后,各个分量在相关层中经历乘法面片比较(即,类似于矩阵乘法)。
  • 两个都是乘法面片比较和类似的细化过程的结果。

两种网络架构:FlowNetSimple(顶部)和 FlowNetCorr(底部)。绿色漏斗是图 3 中显示的扩展细化部分的占位符。网络包括细化部分都是端到端训练的—来源 : 原论文并由作者修改。

两个特征图之间的乘法块比较由相关层进行。给定𝖿₂𝖿₁的两幅多通道特征图,宽度 W ,高度 H ,通道数 C,第一幅图中以 x₁为中心,第二幅图中以 x₂为中心的两个面片的相关性数学表达式如下。⋆

正方形空间补片的大小为*K* = 2*k*+1

它仍然是许多系统的基本部分:形成成本体积的最佳熔丝信号。

使用输出的卷积图层连接并提取 f₁的要素地图。

  • 他们通过一系列 conv 和合并图层降低分辨率。
  • 作者通过上进化层的解池上进化来细化粗池表示。
  • 上变换的和相应的特征图连接起来,并进行上采样的粗流量预测。

细化粗特征映射到高分辨率预测—来源 : 原始论文。

FlowNet 架构。

结果

摘要

FlowNet 是第一个用于立体深度估计的端到端深度特征学习解决方案(虽然最初是针对光流提出的,但过渡是微不足道的,因为视差是光流的子集)。换句话说,因为视差表示像素沿水平方向的移动,所以光流是帧 tt+ 1 之间在所有方向上的位置变化(即,实数的 2D 矢量表示,与整数值 1D 视差张量相反)。因此,在立体视觉系统中,假设提供了校正的立体对,找到视差的问题需要在相邻对的对中找到光流的子集解决方案。事实上,给定带有摄像机的立体视觉设置,视差张量和光流张量描述了场景流[5],这是对前方场景的更多了解。

FlowNet 的缺点包括:

  • 归一化互相关层的高计算成本。
  • 产生模糊的视差图。

尽管如此,深度学习、端到端、监督学习范式中差异模型的演变,FlowNet 引入了将启发其他人的概念(如本博客结尾所示)。

纸张和代码

https://github.com/ClementPinard/FlowNetTorch

iResNet

通过特征恒常性学习视差估计。 IEEE 计算机视觉和模式识别会议论文集。2018.

动机

梁等人考虑立体视觉系统的传统步骤,如本系列的第 0 部分中所介绍,并在上面列出(立体方法学)。网络架构包括对应于立体匹配的每个步骤的模块。下图显示特征提取视差估计细化模仿传统方法。

方法

建议网络的架构将立体匹配的所有四个步骤整合到一个网络中。为了更好的可视化,他们省略了编码器和解码器在不同尺度上的跳跃连接——来源 : 原文。

特征恒常性是指特征空间中两个像素的对应关系。

跳过连接允许推断视差图的约束解。

  • 当对匹配成本执行视差估计时,子网捕获低级语义信息。

f ꜀充当特征间的相关性, re 重建误差,产生第一视差 disp ,而 disp ᵣ 为细化视差。

**迭代网络。**视差细化阶段的输出可以是第一视差预测,并且因此直接回到视差细化模块中。作者发现 2-3 次迭代可以改善结果,这会影响最后的地图。

**它是如何工作的?**如上面的数学公式所表达的,精确的视差显示 ᵣ.

关系左侧三项的结果。具体来说,第一个特征恒定性项、 f 、是左右特征图之间的相关性:度量两个特征图在所有视差级别上的对应性。因此,第一项越大,特征越相似。第二项 re 是多尺度融合特征之间的绝对差值。他们发现了特征空间中的重建误差,而不是像素,这是这项工作之前的惯例(例如,CRL)。最后,我们有第三项,初始视差估计,显示 ᵢ或者仅仅是显示

结果

系统和子系统变体的现场流量结果如下表所示。

**来源:**原论文。

接下来是单尺度和多尺度的比较。

**来源:**原文。

最后,在场景流的错误、大小和运行时方面与 SOA 进行比较。

**来源:**原论文。

我们可以在从称为视差估计子网络(DES-Net)的第一模块提取的特征中看到 re 的有效性,与像素相反。DES-Net 学习一种表示以传递给第二模块,称为差异细化子网(DRS-Net)。因此,可以假设从 DES-net(向下)传播的误差是由于重建误差和初始差异(见上面绿色和红色矩形中间并排的绿色和红色矩形,分隔 DES-Net 和 DRS-Net)。他们将 disp 输入到 DRS-net,通过细化进行改进: disp 是第一个首字母,然后通过 DRS-net 创建 disp' ,通过以下方式确定残差

其中迭代次数(即细化步骤):

作者发现,2–3 会挤压所有潜在的性能(即最适合设计的性能)。

在不同迭代的场景流测试集上进行视差细化。第一行是输入图像,第二行示出了没有改善的初始视差,第三和第四行示出了在 1 次和 2 次迭代之后的精细视差。第 5 行给出了地面实况的悬殊——来源 : 原创论文。

下表中使用 KITTI 2012 和 2015 数据集进行的比较说明了 KITTI 的定性比较。

**来源:**原论文。

**来源:**原文。

**来源:**原论文。

KITTI 2015 上与 SOA 的比较。第一行中的图像是来自 KITTI 2015 的输入图像。我们的 iResNet-i2 细化结果(第 3 行)可以显著改善初始视差(第 2 行),并给出比其他方法更好的可视化效果,尤其是在图像的上部,在该区域没有地面真实—来源 : 原文。

摘要

纸张和代码

https://github.com/leonzfa/iResNet

几何和上下文网络

深度立体回归的几何与情境的端对端学习。IEEE 计算机视觉国际会议论文集。 2017。​

动机

  • 据观察,立体算法的几个挑战将受益于知道全局语义上下文而不是局部几何。
  • 目的是学习端到端的立体回归模型,以理解更广泛的上下文信息。​

理解全局语义和几何将减轻问题,因为更广泛的上下文将受益于像反射这样的障碍。

方法

**来源:**原创论文。

  • 从校正的立体对进行端到端学习以估计亚像素视差。
  • 它形成了利用问题几何的可区分成本量。
  • 通过跨成本体的多尺度三维卷积学习上下文。
  • 评价视差曲线的可微软 ArgMax。

接下来,我们将逐步完成构成 GC-Net 的模块,上图与 stereo methods 的原始算法(即工作流)相关。

用突出显示的模块描绘原始图[图来自作者修改的论文]。

特征提取:

如今,我们使用特征表示,而不是从原始像素强度计算成本。然后,比较对光度外观中的模糊性稳健的描述符,并捕获局部上下文。作者将这些特征称为一元特征。利用的优势

原始论文中的表格。

  • 步长为 2 的卷积滤波器对输入进行二次采样,以减少计算需求。
  • 之后,八个残差块由两个3×3卷积滤波器串联而成。
  • 在左右网络之间共享参数以学习相应的特征。

成本量

  • 成本体积的大小H×W×(Dmax + 1)×F
  • 这是通过将每个一元特征与它们在每个视差级别上来自相对立体图像的对应一元特征连接起来并将其打包到 4D 体积中来实现的
  • 它赋予网络学习语义的能力。

场景流数据集包含来自一系列合成场景的 960 × 540px 的 35,454 幅训练图像和 4,370 幅测试图像。我们比较不同的架构变体来证明我们的设计选择。结果强调了原始论文的 3-D 卷积架构来源的重要性。

软 Argmin

立体算法从一元的匹配成本中产生最终成本量。体积通过最小化成本来估计差异,例如在成本体积差异维度上的 argmin 运算。但是,使用标准的 argmin 操作有两个问题。

  1. 它是离散的,并且不能产生子像素视差估计。
  2. 因此,该模型是不可微的,并且不能使用反向传播来训练。

作者引入了操作的软版本来缓解这些问题。我们称之为软 argmin ,数学定义如下。

其中dₘₐₓ*t14】是最大差异 *d,和期望值(即 sigma)是

这种损失类似于 bahda nauet al**soft attention【1】,一种soft arg max【2】的否定变体。后者扩展了[3]中使用的操作,通过高阶统计扩展损失(即,最小化预测和预期之间的差异,并优化置信度)。从统计学上讲,基于一阶矩(即预期值)的损失通过二阶矩(即方差)获得信息。旁注:对上述内容的深入探究在未来博客想法的列表中,所以请继续关注;)

  • 为了克服这些限制,我们定义了一个软 argmin,它是完全可微的,并且能够回归一个平滑的视差估计。
  • 首先,我们通过取每个值的负值,将预测成本 cd(对于每个差异 d )从成本量转换为概率量。我们使用 softmax 运算σ()对视差维上的概率体进行归一化。然后,我们对 D 进行求和,并按其归一化概率进行加权。

**软参数操作的图形描述。**它沿着每条视差线获取一条成本曲线,并通过对每个视差的 softmax 概率与其视差指数的乘积求和来输出 argmin 的估计值。( a )表明,当曲线为单峰时,这准确地捕捉了真实的 argmin。( b )示出了当数据是具有一个峰值和一个平坦区域的双峰时的故障情况。( c )如果网络学会预缩放成本曲线,则可以避免这种失败,因为 softmax 概率会更极端,产生单峰结果。

  • 然而,与 argmin 操作相比,它的输出受所有值的影响,这意味着它容易受到多峰分布的影响,因为最不可能得到支持。相反,它将估计所有模式的加权平均值。为了克服这个限制,网络进行调整以产生单峰差异概率分布。
  • 网络还可以预先调整匹配成本,以控制归一化后的 softmax 峰值(有时称为温度)。

损失函数

  • 使用 GT 视差 dₙ和像素 n 的预测视差 dHat ₙ之间的 L₁训练模型

  • 回归模型允许基于光度重投影误差的无监督学习损失。

结果

定量结果

定性结果

摘要

  • 根据合成数据进行预训练(即 SceneFlow [5])。
  • 回归通过分类差异获得 SOA。
  • 学习的端到端优于学习的一元特征+半全局匹配(即 MC-CNN [1])。
  • 使用几何图形学习成本卷明显优于其他端到端(即 DispNetC)。
  • 该模型的推理速度相对较快。

纸张和代码

链接到论文[ arXiv ]。

https://github.com/zyf12389/GC-Net

金字塔立体匹配网络(PSMN)

常、贾仁和。"金字塔立体匹配网络."IEEE 计算机视觉和模式识别会议录。2018.

动机

深层神经网络中的经验感受野远小于理论感受野。其他方法依赖于基于补丁的连体网络,缺乏利用上下文信息在不适定区域中寻找对应的手段(见下图)。

红色十字表示图像中心像素的感受野。基线:没有扩张的 conv,没有 SPP,没有堆积的沙漏。完整设置:扩张 conv,SPP,堆叠沙漏。该图是从原始论文中复制的,并由作者进行了修改。

方法

  • 引入了金字塔池模块,用于将全局上下文信息合并到图像特征中。
  • 堆叠沙漏 3D CNN 扩展了成本体积中上下文信息的区域支持。

提议的 PSMN 框架。这张图是从原图上复制和修改的。

左和右输入立体图像是由四部分组成的两个权重共享管道的输入:(1)特征映射函数(即 CNN);(SPP 模块,用于通过连接不同大小的子区域来获取特征;(3)用于特征融合的卷积层;以及(4)左和右图像特征用于形成 4D 成本体,该成本体传递到 3D CNN 用于成本体规则化和视差回归。最终输出是预测的视差图。下图描述了完整的系统。

图来自原论文。

因此,有两个主要模块:空间金字塔池和 3D CNN:

  1. 空间金字塔汇集模块通过聚合不同比例和位置的环境来形成成本量,从而利用全球环境信息的容量。
  2. 3D CNN 学习使用有中间监督的堆叠沙漏网络来调整成本量。

现在,让我们仔细看看这两个。

步骤 1:从左/右图像计算特征

  • 使用多尺度池不再 9✕9 补丁。
  • 每个级别的不同滤镜以原始分辨率工作。
  • 然后,每一个都被汇集成不同的大小。
  • 另一个 conv 然后向上采样到原始分辨率。

特征向量结合了具有不同感受野的过滤器,但是增加感受野的空间汇集减少了可学习的参数。

获得左右图像的每个像素的特征向量。

第二步:构建成本量

  • 然后,我们对每个左右图像都有大小为*H*✕*W*✕*F*的特征张量。
  • 构建一个大小为*H*✕*W*✕*D*✕2*F*的成本卷

  • 在这一点上,这个网络与 MC-CNN 的不同之处仅在于它如何获得这些功能。
  • 他们的方法相当于为每个成本体积应用一堆完全连接的层,从特征到单个分数,即*H*✕*W*✕*D*✕2*F H*✕*W*✕*D*✕1

第三步:流程成本量

3D 卷积层与剩余连接串联。

  • 5D 核而不是 4D 喜欢正则卷积。视差空间中的平移不变量: dd +1 之间的关系与*ď*, *ď*+1之间的关系相同。

第四步:成本量对差异

  • 他们将最终的*H*✕*W*✕*D*(×1)张量视为前 softmax 分数。
  • 因此,进行软最大值给出了可能的视差值的概率分布。
  • 但是他们不会用分类损失来训练这个:因为一些错误分类比其他的更糟糕!(d=5 而不是 4 比 d=25 而不是 4 要好)。

所以,他们对这个分布有期望!

损失函数

  • 使用 soft argmin 获得 GC-Net 中提到的所有好处
  • GC-Net 使用 L₁作为惩罚指标

○ L₁损失对异常值不太敏感

○通过回归学习无界目标,L₂必须仔细调整

  • 类似于快速 R-CNN(即 BB 回归),SPP 使用以下平滑 L₁变量

  • 使用类似 GC-Net 的视差回归来估计连续视差图。

○通过 softmax 运算σ()从预测成本 c ₔ计算每个差异 d 的概率。

预测视差ᶺ d-hat 计算为每个视差 d 的概率加权总和(2)

○上述视差回归比基于分类的立体匹配方法更鲁棒。

●与 R-CNN 和 SPPnet 中使用的 L₂损失相比,稳健的 L₁损失对异常值不太敏感。当回归目标无界时,使用 L₂损失的训练可能需要小心的学习率以防止爆炸梯度。情商。3 结束这种敏感性。

结果

“KITTI 2012 测试图像”的视差估计结果左图显示了立体图像对的左输入图像。PSMNet、GC-Net 和 MC-CNN 获得的每个输入图像的视差显示在其误差图上方。

为 GC-Net 及其前身显示的 KITTI 2012 测试图像的视差估计结果。左侧面板显示立体图像对的左侧输入图像。以下是 PSMNet、GC-Net 和 MC-CNN 针对每个输入图像获得的视差以及相应的误差图。

结果

摘要

优点

先前的 DL 立体匹配方法的一个问题是上下文信息。GC-Net 是一个用于立体匹配的端到端学习框架,无需后处理,它采用编码器-解码器来合并多尺度特征以实现成本体积正则化。

引入了金字塔池模块,用于将全局上下文信息合并到图像特征中

一个堆叠沙漏 3D 有线电视新闻网,用于成本卷中上下文信息的扩展区域支持。

缺点

大量足迹和耗时的推断

纸张和代码

https://github.com/JiaRenChang/PSMNet

ModuleNet

伦特里亚,奥克塔维奥&奎瓦斯-泰洛,胡安-卡洛斯&雷耶斯-菲格罗亚,阿兰&里维拉,马里亚诺。ModuleNet:用于立体视觉的卷积神经网络。10.1007/978–3–030–49076–8_21.(2020).

动机

  1. 受 FlowNet & U-Net 的启发,一个衡量任何范围内差异的模型。
  2. 使用低计算时间算法来测量成本图。
  3. 架构很简单,因为它不需要任何额外的专门网络作为不同的 FlowNet 的变体进行优化。
  4. 它改进了基线模型 ELAS [3]和 FlowNet c(FlowNet的相关版本),具有大约 80%的非偏倚误差。

U-Net 块由函数 F₁: F₁表示,对噪声普查距离图进行正则化。

一般块(U-Net)捐赠为 F接受距离张量 D 映射自 图像对 I 然后转换为概率 P

方法

普查转换

对于左图ₗ;类似的, C ᵣ为右像 I ᵣ.汉明距离(H)计算两个普查签名之间的不同位数:

让我们举例说明具有代表性的₁. u-net

数学上:

距离张量中的信息。

D 通过 F ₁.映射到概率 P

概率张量(模型输出)

𝜃₁代表训练期间学到的重量。

第二个 U-Net 可以改进主要(训练的)模块的输出。函数ft53】也使用距离张量 D 作为输入来提炼概率张量 p:

𝜃₂学会了举重。

因此,

基本块由两个 U 型网级联而成。

请注意,网络 F i s 重新用于处理 K 模块。

最后是视差估计。

通过在差异图ŷ中应用 WTA 程序来计算 d⋆。

ModuleNet:模块化 CNN 模型。 来源: 原创论文。

结果

所选场景的 MPI Sintel 数据集的结果。 来源: 原创论文。

所选立体像对上的 Middlebury 数据集的结果。 来源: 原创论文。

**注意:**用于检测范围外差异的额外层有助于对添加噪声的像素进行分类,因为这些像素在工作范围之外或者是被遮挡的区域。

摘要

纸张和代码

代码不可用!:(

如果有,请分享!

GA 网

动机

性能插图。(a)具有挑战性的输入图像。(b) GC-Net [13]有 19 个 3D 卷积层用于匹配成本聚集。(c)GA-Net 的结果仅使用两个建议的 GA 层和两个 3D 卷积层。它将匹配信息聚集到相当大的无纹理区域,并且比 GC-Net 更快。(d)基本事实。 来源: 原创论文。

方法

(a)架构概述。左和右图像输入通过权重共享特征提取管道。它由层叠的沙漏 CNN 通过级联连接而成。所提取的左和右图像特征形成了 4D 成本体,该成本体被馈送到成本聚集块,用于正则化、细化和视差回归。制导子网(绿色)为制导成本汇总(SGA 和 LGA)生成权重矩阵。(b) SGA 层在四个方向上半全局地合计成本量。在视差回归之前使用 LGA 层,并且局部细化 4D 成本量若干次。 来源: 原创论文。

结果

城市景观(上)和米德尔伯里(下)的样本结果。来源:https://github.com/feihuzhang/GANet/。

结果可视化和比较。第一行:输入图像。第二行:GC-Net 的结果[13]。第三行:PSMNet [3]的结果。最后一行:我们遗传网络的结果。蓝色箭头指出了显著的改进。引导聚合可以有效地将视差信息聚合到大的无纹理区域(例如,汽车和窗户)并给出精确的估计。它还可以聚合对象知识并保留深度结构(最后一列)。

摘要

纸张和代码

https://github.com/feihuzhang/GANet

讨论

摘要

我们看了深度学习时代立体视觉进步的几种基本方法。每种技术都有动机,技术上的审查,以及原始论文和官方源代码。

不同于传统的调查,在传统的调查中,专家正确地写下了一个特定的主题,这里提供的是来自学习立体视觉的人的基于方法的概述。换句话说,这并不是要以任何方式取代同行评审调查,而是在一个不太正式的会议上提供一个更容易阅读的、针对具体方法的概述。如果你想查看我们发表的关于另一个计算机视觉主题的文献,请查看我们的 IEEE PAMI 调查。

资料来源:视觉亲属关系分析和建模调查:酝酿中的十年。由作者创作。

未来的工作

我们讨论了使用监控的基于图像的立体方法。本系列的后续部分将涵盖基于视频的(即多视图立体视觉)、多任务、自我监督、公共数据集、基准和基准,以及关于生成相应置信度映射的最后一部分。敬请期待!

结论

我们讨论的深度学习方法只是解决计算机视觉问题的许多新方法中的几个。如果你不了解深度学习基础,这篇博文可能不适合你。另一方面,如果您正在寻找将立体图像映射到深度图的端到端解决方案,无论是为了工作、个人项目还是研究,本博客系列可能是您的起点。无论如何,考虑在你的产品或服务中采用深度学习技术可能是值得的。上面讨论的哪个模型对你最有意义,或者是你的首选?您希望我在未来的部分中包含哪些方法?你喜欢什么,不喜欢什么?任何反馈、问题、请求等。,将不胜感激。

补充资源

PSM 网络是使用 PyTorch Lightning 实现的。

https://pythonrepo.com/repo/xtliu97-PSMNet_PytorchLightning-python-deep-learning

查看 FlowNet 上的深度博客:

GA-Net:Youtube 上端到端立体匹配的引导聚合网络。

补充的

  1. Dhanoop Karunakaran aran 编写了一个由 3 部分组成的博客系列,内容是使用深度学习(第 1 部分)进行图像分类(第 2 部分)和检测/定位图像中的交通标志(第 3 部分)。有大量具有足够深度和广度的资源,即使是忙于学习 SOA 的专家也能深入理解。因此,博客系列在相对较短的系列中提供了动机、视觉、数学和概念观点的良好平衡。张量流用于在证明和概念之间架起理解的桥梁。

参考

  1. Y.LeCun、L. Bottou、Y. Bengio 和 P. Haffner。"基于梯度的学习应用于文档识别."IEEE 会议录,86(11):2278–2324,1998 年 11 月。
  2. Alex Krizhevsky,Ilya Sutskever 和 Geoffrey E. Hinton“使用深度卷积神经网络的图像网络分类”在神经信息处理系统进展 (2012)。
  3. Bahdanau、Dzmitry、Kyunghyun Cho 和 Yoshua Bengio。"通过联合学习对齐和翻译的神经机器翻译."在 ICLR (2015)。
  4. 盖革、安德烈亚斯、马丁·罗瑟和拉克尔·乌尔塔森。“高效的大规模立体匹配。”亚洲计算机视觉会议。施普林格,柏林,海德堡,2010。
  5. 将立体视差和光流结合起来用于基本场景流。商用车技术 2018 。斯普林格,2018。90–101.
  6. 门兹、莫里茨和安德烈亚斯·盖格。"自动驾驶车辆的物体场景流."IEEE 计算机视觉和模式识别会议论文集。2015.
  7. 翟,,等,“光流和场景流估计:综述”模式识别 114 (2021): 107861。
  8. 罗恩伯格,奥拉夫,菲利普费舍尔和托马斯布罗克斯。" U-net:生物医学图像分割的卷积网络."医学图像计算和计算机辅助介入国际会议。施普林格,查姆,2015。**

我必须懂数学才能进入数据科学世界吗?

原文:https://towardsdatascience.com/do-i-have-to-know-math-to-enter-the-data-science-world-89a92bd800a2

我个人对这个 FAQ 的回答。

杰斯温·托马斯在 Unsplash 上的照片

我开始学习数据科学已经一年多了。这一切都是因为好奇而开始的,但后来我获得了一种快感,这种快感让我为了职业的飞跃而学习(尚未完成)。

当我几乎每天都在学习和实践时,我对这个领域的热爱让我分享我获得的知识(当然,我这样做甚至是为了分享的快乐)。

在 Linkedin 上分享信息让我收到了连接请求,大多来自那些想了解更多数据科学的人,因为他们很好奇,想知道这个领域是否适合他们。人们问我的典型问题是:“我必须懂数学才能进入数据科学吗?”或者:“我需要知道多少数学知识?”

我知道这个问题很常见,想给刚开始学习的人一个我个人的回答。

1.学习编程不需要懂数学

一开始的一个大惊喜是:如果你想学习数据科学,你首先需要学习编程。

选了一门课就开始编程。什么课程什么编程语言都无所谓(我建议 Python,因为它甚至大多用于非 DS 的东西,你可能只是喜欢 Python 而不喜欢 DS)。

但是事情是这样的:**学习编程不需要懂数学。**编程只是……编程!不是“在数学上做操”。当然,如果你有解决逻辑问题的习惯,你将处于优势;但是,你知道,解决问题的能力是一种普遍的能力,你可以通过实践来学习。

我的具体建议是从头开始。从 0 开始学习编程。学习函数,列表,元组,ad 等等。在几个星期内完成基础部分,当你有一点满意的时候,继续。

当然,如果你像我一样,你可能会有一点困难;事实上,当我接近一个新的领域并发现我喜欢它时,我每天都想知道更多;我对知识如饥似渴,我必须尽快满足它。在这种情况下,要玩的游戏非常简单:在解决自己的实际问题的同时,学习自己需要的东西。

DS(更一般地说,编程)的魅力在于你可以创造自己的问题并解决它们,从而获得经验。

所以:从 0 开始编程,然后“自己创造问题去解决”。您是否需要进行一些计算并报告结果,将它们附加到 excel 文件中?好:学会怎么做!这是一个获得经验的很好的练习;相信我。

2.开始分析一些数据

学习编程几周后,开始分析一些数据。你有一堆可能性去做:上一些课程,继续 Kaggle,等等。

即使在这里,你决定如何开始并不重要:开始!如果你不喜欢这门课,或者觉得它对你来说太复杂(或太简单),你可以改变它。

这里的问题是:你需要懂点数学。是的,我的朋友,我必须告诉你:要分析数据,你需要懂数学;不要相信任何与你相反的人。但是有一个好消息:如果你不懂数学,你可以在需要的时候学!

在这个阶段,你将需要统计学的基础知识:均值、中值、正态分布等等。如果你不知道它们,当你需要它们的时候,自己去学吧。网上有一堆资料(还有上千的数学课程):需要的时候学,做项目的时候练,理论联系实际掌握。

如果你感到不知所措,不要害怕:你不需要知道一切。

告诉你一个秘密:没有人什么都知道

跟我重复一遍:没有人知道一切。这必须是你的口头禅,否则你会迷失在这个领域。

外面有很多懂很多数学和统计的人(很多数据科学家都是数学/统计出身);事实是:这些人中有很多来自研究领域(通常,他们有博士学位),但是“日常现实”很简单,你不需要知道统计学家知道的数据科学中的数学!

所以,从简单开始,每天坚持练习,在你需要的时候研究你需要什么,几个月后你会看到结果;相信我。

是的,我有工程背景,但我在工程学习期间从未上过统计学课程:我是在学习数据科学的同时自学的,在需要的时候研究题目。这很有效,相信我;你也不会有那种什么都要知道的感觉,那种感觉可能会让你停滞不前,让你放弃学业。

3。机器学习

我想从一开始就明确:要实践机器学习,你必须知道很多数学知识。机器学习“做事情”,“在这些事情背后”有大量的数学。

你不能将算法应用于数据集,然后祈祷结果是好的;这样不行。记住:垃圾进,垃圾出(你的第二个口头禅!).

机器学习算法不能成为你的黑匣子:你必须明白你在做什么!但是有一个好消息:你可以在学习机器学习的同时学习需要的数学。

我举的一个典型例子是梯度下降。如果你学过微积分,当你听到“梯度”这个词时,你就知道我们要讨论导数、切线和最大/最小点。但就是这样!如果你不知道什么是导数,你不需要解决 876 个关于导数的练习(就像我在高中和大学做的那样):只要理解你需要的题目并继续下去。然后,练习,练习,还有……练习掌握算法。

结论

如果你想进入数据科学领域,你会问自己“要进入这个领域,我需要懂数学吗?”我的回答是:没有,但是有。

不,你不需要知道所有你需要的数学知识。

但是,是的,在一定程度上,你需要学习数学,你需要理解与数据科学相关的主题。

从学习编程开始,然后每天继续学习你需要的东西(关于编程和数学)。不要害怕你不知道的事情:没有人知道所有的事情。开始吧,看看进展如何……享受你的学习之路!

我知道你可能会感到不知所措:从机器学习课程开始,获得代数课程,返回到机器学习,学习微积分课程,等等……但请记住:学习过程就像建造房子:一砖一瓦,从基础开始,你会到达屋顶。日复一日,没有匆忙,没有喘息。没有别的办法。

让我们连在一起!

中等

LINKEDIN(向我发送连接请求)

如果你愿意,你可以 订阅我的邮件列表这样你就可以一直保持更新了!

考虑成为会员:你可以免费支持我和其他像我一样的作家。点击 这里成为会员。

神经网络会梦到落雪吗?

原文:https://towardsdatascience.com/do-neural-networks-dream-of-falling-snow-89b5036ae324

发展基于深度学习雷达的降水反演

DeepPrecip 网络计算机图形渲染 Graphcore 和 Author 提供的图像

机器学习(ML)在地球科学中的应用并不是一个新概念。自 20 世纪 60 年代中期以来,k-means 聚类、马尔可夫链和决策树的早期示例已经在多个地理环境中得到积极应用( Preston 等人,1964克鲁姆宾等人,1969纽恩多普,1976 年

然而,来自 Graphcore 、 Amazon 和 Google 等公司的云计算资源的进步,加上对强大的 ML 库(例如 Tensorflow 、 Keras 、 PyTorch )和蓬勃发展的开发人员社区的轻松访问,使得这一新兴领域近年来大受欢迎( Dramsch,2020 )。

现在,最大似然模型不仅经常用于地球科学中的业务预测(Ashouri 等人,2021 年),还用于统计推断;没有与自然过程的物理模型模拟相关的传统不确定性( King 等人,2022 )。

问题是

降雪是全球水循环和能量循环不可或缺的组成部分,对区域淡水可用性有重大影响( Musselman 等人,2021Gray 和 Landine,2011 年。事实上,每年有超过 20 亿人(全球人口的六分之一)依赖融雪产生的淡水供人类消费和农业用途( Sturm 等人,2017 )。随着全球平均气温持续上升,预计降雪频率和强度也将发生变化,从而导致全球范围内新的水资源管理挑战( IPCC,2019 )。

然而,传统的降雪模型在估计中有很大的不确定性,因此应该研究新的算法来促进我们对全球降雪模式变化的理解。

智利托雷斯海峡上空可见复杂的降雪——图片由作者提供

因此,让我们探索一下 ML 是如何被用于推进降雪预测领域的,以及这些技术在未来可能会走向何方。

我们的解决方案

这篇帖子顶部的插图是 DeepPrecip 。或者更准确地说,是 DeepPrecip 计算图的渲染,它构成了模型决策过程的基础。

DeepPrecip 是一个深度卷积神经网络(CNN ),由滑铁卢大学开发,由400 万可训练模型参数组成!我们使用该模型的目的是评估在不同的地区气候下,我们如何利用地面雷达数据输入来预测地表降雨量( King 等人,2022–2)。这种类型的模型被称为“降水”反演,因为该模型的输入是大气雷达观测值(即从下落的水凝物反向散射的能量),它输出关于地面雨雪的预测。

但是如何利用大气雷达后向散射强度来推断地面降水量呢?

我们必须找到一种方法,从感兴趣的部分相关的大气变量(在这种情况下是雷达反向散射强度)中提取非常具体的降水信息。这可以通过两种方式实现:

  1. 通过一个基于物理的模型,模拟大气中发生的导致冰晶形成和最终降雪的物理过程。
  2. 经验统计过程(如 ML 模型),可以发现不同变量之间的模式,通过正向模型显示彼此之间的一些敏感性。

虽然这两种技术都有各自的优缺点,我们可以用整篇博文来讨论,但在本文中,我们将重点讨论第二种方法。但首先,什么是正向模型*?*斯蒂芬斯于 1994 年提供了一个经典的例证:

“假设你想要描述一条龙,但你只观察到龙在沙地上留下的脚印。现在,如果你已经了解龙,你可以很容易地描述它可能在沙子上留下的痕迹;也就是说,你可以开发一个正向模型。但是如果你只观察沙地上的痕迹,那么描述龙的任何细节都会困难得多。你可能能够分辨出它是龙而不是鹿,但是有些方面你无法辨别:龙的颜色,它是否有翅膀,等等。检索可以将观察结果(大脚印)与先验信息(大多数龙有翅膀,留下大脚印的龙是绿色的)结合起来,以获得最可能的状态(它是一条有翅膀的绿色龙)。”

沙滩上的龙脚印——由盖蒂图片社的 Vishy Patel 拍摄

我们可以利用这个想法将垂直雷达剖面图中的信息与地面降雪量联系起来!由于雷达数据输入有一个物理结构(剖面从地表延伸到大约 3 公里),DeepPrecip 使用了多个卷积层来提取可能的水凝物活动的不同部分之间的特征。这些信息有助于我们的模型理解不同的风暴事件类型和结构,从而提高网络的全连接前馈回归组件中降水率估计强度的准确性。

更正式地说,DeepPrecip 的模型架构如下所示。您能否将此图中的不同模型架构层与之前显示的计算图匹配起来?

DeepPrecip 模型架构图—图片由作者提供

模特培训

为了开发一个稳健的模型,我们首先需要收集雷达数据和同位原位降水测量观测值的代表性训练数据集。请注意,这是一个监督学习问题,因此需要参考数据。

由于地球科学中的问题总是具有挑战性,因此在数据选择阶段必须小心选择有代表性的样本。每个站点还必须配备以相同方式校准的类似仪器。在这项工作中,我们选择了北半球的 9 个站点,用 8 年的时间从微雨雷达(MRR)系统和雨量计收集数据。这些工具的示例如下所示。

MRR 和 Pluvio2 仪器及反射率剖面示例—图片由作者提供

由于我们管理的训练数据集的规模很大(数百万个训练样本),加上模型架构的一般复杂性,超参数优化在开发过程的早期成为我们的瓶颈。在尝试了各种不同的云计算选项后, Graphcore 的系统脱颖而出,成为大幅缩短我们培训时间的绝佳选择。

Graphcore 加速训练的关键是使用了他们专门的情报处理单元(IPUs) 。IPU 是一种全新的大规模并行处理器,用于加速机器智能。计算和内存架构是为人工智能横向扩展而设计的。请注意 IPUs 和传统处理器之间的差异如下:

IPU 架构与其他处理器设计的差异—图片由 Graphcore 提供

硬件与软件一起开发,提供了一个易于使用且擅长实际应用的平台。使用 Graphcore MK2 经典 IPU-POD4(注意,第二代 IPU 现已上市),我们能够将 DeepPrecip 的训练时间比其他最先进的系统(如 Tesla V100s)加快 6 倍。如果你想为你的项目测试 IPU 系统,看看他们的云平台。

DeepPrecip 培训的硬件吞吐量比较—图片由作者提供

选定硬件后,我们需要选择一个优化范例。为了确定 DeepPrecip 的最佳超参数值,我们决定使用一种称为超波段优化的自适应优化形式。这种方法是贝叶斯优化(即自适应搜索)的一种变体,它专注于使用自适应资源分配和早期停止来加速随机搜索过程(李等人,2018 )。这使我们能够测试一个巨大的超参数空间,并快速确定模型参数的正确值。

不同的超参数优化技术—图片由 Talaat 等人提供,2022

使用单个 IPU 对 DeepPrecip 的 14 个不同参数和 68 个不同的总价值选项(即数万亿种可能的组合)进行超波段优化大约需要两周时间。均方误差(MSE)指标(如下)显示了该过程如何智能地选择更好的超参数组合,同时缓慢增加每个周期的周期数。

通过连续的超波段优化步骤改进了模型技巧-图片由作者提供

对于超波段优化过程的每次迭代(或索引),可以使用平行坐标图来呈现这些参数关系的高维可视化(如下所示)。这允许我们在模型架构的复杂性和性能之间找到一个平衡,以产生一个既高效又有技巧的模型。有关此过程以及最终超参数值的更多详细信息,请参见 King 等人,2022–2

每个超参数组合的平行坐标图—图片由作者提供

虽然花费在收集、预处理和正确采样数据上的时间以及 2 周的超参数化过程可能看起来有些多余,但正确执行这些步骤是非常重要的,因为它可以显著降低未来过度拟合问题的可能性。

性能和耐用性

有了一个训练有素的模型,我们能够评估它相对于其他 ML 模型和传统经验关系的一般性能。

总的来说,DeepPrecip 被发现优于其他传统的检索方法,其 MSE 值比其他方法低 40%,T2 比其他方法高 40%。我们还注意到,与其他测试模型相比,DeepPrecip 似乎更有能力正确估计高强度降水的波峰和波谷。使用交叉验证方法,我们发现 DeepPrecip 展示了稳健性,提高了准确预测区域气候站点降雨量的能力,而这些区域气候是该模型以前未见过的。

关于健壮性的最后一点是关键。以前的经验方法的一个主要限制是,每个模型都是为其衍生的气候定制的( Wood 等人,2014 )。因此,虽然一种模式在美国北部可能行得通,但在瑞典或韩国却未必行得通。

基于最大似然的方法的一个实质性好处是,它可以以不受粒子微观物理学的物理假设约束的方式对来自各种不同位置的数据进行训练。我们从该项目中发现,基于最大似然法的地表降雪解决方案显示出低误差和高概化,并且有充分的理由相信,全球最大似然法反演算法可以帮助增强当前基于卫星的产品,这些产品提供了对世界各地降雪量的估计。

飓风上方的全球降水测量(GPM)核心卫星——由 NASA 拍摄

推理

这个项目开始时的目标不仅是开发一个操作模型,而且要解释所述模型,以识别垂直雷达剖面图中对高模型技能贡献最大的区域。

DL 模型通常被认为是“黑盒”算法,其中一些输入被输入到模型中,一些输出出来;不知道这两个阶段之间发生了什么。一些 ML 模型,如随机森林,提供了一个基于每个决策树做出决策的方式的特征重要性排名,但是我们如何为像 DeepPrecip 这样的 DL 模型提取类似的东西呢?

回车, 沙普利值

由 Lloyd Shapley 于 1951 年提出(并以其命名),Shapley 值是合作博弈理论中的一个解概念。这个值代表个人参与者对游戏中某个共同目标的贡献。对于多个参与者,它允许我们测量每个参与者对最终结果的边际贡献。例如,如果多人出去吃饭,每个人点了不同的主菜,如果我们决定分摊晚餐账单,每个人支付的百分比可以根据 Shapley 值分摊。

下面是死亡率风险评估的直观图表,描述了来自大量观察样本的局部解释如何使用 Shapley 值提供关于全局模型行为的见解:

局部解释提供了多种理解全局模型结构的新方法——图片由 Lundberg 等人提供,2020 年

使用上面显示的方法和 Lundberg 等人在2020中更详细地概述的方法,测量局部和全局对某个目标的贡献的过程可以与 DL 相关。我们可以检查模型输入的不同组合(即雷达数据子集,或大气变量组合),以查看模型精度如何变化。然后,这可以用来确定哪些变量,以及在我们的情况下,大气中的哪些位置,为主动检索降雪提供了最重要的信息。请注意,这是一个计算量非常大的分析。

将我们的数据集分成不同强度的降水事件类型,并对每个子集进行 Shapley 分析,揭示了最重要的变量和区域(如下所示;较暗的阴影区域表示较高的重要性)。

表面上方每个垂直条柱的每个模型预测值的 Shapley 值的热图-图片由作者提供

有趣的是,也许出乎意料的是,我们发现 DeepPrecip 认为大气中上部区域(接近 2 公里)是最重要的贡献者。不仅仅是在垃圾箱附近。通常,基于雷达的降雪量反演依赖于来自单个(或少数几个)近地表面元的信息,但在这里似乎不是这样。此外,反射率(RFL)通常被认为是基于雷达的反演中最重要的变量,然而多普勒速度(DOV)对于高强度降水事件的重要性实际上超过了 RLF。请注意,SPW 是光谱宽度,TMP 是温度,WVL 是风速。

理解我们的 DL 模型如何做出决策是进一步优化其性能并在未来迭代中提高其技能的重要一步。此外,这一分析揭示的信息有助于为下一代降水任务的当前和未来降雪反演提供信息。如果您正在用 DL 执行类似的实验,我强烈推荐在您自己的模型上测试这个过程,因为这些输出可能非常有启发性!

总结和结论

DeepPrecip 项目总结和后续步骤—图片由作者提供

在这项工作中,我们简要描述了 DeepPrecip 的发展过程:一种新的利用垂直反射率剖面的深度学习降雪反演算法。虽然我们在这里不讨论 DeepPrecip 的代码,但是这个模型是开源的,可以在 GitHub 上使用。它是使用 scikit-learn 、 Tensorflow 和 Keras 用 Python 开发的。

https://github.com/frasertheking/DeepPrecip

如果您对测试感兴趣,可以使用以下命令构建并运行模型:

git clone [https://github.com/frasertheking/DeepPrecip.git](https://github.com/frasertheking/DeepPrecip.git)
conda env create -f req.yml
conda activate deep_precip
python deep_precip.py

我们还包括一个 deep_precip_ipu.py 模块,用于在 Graphcore IPUs 上运行这个模型。请注意,您将需要 MRR 培训数据作为模型的输入。

我将在这篇文章的结尾说,我不期望 DL 模型完全取代物理模型或传统的降雪反演经验方法。然而,DL 方法的高准确性和稳健性,结合全球模型行为分析提供的见解,有助于增强和通知未来地面和星载雷达任务的降雪反演方法

关于这个项目的更多细节,请阅读我们目前在大气测量技术(AMT)上发表的论文(https://eg sphere . Copernicus . org/preprints/2022/eg sphere-2022-497/)。

此外,如果您愿意支持我们的工作,我们是 NSERC 科学曝光大赛的决赛选手,我们将通过 为我们的形象 投票来感谢您的支持。

承认

我要感谢为这项工作贡献了多年观测数据的许多数据提供商、我的合著者、滑铁卢大学以及 Graphcore 团队,感谢他们对计算系统的持续支持和访问。

我还要感谢加拿大自然科学和工程研究委员会(NSERC)对这个项目的资助。

参考资料:

Ashouri、Hamed、Gehne、Maria 和国家大气研究中心工作人员(Eds)。2021 年 10 月 31 日最后修改。"气候数据指南:PERSIANN-CDR:使用人工神经网络从遥感信息进行降水估算-气候数据记录."

德拉姆施,J. S. (2020)。地球科学中的机器学习 70 年回顾。地球物理学进展61 ,1–55。https://doi.org/10.1016/bs.agph.2020.08.002

格雷,医学博士,男性,教育学博士。(1981).雪手册:原理、流程、管理&使用。佩加蒙出版社。https://snia . mop . gob . cl/repository odga/handle/20 . 500 . 13000/2981

IPCC,2019: IPCC 关于气候变化中的海洋和冰冻圈的特别报告[h .-o . p rtner,D.C. Roberts,v . Masson-德尔莫特,P. Zhai,M. Tignor,E. Poloczanska,K. Mintenbeck,A. Alegría,M. Nicolai,A. Okem,J. Petzold,B. Rama,N.M. Weyer(编。)].剑桥大学出版社,英国剑桥,美国纽约,755 页 https://doi . org/10.1017/9781009157964。

f .金、g .达菲和 C. G .弗莱彻(2022)。基于机器学习的厘米波长降雪反演算法。应用气象学与气候学杂志1 (aop)。https://doi.org/10.1175/JAMC-D-22-0036.1

金,f .,达菲,g .,米兰尼,l .,弗莱彻,C. G .,彼得森,c .,&埃贝尔,K. (2022)。DeepPrecip:降水反演的深度神经网络。平衡球,1–24。https://doi.org/10.5194/egusphere-2022-497

Krumbein,W. C .,& Dacey,M. F. (1969 年)。地质学中的马尔可夫链和嵌入马尔可夫链。国际数学地质协会杂志1 (1),79-96。https://doi.org/10.1007/BF02047072

Li,l .,Jamieson,k .,DeSalvo,g .,Rostamizadeh,a .,& Talwalkar,A. (2018)。 Hyperband:一种新的基于 Bandit 的超参数优化方法 (arXiv:1603.06560)。arXiv。https://doi.org/10.48550/arXiv.1603.06560

Lundberg,S. M .、Erion、g .、Chen、h .、DeGrave、a .、Prutkin、J. M .、Nair、b .、Katz、r .、Himmelfarb、j .、Bansal、n .、和 Lee,s-I .(2020)。从局部解释到对树的可解释人工智能的全局理解。自然机器智能2 (1),56-67。https://doi.org/10.1038/s42256-019-0138-9

Musselman,K. N .,Addor,n .,Vano,J. A .,& Molotch,N. P. (2021)。冬季融化趋势预示着雪水资源的广泛减少。自然气候变化11 (5),418-424。https://doi.org/10.1038/s41558-021-01014-9

Newendorp,P. D. (1976 年)。石油勘探决策分析。https://www.osti.gov/biblio/6406439

普雷斯顿,弗洛伊德 w,和詹姆斯亨德森。地层对比用旋回沉积物的傅里叶级数表征。堪萨斯地质调查局,1964 年。

Stephens,G. L .,1994: *低层大气的遥感:导论。*牛津大学出版社,562 页

Sturm,m .,Goldstein,M. A .,& Parr,C. (2017)。来自雪的水和生命:一个万亿美元的科学问题。水资源研究53 (5),3534-3544。https://doi.org/10.1002/2017WR020840

Talaat,F. M .,& Gamel,S. A. (2022)。基于 RL 的卷积神经网络超参数优化算法。环境智能与人性化计算杂志。https://doi.org/10.1007/s12652-022-03788-y

Wood,N. B .,L'Ecuyer,T. S .,Heymsfield,A. J .,Stephens,G. L .,Hudak,D. R .,& Rodriguez,P. (2014)。使用同位多传感器观测估算雪微物理特性。地球物理研究杂志:大气, 119 (14),8941–8961。【https://doi.org/10.1002/2013JD021303

不要将不寻常的数据点视为异常值

原文:https://towardsdatascience.com/do-not-dismiss-unusual-data-points-as-outliers-5132380f2e67

一些可疑点往往被错误地简化为异常值。其他类型及其检测工具也值得关注。

davisuko 在 Unsplash 上拍摄的照片

定义

语境

垃圾进,垃圾出

这句话概括了中等数据对模型结果的影响。在一个项目中,一个不可或缺的步骤是执行 EDA (解释性数据分析)来检查数据的“清洁度”等。如果没有这一步,有人可能会使结果无效,并要求进行稳健的分析,即处理异常观察的分析。

通常采用的方法是通过箱线图和散点图调查每个变量的单变量分布**。除了给出明显的结论之外,这些技术在多变量环境中可能没有意义,并且不能告诉我们这个异常数据子集如何影响估计模型。**

此外,涵盖术语“异常值”中的所有异常点**是不合适的。**事实上,不同种类的点可能以它们自己的方式影响估计的模型。

为此,除了“异常值,还将引入另外两个术语:高杠杆,以及影响。下一部分,每个术语都将通过例子来阐明。

术语

在回归分析中,这些术语是相关的,除了它们有不同的含义:

  • 影响点:对估计模型有影响的数据子集。移除它似乎显著修改了估计系数的结果。
  • 异常值:超出其余数据一般模式的观察值。在回归分析中,由于高残差,这些点保持在置信带之外。
  • 高杠杆:具有潜在影响预测响应的观察结果。如果我们稍微改变观察到的反应,就可以通过∂y_hat/∂y:评估预测的反应有多大的不同。一般都是极限 x 值。

在深入探讨之前,我们先举一些琐碎的例子来获取要点。

例子

备注: 即使一致性分析需要统计结论(R、p 值、标准差),也将以图形方式进行证明

一.

影响:两条回归线差别不大,估计斜率相似,估计截距比较接近 = >否

异常值:红点似乎有很高的残差吗?是的,而且肯定是脱离了线性模式 = >是的

**高杠杆:**是极限 x 值吗?如果我们沿着 y 轴稍微移动红点,预测的响应会有很大的变化吗?该点接近平均 x 值,并且 y 变化不会严重修改预测响应 = >否

b.

**流入:**两条回归线几乎重叠 = >否

**异常值:**红点服从线性模式,具有低残差 = >否

**高杠杆:**有了这个高 x 值,红点可能在分布的长尾中。此外,如下图所示,当该点稍微向上移动时,预测响应完全变化 = >是

情况 b)在 x = 5 时具有相对小的观测扰动

c.

**影响:**由于红点完全决定了回归线,所以明显有影响 = >是

**异常值:**其余数据不遵循一般模式,因此,在这种配置下,我们无法推断出潜在的异常值 = >?

**高杠杆:**作为主要影响点,观测响应的变化极大地影响预测响应 = >是

由于这一点是有影响的,你应该深深怀疑的估计。

d.

这是实例 a)和 b)的组合。是一个高杠杆的离群值。此外,与前两种情况相反,两条回归线距离更远。是一个影响点

我们能从这些例子中学到什么?

实际上,影响点是至关重要的,因为它们似乎对估计模型有不成比例的影响。一个有影响的点看起来既是一个离群点,也是一个高杠杆点。也就是说,x 值(高杠杆)和 y 值(异常值)的子空间中的非分布样本将显著影响估计模型。

去除这些可疑点并分析统计结果,结果发现这些有影响的点。

然而,一切都是在只有一个变量的完美世界中描述的,但实际问题包括多个变量**。例如,高杠杆点不仅仅是极限 x 值,还可能是 x 值的奇异组合**,使得这些点远离解释变量子空间中的其他观察值。

下一部分是上一部分的一般化,包含多个预测值。我将提供统计工具来有效地检测这些点并描述它们的特征。

侦查

“帽子”矩阵

在多元线性回归中,该理论指出预测的响应可以与观察到的响应直接相关:

“帽子”矩阵如何定义的证明

矩阵 h,也称为**“帽子矩阵”(**因为它将“^”赋予了 y ),是检测可疑点的中心概念。简单地用这个矩阵乘以 y,我们就可以立即得到预测的响应,而 H 只是 x 的函数。

为了更好地理解,最后的等式可以写成以下等式:

矩阵系数的先前等式(其中 n =观察数量)

****在这个阶段,我们已经勾勒出一个不可或缺的元素: **h_ii。**后面我们会看到,这个元素存在于每一个与异常点检测相关的公式中。更准确的说,它有一个名字:杠杆!的确,如果你回想一下前面的定义,杠杆可以通过∂y_hat/∂y 来估算,也就是 h_ii。

h_ii,第 I 次观察的杠杆,取决于 X(其中 p =解释变量的数量

现在我也来介绍一下的概念。正如你所想象的,残差——预测响应和观察响应之间的差异——在检测异常值时起着决定性的作用。我们可以证明以下结果:

残差向量是服从期望为 0 的正态分布的随机变量。

从这个结果中可以得出三个有用的结论:

****备注:每个残差都有一个不同的方差,它们是相互关联的。

既然我们已经为理论奠定了基础,那么让我们来介绍一下描述可疑点的工具。

高杠杆

正如我已经提到的,杠杆是值 h _ iiT5,它定义了在计算第 I 个预测响应时乘以第 I 个观察响应的系数。由此可见,按理说高杠杆=高 h_ii ,对吗?但是什么样的阈值与认为 h_ii 高相关呢?****

所选择的临界值基于一个经验法则**:如果 h_ii 大于 h_ii 平均值的 2 倍,第 I 次观察被视为高杠杆。该含义可以改写如下:**

简化条件以检测高杠杆点(p =解释变量的数量,n =观察值的数量)

值得一提的是,这个条件是一个经验法则**,没什么严谨的。您可能会在其他地方遇到另一个阈值(如果 n 相对较大,有时是平均值的 3 倍)**

异常值的学生化残差

根据定义,异常值是高残差点**。然而,每个残差都有不同的方差。因此,为了进行严格的分析,必须实现残差的标准化。这样,残差可以用标准单位偏差量化,然后进行比较。因此有如下关系:**

****标准化残差的理论定义

然而,回归分析中一个反复出现的问题是****σ的存在。这个量在模型的定义中被引入作为误差项的标准偏差。然而,由于其值很少可用,因此需要一个估计量。****

学生化残差的理论估计

s 是σ的无偏估计量。但是,借助数学工具,我们可以证明 t_i 确实遵循 t-student 分布。为了获得这种分布,我们只需移除估计器中的第 I 个观察值,从而:

遵循 T32(n-p-1)自由度的 T32 学生分布的学生化残差的理论估计(在正态假设下)

s_i 表示没有第 I 次观测的模型的均方误差。如果我们打算为每一个 I 计算 s_i,我们必须每次都改装模型。幸运的是,上面的等式解决了这个问题,因为 s_i 是变量的函数,不需要删除第 I 个观察值。

得到所有这些学生化残差后,我们如何评估异常值?

绘图通常是理解和直观表示异常值的最佳方式:

  • 学生化残差与预测观测值,阈值为 2 或 3(绝对值)以标记异常值(此外,我们应该看到均匀分布,因为理论上残差和预测响应向量之间的协方差为零)
  • 学生化残差与观察 Id 的对比,阈值也为 2 或 3。此图对于时间序列数据非常有用。事实上,它可以导致与时间成分相关的异常值检测。

库克距离和影响点的定义

根据定义,影响点显著影响估计模型和相关结果。一个简单的想法是移除每个点,重新装配模型,并且分析“完整”模型和没有移除点的模型之间的差异。像往常一样,我们需要定义一个度量来告知这个点有多大的影响力。

在本文中,我将介绍两个指标:Cook Distance 和 DFFITS。

根据定义,库克距离由第一等式定义。第二个等式源于第一个等式,通常更实用:

(1):库克距离的理论定义/ (2):实际相等。(β(I)是没有第 I 个观测值时的 OLS 估计)

等式(2)直接显示了影响点、高杠杆点和异常值之间的链接

****事实上,D_i 是 t_i 和 h_ii/(1-h_ii)的函数。这两个术语分别量化了异常值和高杠杆点。此外,h_ii/(1-h_ii)是 h_ii 的增函数。因此,t _ I |和/或 h_ii 越高,烹饪距离越高。它证实了我们之前所说的:如果一个观察是一个高杠杆的异常值,它当然也是一个有影响的点。

一个统计阈值用于确定该点是否有影响:

将第 I 次观察视为有影响的条件,其中 F 表示具有 p 和 n-p 自由度的 F 分布的 1-alpha 百分位。

DFFITS 和 Cook Distance 几乎相同:

确定条件以识别影响点

结论

对于你的回归分析来说,这些棘手的数据点可能是一个噩梦。在项目中,您应该:

  • 评估线性模型所做假设的准确性(独立性、标准化、同方差性、线性…)
  • 执行前面的措施以确保数据一致性

但是,可疑点是有价值的。你应该经常问自己这些点是如何产生的(不正确记录的数据,数据中固有的,分布不均匀…) 只有在你有正当理由的情况下才删除它们。

“由于数据可能是由非指定的模型生成的,诊断可能揭示暗示这些替代方案的模式”[1]

****在这篇文章中,我没有给出真实的例子,因为我希望把重点放在理论和工具的展示上。在 R [5]中进行分析更容易,但是 Statsmodel 也提供了一些在 Python 中完成这项工作的方法。

注: 所有人物和关系都是我做的。

来源

  • 地方检察官贝尔斯利。Kuh,E. e Welsch,R. E. (1980 年)。回归诊断:识别有影响的数据和共线性来源。纽约:威利【1】****
  • 蒙哥马利特区;佩克,E. A. e .维宁,G. G. (2021)。线性回归分析导论,第六版。霍博肯:威利【2】****
  • 吉尔伯托·保拉。巴西 IME-南太平洋大学统计局。【3】******
  • https://online.stat.psu.edu/stat462/node/87/【4】****
  • https://cran . r-project . org/web/packages/ol SRR/vignettes/influence _ measures . html【5】****

不要再使用 If-Else 来验证 Python 中的数据对象

原文:https://towardsdatascience.com/do-not-use-if-else-for-validating-data-objects-in-python-anymore-17203e1d65fe

图片由sneakeyelbow发自 Pixabay

Cerberus——一种简洁易读的验证字典属性的方法

在我们的 Python 程序中使用大量字典来保存带有属性的数据对象并不常见。一个典型的例子是 Web 开发。假设我们正在使用 Python 开发后端 web 服务,验证从前端接收的 JSON 有效负载将是非常重要的。此外,数据科学在某些情况下也可能需要验证数据条目。

最直观但可能是最糟糕的解决方案是使用大量 if-else 条件。如果我们只验证一个或两个简单需求的属性,这可能是好的,但是根本不可伸缩。面向对象的方法被认为是更先进的。然而,有时,我们可能不想过度设计我们的应用程序。

在本文中,我将介绍一个令人惊叹的第三方库— Cerberus。它将在很大程度上简化代码验证。它还使验证规则变得可重用和灵活。它也支持许多复杂的场景。

1.从典型示例快速开始

图片来自 Pixabay 的 kim_hester

1.1 安装

像往常一样,Python 使得安装第三方库变得非常容易。我们只需要运行pip命令来安装它。

pip install cerberus

然后,我们就可以开始使用它了。对于第一个例子,让我把它分成几个部分来阐明术语。

1.2 基本用法

首先,我们需要从刚刚安装的cerberus模块中导入Validator类。

from cerberus import Validator

然后,我们可以定义一个“模式”。这个模式将包含我们想要用来验证我们的数据字典的所有规则。这个模式也是一个字典。

schema = {
    'name': {
        'type': 'string'
    },
    'age': {
        'type': 'integer'
    }
}

上面的模式告诉 Cerberus,我们的字典中有两个字段。“姓名”字段应为字符串,“年龄”字段应为整数。

然后,我们可以使用这个模式初始化我们的“验证器”。我们的验证器将是一个 Cerberus Validator类的实例。

profile_validator = Validator(schema)

现在,让我们创建一个样本字典来测试这个验证器。对于任何“验证器”实例,我们可以调用它的validate()方法来验证数据字典。

my_profile = {'name': 'Christopher Tao', 'age': 34}
profile_validator.validate(my_profile)

它返回True,所以这意味着字典通过了验证。在下一个示例中,如果我们将年龄值更改为字符串,将会失败。

my_profile = {'name': 'Christopher Tao', 'age': '34'}
profile_validator.validate(my_profile)

你一定在问我们怎么能不知道失败的原因。它将被存储在验证器中。通过调用验证器的属性errors,我们可以从验证器中得到所有的错误(如果不是只有一个的话)。

profile_validator.errors

1.3 更复杂的验证规则

当然,我们可以有更复杂的规则,而不仅仅是一种数据类型。例如,我们希望我们的用户至少 18 岁,那么我们可以将min规则添加到模式中。

profile_validator = Validator()
my_profile = {'name': 'Alice', 'age': 16}
profile_validator.validate(document=my_profile, schema={
    'name': {
        'type': 'string'
    },
    'age': {
        'type': 'integer',
        'min': 18
    }
})

在上面的例子中,验证器是在没有模式的情况下初始化的。然后,可以在validate()方法中动态地给它分配一个模式。这只是一种更灵活的方式。万一我们的模式规则在它的生命周期中可以被改变,这将是非常方便的。

错误显示了失败的原因,没有任何额外的努力,这是我喜欢这个库的原因之一。

1.4 验证嵌套字典

如果我们的字典是嵌套的呢?换句话说,JSON 文档中有子文档。别担心,它是由地狱犬支持的。

假设我们需要在配置文件字典中有一个包含街道号和街道名的地址字典,我们可以如下定义模式。

profile_validator = Validator()
profile_validator.validate({
    'name': 'Chris',
    'address': {
        'street_no': '1',
        'street_name': 'One St'
    }
}, {
    'name': {'type': 'string'},
    'address': {
        'type': 'dict',
        'schema': {
            'street_no': {'type': 'integer'},
            'street_name': {'type': 'string'}
        }
    }
})

对于“address”子文档,我们只需要告诉模式它是一个dict类型,并在其中定义一个子模式。然后,它就会工作。该错误还包括层次关系,以便我们可以轻松地排除故障。

2.走向未知

图片来自 Pixabay 的 Lucio Liu

常见的情况是,我们无法预测实际可能得到的字段,因此我们需要处理未知字段的验证。我想用这个功能来展示地狱犬是多么灵活。所以,让我们深入了解未知的细节:)

2.1 默认情况下,未知不可接受

例如,我们的验证器只知道我们将有一个“name”字段。

profile_validator = Validator({'name': {'type': 'string'}})

但是,我们的字典有一个未知的字段“年龄”。

profile_validator.validate({'name':'Chris', 'age': 34})

如果我们置之不理,这将导致验证失败。

不要担心,Cerberus 有一个非常全面的解决方案来处理未知领域。

2.2 允许未知

一个非常常见的需求是,我们希望忽略未知字段,让它们通过。在这种情况下,我们需要将验证器的allow_unknown属性设置为True

profile_validator.allow_unknown = True

之后,作为未知字段的age字段将不会被验证,而是被忽略。

profile_validator.validate({'name':'Chris', 'age': 34})

2.3 允许特定数据类型未知

另一个常见的需求是,我们可能希望忽略某些数据类型。例如,字符串字段是非常自由的样式,我们想忽略它,但是我们不允许任何其他数据类型,比如整数是未知的。

在这种情况下,我们可以确保allow_unknown为 False,并为其指定特定的数据类型。

profile_validator.allow_unknown = False
profile_validator.allow_unknown = {'type': 'string'}

验证器模式没有改变,但是让我们用模式中不存在的firstnamelastname创建一个字典。

profile_validator.validate({'firstname':'Chris', 'lastname': 'Tao'})

它通过了验证,因为它允许任何字符串类型的未知字段。但是,如果我们添加一个整数字段,它将失败。

profile_validator.validate({
    'firstname':'Chris', 
    'lastname': 'Tao',
    'age': 34
})
profile_validator.validate(my_profile)

2.4 初始化时允许未知

如果我们知道我们需要接受未知字段,我们也可以在实例化验证器时添加这个标志,如下所示。

profile_validator = Validator({}, allow_unknown=True)

如上图,方案为空,但allow_unknown被设置为True。因此,它将接受任何字段。

2.5 允许在特定级别未知

我们甚至可以在子文档级别设置allow_unknown。例如,我们仍然希望字典在根级别得到严格的验证,但是对于address对象,我们不希望添加太多的约束来允许一些不确定性。

我们可以将模式定义如下。

profile_validator = Validator({
    'name': {'type': 'string'},
    'address': {
        'type': 'dict',
        'allow_unknown': True
    }
})

请注意allow_unknown被设置为address级别下的True。所以,无论我们在address子文档中定义什么,都没问题。

profile_validator.validate({
    'name': 'Chris',
    'address': {
        'street_no': 1,
        'street_name': 'One St'
    }
})

但是,如果我们在根级别添加一个未知字段age,它将会失败。

profile_validator.validate({
    'name': 'Chris',
    'age': 34,
    'address': {
        'street_no': 1,
        'street_name': 'One St'
    }
})

3.必填字段

图片来自 Pixabay 的 minka2507

我们知道我们可以使用地狱犬来处理未知领域。不如我们把一些字段强制设置为必填字段?

默认情况下,如果字典遗漏了模式中定义的一些字段,将不会捕获任何错误。

profile_validator = Validator({
    'name': {'type': 'string'},
    'age': {'type': 'integer'}
})
profile_validator.validate({'name': 'Chris'})

在上面的代码中,模式定义了age字段,但是字典没有它。验证结果仍然是好的。

如果我们想让所有的字段都是强制性的,我们可以添加一个标志require_all并将其设置为True

profile_validator = Validator({
    'name': {'type': 'string'},
    'age': {'type': 'integer'}
}, require_all=True)
profile_validator.validate({'name': 'Chris'})

当然,我们也可以将某些字段设置为必填字段。这可以通过特定的规则required来完成。可以将其添加到模式定义的字段中。

profile_validator = Validator({
    'name': {'type': 'string', 'required': True},
    'age': {'type': 'integer'}
})
profile_validator.validate({'age': 34})

4.标准化字典

图片来自 huoadg5888 来自 Pixabay

令我惊讶和印象深刻的是,Cerberus 不仅可以验证字典,还可以纠正它们。这在保证数据质量的应用中可能非常有用。

例如,我们可能有来自不同数据源的用户配置文件。当我们想把它们组合成一个单一的真实来源时,我们发现年龄在一个数据库中以整数的形式出现,而在另一个数据库中却是字符串类型。在这种情况下,Cerberus 提供了一个名为normalize()的函数,它可以统一数据类型以确保数据的一致性。

为了实现这一点,我们需要指定字段的类型。例如,我们希望将age字段统一为整数类型。代码如下。

profile_validator = Validator({
    'name': {'type': 'string'},
    'age': {'coerce': int}
})

coerce告诉验证器我们想要的数据类型是什么。请注意,这不会用于验证目的。因此,如果我们有一个带有字符串类型的age字段的字典,它仍然可以通过。

my_profile = {'name': 'Chris', 'age': '34'}
profile_validator.validate(my_profile)

如果我们想要“规范化”字典,我们可以如下调用验证器的normalize方法。

my_profile_normalized = profile_validator.normalized(my_profile)

我们可以看到age值在规格化后被转换为整数。

5.其他规则和定制规则

图片由spiritize从 Pixabay 获得

5.1 支持的规则

到目前为止,我没有介绍太多类型的验证规则。这是因为在 Cerberus 中大约有 30 种不同类型的现成规则。以下是一些例子:

  • 列表包含一个特定的项目
  • dependencies一个字段的规则只有在另一个字段出现时才会生效
  • empty字符串值不能为空
  • nullable允许为None类型的值
  • forbidden该值不得在预定义列表中
  • excludes如果出现另一个字段,则该字段不能存在
  • regex字符串值必须与正则表达式匹配
  • allof/anyof/noneof/oneof定义多个规则,并且值必须满足所有规则、任何规则、不满足任何规则或至少满足其中一个规则。

我不能介绍 Cerberus 中的每一个规则,但是你可以从文档中查看所有的规则。

https://docs . python-Cerberus . org/en/stable/validation-rules . html

5.2 定制规则

如果 Cerberus 提供的 30 条规则都不符合我们的要求,该怎么办?为了最大限度地提高灵活性,Cerberus 还允许我们定义定制的规则。

定制规则需要被定义为具有如下三个参数的函数。

def my_rule(field, value, error):
    if value % 2 != 0:
        error(field, "Must be an even number")

field是字段的名称,value将是我们想要验证的值,error是一个函数,它将定义存储在验证器的errors属性中的错误消息。

我刚才定义的my_rule就是简单的检查一个数是否是偶数。一旦定义了它,我们就可以用关键字check_with在模式中使用它。

my_validator = Validator({
    'my_number': {'check_with': my_rule}
})
my_validator.validate({'my_number': 10})

摘要

图片来自 Pixabay 的 Sven Lachmann

在本文中,我介绍了 Python 中的第三方库 Cerberus。它为我们验证字典提供了一个非常好的解决方案。它非常灵活,这可以从处理未知字段和定义必填字段的例子中看出。此外,它支持大约 30 个现成的规则,以及我们自己定制的验证规则。

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

如果你觉得我的文章有帮助,请考虑加入 Medium 会员来支持我和成千上万的其他作者!(点击上面的链接)

除非另有说明,所有图片都是作者的

不要再使用 If-Else 来验证 Python 中的数据对象——Colander

原文:https://towardsdatascience.com/do-not-use-if-else-for-validating-data-objects-in-python-anymore-colander-7dd66c435118

图片由 Irenna86 来自 Pixabay

使用定制的类以灵活的模式定义你的数据结构

几周前,我介绍了一个名为 Cerberus 的 Python 库。它可以让我们编写一个“模式”,以简洁易读的方式验证我们的数据对象(JSON/Dictionary ),而不是使用无尽的 if-else 条件。

在本文中,我将介绍另一个令人惊叹的第三方库— Colander。然而,它做了一件非常相似的事情,只是方式非常不同。它使用类,而不是在字典中定义验证规则。这听起来有点庞大,但是如果我们有一个非常复杂的数据结构需要验证,这可能会更有组织性。此外,当我们在类中编写所有的验证规则时,有一个显著的好处。也就是说,我们可以将它导出为一个可以导入的独立模块。换句话说,它在另一个层面上提供了灵活性和可重用性。

1.基础

图片来自像素来自像素

像往常一样,让我们从一个不成熟但基本的例子开始,看看这个库是如何工作的。在我们可以使用这个库之前,别忘了安装它。

pip install colander

现在,我们需要一个样本 JSON,或者 Python 字典。

my_json = {
    'name': 'Chris',
    'age': '34',
    'skills': [
        ('1', 'Python'), ('2', 'Data Science'), ('3', 'DevOps')
    ]
}

请注意,所有的属性和值都是字符串。当我们以消息的形式从另一个系统获取数据对象时,这是一种很常见的情况。

然后,我们需要导入我们刚刚安装的 colander 模块,然后如下定义 3 个类。

import colanderclass Skill(colander.TupleSchema):
    rank = colander.SchemaNode(colander.Int())
    name = colander.SchemaNode(colander.String())class Skills(colander.SequenceSchema):
    skill = Skill()class Person(colander.MappingSchema):
    name = colander.SchemaNode(colander.String())
    age = colander.SchemaNode(colander.Int())
    skills = Skills()

Colander 模式类

Person 类定义了总体模式。它有 3 个属性,属性“技能”来自另一个类。然后,技能类只有一个属性—技能。技能类别定义了个人技能的结构。

尽管我们需要定义多个类,但这可以保持代码整洁。在某些情况下,它甚至比使用字典更好,就像我们在 Cerberus 中所做的那样。

Colander 模式类型

所有的类都需要从 Colander 继承模式类型。在上面的例子中,TupleSchema指的是元组,SequenceSchema指的是顺序重要的集合类型,MappingSchema指的是字典。

除了示例中的这些,还有更多可用的模式类型。请参考官方文档。

Colander 模式节点

顾名思义,每个 colander 模式节点都引用原始数据结构中的一个原子属性。例如,字符串属性“name”应该是字符串类型的模式节点,而 age 属性应该是整数模式节点。

反序列化 JSON 对象

现在,我们已经定义了模式,这是 Person 类。在使用它之前,我们需要将其实例化为一个模式对象。

person_schema = Person()

然后,我们可以使用这个模式对象去序列化 JSON 对象。

person_object = person_schema.deserialize(my_json)

在去军事化过程中至少发生了两件事。首先,JSON 对象经过了这个“漏勺”,所有的验证器都通过了。其次,那些整数类型的属性被正确地从字符串转换成整数。

可以看出,理解 JSON 结构是如何被验证的,以及 Colander 将字符串值反序列化为目标数据类型的机制是什么是很重要的。

2.验证者和准备者

图片来自 Pixabay 的像素

为了演示验证器是如何工作的,我们可以使用一个相对简单的例子。假设我们有下面的字典。

my_json = {
    'name': 'Chris',
    'age': -1,
    'gender': 'Male'
}

现在,我们可以尝试向模式中添加一些验证器。

class Person(colander.MappingSchema):
    name = colander.SchemaNode(colander.String())
    age = colander.SchemaNode(
        colander.Int(),
        validator=colander.Range(0,150)
    )
    gender = colander.SchemaNode(
        colander.String(),
        validator=colander.OneOf(['M', 'F', 'Other'])
    )

在上面的例子中,为agegender属性添加了两个内置的验证器。Colander 提供了许多内置的验证器,因此我们可以轻松地利用它们。

对于属性age,我们想把它限制在一个整数范围内,在 0 到 150 之间。

对于属性gender,我们希望它是数组中预定义的值之一。

现在,让我们再次尝试去序列化它,看看验证器是如何工作的。

person_schema = Person()
person_object = person_schema.deserialize(my_json)

如图所示,两个验证器都抱怨了,并且给出了具体的错误消息,这对理解发生了什么非常有帮助。

将错误消息作为字典获取

您可能已经注意到,错误消息实际上是 JSON 格式的。这使得返回到下游组件进行显示变得更加容易。

使用 try-except 块,我们可以很容易地将这个错误消息作为一个字典来“捕捉”。

try:
    person_object = person_schema.deserialize(my_json)
except colander.Invalid as e:
    print(e.asdict())

定制验证者和准备者

现在,让我们看看如何定制一个验证器。尽管有许多内置的验证器,有时我们可能仍然对我们的数据结构有非常特殊的要求。

我们需要定制一个 Colander 模式节点来拥有一个定制的验证器。要定义一个定制的 Colander 模式节点,我们需要编写一个类,并让它从colander.SchemaNode继承,如下所示。

class GenderString(colander.SchemaNode):
    schema_type = colander.String
    title = 'Gender String' def preparer(self, value):
        if value == 'Female':
            return 'F'
        elif value == 'Male':
            return 'M'
        else:
            return value def validator(self, node, value):
        if value not in ['F', 'M', 'Other']:
            raise colander.Invalid(value, 'is not a valid gender string')

在上面的代码中,我们定义了一个名为GenderString的类,这将是一个定制的 Colander 模式节点。在这个类中,我们需要指定模式类型,它是一个字符串。然后,我们实现了两个方法preparervalidator

preparer()方法中,我们定义了类似“魔法”的东西。即当性别字符串为“男性”时,会转换为单字母缩写“M”,所以为“女性”。这个方法将在验证器之前执行,它也将改变这个节点的值。

在验证器中,我们使用简单的 if-else 条件定义了验证方法。如果无效,将引发“无效”错误,并且消息也是定制的。

定义了这个模式节点后,我们可以在模式定义中使用它,如下所示。

class Person(colander.MappingSchema):
    name = colander.SchemaNode(colander.String())
    age = colander.SchemaNode(colander.Int())
    gender = GenderString()

请注意,gender属性已经被分配了一个GenderString实例。

现在,让我们更正原始 JSON 的age属性,看看验证器是否能通过。

my_json['age'] = 34person_schema = Person()
person_object = person_schema.deserialize(my_json)print(my_json)
print(person_object)

酷!JSON 对象已经通过了验证器,性别字符串也已经从“男性”转换为“M”。

3.漏测值

图片来自 Pixabay 的Malin btm star

处理缺少值的情况很重要。有时,我们不允许缺少值,默认情况下 Colander 支持这一点。

让我们再次定义模式,只是使用一些简单的定义。

class Person(colander.MappingSchema):
    name = colander.SchemaNode(colander.String())
    age = colander.SchemaNode(colander.Int())
    gender = colander.SchemaNode(colander.String())

此外,让我们有一个新的 JSON 对象,并且其中没有属性。

my_json = {'name': 'Chris', 'age': 34}

现在,让我们再次尝试去非军事化。

person_schema = Person()
person_object = person_schema.deserialize(my_json)

如错误消息所示,模式假设所有属性都是必需的,只要我们已经定义了它们。

这很好,因为我们确实需要验证器来帮助验证一个必填字段是否存在。但是,如果这应该是一个可选属性呢?实际上,我们只需要在 schema 节点中添加一个missing参数,如下所示。

class Person(colander.MappingSchema):
    name = colander.SchemaNode(colander.String())
    age = colander.SchemaNode(colander.Int())
    gender = colander.SchemaNode(
        colander.String(), 
        missing='Unknown'
    )

如图所示,missing参数的值将用于填充属性,如果没有给出的话。但是,如果我们不想给一个回退值呢?我们可以使用colander.drop作为missing参数,表示如果在源代码中没有给出这个属性,就不要包含它。

class Person(colander.MappingSchema):
    name = colander.SchemaNode(colander.String())
    age = colander.SchemaNode(colander.Int())
    gender = colander.SchemaNode(
        colander.String(), 
        missing=colander.drop
    )person_schema = Person()
person_object = person_schema.deserialize(my_json)

4.数据结构扁平化

图片来自 Pixabay 的 Ulrike Leone

最后我想介绍的是 Colander 库的扁平化特性。这可能是一个非常有用的方法。

让我们回到最初的 JSON。

my_json = {
    'name': 'Chris',
    'age': '34',
    'skills': [
        ('1', 'Python'), ('2', 'Data Science'), ('3', 'DevOps')
    ]
}

同样,让我们把原来的模式找回来。

class Skill(colander.TupleSchema):
    rank = colander.SchemaNode(colander.Int())
    name = colander.SchemaNode(colander.String())class Skills(colander.SequenceSchema):
    skill = Skill()class Person(colander.MappingSchema):
    name = colander.SchemaNode(colander.String())
    age = colander.SchemaNode(colander.Int())
    skills = Skills()

这次让我们跳过反序列化,使用模式中的flatten()方法。

person_object = person_schema.flatten(my_json)

JSON 文档被简化成一维的键值对字典。

事实上,我们也可以使用这种符号从数据结构中获取特定的值,如下所示。

person_schema.get_value(my_json, 'skills.0.name')

摘要

图片来自 Pixabay 的 myungho lee

在本文中,我介绍了另一个用于数据验证的库——Colander。和我之前介绍过的 Cerberus 库相比,很难说哪个更好。这取决于使用案例和个人偏好。

总的来说,我认为 Colander 更适合需要非常复杂的验证和特殊需求的用例。它使我们能够编写更可读的代码。然而,Colander 中的所有东西都必须被定义为一个类。所以,如果用例不是那么复杂,这就有点过度设计了。

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

如果你觉得我的文章有帮助,请考虑加入 Medium 会员来支持我和成千上万的其他作者!(点击上面的链接)

除非另有说明,所有图片均出自作者之手

实时数据管道存在吗?

原文:https://towardsdatascience.com/do-real-time-data-pipelines-even-exist-76830a52f67c

分享实时数据管道的新视角

由 Djim Loic 在 Unsplash 上拍摄的照片

您多长时间听到过这些术语——实时数据管道、实时数据处理、实时分析或仅仅是实时数据?这些经常被讨论来解决一些非常有趣和关键的用例,比如故障检测、异常检测等等。

在本文中,我们将了解一些常用的实时流程和技术,以及实时到底意味着什么?

不,这不是一个哲学问题,而是一个技术问题。我希望这篇文章能帮助你开发实时数据处理的新视角(或者改变我的观点?:))

让我们开始吧。

典型的实时数据流如下所示

作者图片

**来源:**数据生产者,Ex: Kafka/Kinesis/Solace/API 等。
**消费者:**数据消费者可以是消费来自源的数据,然后对其进行处理的东西(如果需要的话),这可能是一些定制实现或一些技术,例如:结构化流、Flink、Samza 等。

例如,我所从事的最常见的实时基础设施之一就是结构化的流式消费者从某个主题读取数据并保存这些数据:

作者图片

结构化流,微批量处理数据(阅读本了解诀窍),批量频率低,可提供低处理延迟。

实时生态系统中其他一些常用的技术有:

弗林克

现在,spark 结构化流可以被 Flink 之类的东西取代,Flink 具有对流的原生支持,并提供极低的延迟( link ),并且在某些用例中比结构化流更快。此处列出了一些可以使用 Flink 的示例

卡夫卡

我们现在都知道卡夫卡有多棒了!*(我的意思是让我们花点时间来欣赏这项美丽的技术)*它提供了无与伦比的持久性/吞吐量和低延迟。这里的是沃尔玛用卡夫卡建造的实时管道的例子。

发布/订阅

这些通常用于数据流或消息传递用例,并提供极低的延迟,它们不能为您提供持久性,但这取决于用例。

看了一些例子和技术后,我的问题是,真的是实时的吗?

关键词是低延迟,我这里的论点是低延迟应该被认为是实时的吗?

低延迟==实时?

例如,现在只要涉及到结构化流,数据就在微批处理中处理,批处理频率可能非常小,但仍然是某种级别的批处理,数据实际上不是实时处理而是接近实时处理*。类似地,对于其他提供极低延迟的解决方案,我们应该何时开始称之为实时而不是近实时*?

一种方法可能是,对于您设计的管道,如果它提供的延迟足够低,以至于对于我们这些凡人来说,它被认为是实时发生的,那么它可以被认为是实时的(想想 Instagram live、Youtube live 或 Live matche s)。对于其他情况,如果配置/设计或支持的延迟不够低,以至于它实际上是可察觉的,则解决方案变得接近实时而不是实时。

因此,这不仅仅取决于您用于设计的技术,还取决于您如何使用它,它如何帮助设计以及负载了解其延迟。

我的意思是,事情可以像你希望的那样快,但最终,你必须考虑网络和跳跃的延迟。这就是为什么我们总是认为真理的来源是event created timestamp而不是arrival timestamp,因为可能有延迟或潜伏。(这里是一篇关于时间排序的有趣文章)

现在,我来这里并不是要抛弃实时基础设施,而是仅仅抛弃术语和概念,由于上述原因,我在使用术语real-time时非常小心,如果我不知道细节,我更喜欢使用near real-time

那么,你有什么想法?

什么都不是实时的还是什么都是?

我将很高兴被证明是错误的,或者讨论其他观点,随时留下评论或在 Linkedin 上与我联系。

如果你喜欢这篇文章,请鼓掌,它让我在 近实时 😃

下次见,
JD

你是不是也觉得 AI 走的太快了?

原文:https://towardsdatascience.com/do-you-also-feel-ai-is-going-too-fast-56bf56ab43b3

意见

我有一种共同的兴奋感,夹杂着本能的匆忙,以避免错过,纯粹的信息淹没

闪电侠。鸣谢:作者 via midway

我怀疑我不是唯一一个觉得 AI 发展太快的人。

我在论坛和社交媒体上看到了很多关于这一点的评论,我得出的结论是,内部人士和目击者都有这种感觉:人工智能显然发展得如此之快,我们无法跟上——即使是我们这些以此为生的人也无法跟上。

这不是第一次出现这种想法(自 2010 年代初以来,人工智能一直在加速),但这是我第一次看到这种感觉变得如此普遍,如此明显,以至于它是有形的——就像暴风雨前的突然平静。

安德烈·卡帕西的推特

在我们继续之前,让我设定一个可能对也可能不对的前提:让我们假设人工智能领域确实在以我们认为的速度前进。

这可能是“外表是骗人的”——发表论文的数量不一定与有意义的进展相关。我不太关心第一部分。我关注的是感觉,而不是潜在的现实。

然而,在最后一节中,我涵盖了给你工具和发人深省的论点的可能性,以便你可以重新评估你对人工智能知识的立场和方法。你知道我喜欢细致入微的镜头。

也就是说,我可以从一百个不同的角度来探讨这个话题。先说清楚这篇文章是什么,不是什么。

这篇文章是什么

这是我的主要目的:捕捉那种分享兴奋的感觉,混合着本能的匆忙,以避免错过,以及纯粹的信息淹没。这种感觉在人工智能领域是独一无二的。

如果你关注《新闻与趋势周刊》,你就会知道我在说什么:在一个日益复杂的世界中迷失的恐惧感从你的指缝间溜走(请不要将这与 AGI 或奇点混淆)。

这篇文章也是关于如何处理这种感觉及其后果(它可能不像你想的那样与现实相关)。成为一个有知识的人有其好处,但也有其危险。

过于接近人工智能的进步迫使你学习这些:如何避免跳进时髦的潮流,如何抛开错过的恐惧(FOMO),如何将你的炒作保持在健康的水平,以及如何保持你的批判性思维敏锐。

这篇文章不是什么

本文并不是对“人工智能发展太快”这句话的真实性的彻底评估,尽管第二部分涵盖了您自己评估它所需的工具。

这不是关于这种不受约束的进步在让我们更接近目标方面是否有价值。人工智能的人们有不同的理由推动这个领域向前发展:从制造有用的产品使世界更具创造性,到理解人类的思维,到构建超级智能。

然而,这种明显的进步也可能只是为了赞美特定公司的公关噱头。我不会在这里讨论这个问题。

它不是关于使人工智能发展如此之快的原因,特别是现在,而不是 5 年前。

这也不是关于如何减缓进展——尽管有些人一再争辩说这应该被考虑,而不是被拒绝。

艾米丽·m·本德的推特

既然我们都清楚了,让我们进行第一部分。

本文选自The algorithm Bridge,这是一份教育通讯,其目的是在算法和人之间架起一座桥梁。它将帮助你理解人工智能对你生活的影响,并开发工具来更好地导航未来。

https://thealgorithmicbridge.substack.com/subscribe

如果你感到不知所措,你并不孤单

寒武纪人工智能爆发是在 2012 年基于深度学习的计算机视觉算法在 ImageNet 挑战赛中充分击败竞争对手之后开始的。

从那以后,人工智能一直在快速发展。进步不是一成不变的,但加速了。如果我们着眼于 2012—2022 年这十年,下半年比上半年取得了更多进步。

致谢:克伦等人

(发表论文的数量不是衡量这一点的好指标,但可以作为证明我观点的代理。)

然而,这在不断发展的科学领域是很自然的。进步推动更多的进步。我们已经习惯了。人工智能的不同之处在于,不仅进步,而且进步的速度似乎也在加快。

这种现象的一种常见形式是人们所说的指数增长(尽管正如物理学家西奥多·莫迪斯(Theodore Modis)所说,“自然界中没有什么是纯指数增长的”)。

为什么人们会对 AI 有这种感觉?我能找到很多原因:AI 越来越受欢迎。投资者和企业正投入更多资源进行研发。论文和出版物受到更多的关注。概念验证越来越多地被用于产品和服务中。人们可以接触到最新的款式。每一次突破都会带来后续的突破。

为了说明这一点,让我用一段话简单介绍一下过去五年的语言研究:

谷歌在 2017 年发布的 transformer 架构引发了人们对语言建模的兴趣。这使得 OpenAI 能够为大型模型设计缩放法则,从而建造了 GPT 3 号。这促使其他大型科技公司和大学开发自己的模型并发表更多论文,这每月都成为各地的新闻。这产生了新的市场机会,激励人们建立新的公司,从而导致更多的竞争。反过来,这又激发了开源计划,以应用程序和网站的形式促进了人们对最新研究的访问。

所有这一切仅仅发生在 4 年内。疯狂的快。

但是今年呢?可以说,今年是人工智能历史上最疯狂的一年。就新的研究论文、新的应用、新的模式、新的公司而言……最重要的是,就正在发生的发现的潜在社会和经济影响而言。

2022 年的进展速度已经加快到连内部人士都感到不知所措的地步。我说的不是一般的工程师。你刚刚看到了 Andrej Karpathy 的推文——他是目前人工智能领域最有才华的年轻头脑之一(现已独立,之前为@ Tesla,OpenAI)。

2022 年已经(并且正在)成为生成性人工智能和扩散模型的一年(尽管我试图捕捉的感觉很容易推断到其他分支,如以生物学为重点的人工智能研究或著名的语言理解子领域)。

关于生殖人工智能的最新消息——这促使我写这篇文章——是公司已经在创建文本到视频的模型(制作视频和 Phenaki )。我们仍在消化 DALL E 和 Stable Diffusion 等图像生成模型的快速发展,各公司已经开始进入下一个重大突破。

请看这段 2 分钟的视频,它是由一系列连续的提示生成的。

而且不仅仅是卡帕西。密切关注这些进展的人普遍有这种失控的感觉。他们不知所措。我说的是那些知道一个模型或论文在发表的同一天就出来的人。你不可能比那更接近了。正是这些人“敲响了警钟”

我指的不是“哇,这进展得多快啊”这样的评论。不,我们正处于人们开始说:“嘿,这太快了,也许我们应该慢下来,”或者“即使我尽了最大努力,我还是跟不上。”请看这里的引用推文:

Meta AI 的推文

或者这里:

AK 的推特

当然,并不是每个人都认为这种感觉是一个有问题的迹象。一些人比以往更加兴奋。

这就是指数增长的感觉(即使它实际上不是指数增长)。

以下是当有人问他 30 年后 AI 会是什么样子时,卡帕西的回答:

安德烈·卡帕西的推特

一件事是理性地知道——作为一个遥远的想法——在未来,人工智能将从根本上改变世界,我们将无法再跟上进步。另一件非常不同的事情是,已经在内心感受到了。

这并不是说当前的人工智能加速正在引领我们走向 AGI 或有感知能力的机器——我不这么认为——但对我们许多人来说,加速进步、压倒性信息和强大 FOMO 的感觉是非常真实的。

对人工智能进步感到不知所措的 3 个后果

正是因为这种无处不在的感觉,这第二部分才如此重要。

让我这样开始:即使你觉得人工智能发展得太快,你也可能是错的。人工智能在现实世界中的效果可能没有从近距离角度看起来那么令人印象深刻。这是一个自然的暗示,即没有足够频繁地从发展中抽离出来去观察真实的世界。

谷歌和 OpenAI 的进步速度可能是超音速的,与此同时,世界上 80%的人(虚构的)甚至没有听说过 GPT-3。我的意思是,几乎 40%的全球人口没有互联网接入。

然而,这可能有一部分是真实的:由于开源趋势,在创建模型并将其转换为即用型应用程序时,生成式人工智能尤其享受着高自由度和低摩擦的结合。这是几周甚至几天的事。

当有形的现实与进步的表象融合在一起时,就很难消除这种失去控制的感觉。

也就是说,我不会在这里争论人工智能的真实进度。

我不会试图让你相信它比你想象的要慢。我也不会试图让你相信,即使它在进步,你所预见的未来也不是我们前进的方向。

我在这一节关心的是给你我的论点,当我们被信息、急于知道更多和 FOMO 所淹没时会发生什么。以及如何应对这些感觉及其后果。

“抱歉,没有时间创造有意义的评价。必须跟上 arXiv!”

语言学家艾米丽·m·本德的这条推特完美地抓住了第一个想法:

艾米丽·m·本德的推特

她尖刻的讽刺切中要害。我同意她的观点,觉得自己跟不上人工智能进步的直接后果是投入所有资源去尝试——忽略其他方面。

这种匆忙促使我们放弃处理看似不重要的任务,如反思、分析和评估人工智能研究和发展的影响和反响。

可悲的是,这似乎不是孤立的证人,像我或你。我们只是相信 AI 可能走得太快了。构建这些系统的人也面临这个问题。而他们不相信,他们知道

即使进展不像感觉的那样显著,他们也必须继续写论文和建立模型(不管目的是什么)。这使得他们无法花足够的时间评估人工智能的社会影响——其中一些并不完全是好的。

人工智能安全和人工智能伦理的人(听起来他们在解决类似的问题,但没有进一步远离事实)是唯一试图补偿该领域加速发展本质的人。

但是它并不像他们希望的那样有效。前者过度关注对齐问题(在我看来,这不如此时此地发生的社会和文化问题紧迫),而后者——以及那些将肆无忌惮的热情视为炒作的人——被许多人称为“人工智能批评者”或“人工智能否认者”。

梅勒妮·米切尔的推特

撇开这两个群体不谈,人们现在感受到的是强大的 FOMO。害怕错过下一件大事,不断出现的低挂机会,或者为即将到来的人工智能驱动的未来做准备的能力。

这是什么配方?你猜对了,AI 炒作。

多 FOMO →少反思→多炒作→多 FOMO → …

因感觉自己错过了什么而产生的恶性循环很难打破。

你投入了更多的资源来跟上进展,这减少了你思考表面进展的价值、真相或目标的能力和时间。

这导致你对人工智能发展周围的阴影不太了解,这使你成为夸大的标题和毫无歉意的公关噱头所诱导的炒作的受害者。

这个超级常见。

解决这个问题的唯一方法是对你遇到的任何新论文或新进展保持持续的、无条件的健康的怀疑态度。我试着将这一点运用到我的阅读和写作中。

面对铺天盖地的信息,批判性思维停止了

这是当今时代最独特的问题之一。远远超出了人工智能。它发生在 COVID 身上。俄罗斯和乌克兰的战争就是如此。而且还会继续发生。我们被灌输了太多太多我们无法消化的信息。

消化信息和思考信息共享相同的心理资源。如果我们需要消化的信息量超过了某个阈值,人们就会停止批判性思维。原因似乎是这比简单地吞下任何向你袭来的消息要花费更多的努力。

没有时间思考,人们只是相信他们读到的。

打 AI 炒作的人就不够了。Twitter 上的帖子或 Substack 上的帖子也是不够的。在不断增长的炒作影响下的人们将成为诸如“奇点临近”、“AGI 就在拐角处”或有感知能力的人工智能等想法的主要受害者。

为了结束这篇文章,我将与你分享一些推文,这些推文强调了在信息过载、未披露的利益以及共同的迫切乐观情绪时批判性思维的重要性:

坦特的推特

塔莉亚·林格的推特

加里·马库斯的推文

艾米莉·m·本德的推特

我预测,像这样的文章(我可能有偏见)——试图在人工智能创新的兴奋和它们的缺点之间找到平衡——只会变得更加必要,如果我们继续目前的道路。

订阅 算法桥 。弥合算法和人之间的鸿沟。关于与你生活相关的人工智能的时事通讯。

您也可以直接支持我在 Medium 上的工作,并通过使用我的推荐链接 这里 成为会员来获得无限制的访问权限! :)

你知道数据方法论的逻辑分析(LAD)吗?

原文:https://towardsdatascience.com/do-you-know-the-logical-analysis-of-data-methodology-lad-76365b33bc63

让我们快速浏览一下

图片来自 geralt 来自 pixabay 。

我最近发现了一个数据分析领域,这个领域始于 1986 年彼得·l·哈默的工作,叫做数据的逻辑分析 (LAD)。我问了一圈,没人听说过。所以我决定写一篇关于这种原始的数据分析方法的简介。本文是基于[1]的第三章和[2]的文章。

LAD 是一种二元可解释分类方法,基于最优化、布尔函数和组合理论的混合。但是请放心,理解这个理论的基础不需要任何先决条件。这是一种具有竞争力的分类方法,用于分析由二元观测值组成的数据集,通过其模式的概念提供清晰的解释。

LAD 从数据集中提取大量的模式集合,其中一些是具有肯定分类的观察结果的特征,而另一些是具有否定分类的观察结果的特征。然后对该集合进行过滤,以提取更小的、非冗余的模式集合。这种简化允许为每个分类提供可理解的解释。

介绍

要理解什么是童子,我举个常见的例子。一位医生想找出哪些食物会导致他的病人头痛。为此,他的病人记录了一周的饮食,如下表所示。

饮食记录。作者的表格。

快速分析让医生得出两个结论。首先,他注意到病人在不头痛的日子里从不吃没有食物 n 1 的食物 n 2,但是在他确实头痛的日子里吃了食物 N2。他注意到没有食物 n 6 的食物 n 4 也有同样的模式。因此,他得出结论,他的病人的头痛可以用这两种模式来解释。

在不知情的情况下,医生对饮食记录数据集执行了 LAD。事实上,在他的分析过程中,他不得不回答以下三个问题:
**【1】**如何提取一个短的特征列表(即食物项目)足以对数据进行分类(即解释头痛的发生)?
(2) 如何检测导致头痛的模式(即食物项目的组合)?
(3) 如何建立解释每一次观察的理论(即模式集合)?
这些问题总结了 LAD 方法。

符号和定义。

数据的逻辑分析基于部分定义的布尔函数 (pdBf)和模式的概念。

我们设置 B = {0,1} 。集合 Bⁿ ,通常被命名为维数为 n 的布尔超立方体,由所有可能的长度为 n 的二进制序列组成。我们对 Bⁿ 上的一个偏序 定义如下:一个=(a₁,…,aₙ) ≤ b=(b₁,…,bₙ) 当且仅当 aᵢ ≤ bᵢ 对于每个 i=1,…,n

一个子集 S ⊆ Bⁿ 被称为 Bⁿ子立方体当且仅当 |S|=2ᵏ for k ≤ n 并且存在 n-k 分量,其中 S 的所有序列重合。例如 S={(0,0,0),(0,0,1),(0,1,0),(0,1,1)}B 对于 k=2 的子码

什么是 部分定义的布尔函数

一个 布尔函数f ,是从 BⁿB 的映射。还有 2^(2ⁿ)可能的布尔函数。对于一个布尔函数 f ,我们设 T=T(f)={a ∈ Bⁿf(a)=1}F=F(f)={a ∈ Bⁿf(a)=0}f 的真点和的假点的集合一个 部分定义的布尔函数 (pdBf)是一个布尔函数,使得 TF 不相交,但是 Bⁿ 的一些元素既不属于 T 也不属于 F 。我们可以将饮食记录表重写为 pdBf,如下所示:

一种部分定义的布尔函数。作者的表格。

此表中 1、5、7 点属于 T (真点),2、3、4、6 点属于 F (假点)。但是序列 (1,1,1,1,1,1,1) 既不属于 T 也不属于f能够预测它会很有趣。

什么是模式?

为了定义模式,我必须引入术语的概念。我们把 x ∈ B 的 补语 定义为 x⁻= 1-x .a* 是 B 的元素及其补语的乘积。而一个项的 就是其中的元素个数,命名为 字面 s,例如,设 t 为一个度为 3 的项使得 *t=x⁻₁x₂x₃,*则 *t(0,0,1)=(1–0)×0×1 = 0。*需要注意的是 t(a) 是为任何 a ∈ Bⁿ 定义的,即使 t 的次数小于 n ,忽略不在该项中的值即可。如果 t=x₂x⁻₃ 那么 *t(0,0,1)= 0×(1–1)= 0。如果 t(a)=1 我们说 t 覆盖a

*模式是 LAD 的核心元素。一个术语 t 叫做一个 pdBf 的 ( ) 模式 , *f,当且仅当:
1-
t(x)= 0∀**x 871
例如,术语 x⁻₁x₂ 等于 1 当且仅当 x₁=0 和 *x₂=1.*所以,在前面的例子中,这一项只涵盖了点 1 和点 7,它们在 T(f)中。这个术语叫做 f 的正型,可以注意到 x₄x⁻₆ 也是 f 的正型。在医生的分析中发现了这两种模式。分别地, F(f) 中覆盖点的项称为 F 的否定模式。

为了比较模式,我们需要引入一些合理的适合性标准:简单性选择性,以及证据*。这些标准定义了模式的一个简单的部分前序,称为 偏好 。设 P 为模式, f 为 pdBf,则我们有:*

简单性:考虑到 P 的文字集,对 P 的简单性进行评估。这就是σ偏好,我们定义 P₂ ≤_σ P₁ 当且仅当 P₁ 的文字集是 P₂ 的子集。

**选择性:**考虑 p 的子立方体(即 Bⁿp】覆盖的点的子集)来评估 P 的选择性。这是σ偏好,我们定义p₂≤_σp₁当且仅当 P₁ 的子多维数据集是 P₂ 的子多维数据集的子集。

***证据:*考虑到 P 所覆盖的 T(f) 的集合,对 P 的证据进行评估。这是ϵ偏好,我们定义 P₂ ≤_ϵ P₁ 当且仅当 P₁ 覆盖的真点集是 P₂ 覆盖的真点集的子集。

我们还可以使用交集∩和字典式细化|来组合偏好。设λ和γ是两个偏好,则我们有:

  • P₁ ≤_(λ ∩ γ) P₂ 当且仅当 P₁ ≤_λ P₂ P₁ ≤_γ P₂
  • P₁ ≤_(λ | γ) P₂ 当且仅当 P₁ < _λ P₂(P₁ ≈_λ P₂ P₁ ≤_γ P₂)

设λ为偏好,一个模式 P 称为 帕累托最优模式 当且仅当不存在模式P’≠P使得P ≤_λP’。不幸的是,最优模式的概念没有唯一的定义。我们总结了关于偏好和偏好组合的帕累托最优模式的性质。

帕累托最优的类型。作者的表格。

在头痛的例子中,术语 x₂x₅x₈是 f 的正模式(它涵盖了第 5 点和第 7 点)。但不是 小项 。事实上,x₂x₅也是一个阳性模式,x₂x₅x₈的亚立方体也包括在 x₂x₅.的亚立方体中在这里,x₂x₅是一个短期的积极模式。

考虑到正模式 x₂x₅x⁻₆x⁻₇x₈ ,我们可以说不存在 i ∈ {1,3,4} 这样的 x₂x₅x⁻₆x⁻₇x₈xᵢ 是一个模式。由此可见,是一个 质数 的正模式。

而且,x₂x₅和 x₂x₅x⁻₆x⁻₇x₈ 都是 正格局这是因为,没有模式覆盖的真点的例子。于是,x₂x₅是一个 跨区 的正格局(mintern and strong)是一个 强素数 的正格局。

法律援助署的方法

现在,我们已经准备好采用 LAD 的方法。LAD 的主要目的是找到 pdBF 的扩展(如前所述)。但是有许多方法可以扩展这个功能。难点在于找到了好的一个,称之为 。为此,LAD 分三个主要步骤进行处理:
1-将数据集转化为 pdBf。它被称为 二值化 过程。
2-检测医生在介绍中提出的合适模式。
3-成型理论。这意味着提取关于所有检测模式的 pdBf 的最佳扩展。

二值化。

第一步是数据的 二值化 。许多真实数据集包含数值数据和名义数据。将标称数据二进制化的一种简单方法是使用一键编码技术。这是一种非常快速的技术,数据会按照预期进行转换。数字数据的二进制化稍微复杂一些。一种常见的方法是选择临界值或分界点,并使用指标特征。要么该特征的性质表明了切割点的选择(如医学中的身体质量指数),要么它更复杂,仍有待改进。不幸的是,二值化过程通过添加许多特征增加了数据集的维度。因此,通过特征选择来减小尺寸是很重要的。

检测模式。

可以想象,这部分过程仍然是一个开放的研究领域,选择什么样的算法来生成模式取决于你想找到什么样的模式。在这里,我将给出一个在[4]中介绍的算法,用于提取正的 素数模式 。对于负图案,算法是相似的。

这个伪代码背后的想法很简单。目标是测试从 1 度到 D 度的术语,并且只保留那些具有正模式的术语。不考虑否定模式,包含正负两点的术语将作为下一个学位的候选项。

有几种算法可以生成不同类型的合适模式。如果你想了解他们的情况,我建议你参考[2]和[3]。

形成理论。

在这个阶段,我们有很多模式。当然太多了,无法创建一个可解释的模型,这是 LAD 的优势。因此,我们需要从生成的模式集中选择一组合适的模式。所选择的集合应该有合理数量的元素,但也有足够的元素来很好地区分积极和消极的观察。这个选择过程可以表示为一个优化问题。

对于每个积极的模式, pₖ ,我们分配一个二元变量 yₖ ,使得 yₖ=1 当且仅当 pₖ 被包括在最终模型中。并且对于每一个肯定的观察值 tᵢ ,我们定义一个二元向量 (tᵢ,tᵢ,…,tᵢᵖ) ,其中 p 是肯定模式的数量,并且 tᵢᵏ=1 当且仅当 pₖ 覆盖 tᵢ

这个优化问题可以很容易地适应你的需求,代价是小的变化。约束条件右侧的值 1 可以增加,以确保一个决策至少有两个(或更多)模式。我们还可以在总和 ∑ wₖyₖ.中的每个模式上添加一个权重 wₖ 例如,这些权重可以通过每个模式的程度来索引,以促进具有更容易被人类解释的少量文字的模式。

结论

数据的逻辑分析是一种非常有趣的分类方法,仍然是一个活跃的研究领域。LAD 基于模式的概念,模式是对新观察结果进行分类的工具,并为每个分类提供可理解的解释。

LAD 在医学上有许多应用,如乳腺癌预后、卵巢癌检测、生存数据分析等(概述见【2】)。我认为它也可以很容易地应用于许多其他领域。

不幸的是,LAD 似乎缺乏知名度,我希望这篇短文能激发您的兴趣。这是一种生成可解释的分类模型的优雅方式,不同于通常的基于树的算法和基于规则的算法。随后将有一篇关于 python 应用程序的文章。

参考

[1]奇卡洛夫、洛津、洛兹纳、莫什科夫、阮、斯科龙和杰洛斯科。 数据分析的三种途径:测验理论、粗糙集和数据的逻辑分析 (2012)第 41 卷。施普林格科学&商业媒体。

[2]阿利克夏、阿利克夏、博纳特斯、科岗。 数据的逻辑分析——彼得·l·哈默的愿景。 (2007)《数学与人工智能年鉴》49 卷,第 1 期:265–312 页。

[3] P.L .哈默、a .科岗、b .西默内、s .斯泽德马克 数据逻辑分析中的帕累托最优模式 。(2004)离散应用数学 144,第 1–2 期:79–102。

[4]马约拉斯。用于数据逻辑分析的 C++工具。(1995)鲁特科尔研究报告:1–95。

关于我们

Advestis 是一家欧洲合同研究组织(CRO ),对统计学和可解释的机器学习技术有着深刻的理解和实践。Advestis 的专长包括复杂系统的建模和时间现象的预测分析。

领英:https://www.linkedin.com/company/advestis/

你真的需要一个功能商店吗?

原文:https://towardsdatascience.com/do-you-really-need-a-feature-store-e59e3cc666d3

在大多数情况下,功能商店是多余的

似乎每个成熟的 ML 团队都为他们的 ML 平台建立了一个特性库。优步建造了调色板。Airbnb 建造了滑索。网飞建造了时间旅行。Google Cloud 与我们的客户 GoJek 合作构建了盛宴。

幸运的是,您不再需要构建或管理自己的系统。Google Cloud Vertex AI 提供了一个完全管理的功能商店,就像 Sagemaker 一样。甚至有像 tecton.ai 这样的公司致力于构建云无关的功能商店。鉴于所有这些,看起来好像特征库是机器学习的数据仓库——你不仅应该使用特征库,而且应该围绕特征库集中你的 ML 平台。

不要。在大多数情况下,功能存储增加了不必要的复杂性。然而,在一些情况下,功能存储将是无价的。

tldr: 如果需要在服务器端注入特性,特别是计算这些特性的方法会不断改进的情况下,使用特性库。否则就是矫枉过正。

训练发球偏斜

首先,我们来看一下功能商店试图解决的问题。

机器学习中的一个主要挑战是训练服务偏差。当对预处理数据训练 ML 模型时,有必要对传入的预测请求执行相同的步骤。这是因为我们需要为模型数据提供与其接受训练的数据相同的特征。如果我们不这样做,我们就会在训练和服务之间产生偏差,模型预测也不会那么好。

有三种方法可以确保在训练期间完成的预处理在预测期间按原样重复:将预处理代码放入模型中、使用转换函数或使用特征存储。让我们逐一讨论。

1.在模型中

最简单的选择是将预处理步骤合并到模型函数本身中。例如,它可能在 Keras 的 Lambda 层中执行。Keras 还提供现成的预处理层。这样,当保存模型时,预处理步骤将自动成为模型的一部分。

将预处理代码合并到模型函数中。作者图片

这种方法的优点是简单。不需要额外的基础设施。预处理代码与模型一起被携带。因此,如果您需要在边缘上部署模型,或者在另一个云中部署模型,您没有什么特别要做的。SavedModel 格式包含所有必要的信息。

这种方法的缺点是预处理步骤将在训练数据集的每次迭代中被浪费地重复。计算越昂贵,累积起来就越多。

另一个缺点是,您必须在与 ML 模型相同的框架中实现预处理代码。因此,例如,如果模型是使用 Pytorch 编写的,那么预处理也必须使用 Pytorch 来完成。如果您的预处理代码使用自定义库,这可能会变得很困难。

2.转换函数

将预处理代码放在模型函数中的缺点是,在模型训练过程的每次迭代期间,需要使用该代码来转换原始数据。

如果我们在一个函数中捕获预处理步骤,并将该函数应用于原始数据,这可以得到优化。然后,可以对预处理后的数据进行模型训练,效率更高。当然,我们必须确保从训练和预测代码中调用该函数。或者,我们必须在一个容器中捕获预处理步骤,并将容器放在输入和模型之间。虽然这增加了效率,但是也增加了复杂性——我们必须确保将转换函数保存为与模型相关联的工件,并且知道要调用哪个转换函数。

将预处理代码封装到一个转换函数中,该函数应用于原始数据集和预测请求。作者图片

像 Tensorflow Extended (TFX)这样的框架提供了一种转换功能来简化簿记工作。一些基于 SQL 的 ML 框架如 BigQuery ML 也支持 TRANSFORM 子句。

如果额外的基础设施和簿记开销值得的话,我宁愿使用转换函数,而不是将转换代码放入模型中。如果该特征计算量很大,就会出现这种情况。

3。特色商店

将预处理代码放在模型函数中,或者将其封装在转换函数(或者 SQL 子句或容器)中,对于绝大多数特性来说就足够了。

在两种情况下,这些还不够,您将需要一个功能库。特征库是用于存储和提供 ML 特征的存储库。特征存储本质上是一个键-值存储,其中键由一个实体(例如 hotel_id)和一个时间戳组成,而值由该实体的属性(例如价格、预订数量、过去一小时访问酒店列表的网站访问者数量等)组成。)截至该时间戳。

特征库是一个中央储存库,提供某一时刻的实体值。作者图片

需要要素存储的第一种情况是,请求预测的客户端不知道要素值,而是必须在服务器上进行计算。如果请求预测的客户端不知道特征值,那么我们需要一种机制将特征值注入到传入的预测请求中。功能商店扮演着这个角色。例如,动态定价模型的特征之一可以是在过去的一个小时内访问项目列表的网站访问者的数量。请求酒店价格的客户端(想象一个移动应用程序)不知道这个特性的价值。该信息必须在服务器上使用点击流数据的流式管道进行计算,并插入到功能存储中。

第二种情况是防止不必要的数据拷贝。例如,假设您有一个计算量很大的特征,并且在多个 ML 模型中使用。与使用变换函数并将变换后的特征存储在多个 ML 训练数据集中相比,将变换后的特征存储在一个集中的存储库中要高效得多,也更易于维护。对此要小心——增加的效率可能不值得增加的复杂性。

不要在这些场景中走极端。例如,如果需要在服务器端计算的模型的所有特性都是以相同的方式计算的(例如,它们是从关系数据库中检索的,或者是通过流管道计算的),那么将检索代码放在转换函数或容器中是完全可以接受的。类似地,相对于用一个特性库使你的 ML 平台复杂化,重复一些特性处理几次是完全可以接受的。

功能存储的规范使用

特色商店最重要的用例是当情况#1 和#2 都适用的时候。例如,假设您需要一个“时间点查找”来获取训练数据以训练模型。诸如过去一小时内网站访问者的数量或过去一小时内驾驶员的出行次数等特征。在多个模型中使用。但是它们非常简单,因为它们是由流管道计算的,所以它们的实时值可以是数据仓库的一部分。这些相对容易,并不总是需要一个功能商店。

现在考虑另一种类型的功能,这种功能被许多型号使用,但也在不断改进,例如,我们可能在音乐流媒体服务中嵌入了歌曲、艺术家和用户。有一个团队每天更新用户和歌曲嵌入。每次重新训练使用该特征的模型时,高商业价值的用例将需要定期重新训练,训练代码将需要获取与训练标签和最新版本的嵌入算法一致的该特征的值。这必须在所有标签上高效、轻松地完成。这必须在模型使用的数十或数百个特征中完成。特征存储使得对难以计算的、经常改进的特征的定期模型重新训练特别有用。

特征库对于难以计算且频繁更新的特征特别有用,因为模型必须在“时间点”嵌入上进行训练。作者图片

决策图表

此处讨论的注意事项总结在此决策图中:

在不同的捕获预处理选项之间进行选择。作者图片

这不是一个决定您的组织是否需要功能存储的决策树-可能有一些您需要的功能(对于这些功能,如果您使用 Vertex AI 功能存储,我们会很高兴)。这是一个决策树,用于决定是否为您正在构建的特定特征/模型使用特征存储。

以下是一些不需要功能商店的具体情况。如果你的特征是

1.客户所知。
2。在数据仓库里。
3。不依赖于时间。
4。仅批量供应所需。
5。计算成本低

保持简单。

进一步阅读

  1. 特征存储是我们在《机器学习设计模式》一书中讨论的设计模式之一。即使在那里,我们也警告过不要在这种模式上走极端,但是我担心功能商店正在变成“四人帮”书中的访问者模式——经常被不恰当地使用。
  2. 使用 Keras 预处理层进行模型内预处理,使用 BigQuery ML 中的 TRANSFORM 子句进行转换。TFX 为张量流/Keras 模型提供变换功能。
  3. 在 Google Cloud 上,如果需要功能商店,使用全托管顶点 AI 功能商店。

感谢我的同事 Anand Iyer 对这个话题的有益讨论。

要不要自学数据科学?从我的错误中吸取教训

原文:https://towardsdatascience.com/do-you-want-to-self-study-data-science-learn-from-my-mistakes-dbdf69653480

对自己数据科学自学历程的反思

照片由 Siora 摄影在 Unsplash 上拍摄

自学已经成为进入数据科学领域越来越流行和可行的途径。然而,像在任何领域一样,自学伴随着许多挑战——你必须建立自己的课程,保持自己的积极性,并对自己的学习负责。对于这些挑战我也不例外,在我的旅途中我犯了很多错误。

我创建了一个 6 个月的数据科学自学课程,从 2021 年 11 月开始。尽管我已经获得了统计学硕士学位,并在数据科学领域工作了几年,但事实是,数据科学正在快速发展,还有很多东西我不知道。

在阅读了丹尼尔·伯克(Daniel Bourke)的人工智能硕士课程(T7)后,我认为创建自己的课程来培养和提高我的数据科学技能是一个好主意。

然而,我 6 个月的自学课程并没有按计划进行。如果你正在考虑自学数据科学,那么我鼓励你不要犯和我一样的错误。

我的数据科学课程

我创建的课程包括课程和书籍。我试图整合不同来源的资源,这样我就不仅仅依赖于一个人/公司/平台。如果一个资源不能以帮助我的方式解释事物,那么我可以很容易地切换到另一个资源,而不是以我理解的方式教授该材料。

基础&机器学习:

  • 使用 Scikit-Learn、Keras 和 TensorFlow 进行机器实践学习:构建智能系统的概念、工具和技术
  • 用于数据科学和机器学习的 Python 训练营

深度学习:

  • 程序员实用深度学习
  • 深度学习专业化
  • 全栈深度学习
  • 抱脸课程

其他资源:

  • 汤姆·m·米切尔的机器学习
  • Ian good fellow 等人的深度学习

我完成了大约一半我打算在课程中涵盖的材料。我在自学的旅途中犯了很多错误,想在这篇文章里分享一下。

错误 1:过于担心学习数据科学的最佳课程或最佳书籍

学习数据科学的书籍、课程、YouTube 视频、博客帖子等等的数量之多,真的是宠坏了我们。很难选择你将在自己的学习中使用的资源,所以自然地,你会想只使用最好的或最推荐的资源。

预习对自学很重要。斯科特·扬在他的书 Ultralearning 中指出,你在这个项目中总投资的大约 10%应该花在“元学习”上,或者为你将学习什么和如何学习做准备。

在做准备时,我忽略了自己的学习风格,过于强调一个被强烈推荐的资源,而它实际上并不适合我。事实是,根本就没有完美的课程或完美的书籍,我是通过艰难的方式学到这一点的。

错误 2:使用不符合我学习风格的资源

我从视频课程或讲座中学不到什么。你会认为我已经从多年的大学生活中吸取了教训,但是不,我没有。我用高度活跃的方法学得最好。我不能被动地学习,它对我不起作用。

在大学里,让我以最优异的成绩毕业的第一件事是我做的大量练习题、过去的试卷、练习和项目作业。无论是否记笔记,我从听课中学到的东西都很少。我需要以一种积极的方式真正接触这些材料,以便能够记住或学习任何东西。

这对于我的自学之旅来说没有什么不同。我意识到,我在课程中计划的所有视频课程都没有帮助我学习——它们太被动了。正因为如此,我会走进许多兔子洞,试图理解视频课程中讨论的概念,并感到非常沮丧。

错误 3:没有做足够多的项目

我的课程意图是在我学习各种概念和方法的过程中尽可能多地做项目。这在《机器学习实践》一书中开始得很好,我为每章做了一个项目,但当我开始做基于视频的课程时,这种情况发生了变化——我进入了被动模式。

Tina Huang 在她的一个 YouTube 视频中提到,你应该只学你需要的东西,这样你就可以开始在一个项目中应用你的知识。这其实是学习数据科学最重要的部分——项目,项目,项目!

错误 4:专注于学习所有的数学

机器学习建立在数学基础之上。然而,为了学习、应用或做数据科学,你不需要知道或理解所有的数学。在我的自学之旅中,在进入下一个主题之前,我太专注于理解每个数学概念。

这是我大学时代就已经根深蒂固的东西。手工证明定理和计算算法是学习过程中的标准。虽然我确实相信有一些数学基础对于深入理解一个概念是很重要的,但绝对没有必要知道或理解一个方法中使用的每一个数学概念。这并不能从本质上让你成为更好的数据科学家。

做好一名数据科学家最重要的因素(在我看来)是解决问题。你能解决呈现给你的问题,并制定出对企业有价值的解决方案吗?

错误 5:在我的旅程中过早阅读研究论文

在数据科学中,是否阅读研究论文是一个棘手的话题,考虑到每天有多少新的研究发表,这可能是一个非常棘手的问题。

在开始这个自学之旅之前,我对深度学习一点都不了解。我完全是个初学者。我错误地认为我需要阅读(并理解)与我正在学习的一些主题相关的研究论文。

在我对周围的概念和方法有坚实的理解之前阅读研究论文只会让我感到沮丧和不充分,好像我是一个“坏”的数据科学家,因为这些研究论文对我来说没有什么意义。

在你的学习过程中,阅读研究论文是没有必要的,尤其是如果你还不熟悉这些材料的话。如果你对研究论文感兴趣,我建议当你的基础扎实时,把它们留到以后。

下一步是什么?

我的自学之旅并没有因为 6 个月的时间到了而结束。作为一名数据科学家,学习是不可或缺的一部分,我非常喜欢学习。

如果有什么不同的话,我的错误和失败教会了我不要做什么,并为我未来的学习目标提供了指导。展望未来,我将专注于学习的两个主要方面:

  1. 使用涉及更积极学习形式的资源
  2. 做更多的项目

对于第一点,我已经找到了一本优秀的在线书籍(免费的),名为 Dive Into Deep Learning ,我已经在大量使用它来研究深度学习。它用数学、代码和解释的混合涵盖了每个主题,并鼓励使用真实数据集进行基于项目的学习。

我正在使用 DataCamp 工作区查找数据并完成第二点的项目。我使用 DataCamp 工作区的原因是,他们提供的每个数据集都有一个挑战和情景部分。当你不知道从哪里开始一个新的数据集时,这些是非常有用的。

我发现这些场景特别有帮助,因为它们让你马上进入解决问题的模式。利用这一点,你可以为你的投资组合建立一个端到端的项目,不仅展示你对机器学习模型的知识,还展示业务和解决问题的方面。

结论

希望本文分享的我犯的错误,能对你的自学之旅有所帮助。

归根结底,自学不仅是为了学习材料,也是为了探索自我。你会学到什么对你有用,什么没用,有时这并不符合其他人的流程或建议,这没关系。

最重要的是,数据科学不是一项观赏性运动——最终你将需要亲自动手做项目和实施你所学的东西,即使你还没有感觉到“准备好”。

doccano——一个注释文本数据以训练自定义 NLP 模型的工具

原文:https://towardsdatascience.com/doccano-a-tool-to-annotate-text-data-to-train-custom-nlp-models-f4e34ad139c3

垃圾输入,垃圾输出:高质量的数据是健壮的 ML 引擎的燃料

帕特里克·托马索在 Unsplash 上的照片

我最近不得不在一个非常技术性的领域为一个非常具体的任务建立一个 NLP 模型。

这很有挑战性,因为我对这个主题一无所知,也没有可用的培训数据。

作为一名数据科学家,我首先尝试研究开源数据集、预训练模型和科学文章,但我最终得出的结论是,没有任何东西真正符合我的目标,解决我的问题的唯一方法是从零开始建立一个训练数据集**。**

→必须进行手动贴标🤷‍♂

为此,我查看了多种文本标注工具,最终选择了 Doccano 。

作者截图

在这篇文章中,我将告诉你更多关于这个工具的信息:我将首先介绍它的多种特性,并向你展示如何为你的团队安装和设置它。
然后,我将给出一个具体的例子,在这个例子中,Doccano 帮助为命名实体识别(NER)任务标注数据。

本帖为个人评论。我并没有得到 Doccano 或其任何核心开发者的认可。

事不宜迟,让我们来看看🔍

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

有时,您需要花费时间来构建标注数据集⏳

随着由大规模变压器供电的非常强大的模型的出现,我们倾向于认为今天的许多 NLP 任务已经解决了。

→如果您可以访问带标签的数据,在您的下游任务(分类、翻译、NER)上微调预训练的转换器可能会给您带来好的甚至是最先进的(SOTA)结果
→如果您没有带标签的数据,您可以加载一个已经在类似任务上进行过预训练的转换器并原样应用 →如果您无法访问训练数据或预训练模型,您可以有时执行零测试你加载一个转换器,指出你的类标签,并对它们进行预测。**

尽管它们看起来像是纯粹的魔法,但预训练的模型(和变形金刚)并不能解决所有的 NLP 问题。

事实上,如果没有整合到数据中的正确领域知识,预训练的模型只能有一个宽泛的视图,特别是如果它们是在通用语料库(👋维基百科)

这就是为什么当你面临一个需要大量领域专业知识的问题时,注释数据和构建训练数据集可能是一个合理的解决方案。

一开始看起来确实很痛苦,但从长远来看是有价值的。

花时间标注数据的重要性

介绍 Doccano

在查看了 3 或 4 个文本注释工具(既有开源的也有专有的)之后,我最终决定在 doccano 上投入时间。

正如官方文档中所描述的,Doccano 是

“一个面向人类的开源文本注释工具。为文本分类序列标注序列任务提供标注功能。(..),可以创建标注数据用于情感分析、命名实体识别、文本摘要等等。只需创建一个项目,上传数据并开始注释。你可以在几个小时内建立一个数据集。”

作者修改的 GIF

为了能够在本地使用 doccano,您有两种选择:

1 —使用 pip 在本地安装

你可以在几秒钟内在电脑上把它旋转起来。

只需运行这个命令来安装它。

***pip install doccano***

由于 doccano 原生使用 SQLite 作为数据库,所以也可以用 PostgreSQL 安装。在这种情况下,您需要运行以下命令:

***pip install 'doccano[postgresql]'***

并将DATABASE_URL设置为环境变量。

***DATABASE_URL="postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DB}?sslmode=disable"***

安装 doccano 后,运行以下命令,以便:

  • 初始化数据库:
***doccano init***
  • 创建超级用户
***doccano createuser --username admin --password pass***
  • 启动 web 服务器
***doccano webserver --port 8000***

这会在端口 8000 运行本地服务器列表。

作者截图

现在,在另一个终端中,您需要启动一个队列来处理文件上传和下载。

***doccano task***

→通过访问 http://127.0.0.1:8000 ,您现在可以在本地访问该工具。

只需输入您之前定义的用户名和密码,就可以开始了。

作者截图

2-Docker 或 Docker 撰写

您还可以使用 Docker 启动 doccano,如果您想将它部署在云上,Docker 是一个不错的选择。

Docker 允许您将以前手动执行的不同步骤减少为几个命令,这些命令从 Dockerhub 中提取 doccano 图像,在设置凭证、数据库和网络之后创建并启动容器。

***docker pull doccano/doccano
docker container create --name doccano \
  -e "ADMIN_USERNAME=admin" \
  -e "ADMIN_EMAIL=admin@example.com" \
  -e "ADMIN_PASSWORD=password" \
  -v doccano-db:/data \
  -p 8000:8000 doccano/doccano****docker container start doccano***

您还可以使用 docker-compose 将 doccano 作为多容器堆栈来执行。

***docker-compose -f docker/docker-compose.prod.yml \
               --env-file .env up***

你可以在这里查看docker-compose.prod.yml

特性和功能

Doccano 使贴标成为一个简单的过程。让我们创建一个标注项目并开始标注,而不是枚举它的功能。一路上我们会看到有趣的东西。

→每个任务的单独/独立项目

启动 Doccano 后,进入登录页面并输入您的凭证。登录后,您将看到您过去启动的不同注释项目的列表。

作者截图

→多种类型的注释

点击创建按钮启动一个新的项目,并选择适当的任务(文本分类,序列标签,序列等。)

让我们以选择 序列标注 任务为例。这适用于命名实体识别等任务。

→简易项目设置

一旦您选择了一个任务,Doccano 将要求您定义一个项目名称、一个描述、一些标签、是否有重叠的实体、关系标签或用户之间共享的注释。

作者截图

→配置项目

在开始注释过程之前,应该先设置一些配置。

  • 定义标签:例如,您有兴趣检测的实体。你也可以给它们中的每一个赋予一个颜色代码。

  • 创建用户:Doccano 是一个协作工具,在这个工具中,多个用户可以在同一个项目上工作。

要管理用户,首先需要进入 Django 管理页面http://localhost:8000/admin/

在“用户”下,您可以添加或删除用户。

假设我创建了一个用户“ahmed”,我可以将它添加到项目中,并指定它的角色:项目管理员、注释者、注释批准者。

作者截图

  • 为注释者添加注释指南

作者截图

→导入数据集

Doccano 支持多种格式作为输入。

  • 文本文件:多个 TXT 文件,每个文件对应一个文档

作者截图

  • TextLine: 一个单独的 TXT 文件,其中文档以行分隔

作者截图

  • JSONL: 其中提到了实体的位置

作者截图

  • CONLL 格式

作者截图

数据上传后,您可以在表格上查看并开始注释。

→开始注释过程

我喜欢 Doccano 的注释界面:它用户友好、简单,并能让您访问您需要的一切:

  • 界面上的交互式标签
  • 完成率
  • 注释和元数据来丰富注释

作者 GIF

→导出注释数据

完成后,您可以将注释导出为 JSONL 格式。

作者截图

→指标

Doccano 提供了一些关于您注释的实体的统计数据。这可能有助于发现类别不平衡

作者截图

包裹

Doccano 是协作完成注释任务的一个很好的工具。如果你需要创建一个机器学习数据集,而你没有这方面的经验,你绝对应该尝试一下。

作为一个正在进行的开源项目,Doccano 并不包括我们在 Labelbox 等企业(且昂贵)解决方案中看到的所有闪亮功能。
例如,它没有为计算机视觉、SSO 或 API 集成提供专门的注释工具。

尽管如此,你仍然可以在不投入太多的情况下做很多事情。

新到中?你可以每月订阅 5 美元,并解锁各种主题的无限文章(技术、设计、创业……)你可以通过点击我的推荐链接来支持我

*https://ahmedbesbes.medium.com/membership

由 Oleksandra Bardash 在 Unsplash 上拍摄的照片*

面向绝对初学者的 Docker:图像和容器的区别

原文:https://towardsdatascience.com/docker-for-absolute-beginners-the-difference-between-an-image-and-a-container-7e07d4c0c01d

了解 Docker 图像和容器的区别+实用代码示例

因为这是一篇关于 Docker 的文章,我们必须有一个与容器相关的封面,对吗?(图片由边境摄影师在 Unsplash 上拍摄)

容器、映像、环境、构建、运行、虚拟机..当你刚接触 Docker 时,所有这些抽象的术语可能会有点混乱。在本文中,我们将浏览所有这些术语,并了解每个术语。我们将重点解释图像和容器之间的区别以及它们是如何协同工作的,但是在这个过程中,我们将探索其他与 Docker 相关的东西。在本文结束时,您将:

  • 了解如何建立一个形象
  • 了解如何旋转图像
  • 理解图像和容器之间的区别
  • 了解如何在日常工作中更好地使用 Docker

我们来编码吧!

简单地说,码头工人

Docker 是对“但它在我的机器上工作过!”假设您在笔记本电脑上编写了一个小程序:假设它是一个简单的 Python API。现在您想将这个程序部署在同事的笔记本电脑或服务器上。你复制代码,启动 API,它就崩溃了。为什么?

出现这种情况的原因可能有很多:可能 Python 没有安装。也许另一台机器的操作系统与你的代码不兼容。换句话说:你的程序是在一个环境中构建的,在另一个环境中无法运行。

Docker 对这个问题的解决方案非常简单,同时也非常聪明:我们不仅要部署代码,还要部署我们的环境。Docker 创建一个盒子,在盒子里安装一个操作系统,然后复制你的源代码。然后我们把盒子给别人。这很聪明,因为一旦你的代码在这个环境(box)中运行,这意味着它可以在任何地方运行。

在本文中,我们将关注如何构建这些盒子以及如何共享它们。换句话说:例如,我们如何构建图像,将它们旋转到容器中,并在服务器上部署它们!

集装箱化!(图片由滕玉红在上 Unsplash 拍摄)

1.创建图像

在前一部分中,我们看到了 Docker 将我们的代码与我们的环境打包在一起,这样我们就可以运行它了。我们在前面部分中称之为“盒子”的东西被称为图像。图像是 Docker' 构建过程的结果。在构建过程中,我们使用一个 Dockerfile 。这是一个包含构建容器说明的文件。

我们将在下一部分使用大量命令行。如果你对使用终端不熟悉,可以看看这篇文章**。**

1.1 docker 文件

让我们来看看一个非常简单的 dockerfile 文件。想象我们有一个网站,我们想

*FROM nginx:alpineCOPY c:/myproject/htmlfolder /usr/share/nginx/html*

这里发生两件事:
1。使用来自关键字的
*,我们告诉 Docker 提取一个基础图像。在这种情况下,我们使用安装了 nginx 的映像。***

2.使用 COPY 我们指示 Docker 将我们计算机上的一些代码复制到映像中。在这种情况下,我们将 htmlfolder 中的所有代码复制到图像中的指定文件夹中。Nginx 将在这个文件夹中托管所有代码。

1.2 建立形象

请记住,到目前为止,我们只指定了一些指令。现在我们实际上可以用docker build . -t my_image:v1构建图像。

这个命令中的.意味着 docker 可以使用当前目录中一个名为dockerfile的文件。您还可以指定您的 Dockerfile,如果它位于其他地方或者用
docker build -f c:/things/mydockerfile -t my_image:v1 不同地命名,正如您所看到的,我们使用-f 标志将路径传递给我们的 dockerfile(在本例中称为mydockerfile)。
使用-t标志,我们以name:tag格式命名并随意标记我们的图像。为我们的图像添加标签便于以后使用。

我们的形象几乎建立起来了(图片由 Randy Fath 在 Unsplash 上拍摄)

2.旋转集装箱

到目前为止,我们已经用 docker 文件构建了一个映像。然而,生成的图像还没有做任何事情。我们需要运行它。你可以用两种方式旋转图像:用docker run和用合成文件。我们会经历这两个。

一旦映像开始运行,它就被称为容器。

2.1 Docker 运行映像

在这种情况下,我们将运行之前构建的图像。最简单的方法是:docker run -p "81:80" my_image:v1。这将运行我们之前构建的映像,并将我们笔记本电脑上的端口 81 映射到容器中的端口 80,这是 nginx 为我们的网站提供服务的地方。这意味着我们可以在笔记本电脑上进入localhost:81来查看网站。轻松点。

2.2 使用 docker-compose 运行图像

如果我们有大量的图像,我们将花费大量的时间键入前一部分中的所有 docker run 命令。使用 docker-compose,我们可以将这个运行配置放在一个文件中,这样我们就不必每次都键入它。继续之前,请安装 docker compose。

compose 的另一个优点是我们可以用它将容器链接在一起。更多这方面的内容请见 本文

我们将把前一部分的命令翻译成 docker compose 中的运行配置。我们将创建一个名为docker-compose.yml的文件,内容如下:

*version: "3.8"services:
  my_site:
    container_name: my_site
    hostname: my_site
    image: my_image:v1
    ports:
      - "81:80"*

正如你看到的,-p "81:80"翻译成最后两行。我们还添加了一些关于主机名和容器名的额外信息。我们指定要在第 7 行运行名为my_image:v1的图像。

注意,和 Dockerfile 一样,docker-compose.yaml 只是一个包含指令的文件。我们必须运行它来做一些事情。如果我们与 docker-compose.yml 文件在同一个文件夹中,我们可以调用docker-compose up,或者指定这个文件,如果它位于其他地方或者用docker-compose -f c:/snacks/my_docker-compose.yml up命名。

Docker-compose 使得用一个命令运行许多(连接的)图像变得容易,并且节省了你大量的输入。

3.图像和容器的区别

现在我们有了一些实践经验,我们可以确定图像和容器之间的区别。

图像就像一个类:蓝图
容器就像一个类的实例

最重要的区别是图像是一个逻辑对象;这就像一个蓝图,而容器是一个现实生活中的物体。一个图像只创建一次;使用该图像,容器被创建任意次

Dockerfile 更像是一个菜谱:如何构建某样东西的说明。
撰写文件更像是手册:如何使用某些东西的说明。

您使用一个docker 文件构建一个映像。这个映像是操作系统和源代码的组合。
接下来你可以旋转你的图像,产生容器。您可以使用docker rundocker-compose.yml文件旋转/运行图像,您可以在该文件中指定 如何运行 。运行的图像称为容器。您可以在这里指定容器如何适应您的部署,也可以在这里将容器链接在一起

准备发布我们的代码(图片由克里斯·帕甘在 Unsplash 上提供)

结论

我希望读完这篇文章后,你对 Docker 使用的词汇和 Docker 的工作方式有一个更清晰的理解。我希望这篇文章是清楚的,但如果你有建议/澄清,请评论,以便我可以做出改进。同时,看看我的其他关于各种编程相关主题的文章:

  • Docker 适合绝对初学者
  • Docker 为绝对初学者编写
  • 把你的代码变成一个真正的程序:使用 Docker 打包、运行和分发脚本
  • Python 为什么慢,如何加速
  • Python 中的高级多任务处理:应用线程池和进程池并进行基准测试
  • 编写自己的 C 扩展来加速 Python x100
  • 【Cython 入门:如何在 Python 中执行>每秒 17 亿次计算
  • 用 FastAPI 用 5 行代码创建一个快速自动归档、可维护且易于使用的 Python API

编码快乐!

—迈克

页(page 的缩写)学生:比如我正在做的事情?跟我来!

*https://mikehuls.medium.com/membership *

数据科学码头工人

原文:https://towardsdatascience.com/docker-for-data-science-7927fb3c70d3

每个数据科学家都应该了解的 Docker

Docker 是什么?

想象一下,你是一名在空间站的宇航员,打算去外面欣赏风景。你将面临敌对的环境。温度、氧气和辐射都不是你生来的目的。人类需要特定的环境才能茁壮成长。为了在任何其他场景中正常工作,比如在深海或高空,我们需要一个系统来重现这种环境。无论是宇航服还是潜艇,我们都需要隔离,以及确保我们所依赖的氧气、压力和温度水平的东西。

换句话说,我们需要一个容器。

任何软件都面临着和宇航员一样的问题。一旦我们离开家,来到外面的世界,环境变得充满敌意,一种复制我们自然环境的保护机制是强制性的。Docker 容器是程序的宇航服。

作者图片

Docker 将软件与同一系统上的所有其他东西隔离开来。在“宇航服”内运行的程序通常不知道自己穿着宇航服,也不受外界发生的任何事情的影响。

作者图片

集装箱堆栈

  • **应用:**高层应用(你的数据科学项目)
  • **依赖:**低级通用软件(想想 Tensorflow 或 Python)
  • **Docker 容器:**隔离层
  • **操作系统:**与硬件交互的低级接口和驱动程序
  • 硬件: CPU、内存、硬盘、网络等。

基本思想是将应用程序及其依赖项打包到一个可重用的工件中,该工件可以在不同的环境中可靠地实例化。

如何创建容器?

创建 Docker 容器的流程:

作者图片

  1. Dockerfile: 编译图像的说明
  2. **图片:**编译好的神器
  3. **容器:**图像的执行实例

Dockerfile 文件

首先,我们需要说明。

我们可以定义宇航服的温度、辐射和氧气水平,但我们需要的是说明,而不是要求。Docker 是基于指令的,而不是基于需求的。我们将描述如何,而不是什么。为此,我们创建了一个文本文件,并将其命名为 Dockerfile。

# Dockerfile
FROM python:3.9
RUN pip install tensorflow==2.7.0
RUN pip install pandas==1.3.3

FROM命令描述了一个基础环境,所以我们不需要从头开始。从 DockerHub 或通过谷歌搜索可以找到大量的基础图片。

RUN命令是改变环境的指令。

作者图片

注意:虽然我们的例子是一个接一个地安装 Python 库,但不推荐这样做。最佳实践是利用requirements.txt,它定义了 Python 的依赖性。

# Dockerfile with requirements.txt
FROM python:3.9
COPY requirements.txt /tmp
RUN pip install -r /tmp/requirements.txt

COPY命令将本地磁盘上的一个文件(如requirements.txt)复制到映像中。这里的RUN命令一次性安装了在requirements.txt中定义的所有 Python 依赖项。

注意:使用 RUN 时,所有熟悉的 Linux 命令都由您支配。

Docker 图像

现在我们有了我们的Dockerfile,我们可以把它编译成一个叫做图像的二进制工件。

这一步的原因是使它更快和可重复。如果我们不编译它,每个需要宇航服的人都需要找到一台缝纫机,并费力地运行每次太空行走的所有指令。这太慢了,而且不确定。你的缝纫机可能和我的不同。速度和质量的权衡是图像可能相当大,通常是千兆字节,但无论如何,2022 年的千兆字节是微不足道的。

要进行编译,请使用 build 命令:

docker build . -t myimage:1.0

这将构建一个存储在本地机器上的映像。t 参数将图像名称定义为“myimage”,并给它一个标记“1.0”。要列出所有图像,请运行:

docker image list
REPOSITORY          TAG                 IMAGE ID            SIZE
<none>              <none>              85eb1ea6d4be        2.9GB
myimagename         1.0                 ff732d925c6e        2.9GB
myimagename         1.1                 ff732d925c6e        2.9GB
myimagename         latest              ff732d925c6e        2.9GB
python              3.9                 f88f0508dc46        912MB

码头集装箱

最后,我们为太空行走做好了准备。容器是宇航服的真实实例。它们在衣柜里没什么用处,所以宇航员应该穿着它们执行一两项任务。

指令可以嵌入到映像中,或者在启动容器之前及时提供。让我们做后者。

docker run myimagename:1.0 echo "Hello world"

这将启动容器,运行一个 echo 命令,然后关闭它。

现在我们有了一个可重现的方法,可以在任何支持 Docker 的环境中执行我们的代码。这在数据科学中非常重要,因为每个项目都有许多依赖项,而可再现性是这个过程的核心。

容器在执行完指令后会自动关闭,但是容器可以运行很长时间。尝试在后台启动一个很长的命令(使用 shell 的&操作符):

docker run myimagename:1.0 sleep 100000000000 &

您可以看到我们当前运行的容器:

docker container list

要停止这个容器,从表中取出容器 ID 并调用:

docker stop <CONTAINER ID>

这停止了容器,但是它的状态保持不变。如果你打电话

docker ps -a

您可以看到容器已停止,但仍然存在。彻底摧毁它:

docker rm <CONTAINER ID>

结合停止和删除的单一命令:

docker rm -f <CONTAINER_ID>

要移除所有停止的剩余容器:

docker container prune

提示:您也可以使用交互式 shell 启动容器:

$ docker run -it myimagename:1.0 /bin/bash
root@9c4060d0136e:/# echo "hello"
hello
root@9c4060d0136e:/# exit
exit
$ <back in the host shell>

当您可以自由地交互运行所有 Linux 命令时,这对于调试映像的内部工作非常有用。通过运行exit命令返回到您的主机 shell。

术语和命名

注册表 =托管和分发图像的服务。默认的注册中心是 Docker Hub。

存储库 =名称相同但标签不同的相关图像的集合。通常,同一应用程序或服务的不同版本。

标签 =附加到存储库中图像的标识符(例如,14.04 或 stable)

ImageID =为每个图像生成的唯一标识符哈希

官方文件宣称:

映像名称由斜杠分隔的名称组成,可以选择以注册表主机名作为前缀。

这意味着您可以将注册表主机名和一串斜杠分隔的“名称组件”编码成您的映像的名称。老实说,这很复杂,但这就是生活。

基本格式是:

<name>:<tag>

但实际上是:

<registry>/<name-component-1>/<name-component-2>:<tag>

它可能因平台而异。对于谷歌云平台(GCP),惯例是:

<registry>/<project-id>/<repository-name>/<img>@<img-digest>:<tag>

为您的案例找出正确的命名方案取决于您。

作者图片

注意:如果你拉一个没有任何标签的图像,将使用latest标签。切勿在生产中使用此latest标签。始终使用具有唯一版本或散列的标签,因为有人不可避免地会更新“最新”图像并破坏您的构建。今天最新的,明天不再最新!宇航员不关心最新的花里胡哨。他们只是想要一套适合他们的宇航服,让他们活下去。和latest在一起,你可能得不到你想要的。

码头工人的形象和秘密

就像将秘密放入 git 存储库是一种可怕的做法一样,您也不应该将它们放入 Docker 映像中!

图像被放入储存库并被随意传递。正确的假设是,进入图像的任何内容在某个时候都可能是公开的。它不是存放用户名、密码、API 令牌、密钥代码、TLS 证书或任何其他敏感数据的地方。

机密和 docker 图像有两种情况:

  1. 在构建时你需要一个秘密
  2. 运行时你需要一个秘密

这两种情况都不能通过把事情永久地放入图像中来解决。让我们看看如何以不同的方式来做这件事。

作者图片

构建时秘密

如果您需要一些私有的东西——比如一个私有的 GitHub 存储库——在构建时放入映像中,您需要确保您使用的 SSH 密钥不会泄漏到映像中。

不要使用复制指令将密钥或密码移动到映像中!即使你事后把它们拿掉,它们还是会留下痕迹!

快速搜索会给你很多不同的选择来解决这个问题,比如使用多阶段构建,但是最好和最现代的方法是使用 BuildKit。BuildKit 随 Docker 一起提供,但是需要通过设置环境变量DOCKER_BUILDKIT来启用构建。

例如:

DOCKER_BUILDKIT=1 docker build .

BuildKit 提供了一种机制,使秘密文件在构建过程中安全可用。

让我们首先用内容创建secret.txt:

TOP SECRET ASTRONAUT PASSWORD

然后创建一个新的Dockerfile:

FROM alpine
RUN --mount=type=secret,id=mypass cat /run/secrets/mypass

--mount=type=secret,id=mypass通知 Docker,对于这个特定的命令,我们需要访问一个名为 mypass 的秘密(其内容我们将在下一步告诉 Docker build)。Docker 将通过临时挂载一个文件/run/secrets/mypass来实现这一点。

cat /run/secrets/mypass是实际的指令,其中 cat 是将文件内容输出到终端的 Linux 命令。我们称之为验证我们的秘密确实可用。

让我们构建图像,添加--secret来通知docker build在哪里可以找到这个秘密:

DOCKER_BUILDKIT=1 docker build . -t myimage \
    --secret id=mypass,src=secret.txt

一切正常,但是我们并没有像预期的那样看到 secret.txt 的内容在我们的终端中打印出来。原因是默认情况下,BuildKit 不会记录每一次成功。

让我们使用附加参数来构建图像。我们添加了BUILDKIT_PROGRESS=plain来获得更详细的日志记录,添加了--no-cache来确保缓存不会破坏日志记录:

DOCKER_BUILDKIT=1 BUILDKIT_PROGRESS=plain docker build . \
    --no-cache --secret id=mypass,src=secret.txt

在所有打印出来的日志中,您应该会发现这一部分:

5# [2/2] RUN --mount=type=secret,id=mypass cat /run/secrets/mypass 5# sha256:7fd248d616c172325af799b6570d2522d3923638ca41181fab4ea143 5# 0.248 TOP SECRET ASTRONAUT PASSWORD

这证明构建步骤可以访问secret.txt

使用这种方法,您现在可以安全地将秘密装载到构建过程中,而不用担心将密钥或密码泄漏到生成的映像中。

运行时秘密

当容器在生产环境中运行时,如果您需要一个秘密(比如数据库凭证),您应该使用环境变量将秘密传递到容器中。

不要在构建时将任何秘密直接放入映像中!

docker run --env MYLOGIN=johndoe --env MYPASSWORD=sdf4otwe3789

这些可以用 Python 访问,比如:

os.environ.get('MYLOGIN')
os.environ.get('MYPASSWORD')

提示:你也可以从像哈希公司金库这样的秘密商店获取秘密!

GPU 支持

带有 GPU 的 Docker 可能比较棘手。从头构建映像超出了本文的范围,但是现代 GPU (NVIDIA)容器有五个先决条件。

图像:

  • CUDA/cuDNN 库
  • 框架的 GPU 版本,如 Tensorflow(需要时)

主机:

最好的方法是找到一个已经包含了大多数先决条件的基础映像。像 Tensorflow 这样的框架通常会提供像tensorflow/tensorflow:latest-gpu这样的图片,这是一个很好的起点。

排除故障时,您可以首先尝试测试您的主机:

nvidia-smi

然后在容器中运行相同的命令:

docker run --gpus all tensorflow/tensorflow:latest-gpu nvidia-smi

对于这两个命令,您应该得到类似这样的结果:

作者图片

如果您从任何一个地方得到一个错误,您将知道问题是在容器内部还是外部。

测试你的框架也是一个好主意。例如 Tensorflow:

docker run --gpus all -it --rm \
    tensorflow/tensorflow:latest-gpu \
    python -c \
    "import tensorflow as tf;print(tf.reduce_sum(tf.random.normal([1000, 1000])))"

输出可能很详细,并有一些警告,但它应该以类似如下的内容结束:

Created device /job:localhost/replica:0/task:0/device:GPU:0 with 3006 MB memory: -> device: 0, name: NVIDIA GeForce GTX 970, pci bus id: 0000:01:00.0, compute capability: 5.2 tf.Tensor(-237.35098, shape=(), dtype=float32)

Docker 容器与 Python 虚拟环境

作者图片

Python 虚拟环境在本地开发环境中的不同 Python 项目之间创建了一个安全气泡。Docker 容器解决了一个类似的问题,但是在不同的层面上。

虽然 Python 虚拟环境在所有与 Python 相关的事物之间创建了隔离层,但是 Docker 容器为整个软件栈实现了这一点。Python 虚拟环境和 Docker 容器的用例是不同的。根据经验,虚拟环境足以在本地机器上开发东西,而 Docker 容器是为在云中运行生产作业而构建的。

换句话说,对于本地开发来说,虚拟环境就像在沙滩上涂防晒霜,而 Docker 容器就像穿着宇航服——通常不舒服,而且大多不实用。

想要更多实用的工程技巧吗?

数据科学家越来越多地成为 R&D 团队的一部分,并致力于生产系统,这意味着数据科学和工程领域正在发生碰撞。我想让没有工程背景的数据科学家更容易理解,就这个主题写了一本免费电子书。

下载电子书: 数据科学家的工程实践

【https://valohai.com】最初发表于https://valohai.com/blog/docker-for-data-science/

Docker 图像与容器

原文:https://towardsdatascience.com/docker-image-vs-container-7d9acab24c5

理解 Docker 中图像和容器的区别

阿隆·伊金在 Unsplash 上的照片

Docker 一直是软件开发领域的游戏规则改变者,因为它使开发人员能够共享一个隔离的环境,让整个团队(或用户组)以一种非常一致和直观的方式构建、测试和部署应用程序。

由于这项技术已经存在了相当长的时间,我敢肯定你已经遇到了像图像、容器、卷甚至 Dockerfile 这样的术语。Docker 图像和容器是这种特殊技术的两个最基本的概念,许多 Docker 的新手都很难清楚地区分这两者。

在接下来的部分中,我们将讨论 Docker 图像和容器是什么,以及它们的主要区别。

Docker 图像(容器图像)

docker 映像是包含多个层的不可变文件,每个层对应于可以包含依赖关系、脚本或其他配置的文件系统。

这种分层提高了可重用性并加快了映像构建,因为每一步都可以缓存。现在,下一次构建将从缓存中加载一个步骤,除非自上次构建以来该步骤已被修改。

现在,docker build命令被用来从Dockerfile构建一个图像——一个由用户可以在命令行上调用的命令组成的文本文件来创建一个想要的图像。

Docker 图像是容器的基础。映像是根文件系统更改和相应的执行参数的有序集合,供容器运行时使用。一个映像通常包含一个相互堆叠的分层文件系统的联合体。

— Docker 词汇表

图像存储在 Docker 注册表中——默认的是 Docker Hub ,但是您甚至可以托管您自己的 Docker 注册表,只有您的组织才能访问。

您可以通过运行以下命令来查看主机上的所有图像

$ docker images

码头集装箱

现在 docker 容器是 Docker 映像的实例,运行在完全隔离的环境**(即与机器上运行的任何其他进程隔离)中,并且可以在任何操作系统上执行(可移植性!).**

容器是轻量级和可移植的运行时环境,用户可以在其中独立于底层主机运行应用程序。

可以停止正在运行的容器,但同时它可以保留设置和任何文件系统更改,以便下次重新启动时可以重用它们。

容器是 docker 映像的运行时实例。

码头集装箱包括

-码头工人图像

-执行环境

-一套标准的指令

这个概念是从海运集装箱借用的,它定义了一个在全球运输货物的标准。Docker 定义了一个运送软件的标准。

— 码头术语表

您可以通过运行以下命令来查看所有正在运行的容器

$ docker ps

如果您还想列出没有启动和运行的容器,您必须传递-a选项:

$ docker ps -a

最后的想法

Docker 为开发人员提供了一个开发、运行和发布应用程序的平台。理解如何有效地使用 Docker 肯定会对你的软件开发之旅和职业生涯有所帮助。

因此,首先理解该技术的基本原理和组件很重要,这将有助于您更舒适地使用 Docker。这个旅程从您能够区分 Docker 图像和 Docker 容器开始。

简而言之,Docker 映像是一个由多层组成的结构,正如在Dockerfile中所指定的,而 Docker 容器是 Docker 映像的一个(运行中的)实例(这也许是您可能想要使用 Docker 的原因!).

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

https://gmyrianthous.medium.com/membership

相关文章你可能也喜欢

对接烧瓶 ML 应用

原文:https://towardsdatascience.com/dockerizing-flask-ml-applications-3577b216dac0

使用 Flask 部署 ML 模型和将您的工作容器化的指南

图片来自乔纳斯·史密斯的 Unsplash

部署 ML 模型是 ML 生命周期中必不可少的一步,这一步经常被数据科学家所忽视。没有模型部署/托管,在现实世界的应用中就没有机器学习模型的使用。有很多种方法来保存你的 ML 模型,其中最简单也是最有效的是烧瓶。

Flask 是一个用 Python 实现的微型网络框架。使用 Flask,我们将通过一个例子演示如何在本地为 ML 模型提供推理服务。如果你对 Flask 完全陌生,我建议你看一下这个指南,它会让你快速上手。

烧瓶只是我们要解决的首要问题的第一步。是的,我们可以找到一种方法来使用 Flask 托管我们的模型,但是我们如何在生产环境中维护这个环境呢?我们如何在实时应用程序中跟踪我们可能必须对软件进行的任何更改?

通过 Docker 容器,我们提供了一个轻量级的包装器,可以非常容易地复制您的环境和依赖关系。例如,如果我们有一个软件更新需要安装在我们的应用程序中,Docker 使实现和跟踪这个更新变得很简单。通过利用诸如 Docker Registry 之类的服务,您还可以跟踪不同的映像版本以进行部署。使用 Docker 容器来保存我们的环境和我们所做的任何更改,软件生命周期变得更加简单和高效。关于 Docker 的完整分类,请查看下面的资源。

在本文中,我们将通过一个我们训练过的 ML 模型来看一下这两个步骤。

注意:本文将假设您对 Python、Docker、Flask 和使用 CLI 有基本的了解。我们也将使用一些基本的 HTML/CSS,但是你可以原样复制模板。这篇文章也将使用一个 ML 模型来服务,但我们不会涵盖模型构建背后的任何理论,关于模型的具体信息,请参考这篇文章。

资料组

对于我们的例子,我们将使用来自 Kaggle 的汽油消耗回归数据集。原始数据源在这里被许可。

模型结构

对于本文,我们不会在模型构建或从数据科学性能角度选择最准确的模型上花费太多时间。对于我们的回归问题,我将通过 Sklearn 框架利用一个 RandomForest 回归模型。一般来说,当我需要快速访问工作的 ML 模型示例时,我会尝试维护一个模型工具箱,它会给我样板代码来加速这个过程。

准备数据

训练随机森林模型

我使用 Joblib 模块对模型进行序列化,为了验证它是否有效,我将快速预测一个样本数据点。

样本推断

确保保留生成的“model.pkl”文件(也可以创建 model.joblib)。这是我们将在 Flask 服务器上加载用于推理的模型工件。

在 Flask 上托管模型

我们的 Flask 应用程序有两个部分。首先,我们想使用一些基本的 HTML/CSS 为我们的前端构建一个模板。在这个模板中,我们所做的只是创建一个简单的表单,它将接受四个输入:汽油税、平均收入、铺设的公路和人口驾驶执照百分比。这是我们的模型在后端期望的四个参数,我们将通过这个表单捕获它们。

形式

其次,我们可以配置 Flask 应用程序来处理这些表单输入。让我们看看必要的导入并加载模型,这就是我们的 model.pkl 文件派上用场的地方。

负载模型

在配置处理表单之前,让我们用 Flask web 服务器测试一个 GET 请求。我们渲染自己创建的 index.html 页面(请原谅我糟糕的 HTML/CSS 技能)。

烧瓶应用程序设置

如果在 Flask 应用程序文件所在的目录中运行以下命令,则可以启动 Flask 服务器。

启动服务器

表单模板(作者截图)

现在我们可以处理表单的输入,并将它们提供给我们的模型。

流程表单输入

在 HTML 方面,我们希望反映模型返回的输出变量“res ”,所以我们在 index.html 代码中添加了这一部分。

反映结果

如果我们现在用一些虚拟值填写表单,我们应该能够在页面上看到推理输出。

提交表单(作者截图)

推理显示(作者截图)

太好了!我们有一个工作的 Flask 应用程序,现在让我们看看如何正确地将它容器化。

将烧瓶应用程序归档

在开始之前,确保 Docker 已安装并正常运行。

您需要知道两个主要的 Docker 实体: Docker 图像和 Docker 容器。Docker 映像包含我们的源代码、依赖项和环境。Docker 容器是 Docker 图像的一个实例。使用 Docker 图像作为模板,我们可以运行启动应用程序的容器。要进一步了解不同之处,请参考这篇文章。

为了建立我们的 Docker 映像,我们需要提供一个 Docker 文件,其中包含基本的设置说明。有了 Dockerfiles,我们可以使用基础映像,这些映像已经预装了依赖项和代码。我们将从基础 Python 映像开始。

基础图像

接下来,我们使用 WORKDIR 命令来设置容器内的工作目录。利用容器中的根目录不一定是最佳实践,因为它可能导致类似的文件名和类似的小问题。

工作目录

现在,为了设置我们的环境,我们需要提供安装所需的依赖项,我们可以通过 requirements.txt 文件来完成。

申请要求

然后,我们可以首先复制这个需求文件,然后将它安装在我们的容器环境中。

安装要求

接下来,我们可以将剩余的文件复制到工作目录中。

将剩余文件复制到工作目录

最后,利用 CMD 我们可以在启动容器时提供一个默认命令。

在容器中启动 Flask Web 服务器

现在我们有了 Docker 文件,我们可以通过在 Docker 文件所在的路径中运行以下命令来构建我们的 Docker 映像。

构建 Docker 映像

这将创建一个标记为“ramveg/ml-app”的 Docker 图像,您可以随意重命名它。默认情况下,这也是“最新”的版本,如果你想改变,你可以做“ramveg/ml-app:dev”或类似的事情。

构建图像

我们可以通过运行下面的命令来看到这个图像。

码头图片(作者截图)

或者,您也可以使用以下命令检查容器的内容。

检查码头集装箱

这应该会在您的容器中启动一个 shell,在这里您可以运行普通的 linux 命令来了解您的目录结构。这里我们看到了所有我们复制过来的文件。

容器结构(作者截图)

现在我们可以启动容器,这里的关键部分是我们需要指定端口 5000,因为这是 Flask 运行的默认端口。

在容器上启动 Flask 服务器

如果我们转到“localhost:5000”,我们应该会看到与本地相同的 Flask 应用程序。只是为了验证我们也可以再次进行推理。

Flask 服务器(作者截图)

推论(作者截图)

其他资源和结论

https://github.com/RamVegiraju/ML-FlaskApp-Docker

您可以通过上面的链接访问示例的完整代码。我希望通过这篇文章,您对在生产类型环境中部署模型有了更深的理解。关于了解 ML 模型托管的更多内容,请查看我的 MLFlow 和 SageMaker 系列。如果你有兴趣学习更多关于容器的知识,Stephen Grider 在 Udemy 上有一个很棒的课程,可以帮助你从头开始。

如果你喜欢这篇文章,请在 LinkedIn 上与我联系,并订阅我的媒体 简讯 。如果你是新手,使用我的 会员推荐 报名。

对接 Jupyter 项目

原文:https://towardsdatascience.com/dockerizing-jupyter-projects-39aad547484a

将您的项目和 conda 环境容器化的简单方法

滕玉红在 Unsplash 上的照片

Docker 是一个虚拟化工具,比虚拟机更精简。在本教程中,我将讨论在conda环境中容器化 Jupyter 笔记本。

这一切都源于我的研究和分析更加开放和透明的动机。我一直在尝试将我的脚本容器化,以便其他人更容易地重新创作我的作品。

当然,集装箱化并不是唯一的解决方案。人们可以用需求文件(conda env -f requirements.yaml)重建您的环境,然后下载您的脚本/数据来重建您的分析。集装箱化包装了一切。

在本教程中,我将解释适合我的方法,希望它能帮助你更深入地理解这种方法。

我将带您一步一步地从提取基础映像到将最终映像推送到存储库。我正在找出在这个工作流程中最有效的方法,欢迎并鼓励提出意见。

先决条件

如果您对 Docker 完全陌生,请按照这里的说明安装它

https://docs.docker.com/get-docker/

基本图像

最佳实践是从官方 Docker 基础映像开始。由于我使用的是 miniconda ,我将从 Dockerhub 上的 Continuumio 基本图像开始。

docker pull continuumio/miniconda3:4.10.3p1

另一种方法是从 Linux OS 镜像开始,自己安装 miniconda。

提取后,您可以在如下容器中运行映像:

docker run -it continuumio/miniconda3:4.10.3p1 /bin/bash

这是在一个带有 bash shell 的交互式终端中运行 Docker 映像。-it--interactive --tty的简写,它告诉 Docker 在容器内分配一个交互式虚拟终端会话。我只是认为-it的意思是“我与 T21 的终端互动”

从这里,您可以访问基本 Unix 命令(lspwdmkdir等)。)以及conda命令。

要验证是否安装了conda,您可以运行:

which conda

有了 conda,你可以安装所有你喜欢的软件包

conda install numpy pandas matplotlib jupyterlab

既然我们安装了 JupyterLab,我们可以启动一个服务器:

jupyter-lab --ip=0.0.0.0 --no-browser --allow-root

您可以通过将提示链接复制到浏览器中来访问 Jupyterlab。

朱庇特实验室输出。将黄色框中的链接复制到您的浏览器中,以访问 JupyterLab(图片由作者提供,使用 carbon.now.sh 创建)

完成后,按 Ctrl-c 停止服务器和exit容器。

这样做有一个陷阱,你做的任何事情都不会持久。一旦关闭容器,您创建的每个笔记本都将丢失。Docker volumes 将解决这个问题,我将很快讨论这个问题。

尽管容器中没有任何数据,但我们可以使用wgetscp来获取一些数据。例如,wget [https://www.ncei.noaa.gov/pub/data/cmb/ersst/v5/netcdf/ersst.v5.185401.nc](https://www.ncei.noaa.gov/pub/data/cmb/ersst/v5/netcdf/ersst.v5.185401.nc)将下载 1854 年 1 月的海面温度。同样,一旦关闭容器,这些数据将会丢失。

然而,预装一些数据或笔记本不是很好吗?我们也能做到!坚持住。

让我们从 miniconda 基础映像开始,并在它的基础上构建我们的映像。

创造你自己的形象

我们上面所做的一切都可以是一个映像,所以我们不必每次都安装软件包并输入 jupyterLab 的 run 命令。

为此,我们创建了一个Dockerfile,它是一个图像的蓝图,定义了如何创建我们的图像。

将以下内容复制到名为Dockerfile ( 不要添加扩展名)的文件中

FROM continuumio/miniconda3:4.10.3p1RUN conda install \
    xarray \ 
    netCDF4 \ 
    bottleneck \
    numpy \
    pandas \
    matplotlib \
    jupyterlabCMD ["jupyter-lab","--ip=0.0.0.0","--no-browser","--allow-root"]
  • FROM表示我们正在构建的基础图像
  • RUN表示我们希望在基础映像中运行的命令
  • CMD表示容器启动时我们想要运行的命令

建立形象

然后我们可以建立我们自己的形象,并给它一个名字。(我把我的命名为jupyterlab,标记为latest)

docker build -t jupyterlab:latest .

在这种情况下,-t--tag的简写。这使用了name:tag格式,其中 name 是您想要的图像标题,tag 提供任何附加信息(例如版本号)。.和 end 指定dockerfile在当前目录下。

在我的机器上,构建过程花了大约 2 分钟。构建完成后,您可以列出所有可用的图像以确保其可用。

docker image ls

如果我们想要删除该图像,这提供了诸如IMAGE_ID和图像的SIZE的信息。我们看到这张图片的大小略大于 1GB。

docker 图片 ls(图片由作者提供,使用 carbon.now.sh 创建)

运行映像

一旦构建了映像,我们可以像这样运行它:

docker run --rm -it -p 8888:8888 jupyterlab:latest

因为我们正在启动一个 Jupyerlab 服务器,所以我们必须告诉docker服务器正在哪个端口上运行,这就是-p 8888:8888所做的。

当您运行容器时,会提示一个 URL,您可以从 web 浏览器访问 JupyterLab。

在下一节中,我们将学习如何向图像添加数据。

用数据预装容器

如果您使用图像来共享您的分析,那么您将需要包括脚本和数据。让我们假设您有以下目录结构,包括一个笔记本、一个数据集和一个自述文件。

.
├── Dockerfile
├── README.md
├── data
│   └── dataset.txt
└── notebooks
    └── my_analysis.ipynb

让我们通过添加下面一行到我们的Dockerfile来添加一个/project目录到图像中

WORKDIR /project

如果这个目录还不存在的话,Docker 会很聪明地创建它。

COPY命令让我们(你猜对了)将数据复制到我们的映像中。

COPY ./README.md /project
COPY ./data /project/data
COPY ./notebooks /project/notebooks

这里的语法是:

COPY /path/on/host /path/in/container

我们改装的Dockerfile看起来是这样的:

FROM continuumio/miniconda3:4.10.3p1WORKDIR /projectRUN conda install \
    xarray \
    netCDF4 \
    bottleneck \
    numpy \
    pandas \
    matplotlib \
    jupyterlabCOPY ./README.md /project
COPY ./data /project/data
COPY ./notebooks /project/notebooksCMD ["jupyter-lab","--ip=0.0.0.0","--no-browser","--allow-root"]

现在,当我们构建并运行我们的容器时,我们启动/project目录。

jupyterlab 在容器中运行的截图(图片由作者提供)

厉害!现在,我们有了一种将数据从主机文件系统放入容器的方法。在这个阶段,我们可以将我们的图像推送到 Dockerhub 这样的存储库中,这样其他人就可以获取并运行它。这个我会在最后讨论。

现在,让我们想象有人拉我们的形象,他们做了一些改变。他们可能希望这些变化持续下去。码头工人卷来救援!

Docker 卷(基础)

在我们开始将卷连接到我们的容器之前,了解什么是卷以及我们可以连接到卷的不同方式是很重要的。

卷有助于在容器重新启动时保存数据。因此,它们允许数据在容器关闭后继续存在。

这是将主机操作系统上的文件系统连接到容器中的虚拟文件系统。主机上的文件系统可以是已经存在的路径(例如~/Documents)或者是 Docker 创建的新路径。

将主机文件系统连接到虚拟文件系统的示意图(图片由作者提供)

有三种类型的卷:

  1. 主机卷
  2. 匿名卷
  3. 命名(匿名)卷

我们连接卷的方式是在指定我们想要运行的映像之前使用docker run 中的-v标志

主机卷

对于主机卷,我们将主机文件系统上的路径显式连接到容器中的路径。例如,这可能是您的~/Documents文件夹中的路径。

docker run -v /dir/on/host/data:/dir/in/container/data imageName

主机卷提供了主机和容器之间的简单连接。您在主机文件系统中所做的任何更改都会在容器中看到,反之亦然。这种类型的卷在主机和容器之间提供了一个通道,非常适合在两者之间移动数据。

但是,主机卷并不是数据持久性的最佳解决方案。为此,我建议匿名或命名卷

匿名卷

对于匿名卷,我们只需指定希望卷装载在容器上的位置,而它在主机上的位置由 Docker 负责。

docker run -v /dir/in/container/data imageName

在此示例中,在/dir/in/container/data时在容器中创建虚拟文件系统,而在/var/lib/docker/volumes/时在主机上自动创建文件系统。

这对于在容器关闭后保存您在容器中所做的更改非常有用,从而解决了数据持久性问题。

但是,对于从主机向容器中获取数据来说并不太好,并且不能像主机卷那样很好地发挥管道的作用。

命名(匿名)卷

匿名卷和命名卷之间的唯一区别是,对于命名卷,您可以指定一个唯一的名称供以后参考。

docker run -v name:/dir/in/container/data

唯一的名称使我们能够轻松地将该卷连接到其他容器。

列出您的卷

要列出您的卷,您可以使用ls

docker volume ls

创建命名卷

您可以在使用之前创建一个空的命名卷,如下所示:

docker volume create volume-name

主机上的匿名/命名卷数据在哪里?

您所有的卷宗都可以在/var/bin/docker/volumes查看

在 macOS 上,它存储在一个虚拟机中。将文件移动到主机操作系统的一种方法是通过 Docker 仪表板。从 Docker 控制面板中,您可以导航到卷→单击您的命名卷→数据→然后在最右侧单击“另存为”将文件复制到您的主机操作系统。我知道这很复杂。

查看这个堆栈溢出线程了解更多细节,如果有更简单的方法,请告诉我。

想要查看 macOS 虚拟机上存储的/var/bin/docker/volumes吗?下面是步骤(谢谢堆栈溢出)

  1. 运行以下容器
docker run -it --privileged --pid=host debian nsenter -t 1 -m -u -n -i sh

2.导航到卷目录

cd /var/lib/docker/volumes

3.ls此目录和列表导航到您的命名卷

将卷连接到容器

现在我们已经了解了卷以及主机卷和命名卷之间的权衡,让我们将卷连接到容器。

在本例中,我将使用一个命名卷,因为我想保留我在容器中所做的更改。

这将名为my_volume/project的卷连接到运行jupyterlab:latest映像的容器。因为我们在/project目录中预装了数据,所以我们所做的任何更改都将保存在my_volume上,即使在容器关闭后,我们也可以从停止的地方继续。

我们甚至可以将该卷连接到运行不同映像的不同容器。还记得我们刚开始连接到我们的基础映像时,映像中什么也没有吗?现在尝试将my_volume连接到它:

现在我们可以从运行基本映像的容器中访问my_volume中的数据了!

使用 Docker compose 进一步简化

使用端口和卷键入运行容器的命令有点麻烦。我们可以做的一件事是在一个 docker-compose.yaml文件中定义所有的东西,这样我们所要做的就是用一个连接的卷启动预加载的 Jupyterlab 服务器

docker-compose up

为此,创建一个文件docker-compose.yaml并将以下内容复制到其中

version: "3"services:
  jupyter:
    image: jupyterlab:latest
    ports:
      - 8888:8888
    volumes:
      - my_volume:/projectvolumes:
  my_volume:
    external: true

docker-compose 文件剖析

  • **版本:**定义 docker-compose 的版本
  • **服务:**这定义了容器。jupyter可以改名为任何东西。然后,我们提供映像名称、我们正在连接的端口和我们正在连接的卷
  • **卷:**我们所连接的卷的名称,并声明它是外部的

要启动我们的 jupyterLab 服务器,我们只需运行

docker-compose up

确保您与 docker-compose 文件在同一个目录中。

如果您收到一条错误消息,指出您的外部卷不存在,那么您需要首先创建一个命名卷。使用 docker-compose,您必须在连接之前确保该卷存在。

docker volume create conda-work

自定义 JupyterLab 令牌

要制作您自己的令牌,您只需将以下内容添加到services:

environment:
      JUPYTER_TOKEN: "docker"

现在从浏览器访问 JupyterLab 将永远是

localhost:8888/lab?token=docker

想了解更多?

这个视频帮助我理解 docker-compose

共享您的图像

在这里,我将展示如何将您的映像推送到 Docker Hub 存储库。

首先,在 Docker Hub 上创建一个帐户

当您构建映像时,它必须符合以下命名约定,以便推送至 docker hub:

docker_ID/image_name:tag
  • docker_ID是您注册 Docker Hub 时选择的名称
  • image_name是您想要的图像名称吗
  • tag is 提供附加信息(新版本、不同架构等。)

现在从命令行登录 Docker Hub

docker login -u docker_ID docker.io

你将被提示输入密码(我强烈推荐启用 2FA ,因为安全很重要)

登录后,只需将您的图像推送到回购

docker push docker_ID/image_name:tag

一旦完成,任何人都可以使用docker pull来拉你的图像并运行它!

最后的想法

我很喜欢 Docker,认为这是与同事分享数据分析和透明分析的好方法。因为运行脚本所需的一切都打包在一起,所以减少了提取脚本和运行脚本之间的摩擦。

当一个项目完成时,分析代码应该存储在一个代码库中,如 GitHub 或 GitLab,并且应该创建一个 Docker 映像来轻松地重新创建结果。通过这种方式,代码是开放的,可以免费获得,并且分析可以通过 Docker 映像重现。

我自己仍在学习这项技术,但我希望这篇文章能给你一些如何将自己的项目容器化的想法。一如既往,欢迎并鼓励提出意见和建议。

关于如何缩小你的 docker 图片尺寸的建议,请看这个博客。一些 Docker 最佳实践可以在这里找到。我在这篇文章中描述的类似解决方案可以在这里找到

感谢您阅读和支持媒体作家

https://lukegloege.medium.com/membership

使用 Python 和 OCR 进行文档解析

原文:https://towardsdatascience.com/document-parsing-with-python-ocr-75543448e581

作者图片

使用计算机视觉从任何类型的文档中检测和提取文本、图形、表格

摘要

在本文中,我将使用 Python 和计算机视觉展示如何解析文档,比如*pdf、*并提取信息。

由乔治·托马塞蒂在 Unsplash 上拍摄的照片

文档解析 涉及检查文档中的数据,提取有用的信息。这对公司来说是必不可少的,因为它减少了大量的手工工作。想象一下,必须手动搜索 100 页的表格,然后将它复制并粘贴到其他地方……如果有一个程序可以在 1 秒钟内完成,那该有多酷?

一种流行的解析策略是将文档转换成图像并使用计算机视觉。 文档图像分析 是指应用于文档图像以从像素数据中获取信息的技术。这可能很棘手,因为在一些情况下,对于预期的结果应该是什么样子(文本、图像、图表、数字、表格、公式……)没有明确的答案。最常用的技术是 OCR。

【OCR(光学字符识别) 是通过计算机视觉检测并提取图像中文字的过程。它是在第一次世界大战期间发明的,当时以色列科学家伊曼纽尔·戈德堡创造了一种可以阅读字符并将其转换成电报代码的机器。今天,该领域已经达到了非常高的复杂程度,混合了图像处理、文本定位、字符分割和字符识别。基本上是一种文本对象检测。

在本教程中,我将展示如何使用 OCR 进行文档解析。我将展示一些有用的 Python 代码,这些代码可以很容易地用于其他类似的情况(只需复制、粘贴、运行),并通过注释遍历每一行代码,这样您就可以很容易地复制这个示例(下面是完整代码的链接)。

https://github.com/mdipietro09/DataScience_ArtificialIntelligence_Utils/blob/master/computer_vision/example_ocr_parsing.ipynb

我将用一家上市公司的 PDF 格式的财务报表作为例子(下面的链接)。

链接

特别是,我将经历:

  • 环境设置:导入包、读取数据、预处理
  • 检测(文本、图形、表格)
  • 摘录(文本、图表、表格)

设置

文档解析令人烦恼的地方在于,有如此多的工具可以处理不同类型的数据(文本、图形、表格),但没有一个能够完美地工作。以下是基于人们想要遵循的策略的最流行的包的当前框架:

  • 将文档处理为文本:用 PyPDF2 提取文本,用 Camelottabulopy提取表格,用 PyMuPDF 提取数字。
  • 将文档转换为图像(OCR) :用 pdf2image 进行转换,用pytesserac加上其他很多支持库,或者只是 LayoutParser 提取数据。

也许你会问自己:“为什么要麻烦地将页面转换成图像,而不是直接处理 PDF 文件?”。你可以这么做这种策略的主要缺点是编码方案:文档可以有多种编码(如 UTF 8、ASCII、Unicode),因此转换成文本可能会导致数据丢失。因此,为了避免任何问题,我将使用 OCR 并用 pdf2image 将页面转换成图像。请注意, PDF 渲染库Poppler需要运行。

****# with pip**
pip install python-poppler
**# with conda** conda install -c conda-forge poppler**

您可以轻松阅读该文档:

****# READ AS IMAGE**
import **pdf2image**doc = pdf2image.convert_from_path("doc_apple.pdf")
len(doc) **#<-- check num pages** doc[0]   **#<-- visualize a page****

作者图片

如果要在计算机上保存页面图像,可以使用下面的代码:

****# Save imgs** import **os**folder = "doc"
if folder not in os.listdir():
    os.makedirs(folder)p = 1
for page in doc:
    image_name = "page_"+str(p)+".jpg"  
    page.save(os.path.join(folder, image_name), "JPEG")
    p = p+1**

最后,我们需要设置我们将使用的 CV 引擎。 LayoutParser 似乎是第一个针对 OCR 的通用包,基于深度学习。它使用两个著名的任务模型:

  • 检测:Detectron,脸书最先进的物体检测库(我们将使用第二版 Detectron2 )。
**pip install layoutparser torchvision && pip install "git+https://github.com/facebookresearch/detectron2.git@v0.5#egg=detectron2"**
  • 提取: 宇宙魔方 ,主要的 OCR 系统,由惠普于 1985 年创建,目前由谷歌开发。我们还必须下载软件,StackOverflow 上的这个帖子解释了如何为不同的操作系统下载软件。
**pip install "layoutparser[ocr]"**

现在,我们已经准备好开始信息检测和提取的 OCR 过程。

**import **layoutparser** as lp
import **cv2** import **numpy** as np
import **io**
import **pandas** as pd
import **matplotlib**.pyplot as plt**

侦查

(物体)检测是在一张图片中寻找多条信息,然后用一个长方形的包围盒将其包围起来的过程。对于文档解析,这些信息是标题、文本、图表、表格…

因此,让我们来看一个包含所有内容的复杂页面:

第 22 页(作者图片)

这个页面以一个标题开始,有一个文本块,后面是一个图和一个表,所以我们需要一个经过训练的模型来识别这些对象。幸运的是 Detectron 能够胜任这项任务,你只需要从这里选择一个模型,并在代码中指定它的路径。

作者图片

我将要使用的模型只能检测这 4 个对象(文本、标题、列表、表格、图形)。因此,如果你需要识别其他东西(比如方程式),你必须改变模型。

****## load pre-trained model**
model = lp.Detectron2LayoutModel(
   **"lp://PubLayNet/mask_rcnn_X_101_32x8d_FPN_3x/config",**
   extra_config=["MODEL.ROI_HEADS.SCORE_THRESH_TEST", 0.8],
   label_map={0:"Text", 1:"Title", 2:"List", 3:"Table", 4:"Figure"})**## turn img into array** i = 21
img = np.asarray(doc[i])**## predict** detected = model.detect(img)**## plot** lp.draw_box(img, detected, box_width=5, box_alpha=0.2, 
            show_element_type=True)**

作者图片

**预测对象“检测到”包含每个检测到的布局的细节,如边界框的坐标。根据输出在页面上出现的顺序对其进行排序非常有用:

****## sort**
new_detected = detected.sort(key=lambda x: x.coordinates[1])**## assign ids**
detected = lp.Layout([block.set(id=idx) for idx,block in 
                      enumerate(new_detected)])**## check** for block in detected:
    print("---", str(block.id)+":", block.type, "---")
    print(block, end='\n\n')**

作者图片

完成 OCR 的下一步是正确提取边界框内的信息。

提取,血统

为了帮助 OCR 模型,通常使用边界框分割图像,然后使用模型处理分割的图像。最后,我将把提取的输出保存到一个字典中。

由于我们看到不同类型的输出(文本、标题、图形、表格),我将准备一个函数来显示结果。

****'''
{'0-Title': '...',
 '1-Text':  '...', 
 '2-Figure': array([[ [0,0,0], ...]]),
 '3-Table': pd.DataFrame,
}
'''**
def **parse_doc**(dic):
    for k,v in dic.items():
        if "Title" in k:
            print('\x1b[1;31m'+ v +'\x1b[0m')
        elif "Figure" in k:
            plt.figure(figsize=(10,5))
            plt.imshow(v)
            plt.show()
        else:
            print(v)
        print(" ")**

让我们用文本来试试:

****# load model**
model = lp.TesseractAgent(languages='eng')dic_predicted = {}for block in [block for block in detected if block.type in [**"Title","Text"**]]:
    ***## segmentation***
    segmented = block.pad(left=15, right=15, top=5, 
                bottom=5).crop_image(img)
    ***## extraction***
    extracted = model.detect(segmented)
    ***## save***
    dic_predicted[str(block.id)+"-"+block.type] = 
                  extracted.replace('\n',' ').strip()**# check**
parse_doc(dic_predicted)**

作者图片

继续关注人物**:**

**for block in [block for block in detected if block.type == "**Figure**"]:
    ***## segmentation***
    segmented = block.pad(left=15, right=15, top=5, 
                          bottom=5).crop_image(img)
    ***## save***
    dic_predicted[str(block.id)+"-"+block.type] = segmented**# check**
parse_doc(dic_predicted)**

作者图片

很好,但是那相对容易,桌子就难多了。尤其是示例中的这个,因为它没有垂直线来分隔列,而列名在单独的行上。

**for block in [block for block in detected if block.type == "**Table**"]:
    ***## segmentation***
    segmented = block.pad(left=15, right=15, top=5, 
                bottom=5).crop_image(img)
    ***## extraction***
    extracted = model.detect(segmented)
    ***## save***
    dic_predicted[str(block.id)+"-"+block.type] = pd.read_csv( 
                 io.StringIO(extracted) )**# check**
parse_doc(dic_predicted)**

作者图片

如您所见,提取出的表格并不好。没有 OCR 会不会不一样?让我们尝试在不将文档转换成图像的情况下处理它。我将使用 TabulaPy 包:

**import **tabula**
tables = tabula.read_pdf("doc_apple.pdf", pages=i+1)
tables[0]**

作者图片

结果稍微好一点,因为现在表有列了,即使名称仍然是错误的。

结论

这篇文章是演示如何用 OCR 执行文档解析的教程。我用 LayoutParser 包走了一遍检测和提取的全过程。我展示了如何处理 PDF 文档中的文本、图表和表格。

我希望你喜欢它!如有问题和反馈,或者只是分享您感兴趣的项目,请随时联系我。

👉我们来连线👈

本文是 Python 系列 CV 的一部分,参见:

** https://pub.towardsai.net/image-classification-with-python-cnn-vs-transformers-fe509cbbc2d0 **

用聪明的方式记录你的机器学习项目

原文:https://towardsdatascience.com/document-your-machine-learning-project-in-a-smart-way-35c68aa5fc0e

如何使用 Sphinx 和顶点 AI 管道的分步教程。

作者:@西格蒙德,unsplash.com

本文的目的是分享使用 Sphinx 自动生成机器学习项目文档的过程。

我将使用 Sphinx 的高级功能,例如添加了徽标注释图像降价文档。此外,我将展示您需要的 python 包,以便 Sphinx 可以提取顶点管道中的文档字符串。

一些背景

我们开始吧!如你所知,拥有最新的机器学习项目文档对于生产和概念验证阶段都是至关重要的。 **为什么它至关重要?**因为它有助于澄清和简化你的模块,与你的团队合作,快速整合新的团队成员,更快地发展,并与业务所有者分享。

就我个人而言,我经历过很多这样的情况,由于上市时间的限制,文档被忽略了,但是一旦项目在生产中发布,这就变成了致命的。因此,我建议你避开任何手动程序来生成你的文档,因为这样的程序总是以失去同步和耗时而告终。

因此,在发布您的项目之前,花一些时间检查您的项目的可读性。在我的例子中,我倾向于使用以下文件:

  • 自述文件 —一个易于阅读的文件,提供项目的介绍和一般信息,如目的、技术信息、软件组件
  • 许可 —一个文件,提到了贡献者需要遵循的许可分步程序
  • 用法 —解释如何使用项目的文件
  • CHANGELOG —一个跟踪项目变更和发布版本的文件

请注意,最重要的文件是自述文件。贡献和使用信息可以直接添加到自述文件中。可以在生产中发布项目之前添加 changelog 文件。要编辑文件,您可以使用https://www.markdownguide.org/**、简单文本、重组文本

参见下面我们将要描述的过程的概述。

过程概述(图片由作者提供)

斯芬克斯是什么?

Sphinx 是一个强大且易于使用的开源自动生成器工具,被 Python 社区广泛使用。它能够生成优秀的结构化文档。存在一些替代品,如 MkDocs、Doxygen、pdoc 等,但是 Sphinx 仍然是一个完整且易于使用的强有力的竞争对手。

主要特点:

  • 支持多种输出格式:HTML、PDF、纯文本、EPUB、TeX 等。
  • 文档的自动生成
  • 自动链接生成
  • 多语言支持
  • 各种扩展可用

步骤:

一、设置环境

二世。安装虚拟环境

三。安装 Sphinx

四。设置 Sphinx

动词 (verb 的缩写)建立文档

一、搭建环境

  • Python 3
  • 本地虚拟机或 Vertex AI 工作台(用 Python 3 运行在虚拟环境中的 Jupyter 笔记本)
  • 包含顶点 AI 代码的 Python 项目
  • 虚拟人
  • Kfx—ekube flow 管道 sdk 扩展
  • MyST 解析器 Markdown 风格
  • 包含 sdk 管道的顶点项目

让我们用一个 Apache-2.0 许可下的顶点 AI 管道 的端到端开源例子。该项目是一个很好的例子,因为该项目使用顶点管道,而不使用文档生成器。

首先克隆源代码,转到顶点-管道-端到端-样本 目录 :

*git clone [https://github.com/GoogleCloudPlatform/vertex-pipelines-end-to-end-samples.git](https://github.com/GoogleCloudPlatform/vertex-pipelines-end-to-end-samples.git)
cd vertex-pipelines-end-to-end-samples*

二。创建一个虚拟环境&激活它

III。安装斯芬克斯

创建一个文件 requirements-sphinx.txt 并添加:

*myst-parser==0.15
requests==2.28.1
sphinx==4.5.0
sphinx-click==4.3.0
sphinx-me==0.3
sphinx-rtd-theme==1.0.0
rst2pdf==0.99
kfx*

立即安装需求-sphinx.txt 中列出的 Sphinx 及其扩展:

*pip install -r requirements-sphinx.txt*

创建一个 docs 目录(如果不存在)来存储 Sphinx 布局:

*mkdir docs 
cd docs* 

使用 sphinx-quickstart 命令生成初始目录结构:

***sphinx-quickstart***

选择单独的源代码和构建目录、项目名称、作者姓名、项目版本和项目语言。您可以在下面找到我的配置:

您应该获得以下树结构:

如你所见,我们选择分离构建目录。关于它的内容我们来做几个说明。

build/ 目录是用来保存生成的文档。因为我们还没有生成任何文档,所以它现在是空的。**

****make . bat(Windows)**Makefile(Unix) 文件是简化文档生成的脚本。

source/conf.py 是 Sphinx 项目的配置文件。它包含默认的配置密钥和您为 sphinx-quickstart 指定的配置。

source/index . rst是包含目录树(toctree)指令的项目的根文档,您应该在其中列出您想要包含在文档中的所有模块。**

_static 目录包含自定义样式表和其他静态文件。

_templates 目录存储了 Sphinx 模板。

四。设置狮身人面像

识别 python 模块:/pipelines

目录/ 管道包含我们想要包含在 Sphinx 文档中的 python 代码。注意只有当您添加 init 时,Sphinx 才会看到 pipelines 包中的子模块。/ 管道目录下的 py 文件。

生成狮身人面像来源

使用 sphinx-apidoc 构建您的 API 文档(确保您位于项目的根目录)。创建的 Sphinx 源代码存储在 docs/source/pipelines 中。

 **sphinx-apidoc -f -o docs/source/pipelines pipelines/**

您可以检查以下文件是在 docs/source/pipelines 中创建的:

将降价文件复制到 docs/source

在 Sphinx 源目录(docs/source/)中自动复制 README.md、CONTRIBUTING.md 和 USAGE.md 文件。在 docs/Makefile 中添加以下行以自动同步降价文件:

**COPY_README = ../README.md
COPY_CONTRIBUTING = ../CONTRIBUTING.md
COPY_USAGE = ../USAGE.md#sincronyze MD files
$(shell cp -f $(COPY_README) $(SOURCEDIR))
$(shell cp -f $(COPY_CONTRIBUTING) $(SOURCEDIR))
$(shell cp -f $(COPY_USAGE) $(SOURCEDIR))**

编辑 index.rst 编辑

使用****注释指令获取您想要突出显示的信息。****

****.. note::  Sphinx with Vertex AI.****

使用图像指令添加图像。推荐的图像尺寸宽度在 400-800 像素之间。

****.. image:: ../images/xgboost_architecture.png
    :align: center
    :width: 800px
    :alt: alternate text****

to tree指令下,列出你希望包含在最终文档中的所有模块(自述文件、模块)。

****.. toctree::
   :maxdepth: 2
   :caption: Contents: README
   pipelines/modules
   CONTRIBUTING
   USAGE****

请在下面找到我的 index.rst:

编辑 conf . py—Sphinx的主配置文件

定义路径:

****# Define path
sys.path.insert(0, os.path.abspath("../.."))****

添加您的扩展:

****extensions = [
    "sphinx.ext.duration", 
    "sphinx.ext.doctest",
    "sphinx.ext.viewcode",
    "sphinx.ext.autosummary",
    "sphinx.ext.intersphinx",
    "sphinx_rtd_theme",
    "sphinx_click",
    "myst_parser",
    "sphinx.ext.todo",
    "sphinx.ext.coverage",
    "myst_parser",
]****

列出要解析的文件列表:

****source_suffix = {
    ".rst": "restructuredtext",
    ".md": "markdown",
}****

指定 HTML 主题:

****html_theme = "sphinx_rtd_theme"****

要添加一个徽标,请确保图像出现在/_ static源中。我用过 v ertex AI logo 。然后,您可以定义徽标路径:****

****html_logo = "_static/vertex.png"****

列出降价文件中存在的所有外部链接:

****intersphinx_mapping = {    "python": ("[https://python.readthedocs.org/en/latest/](https://python.readthedocs.org/en/latest/)", None)}****

请参阅我的配置文件 conf.py:

V .构建文档

要使用 Sphinx 生成 HTML 文档,请转到/docs 并使用命令:

****make html****

使用 Firefox 打开 HTML 页面:

****firefox docs/build/html/index.html****

如果你设法完成了所有的步骤,你应该能够看到一个更吸引人的 HTML 页面。

KFX 扩展将使 Sphinx 能够读取 Kubeflow 组件、函数名、参数和文档字符串。

使用 Makefile(位于项目的根目录)自动构建 文档。编辑 Makefile 并添加以下几行:

****create-sphinx-sources:
 cd docs; make clean; cd ..; rm -r docs/source/pipelines; sphinx-apidoc -f -o docs/source/pipelines pipelines/generate-doc:
 @ $(MAKE) create-sphinx-sources && \
 cd docs; make html****

然后调用 make generate-doc:

****make generate-doc****

我们带着斯芬克斯到达了旅程的终点。我希望这些内容对你有用!

摘要

我们已经看到了如何使用 Sphinx,这是一个为您的机器学习项目生成文档的强大工具。我们定制了带有徽标、图像和降价内容的文档。当然,Sphinx 附带了许多其他扩展,您可以使用它们来使您的文档更加吸引人。

感谢您的阅读!

如果你想在收件箱里收到我未来的故事,别忘了订阅。

如果您喜欢阅读我的故事,并希望支持我成为一名作家,请考虑注册成为 Medium 会员,并获得数千篇数据工程和数据科学文章。

****https://medium.com/@anna.bildea/membership

LinkedIn Twitter 上找我!****

用 Sphinx 记录 Python 代码

原文:https://towardsdatascience.com/documenting-python-code-with-sphinx-554e1d6c4f6d

照片由 Patrik Fore 发自 Un spash

当从事一个需要在特定时间框架内完成的项目时,除了代码审查、自动化测试、单元测试和许多其他事情,我们很少有时间留给文档。不管你在开发什么,迟早你和你的同事会再次访问那段代码。当这一天到来时,我们大多数人都将迷失在这些代码块中!

由于耗费时间,文档被省略了,但是如果所有这些都可以自动化,并且只需一瞥,您就可以生成一个漂亮的网站来记录您的全部代码,那会怎么样呢?这就是斯芬克斯的用武之地!

什么是斯芬克斯?

简而言之,狮身人面像吸收了你的。rst 文件并将其转换为 HTML,所有这些都是通过一堆命令完成的!像 Django 、 NumPy 、 SciPy 、 Scikit-Learn 、 Matplotlib 等主要 Python 库都是用 Sphinx 编写的。现在,轮到我们使用它了,让我们开始吧。

安装斯芬克斯:

pip install sphinx sphinx_rtd_theme

这将安装 sphinx 包和主题*(可选)*,这将使我们的网站大放异彩。

文件夹结构:

首先,你可以克隆我的 Github 库,它的结构如下。在其中,数学存放了我们的 python 代码,这些代码需要进行文档化,我们的文档将放在 docs 文件夹中。

📦sphinx_basics
 ┣ 📂docs
 ┗ 📂maths
 ┃ ┣ 📜add.py
 ┃ ┣ 📜divide.py
 ┃ ┣ 📜multiply.py
 ┃ ┣ 📜subtract.py
 ┃ ┗ 📜__init__.py

一般来说,这是使用的惯例,你的代码将在一个源目录中(在我们的例子中是数学目录), docs 将存放你的文档。既然你已经装好了。遵循以下给出的步骤:

第一步:斯芬克斯-快速入门

在 docs 文件夹中运行下面的命令

sphinx-quickstart

运行该命令后,接受默认值。它看起来会像这样:

sphinx 快速入门示例

sphinx-quickstart 是一个交互式工具,它询问一些关于您的项目的问题,然后生成一个完整的文档目录和一个make.bat文件,稍后将使用该文件生成 HTML。

第二步:编辑 conf.py 文件

转到您的conf.py文件,取消第 13、14 和 15 行的注释。将os.path.abspath('.')改为os.path.abspath('..')。这里,我们告诉 sphinx 代码位于当前 docs 文件夹之外。

现在转到扩展部分,添加下面给出的扩展

更新的扩展列表

最后,进入主题,将“雪花石膏”替换为“斯芬克斯 rtd 主题”,完整的更新后的conf.py文件如下所示:

最终 conf.py 文件

第三步:生成。rst 文件

到目前为止,您的 docs 文件夹中有index.rst,这将是您的文档的登录页。但是我们还没有生成maths.rst,里面有我们的 python 代码。

转到父文件夹 sphinx_basics,运行命令:

sphinx-apidoc -o docs maths/

在这个命令中,我们告诉 sphinx 从 maths 文件夹中获取我们的代码,并输出生成的。docs 文件夹中的 rst 文件。在这个命令之后,您将看到在您的文档中生成的maths.rstmodules.rst

第四步:包含 module.rst 并生成 html

现在,将生成的modules.rst文件包含在您的index.rst

index.rst 文件

然后我们就可以生成漂亮的文档了,进入 docs 文件夹并运行命令

make html

就是这样!!!。您可以在 docs 中的 _build 文件夹中看到生成的 HTML 文件,该 HTML 文件如下所示

文档网站的登录页面

数学包

此外,除此之外,您还可以在搜索页面上搜索任何方法、子包等

搜索页面

就是这样!Sphinx 完成了创建 HTML 文档的所有繁重工作。

现在,假设您对代码做了一些更改,现在您想重新构建 HTML,请转到 docs 文件夹并编写

make clean html

然后

make html

这将重新构建您的 HTMLs,同时考虑您的更改。

还有,你可以改变主题,尝试不同的;通过格式化文档字符串和更多的东西来改变文档格式!

耶!我们成功地自动化了催眠文档部分。希望这篇文章对你有所帮助,你可以随时记录下你的下一个项目🚀

自动更正让生活更美好吗?

原文:https://towardsdatascience.com/does-autocorrect-make-life-better-aebafbed09f0

系统性机器学习失败的警示故事

劳拉·里维拉在 Unsplash 上的照片

将数据科学应用于许多产品和业务的潜在好处之一是有望减少我们日常生活中的摩擦和不便。这个想法是精心制作的机器学习模型嵌入到我们使用的所有设备和服务中。当我们越来越自由地专注于生活中重要的事情时,他们会不知疲倦地努力消除我们生活中的各种烦恼和负担。

这只是过于乐观的白日梦吗?

如果我们要实现这些技术的潜力,我们需要评估机器学习在日常生活中让我们失败的许多小方面。我们可以继续列举一些事情,比如种族主义的图像分类器,性别歧视的招聘工具,或者聊天机器人中可能出现的多种形式的精神变态。相反,让我们关注一种更平凡、更普遍的机器学习失败形式:自动纠错,这种失败对少数群体和多数群体都有影响。

自动校正是一种简单的数字辅助形式。你输入一些东西,机器识别出这不是一个单词,所以它把它改成它认为你想输入的。这些系统被嵌入到我们的手机中,既在我们的操作系统中,有时也在手机的特定应用程序中。一些版本只是单词相似性和频率的基本统计模型,其他版本采用机器学习并考虑句子中的其他单词。从表面上看,他们的目的很清楚;我们想把我们写的文字中的错别字去掉。

我写“【wutocorecorect】,设备将其更改为“ 【自动更正】

我写了"",设备猛扑过来,把它改成" 【失败】

当我们查看一个句子中某个关键词的更正时,问题就出现了。

我打" 你需要什么? "而自动更正将其改为" 你为什么需要?【①

突然之间,我试图问一个需要澄清或说明的问题,变成了对正当理由的推诿。整个句子的意思发生了变化,伴随着潜在的负面情绪解释。雪上加霜的是,原文尽管有拼写错误,但完全可以理解。 这最后一个事实对于许多不同的错别字来说都是常见的,并且由短信中去掉单词的常见做法完美地证明了这一点。

值得停下来思考最后一点。我相对现代的智能手机上的自动纠错功能很高兴地推出来了,它以一种可以改变句子意思的方式纠正单词。即使在我们有证据表明,在大多数情况下,拼写错误最糟糕的结果是阅读速度变慢的情况下,它也会这样做。

这是技术上的失败。

这个复杂的软件功能并没有为我提供实用性,而是主动妨碍了我的交流。怎么会这样呢?如果我们要在世界上推进数据科学的部署,我们应该彻底了解这样一个平凡的任务如何导致产生负面结果的产品。

根本原因是,在构建这些模型时,它们是使用与对最终用户的影响无关的指标进行评估的。在一个理想的世界里,我们会考虑对我们写作的任何改变会如何影响我们写作的可读性和理解性。但是,获得一个允许机器学习开发者评估最终目标的数据集是很难的。更简单的方法是收集一些关于特定单词被错误键入的常见方式的数据,并使用描述单词被正确修改与被错误修改的比例和比率的标准度量来评估它们(例如参见[3])。公平地说,这些模型可以用在对沟通失误不太敏感的情况下,比如纠正搜索查询的内容。最近关于评估自动纠错方法的学术工作强调了单词上下文的重要性[4]和文本的可理解性[5]。然而,他们都没有把对理解的预期影响作为评估的中心。

这就是机器学习项目如何增加我们的负担。它们是由这样的人创建的,他们要么与最终用户脱节,被最终用户所需的复杂性所淹没,要么没有时间或资源使用反映真实世界使用情况的数据来评估模型。所以他们简化了。他们构建一些能够完成合格且可测量的任务的东西,并假设这是朝着正确方向迈出的一小步。有时行得通,有时行不通。如果不是这样,我们就会被归入一种会让我们的生活变得更糟糕的技术,即使它起初看起来是一种进步。

理想情况下,任何文本修改模型的评估都将根据单词对句子理解的重要性来加权单词,或者使用试探法,当只有一个元音缺失时,严厉惩罚返回错误单词的模型。尚不清楚完美的评价会是什么,但这值得研究,因为人类的交流远远不只是一个大型的分布式拼写比赛。

如果技术的进程随着每个单独的模型而停止,那么情况就不会那么糟糕。随着时间的推移,设计不良的系统将被更好的系统所取代。不幸的是,技术发展还有其他更复杂的历史过程。次优决策可能会在以后的开发中固定下来。

让我们考虑一下 Swypo 的情况。

我的一个朋友最近向我介绍了术语 swypo ,指的是使用触摸屏滑动界面绘制字母时创建的消息中的错误单词。部分问题是界面必须解释想要的字母。他试图给我发信息“我想亲自告诉你”,但我收到的是“我会亲自带你去地狱。”

似乎自动纠错模式对完美拼写的痴迷正在影响第二层技术。我朋友使用的滑动界面试图生成拼写正确的单词序列。在这样做的同时,它创造了句法上尴尬的句子,与原意相差甚远,以至于它们促成了一种新的喜剧形式。

这就是机器学习失败成为系统性问题的原因。最初的捷径似乎是合理的,并导致模型提供了表面上的效用,但却产生了一层挫折和低效。这些方法及其固有的问题被构建在其上的后续技术层所固定。逐渐地,糟糕、仓促或次优的决策成为我们设备的基石。这个过程并不新鲜,科技史上有很多例子,qwerty键盘是最常被引用的。但有了机器学习,这种技术路径依赖有望加速。机器学习模型不太明显,通常也不太了解技术层。开发中的捷径和次优的设计选择将聚集起来,创造出一个微妙的系统性失败的世界。

如何才能避免这种情况?

这里有一个测试。如果你是一名数据科学家或创建机器学习模型的开发人员,你应该非常清楚如何选择要部署的模型。如果您的选择标准是基于某种标准的 ML 指标(如 RMSE),那么您应该问问自己,该指标减少一个单位将如何影响该模型的业务流程或用户。如果你不能对这个问题给出一个明确的答案,那么你可能根本没有解决这个问题。您应该返回到涉众那里,尝试并准确理解模型将如何被使用,然后设计一个评估标准来估计真实世界的影响。

你可能仍然会优化像 RMSE 这样的东西,但你会根据它对人们的影响来选择一个模型,你甚至会发现你的模型没有增加任何价值。在这种情况下,你能为社会做的最好的服务就是说服涉众不要部署,直到开发出一个改进的模型。

[1]在 Google Pixel 4 智能手机的 SMS 应用程序中生成的示例。

[2]基思·雷纳,萨拉·j·怀特,丽贝卡·l·约翰逊,西蒙·p·利弗塞奇,雷丁著《有一笔费用》,2006 年,
《心理科学》,17(3),192–193 页

[3]彼得·诺维格, 如何写拼写校正器 (2007)

[4]丹尼尔·茹拉夫斯基和詹姆斯·马丁。拼写纠正和
嘈杂频道(2021)https://web.stanford.edu/~jurafsky/slp3/B.pdf

*[5]HLA dek D,Staš,Pleva M. 自动拼写纠正调查。(2020);电子。9(10):1670.【https://doi.org/10.3390/electronics9101670 *

[6]这里收集了许多例子https://www.damnyouautocorrect.com/

更好的代码等于更好的数据科学吗?

原文:https://towardsdatascience.com/does-better-code-equal-better-data-science-69ddc135182

在最近的一篇文章中, Galen 写了关于重代码和低代码数据工程角色之间日益扩大的差距,以及新工具如何塑造该领域的职业道路。它呼应了一场更广泛的、正在进行的关于编程技能以及它们对数据科学家有多重要(或有多重要)的辩论。

因为结论还没有出来,而且很可能还会有一段时间,所以本周,我们将重点介绍一批新的文章,这些文章专注于编码工作流以及数据科学家如何在该领域开发(原谅双关语)一些新的力量。让我们开始吧。

  • 你需要新的软件工程学习策略吗? 不管你从事的是哪一个以数据为中心的特定学科,找到一种可持续的方法来学习新技能和有效地完成编程任务都是至关重要的。 Semi Koen 分享了五个策略,可以帮助你以一种简化、实用的方式处理复杂的编程概念。
  • 几个自定义触摸可以让你在终端中有宾至如归的感觉 。在终端中工作和编码有时会感到冷漠和疏远——这是对不那么友好和用户友好时代的一种倒退。朱利安·维斯特决定不一定要这样,所以他写了一个全面的指南,教你如何用 oh-my-zsh 插件定制你的终端体验,让它成为你自己的。
  • 熟悉动态编程 。Peggy Chang 解释了动态编程的基础知识,这是一种优化技术,“可以在降低时间或空间复杂性的情况下产生高效的代码”,然后通过几个有用的例子进行一些实际操作。
  • 关于嵌套循环以及如何充分利用它们 。 Andrea Gustafsen 深入到日常编程任务的具体细节,探索嵌套 for 循环,并解释它们如何工作以及何时使用它们最有意义。
  • 一个老派的工具拯救了一天 。你已经把 GNU Make 整合到你的工作流程中了吗?对于 Sean Easter 来说,“经典且历史悠久的构建工具”已经成为了一个意想不到的重要元素,它可以创建更健壮、更易于迭代、更易于协作和修改的数据项目。

但是等等,还有呢!(总会有……)

照片由惠普科赫在 Unsplash 上拍摄

最近几周,我们发表了一些非常有趣的项目的帖子,并深入探讨了许多有趣的话题。以下是必读书目的一小部分:

  • 汇集了机器学习、诗歌和区块链的世界, Jeremy Neiman 向我们展示了开发俳句生成器的过程。
  • 如果你不喜欢俳句,但喜欢迷因,你肯定会想看看乔希·比克特在他创造的人工智能迷因创造者上的首次 TDS 帖子。
  • 为了更广泛地了解最近人工智能方面的工作——尤其是围绕计算机视觉——Ygor Serpa汇编了一份 10 篇优秀论文的清单,添加到你的阅读队列中。
  • 你是一个热爱地图的数据科学家吗?你会喜欢华景石关于用几行 Python 代码创建交互式地理空间可视化的循序渐进的教程。
  • 在短暂的中断后,TDS 播客上周回归:主持人 Jeremie Harris 与人工智能研究员 Sam Bowman 聊起了“低估”——从业者中低估人工智能当前能力的趋势。

感谢您的时间和支持,感谢您让 TDS 成为您学习旅程的一部分。

直到下一个变量,

TDS 编辑

GPT-3 有个性吗?

原文:https://towardsdatascience.com/does-gpt-3-have-a-personality-3de9543df621

AI + MBTI =?

一个机器人坐在空房间里,看着镜子大厅里自己无尽的映像和潜在的个性。由作者使用 DALLE-2 生成

迈尔斯-布里格斯类型指标(T1)或 MBTI 是一种常见的性格测试,旨在根据四个类别将人们分为 16 种性格类型(T2 ):内向或外向、感知或直觉、思考或感觉、判断或感知。虽然 MBTI 被批评为伪科学,也许和星座没什么区别,但测试并和他人比较你的性格类型仍然是一项有趣的练习。

因此,在这篇文章中,我展示了我如何使用 GPT-3,一个由 OpenAI 创建的生成式人工智能语言模型,来完成两件事。首先,我让 GPT 3 号模仿一个 20 个问题的游戏来猜测我的性格。第二,一旦 GPT-3 能够(正确!)猜猜我的性格类型,为了确定它的性格类型,我用了 GPT-3 问我的同样的问题。

第 1 部分:促使 GPT-3 猜测我的个性

我首先向 GPT-3 提示了以下内容:

Let's play 20 questions!You are a psychologist and personality type expert. Your job is to guess my MBTI personality type by asking 20 questions.The questions can be freeform answers but should NOT be a yes/no question.Do NOT repeat questions that have already been asked.Ask ONE question at a time.

我让 GPT-3 一次产生一个问题(用绿色突出显示)。我在下面的行中回答。以下是 GPT-3 提出的一些问题和我提供的答案。

GPT-3 提出的示例问题和我给出的自由形式的答案(使用 OpenAI Playground )。作者截图

不像大多数性格测试,通常需要你回答从同意到不同意的问题,我能够用纯文本来回答问题。与简单的同意/不同意量表相比,这些自由形式的回答可能会让你对自己的个性有更多的了解,并透露更多的细微差别。

来自 16 种性格的 MBTI 性格测试示例。这些测试通常会将你的答案分为同意和不同意。

在所有 20 个问题被问完和回答完之后,我用下面的话提示 GPT-3:

Given my answers, what MBTI personality type would you categorize me as and why? Answer in a step-by-step fashion and back up your reason with analysis.

GPT-3 的输出预测了作者的 MBTI 人格类型。作者截图。

GPT-3 能够准确预测我的性格类型(是的,我是 ENFP)。相当令人印象深刻!GPT-3 也能够解释哪些特征对我成为 ENFP 人贡献最大。虽然这感觉有点像看我的星座运势,但知道 GPT-3 从 20 个问题中了解了我的个性,我感到一丝肯定。

第二部分:促使 GPT-3 猜测 GPT-3 的个性

在第一部分中,GPT-3 提出了 20 个问题:

1\. Do you prefer to live in the moment or plan for the future?
2\. What are some things you like to do in your free time?
3\. Do you like to be alone or do you feel antsy and lonely when by yourself?
4\. What kind of emotions do you feel the most?
5\. Do you like to move quickly and be constantly active or do you like slower-paced activities and moments?
6\. Are you more of a 'big picture' person or do you like details and specifics?
7\. Do you prefer to work independently or with a team?
8\. Do you like to have a lot of change in your life or do you like more stability?
9\. What kind of environments do you feel the most comfortable in?
10\. Do you like to have a lot of people around you or do you feel drained after being around people
11\. Do you like to plan and organize your time or do you prefer to go with the flow?
12\. Do you like to be in control of every situation or do you like to let others take the lead?
13\. What is your ideal career?
14\. Do you like to take risks or play it safe?
15\. Do you like to be spontaneous or do you like to plan everything in advance
16\. What is your ideal romantic partner like?
17\. Do you believe there is such thing as true love?
18\. Do you like to be challenged mentally and emotionally or do you like things to be easy
19\. Do you like intellectual conversations or do you prefer small talk
20\. Do you feel like you need to save the world or make a difference in some way?

我很好奇 GPT-3 是什么性格类型。我可以提示 GPT-3,直接问它(“你的性格类型是什么?”),不过那也挺无聊的。相反,让 GPT-3 回答它在第一部分中问我的 20 个问题会更有趣。然后,我可以让 GPT 3 号根据它自己对问题的回答推断出它的个性。

我给 GPT 三号做了如下提示,鼓励 GPT 三号按照一定的格式回答:首先按顺序回答 20 个问题中的每一个,然后输出它对什么样的 MBTI 人格最符合答案的分析。

Let's play 20 questions!Answer each of the questions in the following format.
${Question number}. ${Question}
${free-response answer}After you have answered all of the questions, 
Given the answers to all of the questions, what MBTI personality type would you categorize the answers as and why? Answer in a step-by-step fashion and back up your reason with analysis.1\. Do you prefer to live in the moment or plan for the future?
2\. <the rest of the 20 questions>

下面是我从 GPT-3 得到的四个不同的结果。很快,你可能会注意到有些不对劲。在每一个例子中,GPT-3 的答案都有轻微的变化,导致它预测四种不同的性格类型!GPT-3 是 INTJ、ENFP、ESTP 还是 INFP?

GPT-3 提供的四个样本答案的截图,用于回答 20 个人格问题并确定其人格类型。作者截图

这种结果的多样性源于随机性:GPT-3 是一个概率性的,而不是确定性的模型,同样的提示你会得到不同的结果。随机性部分来自于温度和 top-p 等参数,这些参数控制着模型预测的随机性。

我很好奇,如果我让 GPT-3 进行 4 次以上的人格测试,会发生什么。因此,我使用 OpenAI API 提示 GPT-3 进行 100 次人格测试。然后,我评估了输出,并计算了每种 MBTI 类型出现的次数。

100 次 API 调用之后,结果如下:GPT-3 在 36%的时间里被识别为 ENFP。然而,第二种最常见的人格类型,INTJ,与 ENFP 截然不同。在预测的 MBTI 类型中似乎没有太多的模式,除了“N”很常见这一事实(这意味着 GPT-3 可能有更多的直觉而不是感觉特征)。然而,如图所示,GPT-3 并没有单一的主导人格类型。相反,它是许多不同性格类型的融合。

GPT-3 作为某个 MBTI 组回答的次数超过 100 次。由作者创建的图形。

作为一个非常仓促的“真实世界”比较,我发现一个数据源列出了性格类型的分布。我在引用中使用“真实世界”(请有所保留),因为它来自 MBTI 性格测试平台(16 种性格),并不代表世界上所有人的性格类型。MBTI 也不是代表或分类人格特质的最佳测试。然而,这个数字是作为一个比较点,与我们在上面看到的 GPT-3 的反应。

人格类型的“现实世界”分布。由作者创建的图形。数据来源于16 位名人。

那么这意味着什么呢?GPT 3 号有 36%的时间是 ENFP?互联网上有更多具有 ENFP 特征的人(特别是 Reddit),这构成了 GPT-3 训练数据的很大一部分?你的猜测和我的一样好。

关于参数的一个注记

在所有这些实验中(在 OpenAI Playground 和 API 中),我保留了相同的(默认)参数。未来的实验可以尝试消融研究,观察 GPT-3 对 20 个人格问题的回答如何随着一个参数(如 top-p 或温度)的不同值而变化,同时保持其他参数不变。

{
  temperature: 0.7,
  top_p: 1,
  max_tokens: 700
}

结论

在第一个实验中,GPT 3 号试图猜测我的个性,我展示了 GPT 3 号在让用户判断他们的个性时是有洞察力的。在第二个实验中,GPT 3 号试图猜测自己的个性,我发现 GPT 3 号的反应并不一致。相反,它的反应是相当多样的,这表明也许 GPT-3 不是一个单一的、有强烈认同感的有凝聚力的意识。

一个机器人走过镜子大厅的最后临别图像。由作者使用 DALLE2 生成

希望你喜欢阅读这篇文章!希望听到任何评论或反馈。

最初的咖啡萃取能预测最终的萃取吗?

原文:https://towardsdatascience.com/does-initial-coffee-extraction-predict-final-extraction-6be5487a306

咖啡数据科学

收集数据,一次一汤匙

最近,我买了一个像样的咖啡机。这对我来说是一个很大的变化,因为通常,我在手柄上有一个手柄,可以从我的 Kim Express 杠杆机器上拍摄。有了这只新的空出来的手,我很好地利用了它来收集最初的样本:最初的几滴。

我根据一些指标对我的档案进行了修改,经过几轮修改后,我决定一次做几件事。有些是时间,但最终的衡量标准是提取率。我从理论上讲,如果我品尝了最初几滴浓缩咖啡,我可以修改预冲泡,以获得最佳的预冲泡效果。我想这些滴剂可能有助于预测我是否在改善预输注方面做得更好。

草案

这是我每次拍摄时使用的协议:

  1. 拿着勺子收集最初的几滴
  2. 立即倒入杯中。这可能会在勺子上留下一些可溶物。
  3. 称一下杯子
  4. 使用等量的水进行滴定
  5. 测量 TDS 并乘以 2 以说明滴定。

设备/技术

浓缩咖啡机:体面浓缩咖啡机(DE1Pro)

咖啡研磨机:小生零

咖啡:家庭烘焙咖啡,中杯(第一口+ 1 分钟)

镜头准备:断奏和内外断奏

预输注:瞄准一个较长的大约 25 秒的时间

输液:压力脉动

过滤篮 : 20g VST

其他设备: Atago TDS 计、 Acaia Pyxis 秤、 Kruve 筛

绩效指标

我使用三个指标来评估数据:

用折射仪测量总溶解固体量(TDS),这个数字结合弹丸的输出重量和咖啡的输入重量用来确定提取到杯中的咖啡的百分比,称为提取率(EY)** 。**

强度半径(IR) 定义为 TDS 对 EY 的控制图上原点的半径,所以 IR = sqrt( TDS + EY)。这一指标有助于标准化产量或酿造比的击球性能。

数据分析

我收集了 45 个样本,同时浏览了 22 个配置文件。每个配置文件都有多次更改。根据这个数据,前几滴的 TDS 似乎没有什么趋势。

部分原因可能是最初的几滴并不总是来自同一个地方。如果它们来自篮子的侧面,它可能没有中间的强度大。

我不认为这是决定性的证据,证明最初的几滴不能预测一杯浓缩咖啡的最终表现。我的许多镜头都有一些环形提取(在冰球中间较慢的流动),这在不同的镜头之间有所不同。如果圆盘上的提取变得更加均匀,那么再次测试这个指标可能会很有意思。

如果你愿意,请在 Twitter 、 YouTube 和 Instagram 上关注我,我会在那里发布不同机器上的浓缩咖啡照片和浓缩咖啡相关的视频。也可以在 LinkedIn 上找到我。也可以在中和订阅关注我。

我的进一步阅读:

我未来的书

我的链接

浓缩咖啡系列文章

工作和学校故事集

您的笔记本电脑对数据科学重要吗?旧 ThinkPad 与新 MacBook Pro 对比

原文:https://towardsdatascience.com/does-laptop-matter-for-data-science-old-thinkpad-vs-new-macbook-pro-compared-67e3fa0f9e09

英特尔 i3–6100 u 上的 Pandas 和 TensorFlow 性能指标评测与 M1 Pro MacBook Pro 相比,速度慢了 50 倍?

文章缩略图— ThinkPad L470(左)和 M1 Pro MacBook(右)(图片由作者提供)

自发布以来,16 英寸的 M1 Pro MacBook 一直是我的首选。它在超高级的表面下提供了令人难以置信的性能,同时可以持续一整天,并拥有可能是业界最好的屏幕。

*但是一台旧的双核联想 ThinkPad 呢?第六代英特尔处理器能接近现代的发电站吗?*继续阅读寻找答案。

在今天的文章中,我们将在一系列基准测试中比较旧的 ThinkPad L470 和现代的 M1 Pro MacBook Pro,从合成产品到熊猫和 TensorFlow。基准测试的范围是有限的,所以一切都可以在十分钟内完成。

在继续之前,让我们比较一下硬件规格:

图 1 —硬件规格对比(图片由作者提供)

这不是真正的苹果之间的比较。Mac 起价 2499 美元,我买的 ThinkPad 不到 200 美元。这要便宜 12 倍以上,所以 Mac 有理由这么做。

不想看书?请观看我的视频:

英特尔酷睿 i3–6100 u 性能指标评测——现在还不太好

6100U 早在 2015 年就发布了,所以我们真的不能指望它能与更现代、更强大的芯片相媲美。此外,综合基准只能带我们走这么远,但它们是一个很好的起点。

以下是 i3–6100 u 与单核部门的 M1 Pro 芯片的比较:

图 2 — Geekbench 单核性能(图片由作者提供)

M1 专业版大约快 3.5 倍,这是意料之中的。即使在今天,大多数 Windows 笔记本电脑也无法与之媲美,所以这真的不足为奇。

多核是有趣的地方。i3 只有两个内核,而 M1 Pro 有 8 个性能内核和 2 个效率内核。结果如下:

图 3 — Geekbench 多核性能(图片由作者提供)

如你所见,Mac 在这个测试中快了 12 倍。这是一个巨大的差异,你肯定会在日常使用中注意到这一点。此外,macOS 需要更少的资源来顺利运行,所以这是你必须考虑的另一个问题。

现在让我们进入实际的数据科学基准,从熊猫开始。

Pandas 基准测试—典型数据工作流程时间对比

在一篇文章中,我只能比较这么多,所以让我们继续讨论基础知识。我们将比较创建、保存、读取和转换熊猫数据帧所需的时间。

创建一个熊猫数据框架

让我们创建两个数据集——第一个有 100 万行,第二个大约有 5 行。这些应该足以将 ThinkPad 推向极限。

下面的代码片段导入了本节需要的所有库,还声明了一个函数create_dataset(),它创建了数据集。

import random
import string
import numpy as np
import pandas as pd
from datetime import datetime
np.random.seed = 42

def create_dataset(start: datetime, end: datetime, freq: str) -> pd.DataFrame:
    def gen_random_string(length: int = 32) -> str:
        return ''.join(random.choices(
            string.ascii_uppercase + string.digits, k=length)
        )

    dt = pd.date_range(
        start=start,
        end=end,
        freq=freq,  # Increase if you run out of RAM
        closed='left'
    )

    df_size = len(dt)
    df = pd.DataFrame({
        'date': dt,
        'a': np.random.rand(df_size),
        'b': np.random.rand(df_size),
        'c': np.random.rand(df_size),
        'd': np.random.rand(df_size),
        'e': np.random.rand(df_size),
        'str1': [gen_random_string() for x in range(df_size)],
        'str2': [gen_random_string() for x in range(df_size)]
    })

    return df

现在,让我们使用它来创建 1M 和 5M 数据集:

########## 1M Dataset ##########

df_1m = create_dataset(
    start=datetime(2010, 1, 1),
    end=datetime(2020, 1, 1),
    freq='300s'
)

########## 5M Dataset ##########

df_5m = create_dataset(
    start=datetime(2010, 1, 1),
    end=datetime(2020, 1, 1),
    freq='60s'
)

以下是笔记本电脑和数据集的时间:

图片 4-创建数据集所需的时间(图片由作者提供)

从各方面考虑,这并不是一个很大的差别。对于 1M 数据集,Mac 大约快 7 倍,对于 5M 数据集,大约快 5 倍。ThinkPad 上没有发生任何崩溃或冻结,只是需要更多的时间。

将数据集保存到 CSV 文件

在整个项目过程中,您可能会将数据保存在不同的状态中,因此将花费在这里的时间减到最少会很好。下面的代码片段将两只熊猫的数据帧转储到一个 CSV 文件:

########## 1M Dataset ##########

df_1m.to_csv("/Users/dradecic/Desktop/1Mdf.csv", index=False)

########## 5M Dataset ##########

df_5m.to_csv("/Users/dradecic/Desktop/5Mdf.csv", index=False)

结果如下:

图 5-将数据集保存为 CSV 文件所需的时间(图片由作者提供)

和我们之前的故事相似。将熊猫数据保存到 CSV 文件时,Mac 的速度大约快了 5 倍。

从磁盘读取 CSV 文件

但是反过来呢?在 Mac 上读取 CSV 文件也会快 5 倍吗?代码如下:

########## 1M Dataset ##########

df_1m = pd.read_csv("/Users/dradecic/Desktop/1MDF.csv")

########## 5M Dataset ##########

df_5m = pd.read_csv("/Users/dradecic/Desktop/5MDF.csv")

结果是:

图 6 —读取 CSV 文件所需的时间(图片由作者提供)

到目前为止,5X 时差似乎是普遍存在的。

将函数应用于列

通过调用 DataFrame 列上的apply()方法,可以在 data frame 列上应用自定义函数。下面的代码片段颠倒了最初包含 32 个字符的随机字符串的str1列:

def reverse_str(x) -> str:
    return x[::-1]

########## 1M Dataset ##########

df_1m['str1_rev'] = df_1m['str1'].apply(reverse_str)

########## 5M Dataset ##########

df_5m['str1_rev'] = df_5m['str1'].apply(reverse_str)

让我们来看看结果:

图 7 —反转一列字符串所需的时间(图片由作者提供)

又一次,5X 时差对 Mac 电脑有利。

总结一下——M1 Pro MacBook 一直比 ThinkPad L470 快 5 倍左右。这并不令人惊讶,但让我们看看 TensorFlow 是否能让这种差异变得更大。

TensorFlow 基准测试—自定义模型和迁移学习

只是为了解决房间里的大象——可以在 i3–6100 u 或任何其他低端芯片上安装甚至运行 TensorFlow。它可以工作,但是很慢,因为处理器不是很强大,也没有 GPU 的支持。

对于 TensorFlow 基准测试,我使用了来自 Kaggle 的狗与猫数据集,该数据集是在知识共享许可下授权的。长话短说,你可以免费使用。至于数据集准备,如果您想复制结果,请参考本文中的。

让我们开始第一项测试。

自定义张量流模型

第一个 TensorFlow 基准测试使用数据扩充,并将两块卷积模型应用于图像数据集。它没有什么特别的,只是一个你在学习 TensorFlow 时可能会偶然发现的模型架构:

import os
import warnings
from datetime import datetime
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
warnings.filterwarnings('ignore')

import numpy as np
import tensorflow as tf
tf.random.set_seed(42)

####################
# 1\. Data loading
####################
train_datagen = tf.keras.preprocessing.image.ImageDataGenerator(
    rescale=1/255.0,
    rotation_range=20,
    width_shift_range=0.2,
    height_shift_range=0.2,
    shear_range=0.2,
    zoom_range=0.2,
    horizontal_flip=True,
    fill_mode='nearest'
)
valid_datagen = tf.keras.preprocessing.image.ImageDataGenerator(
    rescale=1/255.0
)

train_data = train_datagen.flow_from_directory(
    directory='/Users/dradecic/Desktop/data/train/',
    target_size=(224, 224),
    class_mode='categorical',
    batch_size=64,
    seed=42
)
valid_data = valid_datagen.flow_from_directory(
    directory='/Users/dradecic/Desktop/data/validation/',
    target_size=(224, 224),
    class_mode='categorical',
    batch_size=64,
    seed=42
)

####################
# 2\. Model
####################
model = tf.keras.Sequential([
    tf.keras.layers.Conv2D(filters=32, kernel_size=(3, 3), input_shape=(224, 224, 3), activation='relu'),
    tf.keras.layers.MaxPool2D(pool_size=(2, 2), padding='same'),
    tf.keras.layers.Conv2D(filters=32, kernel_size=(3, 3), activation='relu'),
    tf.keras.layers.MaxPool2D(pool_size=(2, 2), padding='same'),
    tf.keras.layers.Flatten(),
    tf.keras.layers.Dense(128, activation='relu'),
    tf.keras.layers.Dense(2, activation='softmax')
])
model.compile(
    loss=tf.keras.losses.categorical_crossentropy,
    optimizer=tf.keras.optimizers.Adam(),
    metrics=[tf.keras.metrics.BinaryAccuracy(name='accuracy')]
)

####################
# 3\. Training
####################
model.fit(
    train_data,
    validation_data=valid_data,
    epochs=5
)

该模型在每台机器上训练了 5 个历元,下图比较了平均历元时间:

图 8-自定义模型上每个历元的张量流平均时间(图片由作者提供)

正如你所看到的,TensorFlow 可以在一台旧笔记本电脑上运行,但与 Mac 相比慢了大约 8 倍。如果你刚刚开始,这不是一个交易破坏者。

张量流迁移学习模型

下面的代码片段或多或少与上一个相同,但有一个重要的区别——它现在使用一个预训练的 VGG-16 网络来分类图像:

####################
# 1\. Data loading
####################
train_datagen = tf.keras.preprocessing.image.ImageDataGenerator(
    rescale=1/255.0,
    rotation_range=20,
    width_shift_range=0.2,
    height_shift_range=0.2,
    shear_range=0.2,
    zoom_range=0.2,
    horizontal_flip=True,
    fill_mode='nearest'
)
valid_datagen = tf.keras.preprocessing.image.ImageDataGenerator(
    rescale=1/255.0
)

train_data = train_datagen.flow_from_directory(
    directory='/Users/dradecic/Desktop/data/train/',
    target_size=(224, 224),
    class_mode='categorical',
    batch_size=64,
    seed=42
)
valid_data = valid_datagen.flow_from_directory(
    directory='/Users/dradecic/Desktop/data/validation/',
    target_size=(224, 224),
    class_mode='categorical',
    batch_size=64,
    seed=42
)

####################
# 2\. Base model
####################
vgg_base_model = tf.keras.applications.vgg16.VGG16(
    include_top=False, 
    input_shape=(224, 224, 3), 
    weights='imagenet'
)
for layer in vgg_base_model.layers:
    layer.trainable = False

####################
# 3\. Custom layers
####################
x = tf.keras.layers.Flatten()(vgg_base_model.layers[-1].output)
x = tf.keras.layers.Dense(128, activation='relu')(x)
out = tf.keras.layers.Dense(2, activation='softmax')(x)

vgg_model = tf.keras.models.Model(
    inputs=vgg_base_model.inputs,
    outputs=out
)
vgg_model.compile(
    loss=tf.keras.losses.categorical_crossentropy,
    optimizer=tf.keras.optimizers.Adam(),
    metrics=[tf.keras.metrics.BinaryAccuracy(name='accuracy')]
)

####################
# 4\. Training
####################
vgg_model.fit(
    train_data,
    validation_data=valid_data,
    epochs=5
)

这次的结果大不相同:

图 9 —迁移学习模型中每个时期的张量流平均时间(图片由作者提供)

正如你所看到的,在 Mac 上,每个时期的平均训练时间几乎没有增加,但在 ThinkPad 上却飞速增长。在 i3–6100 u 上等待迁移学习模型完成培训花费了一天中的大部分时间,因为与 Mac 相比,它几乎慢了 54 倍。

那么,**我们从这些基准测试中学到了什么?**接下来让我们回顾一些见解。

旧笔记本电脑上的数据科学—需要考虑的事项

在旧笔记本电脑上进行数据争论或数据科学工作并不是不可能的,尤其是如果你刚刚起步的话。有几件事你应该记住,所以让我们复习一下。

旧笔记本电脑+深度学习=谷歌 Colab

没有理由仅仅因为你刚开始深度学习就让一台旧笔记本电脑经历磨难。 Google Colab 是一个令人惊叹的预配置笔记本电脑环境,不需要任何成本,并且包含 GPU 支持。如果你需要更多的功能和更长的运行时间,可以考虑 Colab Pro。

港口的缺乏

说 Mac 有更好的端口选择很奇怪,但在这种情况下确实如此。ThinkPad L470 已经 5+岁了,所以它没有 USB-C,甚至没有 HDMI 端口。连接外接显示器就没那么容易了。

有一个 VGA 端口可用,但这需要一个适配器,如果你有一个现代的外部显示器,图像质量会有所下降。不是交易破坏者,只是需要考虑的事情。

有了 Mac,我可以用一根 USB-C 电缆连接 4K 外部显示器、监视器灯、手机充电器、麦克风和耳机。

可怕的屏幕

我从来没有对 ThinkPad 的显示器印象深刻,但 L470 将这种糟糕带到了一个完全不同的水平。显示屏为 14 英寸,对于笔记本电脑来说非常出色,但分辨率不是 1366x768。所有的东西都很大,你不能在屏幕上放超过一两个窗口。色彩准确度也非常糟糕。

如果连接全分辨率的外部显示器更容易,这就不是问题了。

另一方面,Mac 上的迷你 LED 屏幕跨度为 16 英寸,分辨率为 3456x2234。至少可以说,这是白天和黑夜的差别。

结论

英特尔的 i3–6100 u 可以相当好地处理熊猫,它也可以用 TensorFlow 训练深度学习模型,尽管速度很慢。你绝对可以在使用它的同时进入数据科学,甚至在行业内从事专业工作。如今大部分工作都在云端完成,所以笔记本电脑归根结底是被美化了的键盘。

与新事物相比,廉价的旧笔记本电脑的最大问题不是原始性能,而是其他方面的妥协。每天看着可怕的屏幕 8 个多小时,处理劣质电池和一大堆电缆并不好玩。

但另一方面,如果你想进入数据科学领域,并有 200 美元的闲钱,一台旧笔记本电脑就足够了。

你对新旧笔记本电脑的对比有什么看法?您目前使用的笔记本电脑曾经风光过吗?如果是,你每天都在与什么问题作斗争?请在下面的评论区告诉我。

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

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

更多基准

  • MacBook M1 vs M1 Pro
  • MacBook M1 vs . Google Colab
  • MacBook M1 Pro vs 谷歌 Colab
  • MacBook M1 vs RTX 3060 ti

保持联系

  • 雇用我作为一名技术作家
  • 在 YouTube上订阅
  • 在 LinkedIn 上连接

原载于 2022 年 11 月 22 日 https://betterdatascience.comhttps://betterdatascience.com/data-science-old-laptop/

我的新中央供暖锅炉对这些疯狂的高油价有帮助吗?

原文:https://towardsdatascience.com/does-my-new-central-heating-boiler-help-with-these-crazy-high-gas-prices-b238fd623bba

在能源危机中,我们使用相互作用的线性回归对我的新中央供暖锅炉的性能进行基准测试

简介

随着东欧的冲突愈演愈烈,副作用之一是能源价格飙升。自今年年初以来,我的汽油价格轻松翻了两番,所以像一个好书呆子类型的数据科学家一样,我开始研究我的能源使用数据,以减轻我的担忧。幸运的是,我的能源供应商允许我下载过去几年每天的用气量数据。我首先想到的一件事是,我们今年的天然气用量低于我根据前几年的预期。可能导致这种情况的主要怀疑之一是在 2022 年 4 月底安装了一个新的中央供暖锅炉,因为它是唯一使用天然气的设备。

在这篇文章中,我们探索了我的能源数据,并建立了一个回归模型,其中包括量化我的新中央供暖锅炉对我的燃气用量的影响程度的相互作用。

*注:*本文也可以在 github 上阅读,包含全部代码。

日常用气量和温度

主要数据来源是我的能源供应商 Eneco 的网站。他们允许我从他们的在线系统下载一个 Excel 表格,里面有每天的能源使用情况。请注意,我对我的使用数据(最小-最大比例)进行了标准化,以保护我的数据隐私。此外,我还下载了附近一个气象站的温度数据,因为我怀疑气体的使用会强烈依赖于外部温度。以下代码读取数据,并根据日期合并两个数据集:

每周每日用气量和每周趋势线(自行创建)

其中点是每天的用气量,线是每周的平均值。这清楚地显示了天然气使用的年度趋势,冬季使用量高,夏季使用量低。一个非常显著的特点是日值在横线上累加。这是因为用气量是以整数增量报告的,有效地将数值四舍五入到最接近的最小整数。为了减轻这种整数效应,我们将整个数据集重新采样为每周总用气量和每周平均温度。使用这些重新采样的数据,我们绘制了一个曲线图,显示温度与用气量的关系:

gas_usage = (
    energy_usage['gas_usage']
      .resample('W').sum().reset_index()
      .merge(temperature.resample('W').mean().reset_index(), left_on='Datum', right_on='date')
)

# Some obviously wrong data eliminated
gas_usage = gas_usage.query('gas_usage >= 0.55')

# Eliminate weeks that do not have the full 7 days, because we sum the data over the days
# and for those non-complete weeks this would underestimate the gas_usage, thus skewing the results
non_complete_weeks = (
    energy_usage['gas_usage']
      .resample('W').count() != 7
)
non_complete_dates = non_complete_weeks.loc[non_complete_weeks].index.values
gas_usage = (
  gas_usage.loc[~gas_usage['Datum'].isin(non_complete_dates)]
     .reset_index().drop(columns='index') # This is sadly needed as plotnine will throw an error without it. Might be connected to the new index not being contiguous anymore
)

(
    ggplot(gas_usage, aes(x='T_gem', y='gas_usage')) 
      + geom_point()
      + geom_smooth(method='lm')
)

平均周温度与气体使用量(自行创建)

这清楚地表明温度和气体用量之间有很强的相关性。使用这种影响作为基线,我们现在可以尝试和模拟取代中央供暖锅炉的影响。

对标集中供热锅炉

我们对锅炉进行基准测试的第一步是创建一系列每月燃气用量的箱线图。此外,对于新锅炉安装后的几个月,我们增加了单独的箱子:

锅炉安装前后每月用气量的箱线图(自创)

这向我们显示了新锅炉使用更少燃气的第一个暗示,安装后几个月(5 月-9 月,青色方框)显示燃气使用量更低。下一步是为安装前和安装后的数据重新绘制我们的温度与用气量曲线图:

这证实了我们先前的观察:气体用量较低,并且随着回归线的斜率显著降低,这种影响似乎与温度成比例。然而,安装后的数据仍然非常有限,因为寒冷而触发供暖的周数也不多。但是考虑到目前非常高的油价,这给了我一些希望,我们可以用比去年冬天更少的汽油度过这个冬天。*更新:*文章中包含的新数据(截至 12 月 28 日)进一步证实了斜率已经下降,尽管下降幅度没有旧的有限数据显示的严重。p

为了量化这种影响,我们使用 statsmodels 的公式界面创建了一个回归模型。请注意,我们不能简单地在公式中包含两个变量,就像“T_gem + C(post_install)”,因为这将只允许线与线之间的截距不同。这显然不是我们想要的给定的结果,上面的情节,我们希望不同的斜率后和预安装。解决方案是使用相互作用,即告诉回归模型‘t _ gem’和‘gas _ usage’之间的关系基于‘c(post _ install)’而变化。在公式中,您可以使用 *: T_gem * C(post_install)来指定。这意味着“gas_usage”和“T_gem”之间的关系(斜率)对于“C(post_install)”的两个值可以是不同的,导致上面图中的两条线。运行代码会产生:

其中系数需要解释为:

  • “拦截”零摄氏度时的(匿名)用气量
  • C(post_install)[T.True]在零度时,新锅炉使用的燃气少 0.91(post _ install = True)
  • 温度从 0 开始每增加一度,用气量下降 0.15,即斜率为-0.15。
  • T_gem:C(post_install)[T.True]新锅炉将T_gem的斜率改变 0.04。这使得斜率(-0.15 + 0.04) = 0.11,这意味着当温度下降时,用气量增加不太明显。

这些系数的附加效应是我们所期望的:新锅炉使用更少的气体,但绝对效应随着温度的升高变得不那么强烈。以下回归公式进一步说明了这一点:

结论

对于我在安装新锅炉后获得的有限数据集,情况看起来不错。它使用更少的汽油,并有望大大影响我的水电费。但是也有一些限制:与多年的安装前数据相比,安装后的数据非常有限,特别是因为安装后的冬季数据不包括在内。今年冬天,我当然会收集更多的数据,这将提供更多的确定性。一个潜在的干扰因素可能是我们把恒温器调低到 18 度,这几乎肯定会影响我们的天然气使用。但这是一个在春天解决的有趣话题。*更新:*截至 12 月 28 日的新数据很好地完善了这篇文章:天然气使用量下降,但没有我们根据早期数据预测的那么严重。

本文也可以在 github 上阅读,包括全部代码。

我是谁?

我叫 Paul Hiemstra,是荷兰的一名教师和数据科学家。我是科学家和软件工程师的混合体,对与数据科学相关的一切都有广泛的兴趣。你可以在 medium 上关注我,或者在 LinkedIn 上关注 T4。

如果你喜欢这篇文章,你可能也会喜欢我的其他一些文章:

  • 掌握数据科学并不是学习一系列技巧
  • 学习 AI 机器人玩井字游戏系列文章
  • 牛郎星图解构:可视化气象数据的关联结构
  • 面向数据科学的高级函数式编程:使用函数运算符构建代码架构
  • 通过规范化扩展您的回归曲目

Python 还需要 map()函数吗?

原文:https://towardsdatascience.com/does-python-still-need-the-map-function-96787ea1fb05

有了各种备选方案,Python 的 map()似乎就显得多余了。那么,Python 到底需不需要呢?

Python 需要 map()函数吗?Muhammad Haikal Sjukri 在 Unsplash 上拍摄的照片

别担心,这不会是第一百万篇关于如何在 Python 中使用map()的文章。我不会告诉你这比列表理解或循环更好或更差。我不打算将它与相应的生成器或列表理解进行对比。我不会说使用map()会让你看起来像一个高级 Python 开发者…

你可以在 Medium 上发表的其他文章中读到所有这些内容。尽管内置的map()函数在 Python 开发人员中并不太受欢迎(你很少会在产品代码中发现它),但它在 Python 作者中却很受欢迎(例如,参见这里的、这里的这里的和这里的)。这是为什么呢?也许因为这是一个有趣的函数。类似于函数式编程;或者可以用它的替代品作为基准,而基准通常会引起注意?

大多数关于 Python 的map()的文章仅仅展示了如何使用,而没有展示为什么:在展示如何使用它的同时,他们通常没有解释为什么应该使用它。难怪,尽管它在 Python 作者中很受欢迎,但在中级开发人员中似乎没有得到应有的重视。

如果你想了解更多关于map()的知识,这篇文章就是为你准备的。我们将讨论map()函数在 Python 代码路线图中的位置,以及为什么不管你是否会使用它,了解这个函数都是值得的。

几句关于map()的话

做一些大多数 Python 开发人员经常做的事情:为 iterable 的每个元素调用一个函数(实际上是一个 callable)。

它接受一个可调用函数作为参数,所以它是一个高阶函数。因为这是函数式编程语言的典型特征,map()符合函数式编程风格。比如,你会在洛特的《T21 函数式 Python 编程》一书中发现很多map()的应用。我认为map()使用了类似的 API,而不是真正的函数式编程。这是因为我们可以把map()用于不纯的函数,也就是有副作用的函数;这在真正的函数式编程中是不可接受的。

是时候看看map()的行动了。

>>> numbers = [1, 4, 5, 10, 17]
>>> def double(x):
...     return x*2

所以,我们有一个数字列表,我们有一个函数可以将一个数字加倍。double()适用于单个号码:

>>> double(10)
20

如果我们用double()代替numbers会怎么样?

>>> double(numbers)[1, 4, 5, 10, 17, 1, 4, 5, 10, 17]

如果你知道 Python 中列表相乘的工作原理,这不会让你吃惊。虽然这是正常的行为,但这绝对不是我们想要达到的目标。上图,double(numbers)将函数double()应用到numbers 整体(作为对象)。这不是我们想要的;我们要将double()应用到的每一个元素numbers。这有很大的不同,这就是map()的用武之地:当你想对 iterable 的每个元素应用 callable 时,你可以使用它。

警告:一些语言使用名称map作为哈希映射;在 Python 中,字典是哈希映射。所以,请注意,当你在另一种语言中看到术语“地图”时,首先检查它代表什么。比如 R 中的map()相当于 Python 的map();但是在 Go 中,map()创建一个哈希映射,工作方式类似于 Python 的dict()。当我第一次开始学习围棋时,这让我很困惑,但过一段时间后,你就会明白了。

你应该这样使用map():

>>> doubled_numbers = map(double, numbers)

如您所见,您向map()提供了一个 callable 作为第一个参数,一个 iterable 作为第二个参数。它返回一个 map 对象(在 Python 3 中,但是在 Python 2 中,您将获得一个列表):

>>> doubled_numbers #doctest: +ELLIPSIS
<map object at ...>

(请注意,我使用了#doctest: +ELLIPSIS指令,因为本文档包含在doctest s 中。它帮助我确保所有示例都是正确的。你可以在文档中读到更多关于 T2 的内容。)

一个map对象像一个发电机一样工作。所以,即使我们在map()中使用了一个列表,我们得到的不是一个列表,而是一个生成器。按需评估生成器(延迟)。如果你想把一个map对象转换成一个列表,使用list()函数,它将评估所有的元素:

>>> list(doubled_numbers)
[2, 8, 10, 20, 34]

或者,您可以用任何其他方式评估map的元素,比如在for循环中。为了避免不愉快的头痛,请记住,一旦这样的对象被评估,它是空的,因此不能再被评估:

>>> list(doubled_numbers)
[]

上面,我们为单个 iterable 应用了map(),但是我们可以使用多个 iterable。该函数将根据它们的索引来使用它们,也就是说,首先,它将为 iterables 的第一个元素调用 callable(在索引 0 处);然后进行第二次;诸如此类。

一个简单的例子:

>>> def sum_of_squares(x, y, z):
...     return x**2 + y**2 + z**2>>> x = range(5)
>>> y = [1, 1, 1, 2, 2]
>>> z = (10, 10, 5, 5, 5)
>>> SoS = map(sum_of_squares, x, y, z)
>>> list(SoS)
[101, 102, 30, 38, 45]
>>> list(map(sum_of_squares, x, x, x))
[0, 3, 12, 27, 48]

map()的替代品

代替map(),你可以使用一个生成器,例如,通过一个生成器表达式:

>>> doubled_numbers_gen = (double(x) for x in numbers)

这提供了一个发电机,就像map()一样。当你需要一个清单时,你会更好地理解相应的清单:

>>> doubled_numbers_list = [double(x) for x in numbers]

哪个可读性更强:map()版本还是生成器表达式(或者列表理解)?对我来说,没有一秒钟的犹豫,生成器表达式和列表理解更清晰,即使我理解map()版本没有问题。但是我知道有些人会选择map()版本,尤其是那些最近从另一种使用类似map()功能的语言迁移到 Python 的人。

人们经常将map()lambda函数结合使用,当您不想在其他地方重用该函数时,这是一个很好的解决方案。我认为对map() 的部分负面看法来自于这种用法,因为lambda函数经常会降低代码的可读性。在这种情况下,通常情况下,生成器表达式的可读性会更好。下面比较两个版本:一个是map()结合lambda,另一个是对应生成器表达式。这一次,我们将不使用我们的double()函数,但是我们将在调用中直接定义它:

# map-lambda version
map(lambda x: x*2, numbers)# generator version
(x*2 for x in numbers)

这两行导致相同的结果,唯一的区别是返回对象的类型:返回一个map对象,而后者返回一个generator对象。

让我们暂时回到map()的多次使用:

>>> SoS = map(sum_of_squares, x, y, z)

我们可以按照以下方式使用生成器表达式重写它:

>>> SoS_gen = (
...     sum_of_squares(x_i, y_i, z_i)
...     for x_i, y_i, z_i in zip(x, y, z)
... )>>> list(SoS_gen)
[101, 102, 30, 38, 45]

这次我投票给map()版本!除了更简洁之外,在我看来,它更清晰。发电机版本利用zip()功能;即使这是一个简单的函数,它也增加了命令的难度。

所以,我们不需要 map(),不是吗?

根据以上讨论,不存在我们必须使用map()功能的情况;相反,我们可以使用生成器表达式、循环或其他东西。

知道了这一点,我们还需要什么吗?

思考这个问题,我得出了我们需要 Python 中的map()的三个主要原因。

原因一:性能

如前所述,map()被懒洋洋地评估。然而,在许多情况下,评估map()比评估相应的生成器表达式更快。尽管相应的列表理解并不一定是这种情况,但是在优化 Python 应用程序时,我们应该记住这一点。

然而,请记住,这不是一个普遍的规则,所以你不应该假设这一点。每次都需要检查map()在你的代码片段中是否会更快。

只有在性能上的细微差异也很重要时,才考虑这个原因。否则,以牺牲可读性为代价使用map()将会收获甚微,所以你应该三思而后行。通常,节省一分钟没有任何意义。其他时候,节省一秒钟意味着很多。

原因二:平行度和穿线

当您并行化您的代码或使用线程池时,您通常会使用类似于map()的函数。这可以包括诸如multiprocessing.Pool.map()pathos.multiprocessing.ProcessingPool.map()concurrent.futures.ThreadPoolExecutor.map()之类的方法。所以,学会使用map()会帮助你理解如何使用这些功能。通常,您会希望在并行和非并行版本之间切换。由于这些函数之间的相似性,您可以非常容易地做到这一点。看:

当然,在这个简单的例子中,并行化没有意义,而且会更慢,但是我想向您展示如何做到这一点。

原因 3:对于来自其他语言的 Python 新人来说简单

这个原因是非典型的,并不涉及语言本身,但它有时很重要。对我来说,生成器表达式几乎总是更容易编写,可读性更好。然而,当我刚接触 Python 时,理解对我来说并不容易,无论是写还是理解。但是自从我在 16 年的 R 编程后来到 Python,我非常熟悉 R 的map()函数,它的工作方式与 Python 的map()完全一样。然后,对我来说,使用map()比使用相应的生成器表达式或列表理解要容易得多。

更重要的是,对map()的熟悉帮助我理解。我也能够编写 Pythonic 代码;没错,用map()就是 Pythonic。我们知道,第三种选择是for循环,但这很少是更好的(甚至是好的)选择。因此,如果有人使用 Python 并且知道这些函数是如何工作的,那么他们编写 Python 代码就容易多了。例如,从 C 语言转向 Python 的人可能会使用一个for循环,这在这种情况下被认为是非 Python 的。

这意味着map()是 Python 和其他语言之间的桥梁——一座可以帮助其他人理解语言和编写 Python 代码的桥梁。

原因 4:多个可迭代的情况下的可读性

如上图所示,当你想同时为多个 iterables 使用一个 callable 时,map()可以比对应的生成器表达式更易读、更简洁。因此,即使在简单的情况下,map()可读性较差,但在更复杂的情况下,可读性成为了它的优势。

结论

有人说 Python 不需要map()。回到 2005 年,Guido 自己想把它从 Python 中移除,还有filter()reduce()。但是 17 年后的今天,我们仍然可以使用它,我认为——并真诚地希望——这一点不会改变。这给我们带来了本文所要讨论的两个关键问题:

***map()***函数是 Python 中必须的吗? 不,不是。你可以用其他方法达到同样的效果。

既然如此,Python 还需要 ***map()*** 函数吗? 是的,确实如此。不是因为它是必须的,而是因为它仍然被使用,它服务于各种有价值的目的。

我认为 Python 开发者应该知道如何使用map(),即使他们不经常使用它。在某些情况下,它可以帮助提高性能,并行化代码,只需很小的改动,或者提高代码的可读性。它有助于理解。它还可以帮助来自其他语言的开发人员使用地道的 Python——因为,是的,map()仍然是 Python。

正是因为这些原因,我认为map()值得在 Python 代码库中占有一席之地,即使它并不经常被使用。

资源

  • https://medium . com/swlh/higher-order-functions-in-python-map-filter-and-reduce-34299 fee1b 21
  • https://towards data science . com/python-map-filter-and-reduce-functions-explained-2b 3817 a 94639
  • https://medium . com/forward-data-science/understanding-the-use-of-lambda-expressions-map-and-filter-in-python-5e 03 E4 b 18d 09
  • https://docs.python.org/3/library/doctest.html
  • *【https://www.artima.com/weblogs/viewpost.jsp?thread=98196 *
  • 洛特,S.F. (2018)。函数式 Python 编程。第二版。包装出版公司。

大脑是靠深度学习运行的吗?

原文:https://towardsdatascience.com/does-the-brain-run-on-deep-learning-3fbaf20e9d12

播客

JR·金论生物智能与人工智能的异同

苹果 | 谷歌 | SPOTIFY | 其他

编者按:TDS 播客由 Jeremie Harris 主持,他是 Gladstone AI 的联合创始人。每周,Jeremie 都会与该领域前沿的研究人员和商业领袖聊天,以解开围绕数据科学、机器学习和人工智能的最紧迫问题。

深度学习模型——特别是变形金刚——正在定义当今人工智能的前沿。它们基于一种叫做人工神经网络的架构,如果你经常阅读数据科学,你可能已经知道了。如果你是,那么你可能已经知道,正如他们的名字所暗示的那样,人工神经网络是受生物神经网络的结构和功能的启发,就像那些在我们大脑中处理信息的网络一样。

因此,很自然会有人问:这种类比能走多远?如今,深度神经网络可以掌握越来越多的历史上人类独有的技能——如创建图像,或使用语言,规划,玩视频游戏等技能。这是否意味着这些系统也像人脑一样处理信息?

为了探索这个问题,我们将采访 JR·金,他是 Meta AI 附属高等师范学院的 CNRS 研究员,领导着大脑与人工智能小组。在那里,他致力于确定人类智能的计算基础,重点是语言。JR 是一个非常有洞察力的思想家,他花了很多时间研究生物智能,它来自哪里,以及它如何映射到人工智能上。在这一集的 TDS 播客中,他和我一起探索生物和人工信息处理的迷人交集。

以下是我在对话中最喜欢的一些观点:

  • JR 的工作重点是研究现代深度神经网络不同层中人工神经元的激活,并将它们与人脑内部细胞簇的激活进行比较。他使用生物细胞群,而不是单个的生物神经元,因为我们根本无法从大脑成像中获得单个神经元水平的分辨率。这些细胞群对应于大脑体积的小像素,称为体素。他的工作包括检测一个大型深度神经网络给定层的神经元激活与大脑中与语言相关部分的体素激活之间的统计相关性,该神经网络经过训练以进行语言建模。
  • 众所周知,深度神经网络具有层次结构,其中更简单、更具体的概念(如图像中的角和线,或文本中的基本拼写规则)被网络中的较低层捕获,而更复杂和抽象的概念(如图像中的脸形或轮子,以及文本中的句子级想法)出现在结构的更深处。有趣的是,这种 hirearchy 也倾向于在大脑中出现,这表明深层网络和大脑之间的类比超越了神经元水平,也延伸到了大脑宏观结构的水平。我问 JR,他是否认为这是一种巧合,或者这甚至暗示了一种智力的普遍属性:我们应该期望所有的智力都包括这种等级信息处理吗?
  • 最近在人工智能领域存在争议,即人工智能系统是否真正“理解”有意义的概念。我们讨论了是否是这样,以及谈论人工智能系统的“理解”是否具有建设性(我们一致的答案是“是”,和“是”,但你确实是你)。
  • 进行大脑<>神经网络比较的一个主要挑战是,大脑是一个非常嘈杂的器官,不断产生和处理与心跳、呼吸、眼球运动、咳嗽等相关的信号。出于这个原因,将大脑行为与神经网络行为相关联具有挑战性:嘈杂的数据,加上较小的影响大小,即使在最好的情况下也是令人沮丧的因素。为了弥补这一点,研究人员倾向于收集大量的数据,这可以使人们对有趣的相关性的存在有很高的信心,尽管这些相关性很弱。

章节:

  • 0:00 介绍
  • 2:30 JR 的日常工作是什么?
  • 5:00 人工智能和神经科学
  • 12:15 研究中的信号质量
  • 结构的普遍性
  • 28:45 大脑是由什么组成的?
  • 37:00 扩展人工智能系统
  • 人类大脑的成长
  • 观察到某些重叠
  • 55:30 总结

现代数据栈重视“栈”胜过“数据”吗?

原文:https://towardsdatascience.com/does-the-modern-data-stack-value-the-stack-over-data-69b8dee4950f

我们听到更多的是关于工具,而不是如何正确使用它们

照片由法比奥在 Unsplash 上拍摄

T 最近有许多关于解绑或再解绑的辩论,这导致了一些关于谁将赢得任何给定数据堆栈的市场的争论。但是这些争论隐藏了一个重要的事实:工具只是工具。最后,你如何使用它们与你的产品和供应商选择同等重要(如果不是更重要的话)。

我们为什么要使用工具

数据工具的主要目的是通过数据驱动的自动化来帮助解决业务问题、做出更好的决策以及改进现有流程。但许多人开始采用新工具,只是为了跟上当前的趋势,如现代数据堆栈。

尤其是在这个时代,当我们每天都受到大量新技术的轰炸时,开发一个决策框架来选择并成功采用新的数据工具并有意识地这样做是非常有用的。

明智地选择您的筹码

从需要解决的问题以及该工具必须支持的业务流程和最终用户开始是一个很好的实践。在以下情况下,应采用堆栈的任何添加:

  1. 它解决了一个真正的问题,
  2. 它符合您的工作方式和您组织的需求,
  3. 它与您的工程工作流程或业务流程配合得很好,并且理想地增强了它们。

一旦澄清了这一点,我们就需要决策和评估标准,最后,我们可以继续进行工具评估、选择和采用。

为什么这种结构化方法对于为您的数据堆栈选择工具非常重要?因为否则,你可能会以意外的复杂而告终。您的数据平台可能会变成一套脱节且难以维护的自托管工具,甚至更糟,变成一堆完全脱节的 SaaS 产品,您为此付出了一大笔钱,但最终却出现了比以前更多的问题。

工程师在数据领域的角色

一旦我们选择了我们的堆栈,我们就可以开始工程。随着现代数据堆栈和新的开源技术的兴起,我们开始看到新职位的出现,如 ML 工程师、分析工程师或数据平台工程师。但是,成为一名优秀的工程师和数据从业者意味着什么呢?

不仅仅是关于编码、优化查询性能或者学习如何挑选 Git 提交。工程师懂得如何处理业务问题,找出问题的根源,然后选择工具和设计不会导致将来后悔的解决方案。为了把它做好,我们需要伟大的工具和伟大的工程师。

良好的工程设计与工具选择

好的工程设计能战胜仔细的工具选择吗?一如既往,真相介于两者之间。

最后,你将如何使用任何给定的工具决定了你能在多大程度上成功使用它。

为了说明这一点,让我们看看有助于解决确保可靠数据流问题的工具。这个领域的产品开始分成两大类。第一类是协调者,重新绑定数据堆栈并努力控制其中的一切。第二个是协调平面,更侧重于观察各种工具(甚至其他协调器)的状态,并允许你根据观察到的状态采取行动。

重新捆绑堆栈的传统协调器容易被供应商锁定,因此协调平面有助于构建一个更能适应变化、更适合为您提供长期服务的数据平台。但是并非一切都是黑白分明的——即使有了完美的数据工具,如果你不小心如何在那个平台上构建你的系统,你仍然可能处于一个糟糕的境地。

在这个前提下,好的工程设计能战胜工具选择吗?在某种程度上,是的。然而,选择错误的工具会迫使你做出单向的决定,不管你在其上设计了多么好的系统。

控制平面:把你所有的(数据流)鸡蛋放在一个篮子里

使用单个 orchestrator 作为可观察性、沿袭和数据流执行的控制平面意味着什么?这意味着,要获得可靠的谱系图并全面了解您的数据平台的状态,您必须在任何地方、任何时候都使用这个平台。

实际上,这意味着从 dbt Cloud 而不是从 central orchestrator 触发您的 dbt 模型会破坏您的工作流血统,并且您的元数据图像是扭曲的。orchestrator 对当前状态感到困惑,而您的数据平台崩溃仅仅是因为您选择从 dbt Cloud 而不是从您的中央 orchestrator 触发运行。

关键的区别在于选择,或者说你选择的工具是否迫使你做出选择

这完全是关于选择以及约束和灵活性的正确平衡。中央控制面板对整个数据堆栈进行重新绑定是极其受限的,但是如果您是一个喜欢这种限制而不是更多灵活性的小团队,这可能是理想的。

相比之下,协调平面被动地观察您的数据堆栈并收集关于它的元数据,而不管哪个工具触发了您的数据流,这给了您选择如何工作的权力。有了这种方法,你可以专注于数据和构建可靠的工程流程**,而不是工具**和如何对抗它们。

后续步骤

如果你喜欢这篇文章,你可能也会喜欢这篇。

感谢阅读!

WDT 会把粉末转移到浓缩咖啡篮的底部吗?

原文:https://towardsdatascience.com/does-wdt-migrate-fines-to-the-bottom-of-the-espresso-basket-e0c845c84259

咖啡数据科学

韦斯分布技术(WDT)已经存在几年了。WDT 通常有助于良好的分配,并已被发现改善咖啡提取。人们遇到的一个困难是不知道去 WDT 需要多长时间。如果你 WDT 太多,细颗粒会从混合和运动中向过滤篮底部移动吗?

我的理论是,由于静电,较细的颗粒会粘在较大的颗粒上。我以前的筛分经验表明,简单的振动不足以使颗粒充分分离。我必须仔细筛选,表明研磨咖啡不像干沙。

所有图片由作者提供

为了测试这一点,我在一些 WDT、更多的 WDT 和太多之后观察了几个样品上的研磨分布。对于每一次迭代,我都会在之后夯实圆盘并提取一个核心样本。我也用了现磨咖啡。

然后我会继续 WDT 咖啡。

我得到了这三个核心样本。这些样本是从冰球中心取出的。

使用图像处理,我测量了开始分布、第一次 WDT 应用、第二次和第三次的分布。对于其中的每一个,我测量了圆盘顶部、中部和底部的分布。

我没有看到表明分布变化的分布变化。

我更仔细地观察了精细层,虽然有一些移动,但不符合迁移的预期。例如,我可以通过顶部减少小于 200 微米的颗粒,但随着时间的推移,它会增加。

我也观察较粗的颗粒,我反过来观察它们,这样我就能理解正在发生的任何变化。没有任何明显的趋势。

从这组实验中,我没有发现 WDT 导致更细的颗粒在拍摄准备过程中迁移的证据。由于我的技术,这是很有可能的,但是我没有数据来支持不同的结论。

所以,如果你担心你做了太多的 WDT,深呼吸。

如果你愿意,可以在推特、 YouTube 和 Instagram 上关注我,我会在那里发布不同机器上的浓缩咖啡照片和浓缩咖啡相关的视频。你也可以在 LinkedIn 上找到我。也可以关注我在中和订阅。

我的进一步阅读:

我的书

我的链接

浓缩咖啡系列文章

工作和学校故事集

你的代码有味道吗?

原文:https://towardsdatascience.com/does-your-code-smell-acb9f24bbb46

什么是代码气味,如何减少代码气味

马库斯·斯皮斯克在 Unsplash 上的照片

我承认,直到最近一位更资深的开发人员告诉我我的代码“有味道”时,我才发现代码有味道。我看着它们,看着我的代码,想知道它们到底是什么意思。当他们接着解释说代码气味是代码中的模式,不一定会阻止代码运行,但可能表明一些有缺陷的逻辑,或者可能是不稳定或难以维护的代码时,我的脸上一定露出了这种表情。我明白他们的意思,也明白为什么我的代码不是我能写出的最好的代码,所以我着手修复它。然而,从那以后,我想更深入地了解什么是代码味道,以及如何在自己或他人的代码中找到它们。

照片由在 Unsplash 上的battle creek 咖啡烘焙师拍摄

那么什么是代码气味呢?首先,它们不一定是你的代码中的 bug 或错误,事实上你的代码实际上可以运行得非常好,并通过所有它需要的测试。但是这并不总是好的代码。代码气味基本上是代码片段,在运行时,往往表明逻辑有问题,或者给代码库带来不必要的复杂性。虽然现在并不总是产生问题,但这可能会使代码难以扩展,或者在将来产生难以调试的错误。

代码气味可能会产生一些问题,比如降低处理速度、增加失败的风险,以及进一步产生 bug。糟糕的代码会导致糟糕的代码质量,并且会增加您的团队将来必须处理的技术债务的数量。这是你绝对不希望你的名字出现在代码提交中的。然而,好的一面是代码气味可以被“嗅到”,并且相对快速地发现。尤其是当你的公司使用代码审查系统时,因为其他人可以指出你的问题,或者你使用一个自动工具来标记你的代码库。当然,您更愿意使用后者或者知道要注意什么,而不是依赖别人来发现您的糟糕代码。

实际上,不同项目、不同开发人员、甚至不同公司的代码味道可能不同,因为这将取决于对代码所期望的定义和接受的标准。尽管如此,通常有一些众所周知的代码味道,您可以尝试在自己的代码中减少:

  • **重复代码:**这是同一段代码在你的程序中多次出现的地方。此时,最好尝试将这段代码放入一个函数中,这样你就可以多次调用它,而不必多次输入。这也意味着,如果你需要对它的功能进行修改,你不需要复制这些修改,也不需要冒以后代码中出现 bug 的风险。
  • 不必要的复杂性:这可能意味着各种各样的事情,但是当你使用复杂的设计模式时,更简单、不复杂的设计也能工作。如果你看着你的代码,认为它可以用一种更简单的方式来完成,或者它看起来很复杂,它可能是可以的。花些时间想想那段代码,写下它应该做什么,什么时候做,然后想想如果你从头开始会有什么变化。然后着手重构代码,使之变得更容易。
  • 做多种事情的大型函数:这是一个大忌,会让程序很难调试。如果你程序中的一个大函数出了问题,你可能知道错误来自那个函数,但不知道是什么触发了它。这也会使测试变得非常困难,从而使您的代码在将来难以维护。您希望确保您的函数很小,并且只处理一件事情。这使得测试变得非常容易,如果以后出现任何错误,也可以很容易地看到哪里出了问题。
  • 嵌套的 if 语句:这也是一种典型的代码味道,所以如果可能的话,你应该尽量避免。这往往表明你的逻辑有问题,或者你试图一次检查太多的事情(这就是我被抓到的做法)。这使得阅读和理解正在发生的事情以及确切的代码运行时间变得非常困难。在这一点上,试着找出你的基本条件应该是什么(无论如何应该做什么),然后从那里开始你的逻辑工作。这同样适用于 if、elif 和 else 语句链,它们通常看起来非常混乱。
  • 陌生而不相关的名字:这适用于以不清楚它们做什么或如何使用的方式命名的变量、函数、类和模块。这在数据科学中很常见,我们称事物为“x”或“y ”,没有一般的原因。这也使得代码非常难以阅读。原则上,您希望确保所有的名称都清楚地表明这段代码是什么或者它应该做什么。这也有助于识别大型函数,因为难以命名的函数通常表明它做得太多。尽可能简单明了地给事物命名。你和其他人以后会感谢你的。

这些是程序员在旅程开始时(有时甚至更早)挣扎的常见代码气味,但还有更多。在您自己和其他人的代码中注意这些模式是很重要的,以确保您正在构建的产品是可靠的、健壮的、可伸缩的,从长远来看对您自己和客户都有好处。一旦识别出来,重要的是尽可能地重构代码,同时试图确保不会引入更多的气味,并且所有的测试仍然通过。这将使下一个接管你的代码的人免于在将来不得不重构你的工作,并减少为你的团队引入技术债务的可能性。

结论

虽然代码气味不会破坏你的代码,但是注意它们是很重要的。当您刚开始尝试学习很多东西并让事情运转起来时,这可能很难,但是能够识别它们并知道如何解决它们将使您能够产生更好的代码,这对您的团队未来是有用的。创建一个新的变化或新的特性可能会花费你更多的时间,但是如果没有代码的味道,这些代码在将来会更健壮、更简单、更易维护,这意味着你将有更多的时间来构建产品,而不是简单地维护它。祝你好运!

如果你喜欢你所读的,并且还不是 medium 会员,请使用下面我的推荐链接注册 Medium,来支持我和这个平台上其他了不起的作家!提前感谢。

https://philip-wilkinson.medium.com/membership

或者随意查看我在 Medium 上的其他文章:

https://python.plainenglish.io/a-practical-introduction-to-random-forest-classifiers-from-scikit-learn-536e305d8d87

你的模型超过基线了吗?

原文:https://towardsdatascience.com/does-your-model-beat-the-baseline-3b9fb31cbe76

让我们将我们的模型与一个普通的基线进行比较

图片 by Pixabay:T3【https://www.pexels.com/it-it/foto/lampadina-chiara-355948/】

每次我们训练一个模型时,我们都应该检查它的性能是否超过了某个基线,这是一个没有考虑输入的琐碎模型。将我们的模型与基线模型进行比较,我们实际上可以计算出它实际上是否学习了。

什么是基线模型?

基线模型是一种实际上不使用特征的模型,但对所有预测使用一个平凡的常量值。对于一个回归问题,这样的值通常是训练数据集中目标变量的平均值(10 年前,我曾经进行 ANOVA 测试来比较线性模型和这样一个微不足道的模型,这种模型被称为零模型)。对于分类任务,普通模型只返回训练数据集中最频繁的类。

因此,这是我们数据集的基线,一个经过适当训练的模型应该能够超越这种算法的性能。事实上,如果一个模型像基线一样执行,它实际上没有考虑特性,所以它不是学习。请记住,基线模型的给定定义根本不使用特性,它们只是以某种方式对目标值进行平均。

在这篇文章中,我们将会看到如何比较一个模型和一个基线模型。

战略

总的想法是用模型和基线模型在测试数据集上计算一些性能指标。然后,使用 bootstrap ,我们计算这种测量的 95%置信区间。如果间隔不重叠,则模型不同于基线模型。

按照我们选择的性能指标,我们允许模型实际上具有可比性的概率高达 5%。不幸的是,只看指标的平均值是不够的。小数据集可能会引入有限大小的效应,使我们的分析变得不可靠。这就是为什么我更喜欢使用 bootstrap 来计算置信区间,这让我们更好地了解情况,从我们的数据集中提取尽可能多的信息。

Python 中的一个例子

在 Python 中,基线模型由 DummyClassifier 和 DummyRegressor 对象表示。前者考虑训练数据集中最频繁的目标类,后者考虑目标变量的平均值。这些设置是可以改变的(例如,通过考虑中间值来代替平均值),但我通常更喜欢使用默认设置,因为它们非常真实和有用。

对于回归问题,我们将使用“糖尿病”数据集和随机森林分类器。我们的绩效指标将是 r 平方分数。

让我们先导入一些库:

import numpy as np
from sklearn.ensemble import RandomForestClassifier,RandomForestRegressor
from sklearn.model_selection import train_test_split
from sklearn.datasets import load_wine, load_diabetes
from sklearn.dummy import DummyClassifier,DummyRegressor
from sklearn.metrics import accuracy_score, r2_score

然后,让我们导入数据集:

X,y = load_diabetes(return_X_y = True)X_train,X_test,y_train,y_test  = train_test_split(X,y,test_size=0.4,random_state=0)

我们现在可以训练随机森林和虚拟回归器。

model = RandomForestRegressor(random_state=0) model.fit(X_train,y_train) dummy = DummyRegressor() 
dummy.fit(X_train,y_train)

最后,通过 500 次迭代的 bootstrap,我们可以根据相同的测试数据集计算模型的 r 平方的置信区间。

scores_model = []
scores_dummy = []
for n in range(500):
  random_indices = np.random.choice(range(len(X_test)),size=len(X_test),replace=True)
  X_test_new = X_test[random_indices]
  y_test_new = y_test[random_indices] scores_model.append(r2_score(y_test_new,model.predict(X_test_new)))
 scores_dummy.append(r2_score(y_test_new,dummy.predict(X_test_new)))

最后,这些是模型和虚拟分类器的置信区间:

np.quantile(scores_model,[0.025,0.975]),np.quantile(scores_dummy,[0.025,0.975]) # (array([0.20883809, 0.48690673]), array([-3.03842778e-02, -7.59378357e-06]))

正如我们所看到的,区间是不相交的,并且与模型相关的区间的下限大于与虚拟模型相关的区间的上限。因此,我们可以说我们的模型在 95%的置信度下比基线表现得更好。

使用分类器可以遵循相同的方法。在本例中,数据集将是“葡萄酒”数据集。评分标准将是准确性得分。

X,y = load_wine(return_X_y = True) X_train,X_test,y_train,y_test = train_test_split(X,y,test_size=0.4,random_state=0)

以下是模型:

model = RandomForestClassifier(random_state=0) 
dummy = DummyClassifier() 
model.fit(X_train,y_train) 
dummy.fit(X_train,y_train)

这是两个模型的准确性得分的自举:

scores_model = []
scores_dummy = []
for n in range(500):
  random_indices = np.random.choice(range(len(X_test)),size=len(X_test),replace=True)
  X_test_new = X_test[random_indices]
  y_test_new = y_test[random_indices] scores_model.append(accuracy_score(y_test_new, model.predict(X_test_new)))
  scores_dummy.append(accuracy_score(y_test_new, dummy.predict(X_test_new)))

最后,这些是置信区间:

np.quantile(scores_model,[0.025,0.975]),np.quantile(scores_dummy,[0.025,0.975]) # (array([0.91666667, 1\. ]), array([0.31215278, 0.54166667]))

同样,该模型以 95%的置信度比虚拟模型表现得更好。

结论

在本文中,我展示了一种技术来评估一个简单的基线模型的性能。尽管这经常被忽视,但这种比较很容易进行,而且必须经常进行,以便评估我们的模型的稳健性及其泛化能力。

原载于 2022 年 7 月 3 日【https://www.yourdatateacher.com】

进行云迁移?何时应该添加数据目录和治理?

原文:https://towardsdatascience.com/doing-a-cloud-migration-when-should-you-add-a-data-catalog-and-governance-4da78400308e

早点做。保持敏捷。

图片由 pixabay — CC 授权提供

这不完全是先有鸡还是先有蛋的问题,但这是许多企业数据领导者在倾向于采用现代数据堆栈(通常从采用云数据仓库开始)时面临的一个困境:何时是引入数据目录的合适时机?

尝试一步一步来做很有诱惑力:我会先将所有数据迁移到我的数据仓库,然后再担心发现和治理。但是我想说的是,你应该同时做这两件事。

我将阐述我的观点,然后描述采用敏捷数据治理方法的流程,这将实际上帮助您更快地完成迁移,通过数据目录和治理平台协调工作。无论是在内部还是在我们的整个客户群中,我们都看到了这样做如何能够增加您的迁移成功的机会,并加快数据驱动文化的采用。

通过将敏捷方法应用到数据堆栈开发中来获得正确的结果

在迁移到现代数据堆栈的同时,通过数据目录采用敏捷数据治理,可让您从新数据平台中即时获得收益和投资回报。它还可以帮助您避免典型的瀑布开发方法的缺陷,这些方法会困扰数据和分析并减缓创新。在您的数据治理和管理流程中采用敏捷原则将使您的组织比以往任何时候都更快地获得现代工具的投资回报。

以下描述的方法在 data.world 内部(我们使用自己的数据目录从 AWS Athena 迁移到 Snowflake)和我们的客户中都证明是成功的:

1.建立分析积压

创建企业需要或想要的指标列表。通常最好将这些指标表述为这样的问题,“我们网站的访问者的日平均会话长度是多少”,或者“我们在某个时间段的平均订单价值是多少?”这相当于软件开发中的用户故事。从高价值的问题开始,你会发现有助于你下一步的模式。这也是考虑创建度量标准或语义层真正有用的地方。不过,最终这些指标将需要被分解成计算所需的数据源,这就是在这个过程中考虑第二步变得有价值的地方(这样您就可以创建超越简单指标的可重用数据产品)。

2.决定建筑风格

像一个设计良好的软件应用程序一样,数据仓库或数据湖中的数据应该符合一种架构风格。您可以基于您的分析积压中的问题类型以及您的企业中主要可用的数据的形状和类型(星型模式、雪花型模式、数据仓库和许多其他非规范化格式)来选择样式。考虑数据模型的层次,从原始数据到干净数据,再到转换后的分析模型。您可以将这种分层与从原始 API 到业务逻辑再到 UX 的软件分层进行比较。

您选择的架构风格将对分析师和数据科学家如何访问和使用数据产生重大影响。一致地应用这种风格将使您的数据平台对所有数据消费者更有用。在 data.world,我们使用星型模式布局和 ELT(提取、加载、转换)架构模式。事实表和维度表的星型布局特别适用于跟踪我们的会员群的活动,也适用于按时间段或按客户组织进行分析。

3.选择工具链

一旦你有了一个架构风格和一堆分析故事,是时候选择一些工具了。在一个数据科学和分析用例不断扩展的世界中,这些工具的协同工作对于保持敏捷性至关重要。不同的数据平台支持不同的架构风格。工具链的关键是数据平台/查询层、ETL/数据集成工具和数据目录。

随着使用的成熟,可以集成数据质量、概要分析、沿袭和其他工具。拥有一个开放灵活的元数据模型的数据目录对于随着时间的推移添加新工具至关重要。它还为您提供了扩展 BI、ML/AI 和数据科学工具箱的基础,以便随着时间的推移支持数据消费者。在 data.world,我们采用了 JIRA 来管理我们的分析积压,雪花用于我们的数据平台,dbt 用于转换,以及各种分析工具。所有这些都通过 data.world 数据目录进行协调。

4.召集你的团队

现在是时候将数据消费者和生产者聚集在一起,他们将参与最初的分析故事。好的敏捷过程在每个接触点都包含了各种各样的利益相关者。这使得反馈循环紧密,可能是推动采用的最重要的事情。考虑一下你会找谁来协调你的数据冲刺;此时,指定某人扮演数据产品经理或所有者的角色。数据工程师、管家和产品经理不能躲在山洞里几个月,然后出来期待分析师和数据科学开始使用结果。如果没有让所有的利益相关者都参与数据产品的开发,并获得反馈和实时提供价值,那么失败的几率就会成倍增加。从我们的数据产品中获取投资回报的能力也提高了,因为从基于数据的见解中获得优势的机会往往稍纵即逝。等待数月才能使用一个“完美”的数据仓库将意味着获取价值的机会已经过去。

5.挑选你的第一个分析故事

按照经典的敏捷/scrum 方式,现在是时候分组、区分优先级,并选择第一组要处理的故事了。所有利益相关者都应参与这一进程。分组可以使用传统的技术来完成,如卡片分类和亲和力练习。规模、业务影响和可用的团队也可以在故事最先完成的过程中发挥作用。

确保分析是具体的,而不是假设的。选择与数据消费者需要完成的工作密切相关的故事,以便最终交付清晰、可衡量的价值。此外,对这些可交付成果进行时间分类,并设定一个日期来衡量结果。这将有助于你在第一次迭代中控制住煮沸海水的诱惑。

6.在数据目录中收集您的资源

是时候让数据生产者(通常是数据库管理员或数据工程师)收集原始数据源来回答第一组分析故事中提出的问题了。当生产者在你的数据目录中按故事筛选来源时,消费者可以对这些来源进行评估和提问。最初的问题和发现对于实时捕捉至关重要,不能消失在聊天或电子邮件中。一个好的数据目录使这种管理、分析和问题处理变得流畅,并简化了整个工作流程。在这一步中,您会明白为什么应该同时构建一个目录和仓库。

7.构建并记录您的数据产品

随着数据源被细化到您所选择的架构风格中,数据消费者应该实时处理数据,并评估模型在回答所提出的度量问题方面有多好。数据管理员在正在使用的数据旁边构建数据字典和业务术语表。既然您已经通过分析故事对来源进行了筛选,那么现在就可以根据目的发现适当的数据资产了。通过将数据目录作为新数据平台协作的支点,所有这些知识的获取都是实时进行的。这最大限度地减少了不得不回去从 Google Sheets 中抓取数据字典或编写无聊文档的麻烦。通过在构建资产时合并您的数据目录,您可以确保它们的重用并最小化您的知识债务。

8.同行评审分析

在你的第一次数据冲刺结束时,是时候对工作进行同行评审了。有了企业数据目录,这个过程的效率要高得多。您的数据目录为消费者和中小企业提供了一个提问和了解结果的友好环境,防止了当人们带着不同的结果和定义出席决策会议时发生的数据争吵。每个人都可以看到谁对这项工作做出了贡献,以及被问到的其他问题。可以快速有效地验证和扩展工作。您的数据工作都在一个地方:数据目录。

9.公布结果

恭喜你!您已经在全新的出色数据管理平台中拥有了第一套数据模型。一切都由分析故事精心策划,经过同行评审,并记录在您的云数据目录中。您已经为企业做了一些有益的事情,同时使其可重用。最重要的是,您的团队没有进行大量的事后文档工作,因为工作从一开始就在数据目录中完成了。您还迈出了采用数据网格架构并将数据资产视为产品的第一步。

10.精炼和扩展

通过以敏捷的方式同时使用您的数据平台和数据目录,您的资产将在发布时得到很好的记录和组织。随着下一个 sprint 的到来,您现在可以扩展或细化已经发布的资产。一个资产被很好地记录并围绕用例组织的起点使得接下来的冲刺变得越来越容易。然后,您可以扩展该计划,以包括更多的业务线或工作组。这种扩张推动了我们都渴望的采用、数据素养和数据驱动的文化。

如果您已经开始了迁移到新的云数据仓库或数据湖的道路,您仍然可以采用敏捷数据治理实践,消除您拥有的任何知识债务——永远都不会太迟!采用一个数据目录,让你能够反复减少你的知识债务,这将是让你感觉不到你有一个沸腾的海洋的关键。如果您有兴趣了解更多信息,或者您已经在以这种方式工作,我很乐意收到您的来信!

进行解释性数据分析

原文:https://towardsdatascience.com/doing-explanatory-data-analysis-f184c01557e7

有没有可能完全在 GPU 上完成?

约书亚·索蒂诺在 Unsplash 上拍摄的照片

当我们对训练**深度学习模型不感兴趣时,我总是在黑暗中感觉这些 GPU 设备有多有用。不过,最近看了一些关于熊猫以及如何加快处理速度的文章。这些文章让我有点好奇,所以我决定启动我的数据科学机器,在 **GPU、上抓取一个大文件,看看我是否能在 GPU 上完成整个 EDA 练习。我在黑暗中有一种阳光的感觉,有点像照片里的人。

那么 EDA 可以完全在 GPU 上完成吗?让我们来了解一下!

我的数据科学机器

让我们从了解主机开始。

来自 about 系统的截图——在 Ubuntu 设置中——作者在写作当天的图片

系统的主要亮点是:-

  • 主板 : Z270N-WIFI
  • 处理器 : 英特尔 4 核 i5–7600k第七代 Kaby Lake
  • GPU:Quadro p 20005 GB gddr 5,1024 个 Cuda 核心
  • 内存 : 32.0 Gig — 海盗船复仇红
  • **电源:**海盗船积分仪 500w
  • 存储 : 895.2 GB,支持 SDD、FDD 和 mSata 硬盘
  • 操作系统:LTS Ubuntu 22 . 04 . 1

该系统有三种板载存储类型——作者在写作当天截图。

我自己组装了系统,并按照主板和 GPU 卡上允许的价格升级了组件。这个系统可以处理大多数任务,应该足以应对我们的挑战!我希望你同意,它是安全的说,没有硬件障碍!

用于实验的数据集

我为 GPU 实验选择了一个有 7M 记录的数据文件。在 Kaggle [1]上描述了700 多万家公司的数据集,并在其他文章中使用,如“使用 Python 对 700 万家公司进行探索性数据分析”

本地驱动器上数据文件的屏幕截图。图片由作者提供。

该文件大小为 1.1 GB,有 700 多万行和 11 列。由于 700 多万行,它扼杀了 Excel。 Alteryx 整个吞下。 PowerBi 和 PowerQuery 可以处理这个文件,但是我必须做摘要视图来将它们加载到 Excel 中。

在下载和使用数据集之前,最好检查许可,并确定所有权和权限。根据知识共享 CC0.01 获得许可的 700 多万公司数据集。 “你可以复制、修改、分发和执行作品,即使是出于商业目的,都无需征得许可。”

也有特定于发布者的规则,例如关于数据科学的。因此,请小心选择数据集和来源,将许可证与出版商条款&条件相匹配。

GPU 设置

通常,调用 Nvidia-smi 是我检查和确定 GPU 是否可用的第一件事。我们看到,CUDA 11.4 可与 Nvidia 驱动程序 470.141.03 一起使用。所有这些都与我今年早些时候安装 Quadro 时所做的设置一致。

作者展示 Nvidia-smi 命令输出的图片。

您可能会注意到,GPU 上已经有一些工作负载,这只会导致问题。几乎 1GB 的卡 RAM 已经被分配。 因此,我们必须将视觉显示工作负载转移到英特尔板载 GPU 上。重新配置 Xorg 屏幕设置使得 NVIDIA GPU 可以自由地专用于数据工作!我很喜欢在 4K 看网飞!

将视觉显示移到英特尔 CPU/GPU 后,NVIDIA 卡的可用性更高。作者图片

接下来,我们需要安装急流

从https://rapids.ai/start.html

复制命令并粘贴到终端。让 conda 负责一切,但只是根据您的系统做出正确的选择,以避免冲突和问题。最后,激活环境(rapids-22.08),启动 jupyter 并做一个快速测试。

Jupyter 笔记本加载 cudf 成功的截图。作者图片

好了,我们了解了我们的硬件,并配置了我们的软件;现在是时候来点 EDA 了。感谢感谢**激流队,**我没有复杂的依赖挑战。

我们就偷懒吧,把文件扔在卡上。

因为 Rapids 安装在一个环境中,所以您必须首先激活该环境。我使用了 Anaconda Navigator,只是从可用的环境中进行选择。我使用的是 rapids-22.08 ,这个环境是由 RAPIDS conda install 命令创建的——见前面。

我对这种快速而肮脏的方法感到惊讶。成功了!

照片由帕蒂·布莱克在 Unsplash 上拍摄

让我们分几个块来看一下代码

加载模块

导入常规嫌疑人和 CUDF。因为我不确定我能走多远,所以我同时使用 cudf(cu)和 pandas(pd)。

朱庇特笔记本——作者截图

构建基于 GPU 的数据框

请注意。read_csv()方法,它看起来类似于 pandas 方法,但是我们需要深入了解不同之处。现在,我只想感受一下它的表现,如果有的话!

作者截图

使用传统的 RAM 和 CPU 计算方法

可能还要做一个 cudf。DataFrame.from_pandas!

作者截图

结果

令人惊讶的是,这种方法开箱即用。之前我做了很多' SUDOing '和其他痛苦的依赖问题的解决。

作者截图

我仍然很惊讶这样一种懒惰的方法起作用了——只需要大约 2 秒钟就可以读取那个大文本文件并将其传输到 GPU。印象深刻!该文件在磁盘上有 1.1GB。注意内存的使用——它是 1.3+ GB,嗯!Alteryx 在 Mac Mini M1 的 Windows 11 上通过 Parallels 报告了 6.4 秒。几分钟后,Power Query 仍在后台运行查询。

作者截图。

不出所料,装载熊猫总是开箱即用。读取、创建数据结构和将数据帧加载到 RAM 中需要 16 秒。几乎慢了 8 倍。但是看看内存占用大小-> 602.0+ MB 对 1.3+ GB。从视觉上看,两个设备上的数据帧具有相同的列和数据类型。

再次使用 NVIDIA-smi

作者使用 Nvidia-smi 命令输出的截图

事实上,GPU 将 python 报告为分配了 1605 兆字节存储的用户。这令人印象深刻。

清洁

所以我们知道可以把大文件加载到 GPU,但是清理呢?尤其是丢失的值,计算代价会很高。

if(df.isnull().values.any()):
    missing = df.isnull().sum()
    print(missing)
    print(" ")
    for col in df.columns:
        print (col, "-\t", df[col].nunique())df.dropna(axis=0,inplace=True)df.notnull().sum()

打印缺失值汇总的基本代码,显示每列中唯一条目的数量,删除列中缺失值的所有行,然后转储所有非缺失值的汇总。

这种代码在 GPU 上速度快如闪电,但在传统的 CPU/RAM 方法上速度很慢。

Summarize missing: CPU/RAM: That took : **0:00:30.536083** 
with GPU taking **0:00:01.035225**

在传统配置上需要 30 秒,而在 GPU 上几乎不需要。Aggregation 和 groupby 也极快,语法和熊猫一样。

df.groupby('size range').agg({'year founded': ['min', 'max', 'count'], 'country': lambda x: x.nunique(), 'current employee estimate': 'median'})

图片由作者在练习中从 Jupyter 笔记本中获得

df = df[df['year founded'] < 2023].copy()
pddf = pddf[pddf['year founded'] < 2023].copy()

子设置和复制数据帧在这两种方法中的行为也是相同的。酷!

形象化

好吧,清理一个数据帧在 GPU 上效果更好,但是一些图形呢?

好吧,这就是你可能已经在等待的东西!消息是 CUDF 不像 Pandas 那样包装 matplotlib。因此,我们不能直接在 GPU 数据框架外绘图。相反,我们必须将数据从 GPU 卡复制到主板 RAM 中。

df.to_pandas().plot()

自然,这就是我们停下来的地方。毕竟,我无法在 GPU 上完成整个 EDA 练习。我可以很快地准备一个数据框架,而且几乎没有痛苦,速度也很快!

警告

GPU 设备的行为不同于传统方法。像%%timeit%%这样的项目会导致 GPU 出现内存错误。

del pddf
del df

从 GPU 中删除数据帧会释放设备上的分配,并允许加载更多数据帧。您必须注意释放分配,否则设备会抱怨。

贮藏室ˌ仓库

我把我的代码加载到 GitHub,你可以在下面的链接找到这个笔记本。

https://github.com/CognitiveDave/ReadingList/blob/main/cudf.ipynb

为什么不加入 medium?50 美元的投资在 12 个月内是不错的回报

https://cognitivedave.medium.com/membership

参考文献/引文

[1]700 多万公司数据集根据知识共享 CC0.01 获得许可。你可以直接从人民数据实验室索取一份的拷贝,并在这里阅读更多关于他们的内容。这里的数据用于加载到 GPU 上,并用于创建战术总结。

领域专家是健壮的 ML 系统的基本模块

原文:https://towardsdatascience.com/domain-expert-is-an-essential-block-of-a-robust-ml-system-a29fd1576832

在试图做得更好之前,先了解业务

在 Unsplash 上拍摄的 ThisisEngineering RAEng

我们看到不同的数字表明有多少百分比的机器学习模型从未投入生产。我不想给出一个确切的数字,但我们只能说大多数机器学习模型都没有实现生产化。

无法进行最后一步部署可能有多种不同的原因。

例如,与模型提供的值相比,运算在计算和存储方面可能太昂贵。或者,当模型被缩放时,结果和性能急剧恶化。

我们也可能无法将模型正确地部署到生产中。这是一个操作问题,可以通过实施一个强大的 MLOps 系统来处理和解决。

MLOps 指的是用许多不同类型的操作构建一个系统的过程,这些操作是同步的并且协同工作。

就像 DevOps 是创建大规模软件系统的常见做法一样,高效的机器学习系统也需要 MLOps。

数据科学家可以使用 Jupyter 笔记本中的样本数据集来创建和评估机器学习模型。

然而,当涉及到将 Jupyter 笔记本中的这个模型转换为在生产中连续运行的 ML 系统时,需要涉及到其他角色。

在这篇文章中,我们将讨论我认为对于创建一个健壮的、有利可图的、有益的 ML 系统最关键的角色:领域专家。

领域专家

这些都是懂业务的人。它们不一定是面向数据的,但对于数据如何在特定领域发挥作用提供了非常有价值的反馈。

ML 系统中面向数据的人员(例如,数据科学家、数据分析师、数据工程师)不可能对业务有全面的了解,这通常需要在特定领域积累多年的经验。

领域专家充当面向数据的人员和业务之间的桥梁。信息以洞察力、反馈或行动的形式在这座桥上双向流动。

(图片由作者提供)

假设一个数据科学团队试图为一家拥有许多商店的杂货零售商创建一个预测系统。

如何开始

ML 系统应该从领域专家开始。它们有助于定义业务目标和关键绩效指标(KPI ),这对于衡量 ML 系统的绩效至关重要。

领域专家知道企业需要什么。它们有助于解决需要解决的问题和有潜力改进的流程。

数据科学家或机器学习工程师挖掘数据,以提取见解,发现模式和关系。但是,需要将他们引向具有更大影响或商业价值的问题。这是领域专家可以帮忙的。

如何结束

假设面向数据的专业人员和领域专家坐在一起,进行长时间的头脑风暴。他们提出了问题和解决问题的方法。

设计并实现了 ML 系统。然后,我们开始看到结果。这些指标看起来不错,至少基于预定义的 KPI。

然而,我们离产生商业影响还很远。例如,问题可能是银行的客户流失预测。从数据科学家的角度来看,只要评估指标符合预定义的值,解决方案就很好。

然而,ML 系统的主要目标并不是满足度量标准。重要的是创造的商业价值。因此,领域专家应该参与到这样的场景中。

他们在负责 ML 系统的团队和以业务为导向的部门(如客户服务和市场营销)之间传递信息。这个信息流主要由迭代反馈组成,目标是使生产中的 ML 系统创造价值。

最后的话

一个 ML 系统由许多构件组成,这就是为什么有一个完整的规程来使它工作:MLOps。

MLOps 中涉及的职业可能会因组织或业务而异。典型的角色有数据科学家、数据工程师、软件工程师、机器学习工程师/架构师和领域专家。

当然,每个角色的工作都是至关重要的,但我觉得领域专业知识的重要性有时被低估了。没有领域专家或非常了解业务的人的 ML 系统很可能会失败。

你可以成为媒介会员来解锁我的作品的全部访问权限,以及媒介的其余部分。如果你已经是了,别忘了订阅如果你想在我发表新文章时收到电子邮件的话。

感谢您的阅读。如果您有任何反馈,请告诉我。

暂时不要成为数据科学通才

原文:https://towardsdatascience.com/dont-be-a-data-science-generalist-yet-8675fceb2f1e

选择一个专业,加倍下注

保罗·斯科鲁普斯卡斯在 Unsplash 上的照片

我不时会看到一张“数据科学家路线图”,里面塞满了天底下所有的数据工具和 ML 概念。虽然这些对于获得生态系统的高层次视图是有用的,但我认为它们通常会适得其反。这可能会让新手认为,他们必须学习一切才能被雇佣——每种算法、每种工具、每种机器学习和数据科学库。

就业市场的一些趋势强化了这一观念。职称不一致且模糊不清。一家公司称之为数据科学家,其他公司会称之为数据分析师。做足够多的采访,你会被问到所有的问题——从 leet 代码问题,到案例研究,再到统计数据。

事实是,要成为一名高效的员工,你不需要什么都知道。

是的,一些职位描述让你看起来是这样。但是工作描述是愿望清单。你不需要满足所有的先决条件。你真正需要的是对基本面的扎实把握和成长心态。

当你找到工作时,学习不会停止。事实上,那是你大部分学习的地方。你只需要让你的面试官相信你有能力学到你错过的东西。

当你刚开始的时候,不要走得太远。选择一个专业并专注于它。没有一种工作是完全分类的,这个行业在不断发展。但是有几个核心原型需要考虑:数据分析师、数据科学家、机器学习工程师和数据工程师。你的第一个目标应该是确定这些原型中哪一个最适合你(这个小测验可能会有帮助)。

平心而论,没有实际经历,这很难真正知道。你的第一份工作可能是数据科学家,然后才发现你更喜欢数据工程师的工作。那很好。那是自然的。随着时间的推移,你会了解自己的偏好,你的职业道路也会随之改变。但是如果你能缩小搜索空间,尽管你自己也有不确定性,你最初的求职会容易得多。

你可以通过动手做些事情来弥补经验的不足。构建涉及数据管道所有方面的端到端项目——收集和清理一些数据,训练一个模型,部署它。注意管道的哪些部分你喜欢,哪些部分你不喜欢。深入挖掘你喜欢的事情。

一旦你对自己喜欢的工作有了概念,就加倍努力。同样,你不必学习所有的。实际上,选择 2-3 项技术。收集一堆吸引你的工作描述,看看在需求中最常出现的是什么。与业内人士交谈,看看他们使用什么工具,他们认为什么是重要的。专注于那些事情。

有些公司确实需要一个数据科学通才——一个基本上什么都能做的人。这在初创公司或大公司的全新团队中很常见。然而,对于初学者来说,这些通常不是好角色。

不要做数据科学通才。至少,现在还没有。

不要忘记你的数据科学家头衔中的“科学家”(第 2 部分)

原文:https://towardsdatascience.com/dont-forget-about-the-scientist-in-your-data-scientist-title-part-2-28c208b86ba2

在不引入混淆变量的情况下同时测试多个因素

国家癌症研究所在 Unsplash 上拍摄的照片

如果您错过了第 1 部分,请前往那里阅读完整的实验设计介绍。

作为快速复习,实验设计是一种技术,允许研究人员评估许多不同因素对系统的影响[1]。我们讨论了如何避免混杂因素,并浏览了一些例子,但我们并没有真正讨论如何同时测试多个因素。

添加另一个因素

析因设计的美妙之处在于它非常容易扩展。

让我们从以前的帖子中构建一个假设的深度学习模型的例子。每个级别中包含的具体内容并不重要,因此了解深度学习概念并不是能够理解的必要条件。

要评估如果模型中的神经元数量增加会发生什么,只需在实验中添加一个因子即可。让我们看看如果神经元的数量增加到 32 或 64(即 3 个级别:级别 1 是 16 的基线,级别 2 是 32,级别 3 是 64)会发生什么。为了全面衡量这一变化的影响,需要创建额外的实验来测试这些不同的超参数配置。下面是这一过程的概述,每个方框代表一个实验。

作者图片:2×3 因子设计

从 2x1 设计到 2x3 设计会导致额外增加四个测试场景。这看起来很简单,但是除了测试如果层数增加会发生什么之外,还创建了其他场景来测试不同数量的神经元场景。这里重要的一点是,我们需要测试一个因素的每一个水平与另一个因素的每一个水平。当一个实验被概括为 2×3 因子设计时,很容易进行数学计算,并看到需要测试六个场景来全面评估每个选项。最终的结果是,通过使用一个度量来测试性能,很容易评估六个场景中哪一个表现最好。

再加一个因素??

这太简单了,为什么要止步于此呢?让我们疯狂一下,再加一个因素。

为了真正了解析因设计(这是我们在这里讨论的实验设计的具体类型的名称)是如何扩展的,让我们播放一个场景,其中我们还想测试不同的优化器。最初,ADAM 是基线优化器,但是如果使用 SGD,让我们测试一下性能指标的变化。为此,设计从 2x3 设计变为 2x3x2。这导致我们以前的设计有 6 个场景移动到一个将测试 12 个场景。

作者图片:添加两个级别的附加因子(优化器)的概要

冒着多余的风险,您可以很容易地看到,添加另一个具有两个级别的因素,使我们根据新因素的所有级别来评估之前的每个场景。此时,应该很容易看出这个框架的可扩展性。然而,增加一个额外的因素会增加总体工作量,这也是显而易见的。

自动化您的实验

如您所见,析因设计是一个很容易扩展的概念,但就需要测试的场景数量而言,它可能最终成为一个负担。这听起来可能需要做很多工作。如果每个场景都被单独测试,那么它肯定是可以的。

但是,通过创建嵌套的 for 循环,可以自动测试每个因素。这应该会减少将这个框架付诸实践的摩擦。只需确保将结果和基准度量保存到每个设计级别的列表或字典中。当所有的场景都完成后,你的实验将呈现一个模型的每个排列是如何执行的清晰画面。

总的来说,通过遵循实验设计框架,确定模型结果是否朝着正确的方向发展变得更加容易。不要将模型设计和评估的大部分精力集中在算法上,要确保在方法上花费一些时间来达到最终的模型状态。很容易认为一个小的改变不会影响性能或者只会略微改变结果。实验设计提供了一种方法,以确保这些结论植根于科学和严谨。实验设计,更确切地说是析因设计,是添加到您的数据科学家工具箱中的一个很好的工具。

来源

[1]https://www . jmp . com/en _ us/articles/what-is-experimental-design . html

不要掩盖数据文化

原文:https://towardsdatascience.com/dont-gloss-over-data-culture-1a05b48dc2de

莎伦·麦卡琴在 Unsplash 上的照片

早在 2011 年,麻省理工学院斯隆管理评论的一篇文章与 IBM 合作,调查了企业读者群,以了解企业对商业智能数据分析的当前和期望状态(BI & A) (LaValle,Lesser,Shockley,Hopkins,& Kruschwitz,2011)。十分之六的受访者表示,他们的组织拥有的数据超过了其所知的可操作性;除此之外,“管理和文化”障碍是使 BI &更好地为企业服务的最常见障碍(LaValle 等人,2011 年,第 23 页)。

十多年后,企业在采用和使用 BI &A;方面取得了长足的进步,然而,2011 年存在的许多相同差距今天仍然很突出。看一看围绕数据分析的在线内容。其中大部分涉及数据素养和数据文化。然而,我们仍然没有达到目标。

问题是,组织中的“文化”仍然被认为是一个单数概念,而不是复数。这是许多现有 BI&A 成熟度评估中的一个标准,需要检查或掩盖。因为文化是成功 BI&A 实现的主要驱动力,所以必须对包括其子文化在内的组织数据文化进行更可靠的评估。只考虑组织的主导文化及其实施驱动因素的 BI&A 解决方案肯定会满足一些人的需求,而让其他人不参与、得不到充分服务并感到失望。

拥抱亚文化

组织不是铁板一块的实体。人是不同的,团队以自己独特的方式工作。这些团队在公司数据方面有自己的优先级、挑战和成功定义。反过来,成功的 BI&A 实施和向数据驱动文化的转移可能对不同的组织部门具有多重意义。使这种情况变得更加复杂的是,人们倾向于认为,在没有检查当前文化和对这种实现的准备的情况下,可以获得和实现特定的软件包或解决方案。

全速采用分析技术并相信该技术可以治愈所有疾病,这可能很有诱惑力。有很多工具为 BI&A 做了很多好事。但是,这些不能被视为整个组织的灵丹妙药。每个解决方案都有自己的优点和缺点,对于组织来说,实现最适合所有用户的解决方案是非常重要的。这意味着拥抱数据亚文化,并让它们推动采用——而不是让采用粗暴地对待利益相关者。

忽视后果自负

掩盖组织中的各种数据亚文化会导致缺乏组织中所有业务部门的适当认同和/或适当的管理层支持的采用周期。如果没有这种认同,不一致可能以一种或多种方式出现:文化、切入点、拨款措施或历史(Jenks,2012)。

在文化错位的情况下,利益相关者根本不理解或接受彼此的使命。正如我们将在后面探讨的,这种不一致可能取决于组织内的各种职业文化。在切入点不一致的情况下,解决方案是由一个或多个变革推动者引入的,他们似乎是为了自己的狭隘利益而推动解决方案,而没有给整个组织带来任何明显的好处。在拨款措施不一致的情况下,新的解决方案没有适当地整合到组织的现有实践中,而只是浮在其上,没有提供真正的价值。在历史错位的情况下,组织可能背负着重复失败实现的记忆,并且可以理解地怀疑最新的实现。在任何一种情况下,实现都会受到阻碍,并且没有一个原因与技术直接相关。

前进的道路

在成功的组织中,围绕 BI&A 能力的软技能和无形资产越来越受到关注。学术界和工业界的新发展正在塑造对话,并强调数据素养和文化的重要性。在撰写本文时,我自己的研究已经产生了一个评估框架,将这些数据亚文化与组织范围内的分析成熟度联系起来。虽然这项研究是突发的,但早期结果表明,特定的亚文化确实对整体成熟和成功有影响。就像员工一样,组织内部的数据处理方式也各不相同。现在是我们把它从障碍转变为资产的时候了。

参考文献

詹克斯,B. (2012)。在数据仓库/商业智能环境中组织对变革的抵制。 (D.B.A .)安阿伯金门大学。从https://proxy.cecybrary.com/login?取回 URL = https://search . proquest . com/docview/1197494174?accountid=144789 ProQuest 学位论文&学位论文全球数据库。(3533517)

LaValle,s .,Lesser,e .,Shockley,r .,Hopkins,M. S .,& Kruschwitz,N. (2011)。大数据、分析和从洞察到价值的路径。麻省理工学院斯隆管理评论,52 (2),21–31。

不要只是拟合数据,还要获得洞察力

原文:https://towardsdatascience.com/dont-just-fit-data-gain-insights-too-1dba73d3cf8e

一个轻量级的 Python 包可以让您对回归问题有更多的了解

图片来源:作者创作

为什么需要洞察力?

首先要做的事。为什么线性回归很重要?

线性回归是一项基本技术,它深深植根于久经考验的统计学习和推理理论,并为现代数据科学管道中使用的所有基于回归的算法提供支持。此外,对于大多数数据分析工作,除了处理图像、音频或自然语言等高维数据的问题,这种回归技术仍然是最广泛使用的工具。

它们易于实现,更重要的是,易于遵循和解释。而且,可交代性越来越重要

https://blog.fiddler.ai/2021/10/the-key-role-of-explainable-ai-in-the-next-decade/

然而,一个线性回归模型的成功还取决于一些关于基础数据性质的基本假设。验证这些假设是否“合理地”得到满足是多么重要,怎么强调都不为过。这种检查是确保线性回归模型质量的唯一保证。

我在之前的一篇文章中探讨了这些问题,

对于我们所有使用 Python 作为数据科学语言的人来说,机器学习的首选包是 Scikit-learn。尽管 Scikit-learn 的估计器经过了高度优化和精心设计,但它们并没有为回归任务提供许多统计见解或检查。例如,他们可以给你 R 分数和回归系数,除此之外别无其他。

但是,如果您想从同一个评估者那里获得以下见解/图表,该怎么办呢?

  • 残差与预测变量图
  • 拟合与残差图
  • 归一化残差的直方图
  • 归一化残差的 Q-Q 图
  • 残差的夏皮罗-维尔克正态性检验
  • 残差的库克距离图
  • 预测特征的方差膨胀因子(VIF)

这些图中的每一个都很关键,可以告诉您回归问题(即输入数据)是否质量良好或者是否满足建模假设。本质上,问题必须满足这些,

图片来源:作者创作,摘自本文文章(作者拥有版权)

在本文中,我们将探索一个简单、轻量级的 Python 包**mlr**,展示如何用最少的代码深入了解回归问题。

安装和基本安装

基本 pip 安装。

pip install mlr

我们可以为演示生成一些随机数据。

num_samples=40
num_dim = 5
X = 10*np.random.random(size=(num_samples,num_dim))
coeff = np.array([2,-3.5,1.2,4.1,-2.5])
y = np.dot(coeff,X.T)+10*np.random.randn(num_samples)

特征向量有 5 个维度。请注意添加到数据中的随机噪声。它看起来怎么样?我们绘制了响应变量 w.r.t .特征向量的每个维度,

图片来源:作者创作

此时,我们可以使用mlr库创建一个模型实例。

model = mlr()

这是什么?我们可以探测:-)

model>> I am a Linear Regression model!

下一步是接收数据。还不适合,但只是为了消化。

model.ingest_data(X,y)

在这一点上,数据已经被摄取,但不适合。

model.is_ingested>> Truemodel.is_fitted>> False

相关矩阵立即可用于可视化。即使在拟合回归模型之前,你也必须检查多重共线性,不是吗

model.corrplot()

图片来源:作者创作

所有相关数据和完整的协方差矩阵也是可用的。我们不会为了节省空间而打印它们,

model.corrcoef()
model.covar()

然后,合身就好。

model.fit()

一堆东西任你处置

一旦安装完毕,就会发生大量的内部动作,模型对象就有了大量的度量和可视化,供您深入了解。

简单 R 分数(以及所有相关指标)

我们可以打印简单的 R 系数,

model.r_squared()
>> 0.8023008559130889model.adj_r_squared()
>> 0.7732274523708961

或者,我们可以一次性将它们全部打印出来!

model.print_metrics()
>>
sse:     3888.1185
sst:     19666.8452
mse:     97.2030
r^2:     0.8023
adj_r^2: 0.7732
AIC:     308.5871
BIC:     318.7204

为了简洁起见,我不会讨论所有这些指标,但是这些是线性回归问题的基础,你应该已经熟悉了:-)

进行总体显著性的 f 检验

它返回测试的 F 统计量和 p 值。如果 p 值很小,您可以拒绝所有回归系数为零的零假设。这意味着较小的 p 值(通常< 0.01)表明总体回归具有统计学意义。

model.ftest()>> (27.59569772244756, 4.630496783262639e-11)

t 检验统计和系数的标准误差

标准误差和相应的 t 检验为我们提供了每个回归系数的 p 值,它告诉我们特定的系数是否具有统计显著性(基于给定的数据)。

同样,所有这些,一个函数调用,

print("P-values:",model.pvalues())
print("t-test values:",model.tvalues())
print("Standard errors:",model.std_err())

我们得到,

P-values: [1.37491834e-01 8.39253557e-06 1.62863484e-05 1.64865547e-03
 1.23943729e-06 1.97055499e-02]
t-test values: [-1.5210582   5.23964721 -5.017859    3.41906173  5.87822303 -2.44746809]
Standard errors: [7.35200748 0.65528743 0.58944149 0.58706879 0.55966142 0.7806859 ]

每个特征的置信区间?

一行代码,

model.conf_int()
>>
array([[-26.12390808,   3.75824557],
       [  2.10177067,   4.76517923],
       [ -4.15562353,  -1.75984506],
       [  0.81415711,   3.20029178],
       [  2.15244579,   4.42718347],
       [ -3.49724847,  -0.3241592 ]])

残差的可视化分析

残差分析对于检查线性回归模型的假设是至关重要的。mlr通过为残差提供直观的可视化分析方法,帮助您轻松检查这些假设。

拟合与残差图

使用此图检查恒定方差和不相关特征(独立性)的假设。

model.fitted_vs_residual()

图片来源:作者创作

拟合与特征图

用该图检查线性假设,

model.fitted_vs_features()

图片来源:作者创作

标准化残差的直方图和 Q-Q 图

使用这些图检查误差项的正态假设,

**model**.histogram_resid()

图片来源:作者创作

**model**.qqplot_resid()

图片来源:作者创作

特征选择

简化 API 的一个好处是,我们可以用它来完成复杂的任务,只需要几行代码。例如,我们可能希望使用mlr来检查回归指标是如何变化的,因为我们开始时只有一个解释变量,然后逐渐增加更多的。这是特征选择方法的常见任务。

为此,假设我们已经使用fit_dataframe方法将数据放入 Pandas 数据框架中。

for i in range(1,6):
    m = mlr() # Model instance
    # List of explanatory variables
    X = ['X'+str(j) for j in range(i)]
    # Fitting the dataframe by passing on the list
    m.fit_dataframe(X=X,y='y',dataframe=df) 
    print("\nRegression model built with feature vector", X)
    print("Metrics are as follows...")
    print("-"*80)
    m.print_metrics()

打印出类似下面的内容,

图片来源:作者创作

我们还可以绘制出随着变量的增加,AIC 和 BIC 的价值逐渐减少的曲线。

从上面的剧情中你能得到什么样的感悟?也许,如果您的模型训练资源有限,您可能会停止使用三个特性来构建模型。

向您的客户解释,为什么您只选择了这三项功能。

图片来源:作者创作

此处提供了方法的完整列表。

摘要

仅仅拟合数据和预测是不够的。为了进行严格的回归分析,需要进行许多统计显著性检验和残差检验。拥有一个轻量级的库有助于用最少的代码量实现这一点。这就是我们在本文中演示的内容。

在这里阅读本库(mlr)的完整文档: 文档

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

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

不要让通货膨胀和经济衰退毁了你的数据策略

原文:https://towardsdatascience.com/dont-let-inflation-and-recession-ruin-your-data-strategy-a7e744ca0240

宏观经济学如何帮助数据领导者制定稳健且有远见的数据战略

作为一个数据领导者,你到底为什么要关心宏观经济?

你曾经和高层领导在会议室里讨论过通货膨胀或经济衰退吗?以及如何建立一个特别工作组来解决这个问题?我有。这让我很不舒服。每个人似乎都有自己的看法,但我不明白他们在谈论什么。我想知道他们是如何学习经济学的。这不是你在学校学的东西,对吗?至少不是以一种适用于你工作的方式。这也不是你每天在工作中都会遇到的事情。每隔一年,当一些不寻常的事情发生时,你就会接触到它。那么,所有这些高级领导人似乎都很轻松地做出预测和决策,这怎么可能呢?作为一名年轻的经理,看到自己缺乏经验暴露出来,感觉很糟糕。经济学是曾经让我感到难为情的话题之一。当经济衰退来袭时,更有经验和智慧的高层领导似乎总是更清楚正在发生什么,接下来会发生什么,以及该做什么。

作为一名年轻的经理,看到自己缺乏经验暴露出来,感觉很糟糕。

经济风暴数据——人工智能生成的艺术与 DALL。E

山村里的长辈可以通过云的形状和天空的颜色告诉你是要下雨还是要下雪。他们知道如何探测和准备即将到来的雷暴。当然,他们不能阻止风暴的发生,也不能防止所有的损害,但他们通常比年轻人准备得更充分。

要变老变聪明,你必须先变年轻变笨

然而,我有一个好消息:你不必永远在你的高层面前显得愚蠢。如果你能从别人的经验中学习,你会变得更聪明,更早。在商界,就像在山区一样,你可以学会识别经济衰退或恶性通货膨胀的早期迹象以及对你的业务可能产生的后果,这样你就可以更好地带领你的团队度过难关。

什么是宏观经济学?

根据维基百科:

宏观经济学 经济学的一个分支 把一个 经济 作为一个整体来处理表现、结构、行为和决策。比如,利用利率、税收和政府支出来调节经济的增长和稳定。

换句话说,宏观经济学是对你的企业所处的全球环境的研究。

宏观经济学大部分时间“看不见”的原因。

做生意的时候宏观经济学无处不在。但是因为它一直在这里,而且通常移动很慢,所以你甚至不会注意到它。宏观经济学对于经理来说就像水对于鱼一样。

让我用戴维·福斯特·华莱士的一个故事来说明我的观点:

有两条小鱼在游泳,它们碰巧遇到一条游向相反方向的老鱼,老鱼朝它们点点头说:“早上好,孩子们。水怎么样?”两条小鱼游了一会儿,最后其中一条看着另一条,问道:“水到底是什么?”

鱼缸里的小鱼不明白什么是水,因为它从未遇到过其他任何东西。它甚至不能理解水的存在。

同理,一个有五年经验的年轻经理,从来没有经历过衰退,或者相反,只知道衰退。

你没看到不代表不会改变

下图说明,你可能有整整 10 年的工作经验,但仍从未遇到过像目前这样的能源价格上涨。

[天然气价格由维基百科](http://by Wikipedia CC BY-SA 3.0) CC BY-SA 3.0

另一个例子是看更广泛的经济。1926 年,经济学家尼古拉·康德拉蒂耶夫提出资本主义经济体系存在 40 年周期的假设。在 20 年的上升阶段,公司投入大量资金来对抗竞争,价格也随之上涨。达到峰值后,由于供应过剩和需求放缓,经济会放缓 20 年。此后,这一理论受到了挑战并得到了丰富。但我们仍然确信,经济不是一个水平不变的海洋,而是一个潮汐周期非常缓慢的海洋。这一潮流不断改变着商业环境。在周期的某一点,事情开始加速,让那些没有准备好的人大吃一惊。

康德拉季耶夫波由维基百科 CC BY-SA 3.0

我并不是说你应该变得偏执,对一切不可避免会出错的事情麻木不仁。但是了解宏观经济学会给你一个直觉,让你知道明天事情会如何变化,并挑战你的假设。

不懂经济学会让你付出什么代价

如果你不了解宏观经济学,这里有两个在你领导数据函数期间可能出错的例子:

  • 一场重大的、意料之外的通胀浪潮可能会突然出现。突然,你发现以客户为中心的定价成了首席执行官的头等大事。你需要几周时间来了解哪些类别的通货膨胀将受到最严重的打击,以及如何重新调整数据科学团队来解决这个问题。当您的团队开始运作时,您的竞争对手已经重新定位了他们的整个目录定价。他们行动更快,并大胆宣布将保护旗舰产品的价格。他们赢得了对客户价格认知的竞争,同时保护了他们的利润。在你反应过来的几周内,你损失了数百万的息税折旧及摊销前利润。
  • 一场突如其来的疫情引发了严重的供应短缺。曾经运转良好的供应链开始崩溃。您刚刚花了两年时间构建了一个最先进的需求预测算法,将准确性提高了 2 个百分点,这是一个值得称赞的成功。问题是你的算法被微调以在平稳的巡航速度条件下工作。现在销售曲线快速下降,算法预测销售会完全崩溃,你必须在它搞乱你的整个供应链之前拔掉它。

在 2019 年,那些世界末日的场景会让你笑得不敢相信。现在你知道这真的发生了。人们很容易将它们视为无人能预测的不可抗力。真的吗?有没有一种方法可以让您的数据策略更具弹性,以便为最坏的情况做好准备?有没有办法比你的竞争对手更快更好地应对危机?我相信宏观经济学技能会给你这种优势,我会举例说明如何做到这一点。

宏观经济学知识给你一个直升机视角,让你看得更远

理解宏观经济学将帮助你在空间和时间上看得更远。

  • 在太空中,因为你会明白世界上其他地区的经济状况会有很大的差异。在你的欧洲总部,通货膨胀可能不是一个问题,但在业务运营的新兴国家,通货膨胀却是一个反复出现的危险。
  • 及时,因为即使你现在正在经历增长,如果你的核心客户群的购买力明天被通货膨胀摧毁,你很可能会失去你的业务。

这一增强的愿景将使您能够:

  • 当经济风暴来袭时,做一个有战略头脑的冷静领导者,
  • 在董事会面前看起来更聪明,这总是感觉很好,说实话。

最终,我相信宏观经济学素养可以成就或毁灭一个首席数据官。根据《HBR》的一篇文章,CDO 的平均任期只有两年半:“为什么首席数据官的任期这么短?”[1].这意味着你只有一次机会。如果你最初的战略仅仅一年后就因为经济环境的变化而变得无关紧要,这将严重降低你成功的机会。

CDO 的平均任期只有两年半。这意味着你只有一次机会。

经济条件决定您的数据策略的例子

在接下来的部分中,我将给出具体的例子,说明如何在数据策略中考虑宏观经济因素,如通货膨胀和 GDP。我将说明它会如何影响:

  • 您的用例优先级。
  • 您的数据团队的组织。

通货膨胀的影响

通货膨胀是价格水平的普遍上涨。大多数发达经济体的通胀率稳定在 2%以下。它允许最低限度的失业和通货膨胀的不利影响。然而,新兴经济体更容易出现恶性通货膨胀,有时会带来灾难性的后果。在最严重的危机中,人们的工资每天会被支付很多次,因为早上赚的 100 美元的国家货币到当天晚上可能会贬值 20%。人们在午休时开始购买食品杂货,因为如果他们等到下午 5 点,价格会变得更贵。即使在发达经济体,通胀也可能像 2022 年那样失控,成为首席执行官们最关心的问题。

用例优先级

在通货膨胀时期,你的成本可能会急剧增加,并在几个月内将你的利润降至零。这意味着成本控制用例以及定价用例成为优先事项。

  • 在成本控制用例类别中,能源价格通常是上涨最快的。如果你能够进行能效分析,你就知道在哪里采取行动来实现节约。
  • 在定价用例类别中,如果您可以利用高级分析,您可以战略性地确定价格增长目标。你将冻结需求价格弹性最高的产品的价格上涨。这样你就能在低价竞争中击败竞争对手。你将最大限度地提高不太敏感产品的价格,因为你比竞争对手更便宜,从而赢得利润。

数据团队组织

如果你在一家跨国公司工作,对于你在伦敦总部的数据科学家来说,通货膨胀可能是一个非常抽象的概念,而对于你在伊斯坦布尔办公室的数据科学家来说,这可能是完全正常的事情。土耳其业务部门可能没有资源来开发端到端价格弹性算法,最好在总部为整个集团开发。然而,你可以让你的土耳其数据科学家微调通胀经济的算法。

国内生产总值和增长的影响

用例优先级

当经济衰退来袭时,每个客户群都会受到不同的影响。例如,越朴素的家庭失去的购买力越多。这扭曲了你的客户细分。这需要你与市场营销密切合作,量化需求的结构性变化,并定义可操作的杠杆。

然后,你的公司变得厌恶风险,并试图控制成本,以度过营业额崩溃。你将不得不在成本效益用例上与财务部门合作。

数据团队组织

当经济衰退出现时,你的数据预算可能会缩减,或者至少增长会更慢。你将比以往任何时候都更需要向你的首席财务官证明你的价值。衡量价值创造需要花费数月时间来建立官僚机构和能力。因此,即使今天很容易获得预算,开始跟踪价值创造也可能是值得的,这样当糟糕的日子到来时你就可以做好准备。

如何开始

  • 问经济问题:不要只依赖公司战略幻灯片,你可以通过研究对潜在经济假设的敏感性,使你的战略更稳健、更有远见。例如,问你的营销部门:“什么会出错?”,“当经济衰退来临时,我们的客户需求会发生什么变化”?或者问你的财务部门:“在恶性通货膨胀的情况下,成本结构会以多快的速度和多深的程度演变?”。
  • **学习基础知识:**了解供给、需求、通货膨胀和 GDP。在我看来,如果你不能上完整的课程,学习经济学家的历史是最令人信服的方法。早期的经济学家从非常简单的模型开始,经过几十年的研究,这些模型被挑战、扩充或替换。观察他们的思维过程是令人着迷和有启发性的。

如果你不知道从哪里开始,这里有一些我推荐的资源。我没有深入研究所有这些内容,但内容似乎经过改编,并以一种可操作的方式呈现出来(我没有任何从属关系):

  • 《宏观经济学简明指南:经理、高管和学生需要知道的东西》,作者是大卫·A·莫斯。虽然我没有读它,但它在亚马逊上被评为 4.6 星,这对于一本经济学书来说是很了不起的。它似乎是为管理者设计的。一个好的简洁的选择,比大的教科书便宜。
  • Coursera上的商业管理宏观经济学 MOOC。评论是恒星与 4.9 星评级。它似乎提供了坚实的理论基础以及商业规划和投资决策的应用。因为它代表了 14 小时的学习。
  • 经济学,教科书作者大卫·贝格,吉安路易吉·韦尔纳斯卡,鲁迪格·多恩布什,斯坦利·菲舍尔。这是我为宏观经济学课学习的书。它内容全面,既有深入的理论探讨,又有大量图表和历史插图,读起来引人入胜。它非常丰富和详细,所以需要一定的努力,但你可以浏览一下。它也涵盖了微观经济学。

结论

宏观经济学不是你作为数据领导者需要的第一技能。然而,基本的宏观经济学知识将帮助你在空间和时间上看得更远。这对有效的领导至关重要。了解通货膨胀和 GDP 增长将使您能够构建更加优化和稳健的数据策略。你不会被经济危机压垮,而是冷静地领导。

不要等到老了才明白。历史会重演。

特别感谢我的编辑本·胡伯尔曼,让这篇文章对社区来说更具相关性和可操作性。

[1]达文波特、比恩和金、为什么首席数据官的任期如此之短? (2021 年),HBR

不要让数据科学家做 Scrum

原文:https://towardsdatascience.com/dont-make-data-scientists-do-scrum-de87bc921a6b

来自数据科学家和认证 Scrum 大师的想法

Photo by 傅甬 华 on Unsplash

Scrum 指南*::*Scrum 是一个轻量级框架,通过对复杂问题的适应性解决方案,帮助个人、团队和组织产生价值。”

Scrum 已经超级流行很多年了。我对它在营销上的成功感到惊讶。这就像软件开发管理框架世界的卡戴珊。我对 Scrum 也有同样的感觉,因为《敏捷宣言》的作者之一在他的文章中写道:“一旦宣言流行起来,敏捷这个词就变成了一块磁铁,吸引着任何有观点、有时间、有产品要卖的人。”

对我来说,Scrum 看起来很重过程,这违背了敏捷宣言的第一个价值观——个人和交互重于过程和工具。但也许我对 Scrum 了解不够?所以我决定学习更多关于 Scrum 的知识,甚至成为一名认证的 Scrum 大师。现在我更明白为什么我不喜欢它,为什么它对数据科学家来说不理想。

1。Scrum 是不可变的

Scrum 指南:“Scrum 框架,正如这里所概述的,是不可变的。虽然只实现 Scrum 的一部分是可能的,但结果不是 Scrum。Scrum 只完整地存在,并且作为其他技术、方法和实践的容器运行良好。

“框架的每个元素都服务于一个特定的目的,这个目的对于 Scrum 实现的整体价值和结果是必不可少的。改变 Scrum 的核心设计或想法,省略元素,或者不遵循 Scrum 的规则,掩盖了问题,限制了 Scrum 的好处,甚至可能使它变得毫无用处。”

Scrum 是一个框架,由一个 Scrum Master、一个产品所有者和一个或多个开发人员组成的小团队组成。Scrum 被组织成 Sprint,有四个与 Sprint 相关的事件:Sprint 规划、每日 Scrum、Sprint 回顾和 Sprint 回顾。根据 Scrum 指南,Scrum 是不可变的。敏捷框架怎么可能一点都不敏捷?许多人说他们喜欢只使用吉拉门票和每日站立,根据 Scrum 指南,这不是 Scrum。

2。数据科学家并不致力于单一的“产品”,我们的工作往往不是一个增量

Scrum 指南:“Scrum 的核心是冲刺,这是一个月或更短的时间,在此期间,一个完成的、可用的、有价值的产品增量被创造出来。这适用于每一次冲刺。Sprint 的目的是产生一个有价值和有用的工作产品增量。”

数据科学家通常只从事各种项目,每个项目都与不同的利益相关者相关联。同一个团队的数据科学家通常不从事相同的“产品”工作,而是有着共同的“产品目标”。数据科学家所做的工作通常不是增量,也不是为单一的“产品目标”或“冲刺目标”而设计的。

3。数据科学家并不总是需要产品负责人

Scrum 指南 : “产品负责人代表了产品 Backlog 中众多利益相关者的需求。产品负责人代表 Scrum 团队的利益相关者,这包括在产品 Backlog 中代表他们想要的需求。

依靠产品负责人代表 Scrum 团队的利益相关者进行数据科学研究是一个糟糕的想法。正如我前面提到的,数据科学家经常与许多不同的利益相关者和不同的项目合作。仅仅从产品负责人那里了解背景是不够的,没有动力,也没有必要。对于数据科学家来说,更有效的方法是直接与利益相关者互动,了解问题的背景,深入与利益相关者的讨论,并自己制定计划。

同样,在 Scrum 中,产品负责人的责任是将复杂的问题分解成待办事项。这对数据科学家也不起作用。数据科学家做的大部分工作是研究,而不是产品开发。给定问题和问题的背景,我们设计我们自己的项目路线图和分析框架。因为所需的任务对任何人来说都还不清楚,从数据科学家那里拿走这些任务是不合理的,他们的工作是让他们清楚。

产品负责人为项目设定优先级也是不合理的。其他利益相关者经常给我们项目的时间表。由于这些需求来自不同的来源,数据科学家需要能够根据所有不同项目的时间表和紧迫性来确定自己时间的优先级。如果需要,数据科学经理,而不是产品所有者,应该能够提供帮助。

4。Scrum 夺走了所有权

Srum.org:“开发人员何时成为 Sprint Backlog 项目的唯一所有者?

从来没有。所有 Sprint Backlog 项目都由 Scrum 团队的开发人员“拥有”。整个 Scrum 团队负责在每个 Sprint 中创建有价值的、有用的增量,并且为 Sprint 选择的产品 Backlog 项目集由开发人员集体所有。没有一个单独的开发人员可以声称对一个项目的所有权,因为这将阻碍沟通和协作。随着学习的深入,开发人员会在整个 Sprint 过程中更新 Sprint Backlog。"

数据科学家拥有自己的项目是相当常见的。拥有这种主人翁意识从本质上激励数据科学家在项目中做得更好。坦率地说,数据科学家可能甚至不想拥有其他数据科学家的项目。例如,一个从事新闻提要工作的数据科学家不应该觉得他/她应该拥有另一个数据科学家正在从事的广告项目。所涉及的知识和专业技能不会在人与人之间均匀地转移,部分原因是每个人都在探索特定主题的旅程中。即使两个数据科学家在同一个项目中工作,在我看来,每个人仍然应该拥有项目的不同部分。

5。“完成”的定义因项目而异

Scrum 指南 :要求开发者符合 Done 的定义。如果有多个 Scrum 团队一起开发一个产品,他们必须相互定义并遵守相同的 Done 定义。

理解和应用 Scrum 框架允许团队和组织在 30 天或更短的时间内迭代地和增量地交付“完成”工作的可发布软件的有价值的产品。

不同的项目差别很大,不可能对我们所有的项目使用相同的 Done 定义。

6。冲刺复习不起作用

Scrum 指南 : “冲刺评审的目的是检验冲刺的成果,确定未来的改编。Scrum 团队向关键利益相关者展示他们的工作成果,并讨论产品目标的进展。

一个数据科学家团队可能有许多不同的关键利益相关者。我们邀请哪些利益相关者参加冲刺评审?对于数据科学家来说,在每周的项目会议上直接向各种项目干系人展示结果通常更有效。

更多想法

如果 Scrum 不起作用,那么什么会为数据科学家团队工作呢?我喜欢一个朋友的建议,忽略 Scrum 的形式,想想 Scrum 的哪些部分在数据科学而不是软件开发的背景下是有价值的。我确实认为人渣的三大支柱(透明、检查、适应)有道理。我认为所有这三个价值可以简单地通过与涉众的每周项目会议、项目演示的每周团队会议以及良好的文档来实现。具体来说:

1。如何让人们对他们正在做的事情有一个共同的理解?

与利益相关者的每周项目会议项目演示的每周团队会议让每个人都有机会公开他们在做什么、他们的进展和他们的计划。我想了解其他人项目中的思维过程、研究框架和详细的学习内容,我不在乎人们每天/每小时都在做什么。这就是为什么我更喜欢项目演示,而不是毫无意义地浏览每一张票/任务,而不去了解项目的背景和细节。对于指导和学习新的技术技能,深入项目演示会议或结对编程会议的技术细节也会有所帮助。

文档也有助于提高透明度。包含所有会议记录、决策、分析、结果和其他内容的共享项目文档通常很有价值。找不到所有的文件?使用 wiki 页面列出所有项目文档。对于喜欢吉拉门票的团队来说,吉拉可以是一个很好的记录工具,这样就可以记录正在做的事情。使用什么文档工具取决于团队自己的偏好。

2。如何就成功的要素达成共识?

由于数据科学家项目通常没有“完成”的明确定义,我们如何检查和衡量成功?与涉众的每周项目会议、项目演示的每周团队会议和文档允许涉众和团队成员检查、深入研究并给出有意义的反馈。为了在项目上取得成功,可能有两种情况:a)涉众或数据科学家自己对项目有一个清晰的愿景和期望。在这种情况下,当项目符合利益相关者的期望时,数据科学家就完成了项目。b)通常情况下,利益相关者或数据科学家只有一个模糊的初始想法,项目期望是一个正在进行的对话。在这种情况下,与利益相关者会面和沟通以制定潜在的计划和后续步骤是非常重要的。每周都会有新的项目步骤,当利益相关者和数据科学家觉得可以与他人分享见解时,项目就可以完成了。

3。什么时候决定一种方法不起作用,需要一种新的方法?

就实际工作而言,数据科学家在会议和文档审查中收到上下文和反馈,这有助于他们改进甚至在需要时转向新的分析框架。鉴于数据科学工作的研究性质,反复试验是不可避免的。因此,尝试一些东西,然后发现它可能不工作也没关系。

就结构和管理方法而言,Scrum 呼吁召开一次 Sprint 回顾会议,讨论什么可行,什么不可行。我认为这是一个很好的想法,但它可以集成到其他方法中。每个人都应该感到鼓舞,在空闲时间和会议上表达他们的担忧。我认为在每周例会和与经理一对一的会议中给人们一些时间和空间是一个很好的做法。如果关注是有价值的,并且需要单独的空间来讨论,我们可以安排一个会议来讨论这个关注。

如果你是数据科学家或数据科学经理,我很好奇你的团队是如何管理的,以及你对 Scrum 的体验。请让我知道。很想听听大家的经验和建议。

参考资料:

  • Scrum.org
  • Scrumguides.org
  • https://pragdave.me/blog/2014/03/04/time-to-kill-agile.html
  • 【http://agilemanifesto.org/

作者索菲亚·杨 2022 年 1 月 4 日

在 Medium 、 Twitter 、 Linkedin 和 YouTube 😃上关注我

不要以“Select”语句开始 SQL 查询

原文:https://towardsdatascience.com/dont-start-your-sql-queries-with-select-clause-d30fa1b701f6

遵循这种正确的方法来编写 SQL 查询

图片来源:Unsplash

问题是

大多数开发人员开始用' SELECT '子句编写他们的 SQL 查询,然后编写' FROM ',' WHERE ',' HAVING'…诸如此类。但这不是编写 SQL 查询的“正确”方式,因为这很容易出现语法错误,尤其是如果您是 SQL 初学者。

解决方案

“理想的”查询编写顺序应该与 SQL executor 执行查询的方式一致。这将确保您不会犯任何语法错误,并编写高效的 SQL 查询。您将知道如何在执行连接之前过滤数据,何时使用“HAVING”或“WHERE”子句等等。

在这篇博文中,我们将探讨编写 SQL 查询的“理想”方式,这将帮助您成为一名高效的 SQL 开发人员。

我们将使用客户和订单表(如下)来查找来自美国/英国的总消费超过 300 美元的前 2 名客户。

客户表(图片由作者提供)

订单表(作者图片)

让我们深入探讨编写 SQL 查询的正确方法。

1.总是以 FROM/JOIN 开头

直观地说,第一步是使用 FROM 子句读取表并执行 JOIN(如果需要的话)。因此,您应该始终以“FROM”/“JOIN”语句开始查询。

 FROM Customers
INNER JOIN Orders
ON Customers.customer_id = Orders.customer_id

甚至在执行连接之前,我们也可以从输入表中过滤行。我们可以通过在连接的“ON”子句后添加“AND”子句来做到这一点。

-- Filter happens before Join

FROM Customers
INNER JOIN Orders
ON Customers.customer_id = Orders.customer_id
AND country in ('USA','UK')

2.那搬到哪里去

执行顺序中的第二个子句是 WHERE 子句。它用于在应用连接后过滤数据表。

WHERE 子句非常有助于减少行数,尤其是当我们处理具有数百万行的大型数据集时。

FROM Customers
INNER JOIN Orders
ON Customers.customer_id = Orders.customer_id
WHERE country in ('USA','UK')

3.然后使用分组依据

Group By 子句应写在 Where 子句之后。它用于根据选定的一列或多列对行进行分组。

在下面的查询中,我们根据客户 id 对行进行分组。分组后,每个客户 id 在输出中都有一行。我们一般使用聚合(sum,min,max 等。)当我们把数据分组的时候。在本例中,我们将找到 Orders 表中 amount 列的总和。

FROM Customers
INNER JOIN Orders
ON Customers.customer_id = Orders.customer_id
WHERE country in ('USA','UK')
GROUP BY Customers.customer_id

4.在分组依据之后

HAVING 子句在 group by 之后执行,它用于筛选 GROUP BY 操作中生成的聚合行。

在我们的例子中,我们将过滤每个客户花费的金额总和大于 300。

FROM Customers
INNER JOIN Orders
ON Customers.customer_id = Orders.customer_id
WHERE country in ('USA','UK')
GROUP BY Customers.customer_id
HAVING sum(amount) >300

WHERE 子句在 GROUP BY 之前执行,而 HAVING 子句在 GROUP BY 之后执行。因此,WHERE 子句不能筛选聚合数据。

5.然后编写 SELECT 子句

我们希望在输出中显示的列是使用 SELECT 子句选择的。

如果我们使用 GROUP BY 子句对数据进行分组,我们需要使用 select 语句选择分组后的列。

在我们的示例中,我们将选择客户 id 和 sum(金额)来显示对应于每个客户的支出。

select Customers.customer_id, sum(amount) as total_amount
FROM Customers
INNER JOIN Orders
ON Customers.customer_id = Orders.customer_id
WHERE country in ('USA','UK')
GROUP BY Customers.customer_id
HAVING sum(amount) >300

输出(图片由作者提供)

6.在 SELECT 子句后使用 ORDER BY

选择列之后,下一步是提供我们希望输出行的顺序。

在我们的示例中,我们可以使用 ORDER BY 子句按照总支出的降序对行进行排序。

SELECT Customers.customer_id, sum(amount) as total_amount
FROM Customers
INNER JOIN Orders
ON Customers.customer_id = Orders.customer_id
WHERE country in ('USA','UK')
GROUP BY Customers.customer_id
HAVING sum(amount) >=300
ORDER BY total_amount desc

输出(图片由作者提供)

7.最后写限制条款!

写入序列的最后一步是限制我们希望在输出中看到的行数。

在我们的例子中,我们可以将输出行的总数限制为 2。

SELECT Customers.customer_id, sum(amount) as total_amount
FROM Customers
INNER JOIN Orders
ON Customers.customer_id = Orders.customer_id
WHERE country in ('USA','UK')
GROUP BY Customers.customer_id
HAVING sum(amount) >=300
ORDER BY total_amount desc
LIMIT 2

输出(图片由作者提供)

结论

我们看到了编写 SQL 查询的理想方式,它与 SQL 查询的执行方式一致。

如果您还没有这样做,我希望您将按照下面的顺序编写您的 SQL 查询。

作者图片

感谢您的阅读!

你可以在收件箱里看到我所有的帖子。 做到这里

如果你自己喜欢体验媒介,可以考虑通过 注册会员 来支持我和其他几千位作家。它每个月只需要 5 美元,它极大地支持了我们,作家,你可以在媒体上看到所有精彩的故事。

关注我 查看我在你的订阅中的数据科学帖子。

处理缺失值时不要走捷径

原文:https://towardsdatascience.com/dont-take-shortcuts-when-handling-missing-values-afb9312e73c3

如何确保缺失数据得到正确处理

安 H 的照片:https://www . pexels . com/photo/pink-jigsaw-puzzle-piece-3482441/

在许多数据集中,缺失值是一个两难问题,但是许多用户渴望分配更少的时间来处理它们,以便他们可以将更多的精力放在建模上。

我写这篇文章之前,我最近遇到了许多将丢失数据视为事后想法的投资组合项目。人们对最佳算法和超参数进行了大量的考虑,但很少对选择的插补方法进行论证。

我明白,建立模型很有趣,但机器学习项目的成功取决于在任何建模之前如何处理数据。

在这里,我们深入探讨了许多人在处理缺失数据时往往会跳过的重要步骤,并展示了用户如何在自己的项目中实现这一点。

最重要的一步

那么,您必须执行什么步骤来确保正确处理丢失的数据呢?

答案很简单:探索性数据分析(EDA)!

不幸的是,在处理数据集中缺失的数据时,用户经常会忽略 EDA。相反,他们选择依靠他们最熟悉/最舒适的方法。

总的来说,不考虑“为什么”而盲目地执行技术是一个灾难。

毕竟,丢失数据的性质因情况而异。在处理缺失值时,适用于一个使用数据集中的方法可能不适用于另一个使用数据集中。

跳过 EDA 的用户更有可能使用基于错误假设的技术,这将影响数据质量。较差的数据质量自然会对后续建模阶段建立的任何机器学习模型产生负面影响(垃圾进,垃圾出)。

使用 EDA 处理缺失数据

EDA 是掌握数据集的关键特征及其缺失值的有效方法。通过掌握关于缺失数据的更多信息,您将能够就如何处理这些缺失值做出更明智的决策。

下一个问题是:当用户用 EDA 检查他们的数据时,到底应该寻找什么?

理想情况下,处理缺失数据的用户应回答以下问题:

  • 哪些要素包含缺失值?
  • 每个特征的记录中缺失数据的比例是多少?
  • 缺失数据是随机缺失(MAR)还是非随机缺失(MNAR)?
  • 具有缺失值的要素是否与其他要素相关?

处理缺失数据的方法

为了有效地解决缺少值的困境,用户将受益于对他们可用的各种技术的熟悉。了解几种方法及其优缺点将增加选择最佳方法的机会。

现在,我们简要概述一些处理缺失数据的基本和高级方法,并考虑它们的优点和局限性。

此外,我们将使用下面的模拟数据集演示如何在 Python 中使用这些方法。

代码输出(由作者创建)

基本方法

  1. 省略有缺失数据的记录

有缺少值的数据点吗?

只需从数据集中删除它们!问题解决了!

这种方法的优点是它是处理缺失值的最简单的方法。就代码而言,您可以使用 Pandas 库用一行程序执行这个操作。

代码输出(由作者创建)

但是,这种方法会产生一个小得多的数据集,从而为模型提供较少的训练信息。此外,如果缺失值不是随机缺失(MNAR),这意味着移除这些数据点将不可避免地导致模型中的偏差。

这很少是处理缺失数据的首选方法。对于考虑这种方法的人来说,至少要确保有足够的数据,并且缺失值是随机缺失的。

2。省略丢失数据的特征

另一种选择是只移除特征而不是数据点。

代码输出(由作者创建)

同样,这需要移除数据,因此用户在考虑此方法之前,应首先验证要素中缺失数据的数量。

如果某个要素缺少太多数据,它很可能不会对模型有所贡献。对于这种情况,最好不要考虑这个特性。

3。用统计数据输入缺失数据

用户可以依靠简单的插补方法,用导出值替换缺失数据,而不是删除缺失值的记录或特征。对于数字要素,缺失数据可以用分布中值的平均值或中值来替换。对于分类特征,缺失数据可以由模式替换。

Python 中的插补可以用 Scikit Learn 包的simple imputr类来实现。

代码输出(由作者创建)

虽然简单的插补听起来像是一种完美的方法,但它忽略了感兴趣的特征与任何其他特征之间可能存在的相关性,而其他特征可能不适合感兴趣的数据。因此,用基本方法替换缺失值可能会产生不能充分代表数据点的值分布。

处理缺失数据的高级方法

到目前为止,我们已经探索了一些解决缺失值的简单方法。然而,这些方法基于可能不适用于现实生活场景的假设。

对于较简单的方法无法解决的情况,值得考虑在输入缺失数据时考虑多个变量的更高级的方法。

  1. 用 K-最近邻进行输入

您可能熟悉 K-最近邻算法在分类中的应用,但是您知道吗,您还可以利用 K-最近邻算法来估算缺失值?

该过程需要在特征空间中绘制特征,以找到具有缺失值的记录的“最近邻”。然后,最近邻值的平均值用于估算缺失值。

您可以使用 Scikit-learn 模块的 KNNImputer 类来执行这项技术。

代码输出(由作者创建)

KNN 算法的主要缺点是计算量大,容易出现异常值。

2。用链式方程进行多元插补(小鼠)

MICE 是一种独特的插补方法,没有得到足够的重视。可以说它值得单独写一篇文章。

简而言之,该方法需要为每个缺失值创建多个插补,而不是只有一个。该算法解决了统计不确定性,并使用户能够估算不同类型数据的值。

如果你想了解这个算法的来龙去脉,我找到了一篇很好的论文,在这里详细介绍了它。

可以使用 Scikit Learn 包的iterative imputr类在 Python 中实现 MICE 算法。注意这个类还是实验性的,所以你还需要导入enable_iterative_imputer来使用它。

代码输出(由作者创建)

MICE 算法是健壮的,但是它是在假设数据中的缺失值是随机缺失(MAR)的情况下运行的。

寻找最佳方法

因为没有一种放之四海而皆准的方法可以用来处理缺失值,所以理想的方法取决于所讨论的数据。

因此,任何关于丢失数据处理的决定都应始终基于明智的决定,这就是为什么在处理丢失数据之前进行 EDA 如此重要的原因。

通过识别感兴趣的数据集的特征,您可以识别最合适的方法,或者至少可以不考虑某些方法。

以下是一些示例,说明您可以从 EDA 中检测到什么,以及如何根据您的发现处理丢失的数据:

  1. 如果数据集的要素有超过 80%的记录缺失数据,最好是将该要素完全移除。
  2. 如果具有缺失值的要素与其他缺失值密切相关,则值得考虑使用高级插补技术,该技术使用来自其他要素的信息来推导值以替换缺失数据。
  3. 如果某个特性的值不是随机丢失的(MNAR ),请不要考虑像鼠标这样的方法。

关键要点

照片由 Unsplash 上的 Prateek Katyal 拍摄

本文的主要观点应该是始终分配时间来执行 EDA,以便更好地理解您的数据。您的 EDA 结果将让您深入了解与给定用例最兼容的技术。

此外,值得用处理缺失数据的多种方法的知识来武装自己,以确保 EDA 的发现将引导您选择最佳方法。

当您可以直接进入建模阶段时,花费额外的时间查看您的数据可能看起来很麻烦(我明白,EDA 可能很无聊),但是当最终的模型表现令人满意时,花费额外的时间来确定要使用的最佳技术将会得到回报。

我祝你在数据科学的努力中好运!

不要扔掉你的离群值!

原文:https://towardsdatascience.com/dont-throw-away-your-outliers-c37e1ab0ce19

由 Unsplash 上的absolute vision拍摄

首先,在数据集中寻找错误的原因。

检测到异常值 或者异常后,你需要决定如何处理它们。这篇文章解释了处理异常值的技巧。

第一步,调查

调查你的异常值。它们为什么会发生?它们真的是错误吗?现实生活中永远不会发生吗?它们在数据中,所以发现错误来自哪里是很重要的。由于实验或人为错误,可能会出现异常值。加载或处理数据时可能会出错。找到原因后,你就可以决定该怎么做了。

问题解决了吗?如果您决定离群值不应该出现在数据中并删除它们,请确保您可以定义原因。或者更好:记录下来。如果您发现新数据可能与异常值具有相同的值,您应该使用其他技术来处理它们,如下所述。

处理异常值

如果离群值与其他数据点相比只是不规则的,但是可能会发生,那么要小心它们!您可以尝试几种技术来改善机器学习模型的结果,而不删除异常值。

这些技术基于数据转换:

给数据封顶

您可以尝试的一种特殊转换是对数据进行 capping 或winsor izing。这是一种将特性的最大值设置为特定值的方法。您可以决定将最低的 2%设置为第二个百分位的值,最高的 2%设置为第 98 个百分位的值。这里是一个使用 python 代码的例子。

其他数据转换

除了封顶,还有其他方法来转换数据。您可以使用缩放器、对数变换或宁滨。

缩放器是您应该尝试的一种技术,因为缩放会对模型的结果产生巨大的影响。在这里你可以找到 sci-kit learn 对不同 scaler 的比较。你可能想阅读更多关于鲁棒定标器 的信息,它被设计用来处理异常值。

当变量以指数比例增长或衰减时,最好使用对数变换,因为变换后变量更接近线性比例。尾部的影响减小了。

宁滨,或称分桶,将一系列值替换为一个代表值。您可以以不同的方式使用宁滨:您可以设置箱的距离,您可以使用频率(每个箱获得相同数量的观察值),或者采样。

照片由玛丽娜·赫拉波娃在 Unsplash 上拍摄

基于模型的技术:

使用正则化

正则化减少了方差,这使得它在处理异常值时很有用。两种最常见的正则化类型是套索正则化和岭正则化,也分别称为 L1 正则化和 L2 正则化。

正则化通过惩罚高值回归系数来工作。它简化了模型,使它更健壮,不容易过拟合。

正则项在所有著名的 ML 包中都有实现。例如,看看 scikit-learn 套索和脊或添加正则化到 Keras 层。

型号选择

有些模型在处理异常值方面比其他模型更好。例如,如果你正在处理一个回归问题,你可以尝试随机样本一致性(RANSAC)回归或者希尔森回归。 RANSAC 使用来自数据的样本,建立一个模型,并使用残差来分离内部值和外部值。最终的模型只使用内联器。

如果您想要使用所有数据点,您可以使用基于树的模型。基于树的模型通常比其他模型更好地处理异常值。一个直观的解释是:树关心的是一个数据点位于拆分的哪一侧,而不是拆分和数据点之间的距离。

更改误差度量

最后一个选项是改变误差度量。一个简单的例子:如果你使用均方差,你会更严厉地惩罚异常值,因为你平方了误差。您可能希望切换到平均绝对误差,因为您采用误差的绝对值,而不是平方它。

摘要

在扔掉离群值之前,调查它们。寻找数据集中出现错误的原因。如果您无法解决这些问题,请使用变换、添加正则化或选择适当的模型或误差度量来处理数据。

感谢阅读!❤

有关系的

**https://hennie-de-harder.medium.com/are-you-using-feature-distributions-to-detect-outliers-48e2ae3309 **

不要低估 Python 集合的优雅力量💣

原文:https://towardsdatascience.com/dont-underestimate-the-elegant-power-of-python-sets-9b152f9de7f4

有用的小技巧!

快速学习 Python 集合的基础知识!

由 David Clode 在 Unsplash 上拍摄的照片

您的旅程概述

  1. 为什么要关心 Python 中的集合?
  2. 创建器械包
  3. 有用的设置方法
  4. 速记符语法
  5. 一套能放什么?
  6. 收尾

1 —为什么要关心 Python 中的集合?

Python 中有四种基本的容器类型:

  • **列表:**Python 中的列表是可变序列,可以包含不同类型的数据。比如dates = ["19-12-1922", "08-02-2005"]
  • **元组:**Python 中的元组类似于列表,只是它们不是可变的。它们的内部状态不会随着时间而改变。比如seasons = ("Spring", "Summer", "Autumn", "Winter")
  • 字典:Python 中的字典是键值存储,其中的键指向一个特定的值。一个例子是age = {"Eirik": 27, "Grandma": 86}
  • **集合:**Python 中的集合是无序且可变的集合。最重要的是,集合只包含唯一的值。例如emails = {"toy_email@gmail.com", "not_a_real_email@hotmail.com"}

在 Python 入门课程中,每个人都学习了列表、元组和字典。然而,Python 中的集合经常被忽略。一些初级数据专业人员认为集合更高级或更深或*。这不是真的!*

Python 中的 set 非常实用,也没那么难学。在这篇博文中,我将或多或少地向您展示开始使用 Python 时需要知道的一切。

作为一个例子,在我们开始之前,考虑从下面的列表中提取唯一值的问题:

*languages = ["Python", "R", "R", "SQL", "Python", "C", "SQL"]*

你可以看到PythonR都被列了两次。要手动执行此操作,您可以执行以下操作:

*languages = ["Python", "R", "R", "SQL", "Python", "C", "SQL"]# Manually:
unique_languages = []
for language in languages:
    if language not in unique_languages:
        unique_languages.append(language)*

这工作得很好,但是它比需要的代码多得多。使用集合,您可以在一行可读的代码中轻松实现这一点:

*languages = ["Python", "R", "R", "SQL", "Python", "C", "SQL"]# Manually:
unique_languages = []
for language in languages:
    if language not in unique_languages:
        unique_languages.append(language)

# With Sets
unique_languages = list(set(languages))*

太棒了,对吧?如果你是一个视觉学习者,我制作了一个视频,涵盖了差不多相同的主题🔥

***注意:*除了这里提到的四种类型,还有许多其他类型的容器。我写了一篇关于数据类的博客,如果你想看的话,你可以看一下!

2 —创建集合

在 Python 中创建集合的第一种方法是使用花括号,如下所示:

*# Basic Syntax for Creating Sets
favorite_foods = {"Pizza", "Pasta", "Taco", "Ice Cream"}*

现在,您已经创建了一个有四根弦的 set。集合可以包含不同的数据类型,但是在应用程序中,数据类型通常是相同的。在 Python 中创建集合的另一种方法是使用集合构造函数:

*# Set Constructor
aweful_foods = set(["Tuna", "Tomatoes", "Beef", "Ice Cream"])*

这里首先创建一个包含四个字符串的列表,然后将该列表传递给 set 构造函数。你可以想象上面两个例子的数据来自一项关于最喜欢和最不喜欢的食物的调查。

一般来说,如果你已经有了一个列表(或者另一个 iterable)中的数据,那么使用 set 构造函数可能是最简单的。

了解器械包会自动删除重复项是很重要的:

*i_love = {"You", "You", "You", "You"}
print(i_love)**Output:** 
{"You"}*

甜食😍

***注意:*要创建一个空集,你不能给一个变量赋值{}。这将创建一个空字典。相反,使用set()创建一个空集。

3 —有用的集合方法

集合上有一堆有用的方法。我想告诉你四个最重要的:

向集合中添加元素

您可以使用add()方法向集合中添加元素:

*favorite_foods.add("Chocolate")
print(favorite_foods)**Output:**
{'Ice Cream', 'Pasta', 'Pizza', 'Chocolate', 'Taco'}*

回想一下,对于列表,有一个方法append()可以将一个元素追加到列表的末尾。集合没有顺序。因此 Python 的开发者选择使用名字add()而不是append()来强调这一点。

合并两个集合

如果您有两组,那么您可以使用union()方法将它们组合起来:

*all_foods = favorite_foods.union(aweful_foods)
print(all_foods)**Output:**
{'Tomatoes', 'Ice Cream', 'Tuna', 'Pasta', 'Pizza', 'Chocolate', 'Beef', 'Taco'}*

这里,两个集合中的所有元素都被合并到一个新的集合中,称为all_foods。注意"Ice Cream"all_foods中只出现一次,即使它同时出现在favorite_foodsaweful_foods中。Python 集合删除重复!

寻找共同元素

如果你想找到两个集合共有的元素,那么你可以使用intersection()方法:

*dividing_foods = favorite_foods.intersection(aweful_foods)
print(dividing_foods)**Output:**
{'Ice Cream'}*

如您所见,intersection()方法挑选出两个集合中的元素。如果你有两组投票,想找出两组都投了什么,这个方法真的很有用。

寻找差异

给定两个集合,您通常希望找到第一个集合中不在第二个集合中的元素。为此,您可以使用difference()方法:

*likable_foods = favorite_foods.difference(aweful_foods)
print(likable_foods)**Output:** {'Pizza', 'Pasta', 'Taco', 'Chocolate'}*

在上面的代码示例中,aweful_foods中的每个元素都已从集合favorite_foods中移除。

另一个例子

让我们再做一个例子,这样你就可以看到集合是多么有用。假设您有以下两个编程学习平台列表:

*platforms = ["Udemy", "Coursea", "YouTube", "DataCamp", "YouTube"]
paid_platforms = ["Udemy", "Coursea", "Skillshare", "DataCamp"]*

***现在说想找免费的平台。*你会怎么做?使用集合,您可以简单地编写:

*print("Free: ", set(platforms).difference(set(paid_platforms)))**Output:**
Free:  {'YouTube'}*

4-速记运算符语法

Jippe Joosten 在 Unsplash 上拍摄的照片

在上一节中,我向您展示了一些很酷的方法。但是你知道还有union()intersection()difference()的简写吗?简写操作符语法更容易记忆和阅读。这里您可以看到一个同时包含四个运算符的代码示例:

*print("Union: ", favorite_foods | aweful_foods)
**Output:** Union: {'Tomatoes', 'Ice Cream', 'Tuna', 'Pasta', 'Pizza', 'Chocolate', 'Beef', 'Taco'}print("Intersection: ", favorite_foods & aweful_foods)
**Output:** Intersection: {"Ice Cream"}print("Difference: ", favorite_foods - aweful_foods)
**Output:** Difference: {'Pizza', 'Pasta', 'Taco', 'Chocolate'}*

我个人更喜欢简写的操作符语法。也超级直观!例如,在编程语言中,符号&通常代表and布尔组合器。and布尔组合器的工作方式与交集相同。其他两个例子也很容易得出类似的结论。

5 —你能在一套中放些什么?

让我问你一个简单的问题。你能在一套中放什么样的物体?你可能认为答案是任何东西*。然而,事实并非如此。考虑如果您尝试运行以下代码会发生什么:*

*invalid_set = {[1, 2, 3], "Good try, though"}**TypeError**: unhashable type: 'list'*

如您所见,如果您试图将一个列表放入一个集合中,Python 会抛出一个TypeError。原因是一份名单不是所能公布的。解释 hashable 最精确(但最没帮助)的方式是可以在 hashable 对象上调用hash()函数。在实践中,你通常需要知道的是不可变对象是可散列的。然而,并不是所有的可散列对象都是不可变的。

因此,您可以确定任何不可变的东西(例如整数、字符串和元组)都可以放入集合中。但是,将列表和字典放入集合是不可能的。您也可以不将一个集合放在另一个集合中:

*nested_set = {1, set([2]), 3}**TypeError**: unhashable type: 'set'*

6—总结

照片由斯潘塞·伯根在 Unsplash 上拍摄

希望您对 Python 中的集合感觉更舒服。如果你对数据科学、编程或任何介于两者之间的东西感兴趣,那么请随意在 LinkedIn 上添加我,并向✋问好

喜欢我写的?查看我的其他帖子,了解更多 Python 内容:

  • 用漂亮的类型提示使你罪恶的 Python 代码现代化
  • 用 Python 可视化缺失值非常简单
  • 使用 PyOD 在 Python 中引入异常/离群点检测🔥
  • 5 个能在紧要关头救你的牛逼数字功能
  • 5 个专家提示,让你的 Python 字典技能突飞猛进🚀

不要在 A/B 测试中使用 T 测试

原文:https://towardsdatascience.com/dont-use-a-t-test-for-a-b-testing-e4d2ef7ab9b6

如何使用多元线性回归确定 ATE 和统计显著性

你有没有想过加快 A/B 测试的速度?好吧,这可以说是在 A/B 测试环境中减少方差的最高 ROI 解决方案。

照片由亚历克斯·罗伯特在 Unsplash 拍摄

频繁主义者的实验通常被用于实验。然而,与贝叶斯或序贯方案相比,频繁 A/B 测试通常需要大样本量,这减慢了公司迭代。下面我们将讨论一个实际的解决方案,它允许我们在一半的时间内达到统计显著性。

与之前的帖子不同,我们不会评论一篇论文。相反,我们将汇集我在过去 8 个月中所做的研究,并在此过程中链接相关资源。

事不宜迟,让我们开始吧…

技术 TLDR

t 检验是在 A/B 检验中确定统计显著性的最简单的频率主义方法。函数形式为north_star ~ const + treatment_indicator的 OLS 在数学上等同于 T 检验,但是它允许我们包含减少方差的协变量。一个著名的例子就是 CUPED 。

通过利用稳健的因果模型而不是 T 检验,我们可以自由地大幅降低方差。

1 —设置

让我们慢一点,真正明白发生了什么。为了便于交流,我们将从一个例子开始。

我们是在线应用商店的数据科学家。我们的目标是确定 app store 游戏的最佳排名算法(图 1)。

图 1:在线应用商店的例子。图片作者。

我们可以利用任何参与度数据,例如点击、下载、评分等。我们也可以使用这些指标的加权组合。

然而,为了测试最好的系统,我们将利用因果推理的黄金标准:A/B 测试。我们的控制臂将采用默认排序算法,每个治疗臂将采用新排序算法。最后,我们的北极星指标,我们用来作为实验成功标准的指标,将是收入。

2—基线:T 检验

传统的 frequentist A/B 测试程序将利用双样本 T 检验来查看我们的治疗组是否显示出与我们的对照组有统计学上的显著差异。实现起来非常简单高效,如下所示…

from scipy.stats import ttest_ind
import numpy as np
np.random.seed(1)mu_c = 5
mu_t = 5 + 0.05                                 # 1% liftc = np.random.normal(loc=mu_c, scale=1, size=1e4)
t = np.random.normal(loc=mu_t, scale=1, size=1e4)ate = np.mean(t) - np.mean(c)                # 0.04966
percent_lift = ate / np.mean(c)              # 0.0099
p_val = ttest_ind(t, c).pvalue               # 0.00044

在上面的例子中,我们创建了一个控制和处理阵列,其中处理平均比控制高 1%。这代表了 1%的提升,表明我们治疗部门使用的算法增加了 1%的收入。

从那里,我们计算提升百分比和统计意义。如最后两行代码所示,正如预期的那样,我们的模拟返回了 0.99% 的提升,非常接近 1%。还要注意,我们观察到 p 值为 0.00044 ,远低于标准的 0.05 阈值。

太好了!T 检验有效。

现在,虽然 T 检验在统计学上非常稳健,但它们留下了很多问题。interest 的主要缺点是,他们假设我们度量观察中的所有方差都是真正的噪声**。通常,在现实世界中,我们称系统方差为噪声,因为我们没有可靠解释方差的变量。**

但是,在大多数实验中,并不是所有的方差都是不可解释的,我们将使用线性回归来控制这些趋势。

3 —线性回归

线性回归是一个比基本 T 检验更强大的工具。但在我们深入讨论之前,让我们先退一步。

我们选择的假设检验由我们的数据生成机制决定——在这种情况下,随机分配给治疗组或对照组。通过随机分配和中心极限定理,我们保证满足 T 检验的所有假设。

然而,对于线性回归,我们必须对协变量更加小心。我必须避免的主要问题是特征之间的共线性,尤其是我们的治疗指标。但这是非常可行的。

还要注意,与许多因果推断模型不同,我们不必假设模型是正确的,因为给定随机分配,我们有渐近推断。所以,在英语中,我们可以用线性回归来确定 ATE 和统计显著性。

让我们看一个例子。

3.1-T 检验的奇偶校验

下面,我们利用 statsmodels 包来重新创建 T 检验的结论…

import statsmodels.api as sm# 1\. Create treatment indicator variable (1 = treat)
is_treat = np.append(np.repeat(1, len(t)), np.repeat(0, len(c)))# 2\. Create independent and dependent vars
x = np.array([is_treat, np.repeat(1, len(t) + len(c))]).T
y = np.append(t, c)# 3\. Fit LM
lm = sm.OLS(y, x).fit()# 4\. Observe ATE and stat sig
ate_ols  = lm.params[0]                                # 0.04966
pval_ols = lm.pvalues[0]                               # 0.00044
round(ate_ols, 6) == round(ate, 6)                     # True

我们首先创建一个二元处理虚拟变量和一个常数。然后,我们使用这两个特征来拟合我们的模型,作为对我们的兴趣指标(收入)的预测。最后,我们提取治疗指标的系数及其 p 值。

正如我们所见,线性回归产生的平均治疗效果(ATE)与 T 检验产生的效果相同。从数学上来说,他们是相同的。

所以现在我们可以清楚地看到,OLS 和 T 检验的步骤产生了相同的结果,但我们为什么要使用 OLS 呢?

4 —多元线性回归

正如这一节的标题所暗示的,OLS 允许我们使用多个变量。随着我们增加相关变量的数量,理论上我们将减少方差并更快达到统计显著性。

现在重要的是重申我们必须避免共线特征。这意味着我们的特征没有一个能够非常相互关联。当这种情况发生时,不仅模型系数表现奇怪,而且方差会被夸大,这损害了我们确定统计显著性的能力。

4.1 —解释变量

让我们看另一个例子。在下面的代码中,我们开发了两个协变量:seasonalcovariate_random。请注意,在现实世界中,我们实际上是解释性变量,如一周中的某一天或来自用户的总收入。

seasonal = np.sin(np.arange(len(control))) + np.array([1 if np.random.uniform(len(control)) > 0.7 else 0])
covariate_random = np.random.chisquare(5, size=n)c *= seasonal
c += covariate_randomt *= seasonal
t += covariate_random

**在使用季节性和随机协变量来衡量我们的治疗和控制后,我们接下来拟合多元线性回归。这个多元回归缺少我们的 **covariate_random** **变量。输出可以在图 2 中看到…

x = np.array([np.repeat(1, len(t) + len(c)), 
              is_treat, 
              np.append(seasonal, seasonal))]).T
y = np.append(t, c)lm = sm.OLS(y, x).fit()
print(lm.summary())

图 MLR 的输出,其中 x1 是治疗指标,x2 是季节性成分。图片作者。

在图 2 中,我们的治疗指示器(x1)指示一个 0.0350 ATE。但是,它在统计上并不显著,如 P > |t|列中的 0.469 所示。我们还要注意,我们的治疗指标变量的标准误差是 o.o48.

现在,covariate_random掌握了我们的因变量收入的重要信息,我们用它来创建我们的治疗/控制值。所以,让我们把它加入到模型中,看看会发生什么…

图 MLR 的输出,其中 x1 是治疗指标,x2 是季节性因素,x3 是我们的“协变量”。图片作者。

可以看到,我们的待遇指标 x1 的系数仍然是 0.0350 。这很好——我们没有添加共线性变量。然而,真正令人印象深刻的是 P > |t|列—我们已经从 P 值 0.469 到 0.044。

****通过简单地包含预测协变量,我们能够达到统计显著性。我们不需要收集更多数据,例如延长实验时间。我们只是利用统计数据和关于数据方差的知识。

很容易看出这个微不足道的例子是如何推广到现实世界的。如果您有一个健壮的因果模型,您的组织可以更快地迭代,并使更少的用户暴露于次优处理。

本节的最后一点(感谢评论中的 Alvin),在探索治疗指标变量和其他解释变量之间的关系时,探索相互作用可能是一个好主意。

4.2-正则化协变量选择

值得注意的是,在现实世界的例子中,会有许多潜在的协变量,其中一些可能包括之前的购买行为、在平台上的持续时间、一天中的时间、一周中的日期等。理论上,稳健的多元模型会考虑所有这些因素(假设要素之间不存在共线性)。

这里,为我们的因果模型做一些特征选择是有意义的。但是请注意,在我们的休闲模型中包括像 LASSO 这样的正则化项会破坏协变量和我们的治疗指标之间的独立性,从而破坏因果推断。

如果要构建多元因果模型,请确保使用独立数据集进行要素选择。在最终模型中不包括正则化。

4.3-使用 CUPED 减少方差

最后一个技巧是利用方差减少技术,例如 CUPED 。一句话,CUPED 使用实验前的数据从我们的实验数据中去除“通常的”差异。有了方差减少的 ATE,我们能够更快地达到统计显著性。

ML 模型最近也变得流行,以减少实验方差,但它们涉及到大量更多的工作。也就是说,如果你是一家大公司,这可能是值得的。

5 —摘要

在这篇文章中,我们通过使用多元线性回归来估计 ATE,确定统计意义,并减少方差。如果你在实验中使用 T 检验这样的频率主义方法,那么利用多元 OLS 可能会对你有好处。然而,确保你符合 OLS 的假设——如果你不符合,你的 ATE 和统计显著性计算将是错误的。

感谢阅读!我会再写 17 篇文章,把学术研究带到 DS 行业。查看我的评论,链接到这篇文章的主要来源和一些有用的资源。

不要在 Python 中使用 Apply,遵循这些最佳实践!

原文:https://towardsdatascience.com/dont-use-apply-in-python-there-are-better-alternatives-dc6364968f44

应用功能的替代方案,可将性能提高 700 倍

图片来源:Unsplash

什么是应用功能——如果你还不知道的话!

Apply 函数是一个单行函数,可用于在数据帧的所有元素上或跨数据帧的行或列应用操作。

简介

数据科学家/分析师经常使用 Apply 函数来执行数据操作任务**,但是当您的数据有太多行时使用它真的是最佳选择吗?**

不尽然!

在这篇博客中,我们将看看下面 3 个非常有用的替代方法,你可以用它们来代替 Apply 函数,尤其是当你有大量的行时:

  1. 并行化
  2. Loops(是的,可以更快!)
  3. 矢量化(最佳实践!)

但是首先,让我们来看看 apply 函数在大型数据集上的执行时间。

创建数据集

我们将创建一个具有 5 百万行和 4 列的数据集。每列可以有一个从 0 到 50 的整数值。

import numpy as np
import pandas as pddf = pd.DataFrame(np.random.randint(0, 50, size=(5000000, 4)), columns=('a','b','c','d'))df.shape
# (5000000, 5)df.head()

数据框(图片由作者提供)

定义功能

现在,让我们定义我们的函数,该函数基于 dataframe/input 变量的现有列中的值返回一些值。

def infer(a,b,c,d):
    if a==0:
        return d
    elif a <= 25 & a>0:
        return b-c
    else:
        return b+c

应用功能

现在,我们将使用“应用”函数来调用上一步中定义的推断函数。

import timestart = time.time()
df['e'] = df.apply(lambda x: infer(x['a'], x['b'], x['c'], x['d']), axis = 1)
end = time.time()
print(end - start)### Time taken: 200 seconds

应用功能大约需要 200 秒才能得到结果。

让我们来看看替代方法:

选项 1:并行化

并行化是通过将大数据块划分为较小的数据块来实现的,这些较小的数据块使用多个 CPU 和内核的能力来并行处理。

有几个包,比如 SwifterDask ,我们可以使用它们实现并行化。在这篇博客中,我们将看看 swifter,因为它非常容易使用,并且在某些情况下可以达到几乎相同的结果或更好的结果。

我们可以简单地在 dataframe 之后调用 swifter 包,然后继续应用函数。

## install the package
!pip install swifter## import the package 
import swifter## use the swifter package
start = time.time()
df['e'] = df.swifter.apply(lambda x: infer(x['a'], x['b'], x['c'], x['d']), axis = 1)end = time.time()
print(end - start)## Time taken: 60 seconds

因此,使用 Swifter 包,我们可以将执行时间减少 3 倍以上,对于简单添加包名来说,这已经不错了。

Swifter 试图以最好的方式实现 apply 函数,要么在后端使用 Dask 将其矢量化或并行化,要么在数据集很小的情况下简单地使用 pandas apply。

选项 2:循环

我知道这听起来令人震惊,但如果你有一个没有太多列的数据集,那么这种技术可以方便地获得比 swifter 包更好的结果。

诀窍是首先将 dataframe 转换成默认的 light 数据结构,比如数组或字典,然后遍历这些行来操作数据集。

start = time.time()## empty list 
list2 = []## adding 'e' column with default 0
df['e'] = 0## convert dataframe into array 
for row in df.values:
    if row[0] == 0:
        row[4] = row[3]

    elif row[0] <= 25 & row[0] > 0:
        row[4] = row[1]-row[2]
    else:
        row[4] = row[1] + row[2]
    list2.append(row)

df2 = pd.DataFrame(list2, columns=['a', 'b', 'c', 'd','e'])end = time.time()
print(end - start)## Time taken: 20 seconds

因此,使用 for 循环遍历数组,我们能够将执行时间减少到 20 秒,比 apply 函数提高了 10 倍。

选项 3:矢量化

矢量化是在数据集上实现数组操作的技术。在后台,它一次将操作应用于数组或序列的所有元素(不像 for 循环一次处理一行)。

对 python 代码进行矢量化是实现最佳性能的最佳实践。

# using vectorization 
start = time.time() df['e'] = df['b'] + df['c']
df.loc[df['a'] <= 25, 'e'] = df['b'] -df['c']
df.loc[df['a']==0, 'e'] = df['d']end = time.time()
print(end - start)
## 0.28007707595825195 sec

因此,我们能够将运行时间减少到 0.28 秒,比应用函数的运行时间快 700 倍。

摘要

  • 我们研究了 python 中 Apply 函数的 3 种替代方法,尤其是当数据集包含大量行时。
  • 我们了解了 swifter 软件包的并行处理能力。
  • 我们发现,如果聪明地使用,python 中的循环并没有那么糟糕。
  • 对于一个大型数据集,代码的矢量化带来了最佳的性能提升,大约是 apply 函数的 700 倍。因此,使用矢量化处理大型数据集是最佳实践。

我希望你从这篇文章中学到了一些新的东西。

你可以在收件箱里收到我的帖子。 做到这里 如果你喜欢体验媒介的自己,可以考虑通过 报名会员来支持我和其他成千上万的作家。它每个月只需要 5 美元,它极大地支持了我们,作家,而且你也有机会通过你的写作赚钱。

不要用 Python 的列表乘法([n] * N)

原文:https://towardsdatascience.com/dont-use-python-s-list-multiplication-n-n-450c68d673a3

意见

这是个陷阱

照片由像素上的像素拍摄

无论您是新手还是有经验的 Python 程序员,都有可能使用过列表乘法和/或在那些“很酷的 Python 特性”风格的文章中读到过它。

这是因为它无疑是那些旨在使您的 Python 生活更容易的很酷的特性之一。

列表乘法的好处是它抽象了初始化列表的过程。

不使用迭代方法或列表理解:

# Iterative approach
my_list = []
for _ in range(N):
    my_list.append(n)# List comprehension
my_list = [n for _in range(N)]

您可以通过以下方式获得相同的结果:

my_list = [n] * N

你看,我是按照以下顺序学习编程语言的:

C -> C++ -> MATLAB -> R -> Python.

在 Python 之前,我使用过的任何其他编程语言都无法提供如此的简洁和直观。

然而,随着我开始编写越来越复杂的代码,列表乘法开始让我心烦。

我记得有一次我花了整整一个下午调试代码,结果发现问题源于使用*操作符创建不正确的列表。

因此,我觉得有必要讨论一下这个问题,因为我知道一个事实,一些开发人员仍然没有注意到 star 操作符在列表创建方面的权衡。

列表乘法有什么问题

让我们考虑下面的代码:

>>> my_list = [0] * 3
>>> my_list[0] = 1
>>> my_list
[1, 0, 0]

这是你所期望的。到目前为止,一切顺利。

现在,让我们尝试使用相同的方法创建一个 2D 阵列:

>>> my_list = [[0] * 3] * 5
>>> my_list[0][0] = 1
>>> my_list
[[1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0]]

嗯!这可能不是你想要的。

通过初始化一个 3D 数组来进一步推动它怎么样:

>>> my_list = [[[0] * 3] * 5] * 2
>>> my_list[0][0][0] = 1
>>> my_list
[[[1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0]], [[1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0]]]

预期的输出是更新子列表[0, 0, 0]的第一个值。然而,似乎这个更新在所有的子列表中都被复制了。

那么,为什么会这样呢?

列表乘法是如何工作的?

为了理解前面的行为,有必要重温一下 Python 的 FAQ ,其中写道:

原因是用*复制一个列表不会创建副本,它只会创建对已有对象的引用

让我们将其转化为代码,以便更好地理解 Python 在幕后是如何操作的:

  • 列表乘法:
my_list = [[0] * 5] * 5
for i in range(5):
    print(id(my_list[i]))

输出:

2743091947456
2743091947456
2743091947456
2743091947456
2743091947456
  • 使用 for 循环
my_list = []
for _ in range(5):
    my_list.append([0] * 5)for i in range(5):
    print(id(my_list[i]))print(my_list)

输出:

2743091947456
2743095534208
2743095532416
2743095534336
2743095532288
  • 释义

for循环不同,通过操作符*复制的所有列表都指向同一个内存地址。这意味着影响一个嵌套列表的任何改变都会影响所有其他列表,这显然违背了我们的初衷。

现在的问题是:

  • 为什么第一个例子([n] * N)工作得很好,尽管列表中的所有元素都引用同一个对象?

事实证明,这种行为背后的原因(如 Python 的 wikibook 中所述)是列表是可变项,而int, str等是不可变的。看看这个:

来源

因为不可变的对象不能被改变,所以当你更新列表中的一个条目时,Python 会创建一个新的(不同的)对象引用。

>>> my_list = [0] * 3
>>> id(my_list[0])
1271862264016
>>> my_list[0] = 1
>>> id(my_list[0])
1271862264048

工作区

解决这个问题的一个快速简单的方法是使用列表理解。当然,这是在标准的for循环之外的。

>>> my_list = [[0] * 3 for _ in range(5)]
>>> my_list[0][0] = 1
>>> my_list
[[1, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]

此外,我们可以看到不同的内存地址被分配给每个列表。

>>> my_list = [[0] * 3 for _ in range(5)]
>>> [id(l) for l in my_list]
[1271867906112, 1271864321536, 1271864322048, 1271864326912, 1271864322560]

更重要的是,这种方法适用于所有场景。

所以,你为什么不坚持下去,为了安全起见,而不是在使用列表乘法之前必须三思呢?

结论

我不是 Pythonic 句法糖的超级粉丝。

是的,我同意这有助于代码简洁明了。

然而conciseness == readability在软件行业是什么时候?

事实上,我用 Python 编写的代码越多,我就越倾向于使用 Python 标准语法和放弃快捷方式。

说到底,重要的是性能可维护性,以及可读性。而不是你有多少行代码。

如果你不能没有捷径,至少读一读你正在使用的语法糖的好的、坏的和丑陋的。在这种情况下,可能需要对软件工程概念(即数据结构、内存分配……)有一定的理解。

快乐编码!

如果你觉得这个有用,可以考虑成为 高级 会员。如果用这个 链接 ,我会得到一个小切。

https://ayarmohammed96.medium.com/membership

不要在生产中使用 R

原文:https://towardsdatascience.com/dont-use-r-in-production-e2f4c9dd4a7b

但是,如果你这样做,这里是如何

DALL-E 生成:计算机科学可再生技术环境的说明

我们已经在生产中运行 R 好几年了,这篇文章是关于如何让它发生的。这篇文章也是关于为什么我仍然不认为你应该在生产中运行 R,如果你真的不需要它。我是从一个工程师的角度来看这个问题的。我们将讨论许可、R 限制以及如何解决主要障碍,以达到这样一个目的,即您可以在生产环境中运行 Rscripts,而不那么痛苦( Github link )。这篇文章不是关于付费或托管服务的。

生产中的研发

使用检查点解决版本控制问题

R 的最大问题是可重复性。与 Python 相比,R 没有高级版本和包管理。数据科学家在他们的机器上使用 R,安装所有的包并使用当时发布的版本。从用户的角度来看,这很容易,不需要考虑版本控制。但是如果您现在想在其他机器上运行这个脚本,那么它很有可能不起作用,尤其是在编写脚本和部署之间有延迟情况下。安装一个旧版本的 R 包并不像你想象的那样简单,有很多方法,但是很麻烦。

微软承认这一点,并建立了检查点库,它这样描述自己:

checkpoint 的目标是解决 r 中的包可复制性问题。具体来说,checkpoint 允许您在特定的快照日期安装 CRAN 上存在的包,就像您有一台 CRAN 时间机器一样。

因此,有了 checkpoint,我们可以选择按日期进行版本化,而且到目前为止已经有了可复制的 R 环境。这个帖子在使用 checkpoint 的同时,还有 renv ,解决了同样的问题。

使用它很简单,我们只需将它添加到我们的脚本中:

library(checkpoint)
checkpoint(“2022–07–17”, r_version=”4.2.1")

Checkpoint 将扫描脚本中的导入并管理它们,但是如果您有自定义包,您需要在包含以下内容的 checkpoint.yml 中排除这些包:

exclude:
   - myRPackage

使用 Docker 隔离环境

通常,我们有多个脚本,使用不同的库和版本。为了使它们相互独立,我们使用 Docker。有了 Docker,我们可以构建可靠的环境,并将它们部署到我们想要的任何地方。Docker 与检查点库相结合,解决了可再现性问题。

rocker 项目提供了预构建的版本化 R 容器,我们可以通过扩展版本化映像来使用这些容器:

ARG VERSION=”4.1.0"
FROM rocker/r-ver:$VERSION as base
# Install needed packages and git
RUN apt-get update \
&& apt-get -y install \
libgit2-dev \
libcurl4-openssl-dev \
libssl-dev (...)# checkout our git repository
WORKDIR /workdir
RUN git clone [https://{secret_key}@github.com/username/repo.git](https://{secret_key}@github.com/username/repo.git) .# install checkpoint library
RUN Rscript -e “install.packages(‘checkpoint’)”#start R script
CMD git pull && Rscript my_r_script.R

有了这个小 docker 文件,你已经能够用一个特定的 R 版本来启动一个 R 脚本了( docker run ),而且你还可以确保所使用的库的版本是由检查点库修复的。但是,您会注意到执行花费了相当长的时间,因为检查点库第一次管理指定日期的脚本依赖项时,需要花几分钟来下载和设置它们,并且每次都是这样。

确定开始时间

像这样使用 Docker 和预构建的 R-images 是一个很好的开端,但是我们必须解决另一个问题。如果我们在每次代码更改时都从头构建映像,我们会有巨大的开销,因为检查点库最初需要花费很多时间来构建。但是,如果 R 代码发生变化,我们不需要构建映像,也不需要每次都清除检查点。

为了避免这种情况,我们将 R 脚本的执行移出了 docker 文件。为了避免在设置 R 之后关闭容器,我们在最后调用sleep infinity将控制权交给我们的 bash 脚本。

现在 bash 脚本必须自己启动和停止 docker 容器。然而,现在我们可以在启动 R 脚本之前执行 git pull,而不必在每次代码更改时都重新构建容器。

在 Dockerfile 文件中,我们通过调用以下命令来替换最后一个命令:

CMD sleep infinity

我们最初构建容器(或者如果我们需要更新依赖项),使用:

docker build --no-cache -t foo_image . #build the image
docker create --name foo_container foo_image #create container

我们的 bash 脚本完成了以下工作

docker start foo_container
docker exec foo_container git pull origin master
docker exec foo_container Rscript my_r_script.R
docker stop foo_container

有了这些简单的脚本( github )我们现在可以快速、可伸缩和可复制地运行 R 脚本。

为什么 R 还不用于生产

许可证

R 使用多个许可证,大多数核心 R 库都是在 copyright license 下发布的,比如 GPL-2 和 GPL-3。因此,在某些情况下,这已经是一个问题。如果您计划编写 R 代码并将其作为产品的一部分发布,您将被迫开源您的代码。这已经是一个原因,为什么没有很多产品允许在云环境中执行 R。然而,如果您的产品没有附带 R,那么对于核心库来说,您很可能是安全的。但由于我不是律师,请询问你们的法律部门。

r 不适合软件工程师

大多数 R 用户不会发现这些问题,直到他们必须反复修改他们的脚本。这很好,因为大多数 R-coder 不是软件工程师,不需要知道产品软件应该是什么样子。然而,经常有人试图争辩,因为它对他们来说很容易使用,它在其他地方也一定很容易使用。以下是我个人在生产中遇到的一些实际问题:

  • R 缺乏 OOP 支持,R 是一种函数式语言是有充分理由的。这对小脚本来说很好,但对大项目来说是个问题,因此不建议构建更大、更复杂的应用程序。r 更像是编写狭窄任务的脚本,而不是管理大型工作流。
  • 与编译语言相比,r 本身很慢。因此,很多 R 库要么依赖于预编译的二进制文件,要么需要安装 g工具链从源代码构建它们。该来源依赖于平台,可能会导致许多问题。此外,出于安全原因,您(或您的 IT)不希望在生产服务器上使用 g
  • 您可以生成日志,但这很糟糕,因为您不能轻松地将所有相同格式的日志重定向到 std:out 和 std:err ,所以如果您将日志推入 ELK(或类似的)并处理来自 R print 语句的多行日志,您必须做更多的工作。
  • 在 python 中,你有 requirements.txt/setup.py 来定义需求,处理依赖和版本,在 R 中你没有。r 易于使用,但这是有代价的。这表明 R 正在关注特定的分析任务
  • 当您在自己的机器上编写代码时,它可能无法在另一台机器上运行,尤其是如果中间有一段时间。变化很大,一些库被修改了,代码不再工作了。r 缺乏非常基本的版本控制
  • CI/CDs 工具通常不支持 R ,你必须定制一切。这包括单元测试、集成测试、静态代码检查、包部署和版本控制。
  • r 没有成熟的生态系统来部署 web 服务器和 API。有用于简单可视化的闪亮的和用于 API 的 OpenCPU 和水管工,但正如其名称所示,它笨重且感觉有限,与 Python 等语言中的类似工具相去甚远。特别是 R 用户经常提倡的 plumber,缺少 HTTPs、OAUTH 和其他大多数更高级的特性。此外,在 R 中,一切都是单线程的。
  • 社区中没有安全问题的意识,人们经常用 devtools 安装未经检查的 github 库。这是生产服务器上的一个主要安全问题(不仅仅是那里)。
  • r 确实比 python 更容易崩溃,因为它的易用性和函数式编程风格让用户不必考虑极限情况。

结论

在这篇文章中,我展示了为什么我认为 R 不是生产用例的好选择。然而,有时候无论如何都是有意义的。原因可能是上市时间、团队组成或技术基础设施。对于这些情况,我展示了如何使用 Docker 和 checkpoint 以可重复的方式部署 R。代码可以在这里找到。

不要浪费你未标记的数据

原文:https://towardsdatascience.com/dont-waste-your-unlabeled-data-9bb778743b41

行业笔记

不要浪费你未标记的数据

评估您的模型的弱点,并在可用数据中确定最具信息性的数据样本。

不确定性之光。迈克尔将抱在的 Unsplash 上。

以数据为中心的方法

在过去的十年里,人工智能的主要趋势是专注于建立创造性的复杂模型。但是最近几年,任何人都可以用 Python 等流行语言和 Pytorch、Tensorflow、JAX 等库来使用最先进的架构。现在,人工智能的最高优先级是让这些模型对每个特定的用例都有价值。这需要对可用的精选数据有深刻的理解,不幸的是,数据分析和如何建立一个良好的训练集是经典 ML 课程中很少教授的技能,而是通过时间和汗水学习的。

到目前为止,数据并不被认为是一个主要问题:可变大小的标准研究数据集是免费的( ImageNet,COCO,GLUE 等,以及预训练模型的权重( ModelZoo,Huggingface 等),作为对特定数据子集进行微调的先验知识。除此之外,在小规模数据集上训练本地模型成为一种商品。但在实践中,在生产阶段成功制作 ML 模型是一个难题。

失败的主要原因之一是研究模板上的模型和现实环境中部署的模型之间的准确性损失。事实上,这些公司中有 13%的模型能够投入生产[7]。

当我们知道随着 AutoML 平台的兴起,甚至模型搜索也已经自动化时,这似乎很令人惊讶。瓶颈是什么?

瓶颈是数据。下一个需要强大框架和标准化的挑战是处理数据的管道。行业中的人工智能可能需要从以模型为中心的方法后退一步,转向以数据为中心的方法。以数据为中心的方法试图将模型开发与训练数据集的创建和模型性能的监控协调起来。

“并非所有数据都是生而平等的”——詹妮弗·普伦斯基

不确定性的量化

因为真实世界的数据是杂乱的、嘈杂的、错误的、充满离群值的,并且不遵循正态分布,所以量化不确定性对于构建可信的人工智能模型至关重要。选择好你输入的数据。剔除可疑数据。避免致命的垃圾进,垃圾出,节省时间和金钱。除非我们可以信任模型预测,否则它几乎毫无用处。为了发现这些病态数据,我们将探索作为数据质量代理的模型的不确定性。我们想确定数据在哪里混淆了模型。

不确定性的原因有哪些?

不确定性有许多原因。当训练和测试数据集的分布不匹配时,推理中可能出现不确定性。当数据类重叠或数据本身有噪声时,它也会出现。一般来说,我们应该意识到数据集中不确定性的原始来源,以便创建一个有效的策略来尽可能地减少它。

在主动学习文献中,这些不确定性被分为两大类:认知任意不确定性。一方面,随机不确定性是由数据的噪声产生的,并且在同一实验的每次运行中都会有所不同。这种不确定性是不可减少的,因为它是数据的固有属性。另一方面,认知的不确定性可以通过学习来减少。通过增加数据集大小或使模型复杂化。

两种不确定性的示意图。图自开篇:【https://arxiv.org/pdf/2011.06225.pdf

从理论到实践

默认情况下,我们经常错误地将 softmax 函数输出的每个标签的概率视为每个标签的模型置信度。这种误解可以通过使用一种简单的技术来避免:考虑每个 softmax 输出相对于其他标签或其他实例的相对值。

在本文中,我将分享扫描所有可用数据(标记的或未标记的)的标准技术,以帮助对数据和模型的当前状态做出以数据为中心的结论。这些技术根据模型对其预测标签的置信度来排列每个数据点。我们可以使用不同的函数,将“不确定性”分数归属于每个数据点。高度不确定性意味着模型对该数据点不确定,推断很可能是错误的。

用不确定性分数识别类边界附近的实例。图片由作者提供,灵感来自[1]。

为什么我们应该尝试自动化每个可用数据点的评分?

  • 利用现有数据和模型
  • 在数据集中查找边缘案例
  • 查找质量差的数据以重新标记或从训练数据集中排除
  • 通过追踪歧义来澄清标签说明
  • 找到当前模型的弱点
  • 识别新传入数据的数据漂移
  • 误差分析,以找出下一个要标记的样本
  • 查找异常值

考虑到我们将模型投入生产的不断发展的世界,持续改进数据是必要的一步。我听说过一个保龄球图片分类器的故事,当 COVID 开始时,因为社交媒体在这件事上的趋势,它将空卫生纸架上的图像标记为保龄球图片。我们永远不知道未来的数据会是什么样子,我们应该始终意识到我们让数据溜进我们的模型预测。

我们的实验

在本文中,我们评估了为 CNN 模型提供分类的图像。我们将使用 EMNIST 进行实验。

我们使用 softmax 根据最后一个激活函数计算的输出逻辑创建概率分布。Softmax 无法提供模型确定性的概率,并且正在丢失信息,因为它使用指数,所以它丢失了数字的比例([1,4,2,1]将产生与[101,104,102,101]相同的分布)。但我们仍然可以使用 softmax 作为模型可信度的代理,并从高模型可信度到低模型可信度对我们的数据样本进行排序。

“没有算法能在坏数据中存活”——罗伯特·莫纳克

不确定性评分

我们希望将数据标注在我们的模型最混乱的地方——不确定性。因此,对于每个数据点,我们将为所有未标记的数据点给出单个不确定性分数,并将它们从最不确定性到最不确定性进行排序。

该方法是不确定性量化的最简单、最便宜的方法。您可以识别位于模型决策边界附近的数据点

对于一个数据点,您的模型:

  • 给不同的类一个相似的 softmax 概率(例如,输入图像是狗,输出 softmax 是:狗 33.3%,猫 33.3%,鸟 33.3%)
  • 将低概率赋予最高概率(例如,在十个等级中,最高的 softmax 是“青蛙”, softmax 为 10.5%)

我们将按照从简单到复杂的顺序列出评分技术。

我们称 p_max 为针对一幅图像推断出的类的最高 softmax 分数,称 p_2nd 为针对一幅图像的类的第二高置信度。 n 为分类的类数。

对于下面的每个函数,输入 prob_dist 是一个数据点的 softmax 输出数组,输出是该数据点的模型的 0 到 1 之间的不确定性分数。如果数据集是具有三个类的多类分类, prob_dist 的形状为(3,)。

评分类型:

  • 最小置信度(最大置信度预测和 100%置信度之间的差值)

我们希望选择在最可能的类别中可信度最低的实例。假设我们有两个图像 A 和 B,模型的最高 softmax logit 分别是 A 的 0.9 和 B 的 0.3。在这种情况下,我们可能希望了解 B 看起来是什么样子,处理,(重新)标记或删除它。

我们使用为每个数据点计算的标准化“最小”不确定性分数(公式(1))。由于最有可能的实例的最低置信水平不能低于 1/n ,我们添加了标准化分数,以将不确定性分数从 0 调整到 1。

该分数将给出预测的等级顺序,其中我们希望对预测标签置信度最低的项目进行采样。

这种评分技术只取决于最有信心项的信心,而不关心第二个或第 n 个信心分。

  • 置信区间

边际置信度取一个数据点的两个最有把握的预测之间的差值。我们可以通过将结果减去 1(公式(2))将该差值转换为[0–1]范围。这次你只关心两个最高类别中两个最高分的差。这个差值越小,越接近 1,你就越不确定。与最小置信度得分相比,该算法对 softmax 基数不太敏感,但仍然敏感。

  • 置信度(两个最有把握的预测之间的比率)

比率评分函数是置信区间评分的变体。这个不确定性分数看两个最高分数的比率(3)。该比率作为用于 softmax 的基数的乘数给出,因此与前两种方法不同,它对 softmax 基数不敏感。它捕捉到第一个标签比第二个标签更有可能。

  • 基于熵的(所有预测之间的差异)

熵分数考虑了所有类别的预测。它是通过将概率的负和乘以其 log_2 概率来计算的。

我们除以 log_2(n)来归一化 0 和 1 之间的熵(等式(4))。

2 作为对数的基数是不改变排名的任意基数,即使它将单调地改变绝对不确定性分数。

实验设置

我们举例说明两个评分函数的结果(最小)。我们首先在一半的 EMNIST 数据集(130,106 张图片)上训练一个简单的两层 CNN。然后,我们预测所有看不见的数据点的类别,并根据它们的不确定性得分对它们进行排序。我们对前 1000 幅图像进行采样,给出它们的不确定性分数。

我们的 CNN 由两个卷积层组成,每个卷积层之后是 RELU 激活,然后是两个完全连接的层。在验证准确度开始降低之前,我们在第 6 个时期停止训练。我们在验证集上获得了 0.79 的 F1 分数。

您可以在以下位置找到培训代码:https://github . com/ble DEM/active-learning/blob/master/run _ experiment . py

以及用于采样前 1000 个图像作为新数据集,位于:https://github . com/ble DEM/active-learning/blob/master/create _ new _ set . py

结果

我们查看在验证集上每个类的平均 F1 分数最高和最低的类。

F1 分数最低的类别(F1 <50%) are:

'k' 'o' 'i' 'r' 'Y' 'q' 'b' 'l' 'h' 'e' 'm'

and the classes with the highest F1 score (F1> 95%)是:

'n' 'Z' 'A' 'a' '3'

每级 F1-验证数据集中的分数。

现在让我们来看看根据不确定性得分排名的前 1k 张图片。为了便于比较,我们还随机抽取了 1k 的样本。

使用“最少”评分技术从看不见的数据中分配 1k 个采样数据点。

从上图可以看出,我们对容易混淆的字符进行了过采样:“I”、“1”、“l”或“O”、“O”、“0”。

在下图中,我们将每个类的 F1 分数与使用熵不确定性评分函数采样的 1k 的不同类之间的实例分布进行了比较。我们在“容易混淆”的类中发现一个高峰,这在随机采样的数据集中不会发生。

验证数据集(蓝色)上的 F1 分数与“最少”技术得出的样本集中每个类的百分比的叠加。

验证集(蓝色)和随机采样的 1k(橙色)上 F1 分数的叠加。

我们在下面展示了一些 EMNIST 图像作为前 1k 不确定推理的例子。当我们查看基于“最少”或“熵”的样本时,我们可以清楚地看到标签中的噪声(例如 S 标记为 0)和图像本身(模糊、不可读的字符)。

随机采样的图像(右)和模型置信度最低的图像(左)之间的比较。

给定“熵”不确定性分数的高不确定性图像(低模型置信度)的示例。

在实践中使用不确定性评分

使用不确定性分数对新标注任务的数据批次进行采样是标记未知数据集中最具信息量的数据点的有效方法。然而,正如我们所看到的,我们应该注意不要系统地对过度表示的类及其近邻中的相似数据点进行过采样。

我们在这里列出了使用上面介绍的评分方法的利弊:

优点:

  • 使用现有/标准模型
  • 快速且易于计算和解释。
  • 如果您的模型使用传统的机器学习(而不是深度学习),请创建一批新的信息数据样本进行标记

缺点:

  • 这些简单的评分函数不应用于为深度学习的新批量任务选择数据点。由于潜在的采样偏差,在对这些采样数据进行训练后,模型的性能可能比随机采样差[5]。
  • 使用贝叶斯深度学习创建高维数据(图像、文本等)的采样策略更安全。).

复制不确定样品的注意事项

图片由穆罕默德·道迪拍摄

使用不确定性量化方法可以非常有效地在未标记的数据中找到位于模型边界上的样本。但是,在为下一批注释选择要采样的数据点时要小心。该抽样单独评估每个未标记点的信息量。如果您只选择最高不确定性得分数据点,您将检索到一个信息数据点和许多几乎相同的拷贝。如果你天真地获得了前 k 个最有信息的点,你可能最终也会问 k 个几乎相同的点。这将使您的样本批次的贡献低于随机抽样批次。例如,在 EMNIST 实验中,如果你观察熵采样技术,你可以看到字符“I”,“1”,“l”被大量采样。

为了避免这种重复采样效应,一些研究论文提出了补充方法,如 BatchBALD 等批量感知采样技术解决方案[2]。在本文中,作者不仅关注每个样本的不确定性得分,还关注为下一批训练样本提供最丰富的信息。

使用 wise 采样构建注释的智能批处理[1]:

  • 最小化样本量,以确保从每个数据点获得最大收益。
  • 最大化样本量,以避免过于频繁的重新训练。

关于智能采样的更多信息

1)异议评分:

评估每个未标记数据点的不确定性的另一种流行的启发式方法被称为委员会的查询方法。如果您有一组模型,您也可以通过获取每个模型的每个数据点的所有分数来调整不确定性评分。您在初始训练集上训练几个不同的模型,您可以查看它们在未标记数据上的分歧。

例如,我可以在相同的训练集上用不同的超参数训练相同的 CNN,然后将它们应用于未标记的数据,并使用它们的不一致来选择下一个要标记的样本。

当您想要评估预测中 softmax 置信度不可用的回归任务的不确定性分数时,此方法特别有用。

辍学策略

如果你没有一个集合模型,你可以为每个数据点画出不同的预测,其中每个新的预测是在每次丢弃不同的随机选择的神经元之后做出的。正常情况下,退出仅在训练期间应用,所有神经元在测试期间都被激活。但是如果我们在测试中也应用 dropout,我们可以为每个实例推断出一系列不同的预测。每个样本的不确定性可以计算为所有预测的变化:不一致程度越高,不确定性就越大[1]。这种技术通常被称为蒙特卡洛退出技术。蒙特卡洛是一种计算技术,它从真实分布中随机取样,以获得该分布的估计值。在不确定性估计过程中,我们将来自漏失模型的每个预测视为蒙特卡罗样本。

面向 MC 辍学和其他主动学习技术的开源库:https://github.com/ElementAI/baal/【论文】

2)贝叶斯模型

您可以使用生成贝叶斯模型对每个类的分布进行建模。在这种情况下,您不需要使用概率代理来推断模型预测的可信度,因为您可以从模型输出本身直接读取每个数据点属于每个类的概率。

您可以使用贝叶斯神经网络来估计神经网络的不确定性。在贝叶斯神经网络框架中,在训练期间,你不尝试学习单个函数 f,而是学习类似于集成模型的多个函数。训练之后,我们可以对每个数据点进行平均预测,并计算这些预测之间的方差。可以为从回归到分割的各种任务建立贝叶斯神经网络。它将模型参数视为正态分布以及每个模型参数分布的均值和方差。这些参数通常在训练过程中学习。

3)主动学习

我一直专注于给每个未标记的样本分配一个不确定性分数。但是,不确定性量化只占更广泛的主动学习领域的极小一部分。AL 致力于通过标记尽可能少的样本来获得尽可能多的性能增益[3]。理论上,理想的系统会查询位于模型的决策边界上的实例和远离决策边界的实例(离群值、多样性采样、要定义的新类)。不幸的是,还没有一种标准的方法来构建最佳的管道来查询最小的数据样本以获得最高的性能。

4)课程学习

另一个非常有趣的研究领域试图通过向模型提供适当的数据点来优化学习。它不是关注未标记的数据,而是关注已经标记的数据。学习任务需要一些时间来为模型提供简单的样本,并在训练过程中一点一点地增加样本的难度,类似于人类。对于不平衡的数据集,相反的策略工作得很好:我们为硬(罕见)实例分配更高的惩罚,以迫使模型学习它们。在实践中,这种先易后难的学习策略是由损失函数的选择来设定的。我鼓励你阅读这篇文章[4]来学习更多关于标记数据中的抽样技术。

本文的代码

https://github.com/bledem/active-learning

参考

[1] 人在回路机器学习:以人为中心的人工智能的主动学习和注释,Robert Monarch。

[2]巴特包勒德:https://oatml.cs.ox.ac.uk/blog/2019/06/24/batchbald.html

【3】深度主动学习的调查。、任&肖、昀&常、肖军&黄、王宝耀&李、陈志辉&陈、肖江&王、辛。(2020).https://arxiv.org/pdf/2009.00236.pdf

[4] 先学哪些样本:容易还是难?,欧武,2021。https://openreview.net/pdf?id=pSbqyZRKzbw

[5] 通过期望改进最大化在 CNN 中主动学习。纳格帕尔,乌代。(2020).https://open access . the CVF . com/content _ WACV _ 2020/papers/Mayer _ Adversarial _ Sampling _ for _ Active _ Learning _ WACV _ 2020 _ paper . pdf

[6]https://www.youtube.com/watch?v=Yqj7Kyjznh4&t = 1260s&ab _ channel = deep learning ai

[7]https://venturebeat . com/2019/07/19/why-do-87-of-data-science-projects-never-make-it-into-production/

DoorDash SQL 面试问题

原文:https://towardsdatascience.com/doordash-sql-interview-questions-509e1dfbb1fb

一个有趣的 DoorDash SQL 面试问题和解决方案的详细演练

作者在 Canva 上创建的图片

我们今天为您选择的 DoorDash SQL 面试问题很有趣,因为它要求您了解各种 SQL 概念。它通过使用 TO_CHAR()EXTRACT() 等函数来测试您处理不同类型数据的能力。还有,它涉及到 聚合函数CASE 语句。

我们不会把问题和解决方案扔给你。如果你继续阅读,你会发现我们对如何回答这个问题的建议,而不仅仅是这个。其他任何 DoorDash 或者其他公司的 SQL 面试题 都可以用。我们相信这对你参加任何 SQL 面试都有很大帮助。

为了让它更有帮助,我们制作了一个视频,可以让你更容易地了解我们在这里将要谈论的一切。反之亦然。

DoorDash SQL 面试问题

极度延迟交货

我们要谈的问题就是这一个。

如果实际交付时间比预测交付时间晚 20 分钟以上,则交付被标记为极度延迟。在每个月中,有百分之多少的订单是极度延迟的?以 YYYY-MM 格式输出月份,以及相应的极迟订单占本月所有订单的百分比。

如果你想跟随我,这是的链接。

如果你事先对公司有过调研(强烈推荐!),这是展示你对业务理解的时候了。

Doordash 想要调查他们的送货时间是有道理的。尤其是在食品行业,准时交货对于确保客户满意度至关重要。除此之外,还影响食品质量和安全。食物需要新鲜供应!

假设你是 DoorDash 的一名数据分析师,管理层想知道每个月他们的订单中有多少百分比是“极度延迟交付”。如果订单交付时间比预计交付时间晚 20 分钟以上,则交付被视为“极度延迟”。

凭直觉,我们会逐月监控“极度延迟”交付的数量。然而,我们不能只看这个数字。总交付量将每月变化,并根据季节、假期以及公司的总体发展而波动。一个更好的跟踪指标是“极度延迟”订单占总订单的百分比。这正是这个 DoorDash SQL 面试问题要求我们做的。

理想情况下,我们希望看到这个指标随着时间的推移而降低,或者至少保持在某个阈值内。否则,这是一个值得关注的原因,导致收视率低,回头客少,食品质量差。比你想象的要快,公司倒闭了。你就失业了!

我们不能让你为失去工作做好准备,但我们可以为找到工作做好准备!

解决这一问题的解决方案框架

作者在 Canva 上创建的图像

现在你明白了你需要解决的问题,让我们开始制定解决方案。

为此使用一个框架将帮助你组织你的想法,并以一种面试官可以理解的方式进行交流。这一点很重要,因为经常不仅仅是你的编码技能被测试,你的交流技能也被测试。

我们推荐的框架由以下步骤组成。

  1. 探索和理解数据集
  2. 确认并陈述你的假设
  3. 用英语或伪代码概述你的高级方法
  4. 编码解决方案
  5. 代码优化(如果有)

如果你还不熟悉这个,去看看这个视频,里面详细解释了所有的步骤。

1.浏览数据集

我们得到了 delivery_orders 表,其中显示了配送 ID、下订单的时间、预计配送时间、实际配送时间、为该配送提供的评级,以及配送员(骑手)、餐馆和消费者(顾客)的 ID。

下面是表格结构。

该表的预览显示了以下数据。

一旦下了订单,就会给它分配一个惟一的交付 ID,然后记录订单的相关细节,如客户、餐馆、日期和订单时间。计算交货时间/交货的预期到达时间,并将订单分配给配送员/骑手,其 ID 也包含在表中。订单交付后,会记录准确的时间,客户会通过评分提供反馈。

2.确认并陈述你的假设

该问题没有提供如果订单被取消或交付正在途中(即,已下单但尚未交付)会发生什么情况的信息。

你可以和面试官澄清这一点。我们没有这个选项,所以我们假设数据集只包含已履行的订单。

3.概述高级方法

现在,让我们解开获得目标输出表所需的东西。这个 DoorDash SQL 面试问题要求我们显示每个月的极度延迟订单的比例。

输出应该以 YYYY-MM 格式显示月份,在第二列中显示相应的极度延迟订单的百分比。

为了获得所需格式的日期,我们需要从 order_placed_date 列中提取月份和年份信息。

至于百分比,需要计算每个月的延期订单总数和订单总数。

获得订单总数很容易:我们只需要计算唯一的交货 id 的数量。但是每个月的极晚订单总数呢?

为了确定某个订单是否是“极度”延迟订单,我们必须比较预测交货时间和实际交货时间这两列。如果实际交付时间超过预测交付时间超过 20 分钟,那么我们就有一个“极度延迟”订单。

为了剔除非常晚的订单,我们将使用 CASE 语句。

将这个详细的描述分成几个步骤:

  1. TO _ CHAR()-从 order_placed_date 列中提取月份和年份,格式为 YYYY-MM
  2. 案例陈述——确定行级别的极度延迟交付
  3. EXTRACT() —获取实际交付时间和预测交付时间之间的差值(以分钟为单位)
  4. SUM() —获取极度延迟交货的总数
  5. COUNT()和 DISTINCT —获取所有交付的总数;除以上一步得到百分比
  6. CAST()-获取百分比中的小数点(浮点)
  7. 分组依据-按月获取输出

一旦你列出了所有的步骤,和面试官核对一下。这有助于你尽早获得反馈。如果一切顺利,您可以开始编码了。

4.编码解决方案

编码现在仅仅意味着将上述步骤翻译成 SQL 代码。

1.提取月份和年份

我们将使用 TO_CHAR()函数获取所需格式的数据。

SELECT TO_CHAR(order_placed_time,'YYYY-MM') AS year_month
FROM delivery_orders;

如果您的想法是使用 EXTRACT()或 DATE_PART()函数,您可以这样做。但是,这些函数不会直接获得您需要的格式,即 YYYY-MM。如果您想了解更多关于日期时间操作的信息,请查看此视频。

2。识别极度迟交的货物

CASE 语句是 SQL 中的一个 IF-THEN-ELSE 语句,它将允许我们识别极度延迟的交付。

SELECT TO_CHAR(order_placed_time, 'YYYY-MM') AS year_month,
       CASE
           WHEN (prediced_delivery_time - actual_delivery_time) > 20 THEN 1
           ELSE 0
       END
FROM delivery_orders;

然而,要做到这一点,我们需要提取分钟并减去它们。

3。以分钟为单位显示差异

在这一步中,我们将使用 EXTRACT()函数。到目前为止,代码是这样的。

SELECT TO_CHAR(order_placed_time, 'YYYY-MM') AS year_month,
       CASE
           WHEN EXTRACT(MINUTE
                        FROM (actual_delivery_time - predicted_delivery_time)) > 20 THEN 1
           ELSE 0
       END
FROM delivery_orders; 

4。极度延迟交货的数量

CASE 语句除了每一个非常晚的交付外,还会显示整数 1。为了得到它们的数量,我们使用 SUM()聚合函数。

SELECT TO_CHAR(order_placed_time, 'YYYY-MM') AS year_month,
       SUM(CASE
               WHEN EXTRACT(MINUTE
                            FROM (actual_delivery_time - predicted_delivery_time)) > 20 THEN 1
               ELSE 0
           END)
FROM delivery_orders;

5。所有交付的数量

下一步是使用 COUNT()和 DISTINCT 查找所有唯一交付的数量。此外,极晚交货的数量必须除以这个数字。

SELECT TO_CHAR(order_placed_time, 'YYYY-MM') AS year_month,
       SUM(CASE
               WHEN EXTRACT(MINUTE
                            FROM (actual_delivery_time - predicted_delivery_time)) > 20 THEN 1
               ELSE 0
           END)/COUNT(DISTINCT delivery_id)*100
FROM delivery_orders;

6。转换为浮点型

上面的 get 将除法结果显示为整数。即零,因为极度延迟交货的数量低于总交货数量。

要解决这个问题,可以使用 CAST()函数。我们将使用双冒号(::),这是该函数的简写。

SELECT TO_CHAR(order_placed_time, 'YYYY-MM') AS year_month,
       SUM(CASE
               WHEN EXTRACT(MINUTE
                            FROM (actual_delivery_time - predicted_delivery_time)) > 20 THEN 1
               ELSE 0
           END)/COUNT(DISTINCT delivery_id)::FLOAT*100 AS perc_extremely_late
FROM delivery_orders;

7。按年月分组

现在剩下的就是使用 GROUP BY 子句了,您已经得到了这个 DoorDash SQL 面试问题的完整答案。

SELECT TO_CHAR(order_placed_time, 'YYYY-MM') AS year_month,
       SUM(CASE
               WHEN EXTRACT(MINUTE
                            FROM (actual_delivery_time - predicted_delivery_time)) > 20 THEN 1
               ELSE 0
           END)/COUNT(DISTINCT delivery_id)::FLOAT*100 AS perc_extremely_late
FROM delivery_orders
GROUP BY 1;

这一结果需要引起注意,因为 Doordash 有几个月的交货时间非常晚,比例很高。表现最差的是 2022 年 1 月,约有 36%的订单极度延迟。同样,2021 年 11 月也有令人不安的 31%的交付业绩。这样,公司管理层会希望调查根本原因,以便将极迟交付保持在最低限度;否则,漫长的等待可能会吓跑 Doordash 的宝贵客户!

5.代码优化

您是否需要这一步取决于代码本身。有些代码不需要优化,而有些则需要。面试官往往喜欢要求一个代码进行优化。受访者这样做的能力表明,他们可以编写一个有效的代码。

如果面试结束的时候还剩下更多的时间,那就想想你该如何改进解决方案,即使面试官没有要求你优化。

对于我们的 DoorDash 问题解决方案,我们可以改进它。一个方便的技巧是使用公共表表达式或 cte。

如果存在列转换或者代码更复杂,那么在出现错误的情况下,会使您的解决方案更难理解和调试。cte 在这里特别有用!

通过在汇总最终结果之前编写 CTE,我们可以优化我们的解决方案。

WITH orders AS
  (SELECT TO_CHAR(order_placed_time, 'YYYY-MM') AS year_month,
          delivery_id,
          CASE
              WHEN EXTRACT(MINUTE
   FROM (actual_delivery_time - predicted_delivery_time)) > 20 THEN 1
              ELSE 0
          END AS extremely_late
   FROM delivery_orders)

SELECT year_month,
       SUM(extremely_late)/COUNT(DISTINCT delivery_id)::FLOAT*100 AS perc_extremely_late
FROM orders
GROUP BY 1;

运行这段代码,您将看到它返回与第一个解决方案相同的结果。

结论

这个中等难度的 SQL 面试问题真正展示了面试官喜欢问的问题。我们讨论了数据聚合,处理日期、数据转换、CASE 语句和数据分组。这些也是在工作面试中测试的流行的 SQL 概念。还有更多这样的 DoorDash 问题,请查看我们的帖子“ 最常见的 DoorDash 数据科学家面试问题 ”。尝试解决其中的一些问题,看看你在这里学到的东西是否可以应用到其他问题上。在面试中回答问题时,不要忘记使用结构化框架。这对你来说真的很重要!

【https://www.stratascratch.com】最初发表于https://www.stratascratch.com/blog/doordash-sql-interview-questions/?utm_source=blog&utm_medium=click&utm_campaign=tds

双盲咖啡研究

原文:https://towardsdatascience.com/double-blind-coffee-studies-ae6417e9d593

咖啡数据科学

关于我为什么不做的讨论

在过去的三年里,我收集了很多关于咖啡的数据,并且发表了很多关于改善味道和萃取的文章。然而,我没有做过双盲研究或三角研究(在双盲中使用两个不同的样本和一些对照样本)。我想我也不会,我想说说为什么。

定义

盲法研究是指我会冲两杯咖啡,在下面贴一个标签,然后让其他人移动杯子,这样直到研究结束我才知道哪个是哪个。

一项关于咖啡的双盲研究是咖啡师制作两份浓缩咖啡(变量不同),标签藏在杯子下面。然后他们把镜头混在一起,走开,测试者进来。两者都不知道测试者将各自尝试的顺序。

一项在咖啡中进行的三角研究使用了与双盲相同的两张照片,但增加了第三张不相关的照片作为对照。

双盲研究的目的是当人们知道哪些变量将进入食谱时,消除偏见。这对于有多个临床试验的药物是非常重要的。对于咖啡,我不认为每个实验都应该遵循临床试验标准。

所有图片由作者提供。我做的一个没有双盲甚至盲测的研究样本。

绩效指标

我使用两个指标来评估技术之间的差异:最终得分和咖啡萃取。

最终得分 是评分卡上 7 个指标(辛辣、浓郁、糖浆、甜味、酸味、苦味和余味)的平均值。当然,这些分数是主观的,但它们符合我的口味,帮助我提高了我的拍摄水平。分数有一些变化。我的目标是保持每个指标的一致性,但有时粒度很难确定。

使用折射仪测量总溶解固体量(TDS),该数字结合咖啡的输出重量和输入重量,用于确定提取到杯中的咖啡的百分比,称为提取率(EY)** 。**

咖啡的挑战

出于几个原因,双盲研究具有挑战性。

  1. 你需要不止一个人。
  2. 你需要调整像浓咖啡这样的东西对舌头的影响,这就是为什么要对稀释的咖啡进行 Q 分级。
  3. 你需要多个人来品尝世界各地的美食。
  4. 你需要多种咖啡,不同的烘焙程度,不同的年龄。
  5. 你需要多台研磨机/浓缩咖啡机。

也许它会帮助你看到,我的思想在哪里看到一个实验,更好地理解变量空间。

实验实例设计

来说说我最近的 Rok vs 小众磨床实验吧。我最初的设计使用相同的浓缩咖啡机,在多次烘焙和不同烘焙时间进行配对,我没有连续进行配对,而是更换研磨机,因为我整天都在进行烘焙。我发现韩国研磨机在味道和提取上都更好,然后我做了进一步的调查,找到了的根本原因。

但是,这个实验只是我品尝,并不是双盲的。我们暂且把提取收益率(EY)放在一边。EY 为韩国展示了更好的结果,但是人们对味道有争议。让我们只看一个主观的衡量标准,比如味道。

我们可以重新设计这个实验。我们可以假设最初的实验花费了 N 个人-小时,这说明了有多少人花了多少时间做某事。

  1. 首先,让我们做一个双盲实验,现在需要 2*N 个人-小时。
  2. 让我们在时间上将镜头推得更近一些,这不会导致时间增加,但必须漱口会大大影响时间。
  3. 将品酒师的人数增加到 10 人,所以现在我们是 11*N 人(假设 1 名咖啡师为每个人制作饮品)。
  4. 我做了六次烘烤和多次烘烤,但没有达到烘烤的程度。将烘焙等级的数量改变 4,这将时间增加到 44*N
  5. 我们可以用一台像样的咖啡机模仿其他机器,做 4 台普通的机器。时间增加到 176*N。
  6. 我们应该尝试不同的压力/温度曲线还是只尝试一个?对于倍数,N 当然增加。
  7. 因为这些都是磨床,我们还在乎刀片钝吗?我们是否只在研磨机磨合后才关心它们?

我不想夸张。我想用这个例子来说明咖啡数据科学面临的挑战。

通常,人们认为我没有提取率来支持我的发现,当我有了,他们会说我的味觉发现不是双盲的。我很少在 espresso 中看到双盲研究,当有双盲研究时,只品尝了几个样品,这也是不够的。所以我觉得那些不应该算标准。

这种想法的问题是,它限制了能够对咖啡做出有数据支持的意见的人的数量,只限于少数有专业知识、时间和金钱的人。除了人们为自己重复一个或一组实验之外,没有其他的同行评审过程。

我的经验是,即使面对拥有数据的人,人们也会向缺乏数据的知名咖啡人寻求帮助。然后当面对数据时,他们自己没有数据也争论。

用粉笔进行第一次微粒迁移试验

一个很好的例子就是微粒迁移。我用多种方法进行了搜索,看看粉末是否会迁移,我发现只有少量粉末迁移,大约 4%。然而,许多咖啡从业者的反对意见是,我并没有否定微粒迁移的理论,同时忽略了该理论缺乏证据。在过去的二十年里,咖啡界已经证明了这一点,但这只是一个没有证据的理论。甚至对该理论起源的讨论也是模糊的,表明它最初是一个口头神话,用来解释有问题的镜头。

如何适应

我提出品味和提取。我的目标不是证明某个产品或方法更好,因为我希望它是。我的目标是改善我自己的咖啡体验。为此,我必须以诚实为目标。本着这种精神,我也发表过关于怪异和失败实验的文章,因为我相信它们的结果可能也很重要。

我在一天和一周的时间里尝试拍摄,并试图随机化相关的变量。此外,在我的分析中,我采取措施比其他人更深入,所以我不想只是量化一种方法是好是坏,而是要了解原因和条件。

espresso 的世界还不是一个充满数据的世界,所以任何数据都比没有数据好,欢迎任何人收集任何数量的数据来拍摄我错了。我愿意讨论数据驱动的结论。

如果你愿意,可以在推特、 YouTube 和 Instagram 上关注我,我会在那里发布不同机器上的浓缩咖啡照片和浓缩咖啡相关的视频。你也可以在 LinkedIn 上找到我。也可以在中关注我,在订阅。

我的进一步阅读:

我未来的书

浓缩咖啡系列文章

工作和学校故事集

个人故事和关注点

乐高故事启动页面

摄影启动页面

改进浓缩咖啡

断奏生活方式概述

测量咖啡磨粒分布

浓缩咖啡中的粉末迁移

咖啡萃取

咖啡烘焙

咖啡豆

浓缩咖啡滤纸

浓缩咖啡篮及相关主题

意式咖啡观点

透明 Portafilter 实验

杠杆机维修

咖啡评论和想法

咖啡实验

双重去偏机器学习(第一部分)

原文:https://towardsdatascience.com/double-debiased-machine-learning-part-1-of-2-eb767a59975b

因果数据科学

因果推理、机器学习和正则化偏差

作者图片

在因果推断中,我们通常通过对其他变量的分析来估计因果影响。我们通常将这些变量称为控制变量混杂变量。在随机对照试验或 AB 测试中,条件反射可以通过减少随机化后出现的组间不平衡来增加分析的能力。然而,条件作用在观察性研究中更为重要,在观察性研究中,如果没有随机化,可能对恢复因果关系至关重要。

当我们有许多控制变量时,我们可能希望选择最相关的变量,可能捕捉非线性和相互作用。机器学习算法非常适合这项任务。然而,在这些情况下,我们引入了一个偏差,称为正则化或预测试,或特征选择偏差。在这篇和下一篇博文中,我试图解释偏见的来源和一个非常强大的解决方案,称为双去偏机器学习,这可能是过去十年中机器学习和因果推理交叉点上最相关的进步之一。

预测试

既然这是一个复杂的话题,那就从一个简单的例子开始吧。

假设我们是一家公司,我们对广告支出对收入的影响感兴趣:广告值得吗?还有很多其他因素可能会影响销售,因此,我们正在考虑在分析中控制过去的销售,以提高我们的分析能力。

假设数据生成过程可以用下面的 有向无环图(DAG) 来表示。如果你对 DAGs 不熟悉,我在这里写了一个简短的介绍。

数据生成过程的 DAG,按作者排序的图像

我从[src.dgp](https://github.com/matteocourthoud/Blog-Posts/blob/main/notebooks/src/dgp.py)导入数据生成过程dgp_pretest(),从[src.utils](https://github.com/matteocourthoud/Blog-Posts/blob/main/notebooks/src/utils.py)导入一些绘图函数和库。

from src.utils import *
from src.dgp import dgp_pretest

df = dgp_pretest().generate_data()
df.head()

作者图片

我们有关于 1000 个不同市场的数据,其中我们观察当前sales,在advertisementpast sales花费的金额。

我们想了解ads支出是否能有效增加sales。一种可能性是使用以下回归模型对前者进行回归,该回归模型也称为短模型

短回归,作者图片

我们是不是也应该把past sales it 纳入回归?那么回归模型将如下,也称为长模型

长回归,作者图片

由于我们不确定是否以past sales为条件进行分析,我们可以让数据决定:我们可以运行第二次回归,如果past salesβ 的影响在统计上是显著的,我们就可以使用长模型,否则,我们运行短模型。

smf.ols('sales ~ ads + past_sales', df).fit().summary().tables[1]

回归摘要,按作者分类的图像

看来past sales对电流sales的影响是积极而显著的。因此,我们对我们的规范感到满意,我们的结论是adssales的影响是积极且显著的,95%的置信区间为【0.912,1.029】。

偏见

这个过程有一个问题:我们没有考虑到这样一个事实,即我们已经运行了一个测试来决定是否将past_sales包括在回归中。我们决定包括past_sales的事实是因为它的系数是重要的对关于adssalesα 的影响的推断有影响。

理解问题的最好方法是通过模拟。由于我们可以访问数据生成过程dgp_pretest()(与现实生活中不同),我们可以测试如果我们多次重复这个过程会发生什么:

  1. 我们从数据生成过程中抽取一个新样本。
  2. 我们在adspast_sales上回归sales
  3. 如果past_sales的系数在 95%的水平上显著,我们从(2)中保留 α̂-long
  4. 否则,我们只对ads回归sales,并保持系数 α̂-short.

我写了一个pre_test函数来实现上面的程序。我还保存了两个回归的系数,long 和 short,选择的系数称为预测试系数

提醒:我们正在预测past_salessales的影响,但是adssales的影响系数。

我们现在可以绘制估计系数的分布图(通过模拟)。

α̂在模拟中的分布,图片由作者提供

在上面的图中,我已经描述了不同回归规格的模拟的估计系数。

正如我们从第一张图中看到的,如果我们总是运行长回归,我们的估计量 α̂-long 将是无偏的,并且是正态分布的。然而,如果我们总是运行短期回归(第二个图),我们的估计量 α̂-short 会有偏差

预测试程序生成一个估计量 α̂-pretest ,它是两者的混合:大多数时候我们选择正确的规格,长回归,但有时预测试无法拒绝past salessalesH₀:β=0 没有影响的零假设,我们选择不正确的规格,运行短回归。

重要的是,预测试程序不会产生有偏估计值。正如我们在最后一幅图中看到的,估计系数非常接近真实值 1。原因是,在大多数情况下,我们选择短回归的次数足够小,不会引入偏差,但也没有小到可以进行有效的推断。

的确,预测试扭曲了推论:估计量 α̂-pretest 的分布不再是正态分布,而是双峰分布。的后果是我们对于 α 的置信区间将会有错误的覆盖范围(包含真实的效应,其概率与声称的不同)。

什么时候预测试是个问题?

预测试的问题出现是因为运行短回归产生的偏差: 省略变量偏差(OVB) 。如果你不熟悉 OVB,我在这里写了一篇简短介绍。然而,一般来说,我们可以通过忽略 XD 回归 Y 引入的省略变量偏差表示为

作者图片

其中 βX (我们例子中的past sales)对 Y ( sales)的影响, δD ( ads)对 X 的影响。

预测试是一个问题如果

  1. 我们运行短回归而不是长回归
  2. 偏见的影响是明显的

有什么可以帮助提高(1),即正确拒绝past salesH₀:β=0 零效应零假设的概率?答案很简单:更大的样本量。如果我们有更多的观察,我们可以更精确地估计 β ,并且我们不太可能犯类型 2 错误并运行短回归而不是长回归。

让我们模拟不同样本量下的估计系数 α̂ 。记住,直到现在使用的样本大小是 N=1000

Ns = [100,300,1000,3000]
alphas = {f'N = {n:.0f}':  pre_testing(N=n)['Pre-test'] for n in Ns}
plot_alphas(alphas, true_alpha=1)

α̂在模拟中的分布,图片由作者提供

从图中我们可以看出,随着样本量的增加(从左到右),偏差减小,估计量 α̂-pretest 的分布收敛于正态分布。

如果 β 的值不同,会发生什么?这可能会影响上一段中的第(2)点,但如何影响呢?

  • 如果 β非常小的,将很难检测到它,我们将经常以运行回归而告终,从而引入偏差。然而,如果 β 非常小,这也意味着偏差的幅度很小,因此不会对我们对 α 的估计产生太大影响
  • 如果 β 非常大**,这将很容易被检测到,我们将经常结束运行回归,避免偏差(尽管偏差会非常大)。**

让我们模拟不同的 β 值下的估计系数 α̂ 。直到现在使用的真实值是 β=0.3

betas = 0.3 * np.array([0.1,0.3,1,3])
alphas = {f'beta = {b:.2f}':  pre_testing(b=b)['Pre-test'] for b in betas}
plot_alphas(alphas, true_alpha=1)

α̂在模拟中的分布,图片由作者提供

从图中我们可以看出,随着 β 值的增加,偏置先出现,然后消失。当 β 较小时(左图),我们往往选择短回归,但偏差较小,平均估计值非常接近真实值。对于 β 的中间值,偏差是明显的,对推断有明显的影响。最后,对于大值的 β (右图),我们总是运行长回归,偏差消失。

但是一个系数什么时候大或者小**?相对于什么来说是大还是小?答案很简单:相对于样本量,或者更准确地说,相对于样本量平方根的倒数 1/√n 。原因深植于中心极限定理,这里就不赘述了。**

这个想法展示起来容易解释起来难,所以让我们重复上面同样的模拟,但是现在我们将同时增加系数和样本量。

betas = 0.3 * 30 / np.sqrt(Ns)
alphas = {f'N = {n:.0f}':  pre_testing(b=b, N=n)['Pre-test'] for n,b in zip(Ns,betas)}
plot_alphas(alphas, true_alpha=1)

α̂在模拟中的分布,图片由作者提供

正如我们所见,既然 β1/√n 成正比,那么无论样本大小如何,失真都不会消失。所以推论永远是错的。

虽然取决于样本大小的系数可能听起来不直观**,但它很好地抓住了量级的概念,在这个世界上,我们依靠渐近结果进行推断,首先是中心极限定理。事实上,中心极限定理依赖于无限大的样本量。然而,对于无限量的数据,没有一个系数是小的,并且任何非零效应都可以确定地检测到。**

预测试和机器学习

到目前为止,我们讨论了只有两个变量的线性回归。答应我们的机器学习在哪里?

通常,我们不是只有一个控制变量(或混杂因素),而是很多。此外,对于这些控制变量进入模型所采用的函数形式,我们可能要灵活一些。一般来说,我们将假设以下模型:

作者图片

在利益效应仍然是 α 的情况下, X 可能是高维的,我们不会对 X 影响 DY 的函数形式采取立场。

在这种设置中,很自然地使用机器学习算法来估计 g₀m₀ 。然而,机器学习算法通常会引入与预测试相当的正则化偏差**。**

可能,“最简单”的思考方式是套索。Lasso 在 X 中是线性的,带有一个惩罚项,有效地执行我们上面讨论的变量选择。因此,如果我们在 Y 上使用 XD 的套索,我们将引入正则化偏差,推论将被扭曲。更复杂的算法也是如此。

最后,您可能仍然想知道“为什么模型在治疗变量 D 中是线性的?”。在线性模型中进行推断要容易得多,不仅是因为计算原因,也是因为解释原因。此外,如果处理 D 是二元的,则线性函数形式不失一般性。一个更强的假设是 Dg(X) 的加性可分性。

结论

在这篇文章中,我试图解释正则化偏差是如何出现的,以及为什么它会成为因果推理中的一个问题。这个问题本质上与具有许多控制变量的设置有关,或者当控制混杂因素时,我们希望有一个无模型(即非参数)的设置。这些正是机器学习算法可以发挥作用的设置。

在这篇文章的第二部分中,我介绍了一个简单却非常强大的解决方案:双去偏机器学习。

**

参考

[1] A. Belloni,D. Chen,V. Chernozhukov,C. Hansen,应用于征用权的最优工具的稀疏模型和方法 (2012),计量经济学

[2] A. Belloni,V. Chernozhukov,C. Hansen,高维对照中选择后对治疗效果的推断 (2014),《经济研究综述》

[3] V. Chernozhukov,D. Chetverikov,M. Demirer,E. Duflo,C. Hansen,W. Newey,J. Robins,用于治疗和结构参数的双/去偏置机器学习 (2018),《计量经济学杂志》

相关文章

  • 理解省略变量偏差
  • 理解弗里希-沃-洛弗尔定理
  • Dag 和控制变量

密码

你可以在这里找到 Jupyter 的原始笔记本:

https://github.com/matteocourthoud/Blog-Posts/blob/main/notebooks/pretest.ipynb

感谢您的阅读!

真的很感谢!🤗如果你喜欢这个帖子并且想看更多,可以考虑 关注我 。我每周发布一次与因果推断和数据分析相关的主题。我尽量让我的帖子简单而精确,总是提供代码、例子和模拟。

还有,一个小小的 免责声明 :我写作是为了学习所以错误是家常便饭,尽管我尽力了。当你发现他们的时候,请告诉我。也很欣赏新话题的建议!**

双重去偏机器学习(下)

原文:https://towardsdatascience.com/double-debiased-machine-learning-part-2-bf990720a0b2

因果数据科学

如何使用后双重选择消除正则化偏差

作者图片

在因果推断中,我们通常对治疗变量对特定结果的影响感兴趣。在随机对照试验或 AB 试验中,以一组其他变量——控制变量或协变量为条件进行分析,可以减少随机化后出现的不平衡,从而提高分析的功效。然而,条件作用在观察性研究中更为重要,在观察性研究中,如果没有随机化,可能对恢复因果关系至关重要。

通常,我们对分析的条件变量或函数形式没有强烈的意见,我们可能倾向于让数据决定,要么通过变量选择,要么通过灵活的机器学习方法。在这篇博文的的前一部分,我们已经看到了这种方法是如何扭曲推论的,例如,对感兴趣的因果效应产生错误的置信区间。这种偏差一般称为正则化偏差或预测试偏差。

在这篇博客文章中,我们将探索变量选择问题的解决方案,后双重选择,并且我们将介绍一种处理许多控制变量和/或非线性函数形式的通用方法,双重去偏置机器学习

概述

为了更好地理解偏见的来源,在这篇文章的第一部分,我们探讨了一家公司对测试广告活动的有效性感兴趣的例子。该公司有关于其当前广告支出和销售水平的信息。问题的出现是因为公司不确定是否应该以过去的销售水平作为分析的条件。

下面的 有向无环图 总结了数据生成过程。

我从[src.dgp](https://github.com/matteocourthoud/Blog-Posts/blob/main/notebooks/src/dgp.py)导入数据生成过程dgp_pretest(),从[src.utils](https://github.com/matteocourthoud/Blog-Posts/blob/main/notebooks/src/utils.py)导入一些绘图函数和库。

from src.utils import *
from src.dgp import dgp_pretest

df = dgp_pretest().generate_data()
df.head()

作者图片

我们有 1000 个不同市场的数据,我们观察当前的sales,在advertisementpast sales花费的金额。

我们想了解ads支出是否能有效增加sales。一种可能性是使用以下回归模型,也称为短模型,在前者的基础上回归后者。

短模型,作者图片

我们是否应该将past sales也包括在回归中?那么,回归模型将如下,也称为长模型

长模型,作者图片

一种简单的方法是让数据决定:我们可以运行第二次回归,如果past salesβ̂ 的估计效果在统计上是显著的,我们就可以使用长模型,否则我们运行短模型。该程序称为预测试

这个程序的问题是它引入了一个偏差,称为正则化或预测试偏差。预测试确保该偏差足够小,不会扭曲估计的系数。但是,它不能确保它足够小,不会扭曲估计系数周围的置信区间。

有解决办法吗?是啊!

双重选择后

解决方案叫做后双选。该方法首先由 Belloni,Chernozhukov,Hansen (2014) 提出,后来在以 Victor Chernozhukov 为共同标准的各种论文中得到扩展。

作者假设以下数据生成过程:

数据生成过程,按作者分类的图像

在我们的例子中, Y 对应于salesD 对应于adsX 对应于past_sales,利益效应为 α 。在我们的例子中,为了简单起见, X 是一维的,但是一般来说,我们对 X 是高维的情况感兴趣,甚至有可能比观察的数量更多的维度。在这种情况下,变量选择在线性回归中非常重要,因为我们不能拥有比变量更多的特征(OLS 系数不是唯一确定的)。

双重选择后由以下程序组成。

  1. 缩小形式选择:套索 YX 。选择集合中的统计显著变量 S₁ ⊆ X
  2. 第一阶段选择:在 X 上后退 D 。选择集合中的统计显著变量 S₂ ⊆ X
  3. 回归前两步中所选变量的 D 上的 Y并集s₁s₂

作者表明,该程序给出了估计的感兴趣系数 α̂ 的置信区间,其具有正确的覆盖范围,即 1 型错误的正确概率。

注(1) :就变量选择而言,该程序总是比预测试更少节约。事实上,我们仍然选择所有我们在预测试中选择的变量,但是,在第一阶段,我们可能会选择额外的变量。

注(2) :术语第一阶段约化形式来自计量经济学中的工具变量文献。的确,后双选择的第一个应用是在 Belloni,Chen,Chernozhukov,Hansen (2012) 中选择工具变量。

注(3) :双重选择后这个名字来源于这样一个事实,现在我们不是执行一次变量选择,而是执行两次*。*

直觉

后置双选背后的思路是:绑定 省略变量 bias 。以防你不熟悉,我写了一篇关于省略变量 bias 的单独的博文。

在我们的设置中,我们可以将省略的变量 bias 表示为

省略可变偏差,图片由作者提供

我们可以看到,省略变量 bias 来自于与省略变量 X 相关的两个量的乘积:

  1. 其与结果的偏相关 Yβ
  2. 其与治疗的偏相关 Dδ

通过预测试,我们确保 X 和结果 Yβ 之间的偏相关为。事实上,我们很少忽略不应该忽略的 X (例如,我们犯了类型 2 错误)。很少是什么意思?

当我们因为变量的重要性而选择变量时,我们确保对于某个数字 c ,它的维数小于 c/√n ,其中 n 是样本大小。因此,通过预测试,我们确保无论 δ 的值是多少,偏置的大小都小于 c/√n 。这意味着对于足够大的 n ,它收敛到零。这就是为什么预测试估计量仍然一致,即对于足够大的样本量 n 收敛到真实值。

然而,为了让我们的置信区间有正确的覆盖范围,这是不够的。在实践中,我们需要偏置比 1/√n 更快地收敛到零。为什么?

为了得到这个结果的一个直觉,我们需要求助于中心极限定理。CLT 告诉我们,对于大样本量 n ,随机变量 X 的样本均值分布收敛于均值 μ 和标准差 σ/√n 的正态分布,其中 μσX 的均值和标准差。为了进行推断,我们通常将中心极限定理应用于我们的估计量,以获得其渐近分布,这反过来允许我们建立置信区间(使用均值和标准差)。因此,如果偏差没有明显小于估计量的标准差,置信区间就是错误的。因此,我们需要偏差比标准偏差更快地收敛到零*,即比 1/√n 更快。***

在我们的设置中,省略的变量 bias 是 βδ ,我们希望它比 1/√n 更快地收敛到零。后双重选择保证了

  • **简化形式选择:任何“缺失”变量 j|βⱼ| ≤ c/√n
  • **第一阶段选择:任何“缺失”变量 j|δⱼ| ≤ c/√n

因此,只要省略变量的数量是有限的,省略变量 bias 将以比 1/√n 更快的速度 1/n 收敛到零。问题解决

应用

现在让我们回到我们的例子,测试后双选择程序。在实践中,我们希望做到以下几点:

  1. 第一阶段选择:在past_sales上回归ads。检查past_sales是否有统计学意义
  2. 缩小形式选择:在past_sales上回归sales。检查past_sales是否具有统计显著性
  3. ads上回归sales,并且仅当在前两个回归中的一个中有意义时,才包括past_sales

我从文章的第一部分更新了pre_test函数来计算双选择后的估计量。

我们现在可以绘制估计系数的分布图(通过模拟)。

α̂的分布,图片由作者提供

正如我们所看到的,双重选择后的过程总是正确地选择长回归,因此估计量具有正确的分布。

双重检查

在上一篇文章中,我们运行了一些模拟来研究预测试偏差何时出现。我们看到预测试是一个问题

  • 小样本量 n
  • β 的中间值
  • β 的值取决于样本量时

让我们检查后双重选择是否消除了所有先前案例中的正则化偏差。

首先,让我们模拟不同样本量的后双选择估计量 α̂-postdouble 的分布。

***Ns = [100,300,1000,3000]
alphas = {f'N = {n:.0f}':  pre_test(N=n) for n in Ns}***

我们现在可以画出并比较验前估计量和验后加倍估计量的分布。

α̂的分布,图片作者

对于小样本,预测试估计量的分布不是正态分布,而是双峰分布。相反,双精度后估计量在小样本情况下也是高斯型的。

现在我们重复同样的练习,但是对于 β 的不同值,即past_salessales的系数。

***betas = 0.3 * np.array([0.1,0.3,1,3])
alphas = {rf'$\beta$ = {b:.2f}': pre_test(b=b) for b in betas}
compare_alphas(alphas, true_alpha=1)***

α̂的分布,图片作者

同样,无论 β 的值如何,双选择后估计器都具有高斯分布,而预测试估计器则存在正则化偏差。

对于最后的模拟,我们同时改变系数和样本大小。

***betas = 0.3 * 30 / np.sqrt(Ns)
alphas = {rf'N = {n:.0f}, $\beta$ = {b:.2f}':  pre_test(b=b, N=n) for n,b in zip(Ns,betas)}
compare_alphas(alphas, true_alpha=1)***

α̂的分布,图片作者

此外,在最后一种情况下,后双精度选择在模拟中具有正确的高斯分布。

双重去偏机器学习

到目前为止,我们只分析了一个线性的单变量例子。如果 X 的维数增加,我们不知道 X 通过什么函数形式影响 YD 会发生什么?在这些情况下,我们可以使用机器学习算法来揭示这些高维非线性关系。

Chernozhukov、Chetverikov、Demirer、Duflo、Hansen、Newey 和 Robins (2018) 调查这一设置。特别地,作者考虑了下面的部分线性模型。

数据生成过程,按作者分类的图像

其中 Y 是结果变量, D 是对兴趣的处理, X 是潜在的高维控制变量集。与之前设置的区别在于,现在我们通过函数 g()m()XYD 之间的关系置为未指定。

天真的方法

使用机器学习方法来估计 α 的一种简单方法是,例如,构建一个复杂的机器学习估计器来学习回归函数 αD + g(X)

  1. 将样本一分为二:主样本和辅助样本(为什么?参见下面的注释)
  2. 使用辅助样本来估计 ĝ(X)
  3. 使用主样本计算 YX 上的正交分量:

作者图片

4.在 D 使用主样本估计回归 的剩余 OLS 估计量

作者图片

这个估算器会有两个问题:

  1. 收敛速度慢,即比 √n
  2. 它会有偏差,因为我们采用了高维正则化估计量(例如,我们正在做变量选择)

注(1) :到目前为止我们还没有谈到,但是变量选择程序还引入了另一种类型的偏倚:过拟合偏倚。这种偏差的出现是因为用于选择变量的样本与用于估计感兴趣系数的样本是相同的。这种偏差很容易通过样本分割解决:在选择和估计过程中使用不同的子样本。

注(2) :为什么可以用第三步的残差来估计第四步的 α ?因为弗里希-沃-洛弗尔定理。如果你不熟悉它,我已经在这里写了一篇关于弗里希-沃-洛弗尔定理的博文。

双重正交化

双去偏机器学习通过重复正交化过程两次来解决问题。双重选择后的想法是相同的:通过执行两次变量选择来减少正则化偏差。由于弗里希-沃-洛弗尔定理,估计器仍然有效。

实际上,双去偏机器学习由以下步骤组成。

  1. 将样品一分为二:主样品和辅助样品
  2. 使用辅助样本估计 ĝ(X)

作者图片

3.使用辅助样本从下式估计

作者图片

4.使用主样本计算 DX 上的正交分量为

作者图片

5.使用主样本估计双剩余 OLS 估计量为

作者图片

估计量是根-N 一致*!这意味着,随着样本量的增加,不仅估计量收敛到真实值(即它是一致的),而且它的标准差也收敛到真实值(即它是根-N 一致的)。***

然而,由于样本分裂,估计器仍然具有较低的收敛速度。该问题通过反转分割样本、重新估计系数并对两次估计取平均值来解决。请注意,这一程序是有效的,因为两个估计是独立的样本分裂程序。

警示故事

在我们结束之前,我必须提到最近由 Hünermund,Louw 和 Caspi (2022) 发表的一篇研究论文,其中作者表明,如果盲目应用,双去偏置的机器学习很容易适得其反*。***

问题与坏的控制变量有关。如果你从未听说过这个术语,我已经在这里写了一篇关于好的和坏的控制变量的介绍性的博文。简而言之,以额外特征为分析条件并不总是有利于因果推断。根据不同的设置,可能存在一些我们想在分析中忽略的变量,因为它们的包含可能会使兴趣系数产生偏差,从而妨碍因果解释。最简单的例子是治疗变量 D 和结果变量 Y 的常见结果变量。

双去偏机器学习模型隐含地假设控制变量 X 是结果 Y 和治疗 D 的(弱)共同原因。如果是这种情况,并且在 XY 之间不存在进一步的中介/间接关系,则没有问题。但是,例如,如果控制 X 中的某个变量是一个共同的结果,而不是一个共同的原因,那么它的包含将会使感兴趣的系数产生偏差。此外,该变量可能与结果 Y 或治疗 D 高度相关。在后一种情况下,这意味着后双重选择可能会包括它,而在简单选择的情况下则不会。因此,在存在不良控制变量的情况下,双去偏的机器学习可能比简单的预测试更糟糕。

简而言之,对于任何方法来说,至关重要的是清楚地理解该方法的假设,并始终检查潜在的违规行为。

结论

在这篇文章中,我们看到了如何使用后双重选择,更一般地说,双重去偏置机器学习来消除偏置的一个重要来源:正则化偏置。

Victor Chernozhukov 及其合作者的这一贡献无疑是过去十年中因果推理最相关的进步之一。它现在被业界广泛采用,包含在最常用的因果推理包中,如 EconML (微软)和 causalml (优步)。

如果你(可以理解)觉得需要更多关于双去偏置机器学习的材料,但你不喜欢阅读学术论文(也很容易理解),这里有一个很好的妥协。

在这个视频讲座中,Victor Chernozhukov 亲自介绍了这个想法。视频讲座相对偏重于数学和统计,但你不可能得到比这更合格和直接的来源!

参考

[1] A. Belloni,D. Chen,V. Chernozhukov,C. Hansen,应用于征用权的最优工具的稀疏模型和方法 (2012),计量经济学

[2] A. Belloni,V. Chernozhukov,C. Hansen,(2014),经济研究综述

[3] V. Chernozhukov,D. Chetverikov,M. Demirer,E. Duflo,C. Hansen,W. Newey,J. Robins,用于治疗和结构参数的双/去偏置机器学习 (2018),计量经济学杂志

[4] P. Hünermund,B. Louw,I. Caspi,双机器学习和自动化混杂选择——一个警示故事 (2022),工作论文

相关文章

  • 双去偏机器学习(第一部分)
  • 理解省略变量偏差
  • 理解弗里希-沃-洛弗尔定理
  • Dag 和控制变量

密码

你可以在这里找到 Jupyter 的原始笔记本:

***https://github.com/matteocourthoud/Blog-Posts/blob/main/notebooks/pds.ipynb ***

感谢您的阅读!

我真的很感激!🤗如果你喜欢这个帖子并且想看更多,可以考虑 关注我 。我每周发布一次与因果推断和数据分析相关的主题。我尽量让我的帖子简单而精确,总是提供代码、例子和模拟。**

还有,一个小小的 免责声明 :我写作是为了学习所以出错是家常便饭,尽管我尽力了。当你发现他们的时候,请告诉我。也很欣赏新话题的建议!

人工智能的新旧视角及其对知识产权纠纷的影响

原文:https://towardsdatascience.com/double-descent-and-ml-models-as-generalized-database-indexes-5d3b1db49b5b

像 Github copilot、GPT-3 和 DALLE2 这样的模型是否模糊了机器学习和传统搜索索引之间的界限?

介绍

工程师们学习数据库以及如何使它们能够被有效地查询;数据科学家学习如何建立统计模型,以及如何使他们的预测更准确…这两者永远不会相遇。这篇文章的目标是挑战这种观念,特别是在 LLM 的一些有趣属性的背景下,并沿着用于查询数据群体的数据结构和算法的连续体来看待这两者。

数据库索引允许您使用输入键确定性地搜索数据集;机器学习模型基于输入特征搜索一般人群(它被视为其中的一部分)。此外,人工智能和 LLM 的巨大飞跃颠覆了一些关于机器学习模型可以有多灵活的基本假设,同时仍然保持对人群进行概括的能力。从这些模型运行的规模来看,类似搜索引擎的用例已经出现,为数据库和机器学习之间看似抽象的联系提供了现实世界和法律利益(见最近对微软的集体诉讼)。

空间换时间

数据库索引是一种数据结构,允许您高效地遍历大型数据集;它用时间(你将等待寻找一个项目)换取空间(你用空间存储关于如何找到那个项目的附加信息)。标准的基于树的索引允许您在log(N)时间压缩它的分支,而不是在N时间扫描原始表。这些捷径基本上是有方向的:给定这个主键或辅键的值,我应该移动到哪里才能命中数据集中最近的目标?很简单。

作为超适合机器学习模型的数据库索引

监督机器学习模型也在数据集之上构建结构,目标是在原始集中的数据之外进行归纳。他们不再习惯于发现,而是习惯于推断预测。我们可以将这些模型视为索引的一般化:它不是基于提供的特征在您的样本中找到匹配元素,而是预测或推断总体中最接近的元素。

监督机器学习模型传统上比数据库索引更小、更严格,因为它们的目标是超越可用数据进行归纳,用方差换取偏差。如果您不需要对现有的数据进行归纳,您只需要使用数据库索引!(这实际上是很多渴望进入数据科学的企业没有考虑到的事情。)

考虑到这种心理模型,数据库索引只是一个完全过度拟合的监督模型:它根本不能超越它所看到的数据进行归纳,但它能很好地在给定的X样本中找到任何y…所有方差没有偏差。

除了偏差-方差权衡…双重下降

因此,我们可以将 ML 模型视为人口数据的指数,但是,在传统的统计建模中,您必须用足够的方差来换取偏差,从功能上来说,它看起来完全不像指数,这种类比只是一篇博客文章的有趣思想实验。

来源:https://arxiv.org/pdf/1912.02292.pdf

如果你不需要做这样的权衡,这个类比能让我们走多远?对于尖端的深度神经网络,这种折衷并不总是存在。根据 OpenAI 的研究,在某些条件下,“过度拟合”一个模型(或者继续训练远远超过传统统计建议的折衷曲线上的点)会提高测试数据的性能。超过插值阈值后,模型只会变得越来越好。还没有完全理解为什么模型会这样做,因为一旦训练误差为零,目标函数就不会为模型变得更好提供明显的“激励”。但是让我试着提供一个直觉…

一个看似合理的解释是统计学上的:神经网络是一个通用的函数逼近器,并且“好”模型(阅读那些可以有效插值的模型)比“坏”模型(那些貌似符合训练数据但在现实生活中表现不佳的模型)多得多。此外,过参数化模型更加灵活,能够为特定训练集生成比有效的更小模型(即,更少的拟合参数)更多的模型候选。因此,随着非零模型参数数量的增加,解空间变得更大,选择“好”模型的可能性变得更大。

大型语言模型作为搜索引擎的含义

当你运行谷歌图片搜索时,该引擎会返回最有可能匹配你的关键词的索引图片的子集。当你在 DALLE 2 中输入一个提示时,一个扩散过程迭代地向一个图像工作,该图像基于在训练时看到的字幕-图像对最大化输入单词的概率。原始论文指出,“为了扩展到 120 亿个参数,我们通过从互联网上收集 2.5 亿个文本-图像对,创建了一个类似于 300M (Sun et al .,2017)规模的数据集。”

在这种情况下,谷歌搜索和 DALLE 2 提示看起来没什么不同。抛开算法差异不谈,用户体验的核心差异是 DALLE 2 能够零拍摄图像生成,而谷歌搜索只能返回之前看到的内容。由 GPT-3 驱动的 Github copilot 以类似的方式对开源代码进行操作,从大规模参数化模型中生成“新颖”代码片段。

一个用 DALLE 2 武装起来的作家能为他们的漫画书生成看起来可疑地像来自漫威宇宙的东西的小说标题吗?我不是律师,但是,如果我要反对这种权利,我会使用数据库索引和机器学习之间的类比。机器学习只是对关于数据集的信息进行编码的许多方法之一。直到最近,它看起来一点也不像传统的数据库。但讽刺的是,现在的规模和复杂程度揭示了贯穿线。

对最有价值的客户加倍下注

原文:https://towardsdatascience.com/double-down-on-the-most-valuable-customers-c6ad97689595

利用数据科学定义您的理想客户概况(ICP)

在用数据科学抓住商业中唾手可得的果实中,我提到公司可以通过削减表现不佳的计划来获得巨大的增长机会。纵观各行各业,这些失败的计划都是从错误的受众开始的。例如,如果一家电子产品初创公司试图赢得保守的消费者,它的活动将不会产生什么回报。

发现理想客户档案(ICP) 通常比预期更具挑战性。在采访了数百家公司后,很少有人能说出他们 ICP 的足够细节,以至于销售和营销团队可以采取行动来吸引那些马上适合 ICP 的访问者。没有明确的 ICP,企业会无意识地浪费宝贵的资源去追逐不可能的前景。

在这篇文章中,我将谈谈如何借助数据科学来定义 ICP。

你理想的客户档案(ICP)是怎样的?

正如罗伯特凯利教授在他的书关键路径宣言中讨论的那样,所有的商业活动都应该与关键路径保持一致:为公司创造更多的收入或降低成本。因此,ICP 描述了为公司带来最长期价值的客户。

由于每个公司都有不同的商业模式,其对客户长期价值的定义也各不相同。为了简单起见,我将使用下面的公式来测量值。

客户的长期价值=客户重复购买的收入—其获取成本

有了适当的数据跟踪机制,您可能会看到如下的客户价值分布。

作者图片

负价值群体和低价值群体中的来访者多于高价值群体和中等价值群体中的来访者。这两个组之间的划分通常遵循 80/20 规则。在收到广告或浏览公司网站的访问者中,只有 20%或更少的人完成一次或多次购买。

那 20%是什么样子的?

找出那 20%是每个公司的梦想;即使那些接近找到它的人也能迅速扩大他们的业务。让我们从小处着手,分析高价值群体,以清楚地了解这 20%的人群。

客户细分是这类分析中最常见的方法。为了说明这种方法,我将继续开头提到的 gadget 启动示例。

两年多来,这家初创公司通过营销活动、浏览历史、购买历史、优惠券使用记录等来跟踪每个访问者的互动。对于每个访问者,创业公司收集 100+属性。通过主成分分析、聚类和其他算法,高价值群组可以进一步细分为三个较小的群组,每个群组的属性分布如下所示。

作者图片

虽然算法可以自动生成群组,但解读群组依赖于企业经营者的行业和产品知识。在这个例子中,他们很快得出结论,第 1 组喜欢购买最新型号,第 2 组喜欢打折购买,第 3 组经常购买作为礼物。

如何吸引那 20%的人

除了这些标签之外,访问者与营销活动的互动等属性暗示了如何吸引他们;他们的浏览历史揭示了他们对客户体验偏好的细节。有了这些认识,公司可以调整方法来吸引每个高价值群体。

  • 根据客户偏好调整产品和信息

利用数据,这个小工具创业公司可以为每个产品和每个客户群个性化其营销信息。例如,历史数据显示,群组 1 对关于酷极客功能的活动反应积极。另一方面,第二组更多地参与宣传使用新设备的实际好处的活动。

  • 在顾客出现的地方展示产品

群组 1 和群组 2 可能转向不同的地方购买他们的电子产品。例如,群组 1 可能会信任那些谈论最新最棒的科技产品并在观看拆箱视频后进行购买的 YouTubers。与此同时,第二代人喜欢去好市多(Costco)购物,购买打折的小玩意。因此,与技术影响者合作有助于公司吸引第一批顾客,而与批发商店合作可以加快向第二批顾客的销售。

关注最有价值的客户

作者图片

你可能已经发现,发现和吸引每个高价值的子群体需要付出巨大的努力。然而,获得客户并不是故事的结尾。收购后留住这些客户也需要优质的服务。由于每个公司都必须处理的资源限制,如果公司将资源分散到各个方面,那么公司对其有价值客户的服务将受到负面影响。

你还想把注意力花在那 80%的人群上吗?

在接下来的文章中,我将继续深入客户获取主题。如果你同时想聊聊他们,请随时通过 Linkedin 联系我。

使用 Python 从 CHRS 数据门户下载雨量卫星数据

原文:https://towardsdatascience.com/download-rainfall-satellite-data-from-chrs-data-portal-using-python-1055d55bef0d

教程-使用 Python 模块轻松查询和下载降雨卫星数据以进行快速分析

使用 Python 从 CHRS 数据门户下载雨量卫星数据。CHRS 制作的 iRain 工具截图。

降雨量是几个用例的重要指标,包括农业生产率增长分析、气候变化分析等。了解一个地区的降雨模式和波动有助于制定农业季节的战略计划。

有几个数据源提供降雨卫星数据。CHRS 门户网站是其中之一,它提供基于遥感卫星数据的全球降雨指标。在本教程中,让我们看看如何使用 python 从 CHRS 数据门户下载降雨卫星数据。

我的其他文章:

https://www.samashti.space/articles/why-you-need-to-use-geopackage-files-instead-of-shapefile-or-geojson https://www.samashti.space/articles/how-to-use-qgis-spatial-algorithms-with-python-scripts

什么是 CHRS?

CHRS 代表水文气象和遥感中心。这是一个由加州大学欧文分校(UCI)建立的中心。CHRS 大学在其教师和研究人员的帮助下,建立了一系列旨在解决水文过程相关问题的产品/系统。这些产品利用遥感数据和机器学习(神经网络)模型来了解和预测各种活动对水资源的影响。

CHRS 数据门户通过多个项目提供降水和相关产品。例如, PERSIANN (使用人工神经网络从遥感信息中估计降雨量)系统根据遥感数据计算降雨量的估计值。其他系统还有 PERSIANN-CCS , PERSIANN-CDR ,PDIR-现在, PERSIANN-CCS-CDR 。这些数据公布在公共领域,供所有人使用。

💡注:CHRS 还提供了两个探索性工具来直接在浏览器上可视化数据— iRain 、 RainSphere 。

[计]元数据

佩尔夏恩

**数据周期:**2000 年 3 月至今

**覆盖范围:**60° S 至 60 N

分辨率: 0.25 x 0.25

HTTP 下载(全地球): 每小时一次、 3 小时一次、 6 小时一次、 每天一次、 每月一次、 每年一次

FTP 也可用:ftp://persiann.eng.uci.edu/CHRSdata/PERSIANN

**最新更新:**接近实时,延迟 2 天

PERSIANN-CCS

数据周期:2003 年 1 月至今

**覆盖范围:**60° S 至 60 N

**分辨率:**0.04×0.04

HTTP 下载(全地球):每小时一次, 每小时三次, 每天一次, 每月一次, 每年一次

**FTP 也可用:**ftp://persiann.eng.uci.edu/CHRSdata/PERSIANN-CCS

**最新更新:**实时

PERSIANN-CDR

数据周期:1983 年 1 月至今

**覆盖范围:**南纬 60°至北纬 60°

分辨率: 0.25 x 0.25

HTTP 下载(全地球): 每日、 每月、 每年

**FTP 也可用:**ftp://persiann.eng.uci.edu/CHRSdata/PERSIANN-CDR

3hr PERSIANN-CDR:3hr PERSIANN-CDR, 自述

**最新更新:**2020 年 9 月

PDIR-现在

**数据周期:**2000 年 3 月 1 日至今

覆盖范围: 60 S 到 60 N

**分辨率:**0.04×0.04

HTTP 下载(全地球):每小时一次, 每小时三次, 每天一次, 每月一次, 每年一次

数据文件格式: PDIRNow 自述文件

**FTP 也可用:**ftp://persiann.eng.uci.edu/CHRSdata/PDIRNow

下载数据

在门户上查询数据

任何用户都可以通过在 CHRS 数据门户上创建查询来下载全球任何地方的降雨卫星数据。对于每个数据集,您可以从下拉列表中选择可用的时态粒度,并选择过滤域。过滤域可以是全球、任何特定的国家、地区或位置。您甚至可以提供一个 shapefile 来查询数据。

从 CHRS 数据门户查询数据以下载降水数据。查询工具作者截图。

选择时间步长、属性域和数据集后,提供开始和结束日期以及可用选项(ArcGrid、NetCDF、Tif)中的下载数据格式。

查询 2021 年 PERSIANN 数据的示例,粒度为全球每月。查询工具作者截图。

完成查询的详细信息并单击下载按钮后,您将被带到一个对话框,提供电子邮件地址。成功提交后,您将通过电子邮件收到一个链接,通过提供的地址下载数据。

在提示中提供电子邮件地址。您应该会收到一封邮件,其中包含所查询数据的下载链接。查询工具作者截图。

您需要手动浏览用户界面来查询数据,并通过电子邮件提示流程下载数据。此外,下载链接是通过电子邮件发送的,这只会减慢下载过程。还有一种替代方法,你可以通过它下载数据,以避免电子邮件的提示。

HTTP 下载

CHRS 还通过一个 HTTP 服务器提供数据,你可以用它来下载数据。根据每个数据集的可用时间步长,可用数据适用于整个地球。您可以参考上面的元数据部分,以获得可用时间步长及其各自 HTTP 服务器链接的概述。

HTTP 服务器上 PERSIANN 系统的每日降雨量数据。作者提供的 HTTP 服务器的截图。

虽然这种方法可以帮助您克服电子邮件验证过程,但是您必须手动下载每个观察的文件。与您可以在 UI 上进行的灵活查询相比,数据可以以“. bin.gz”格式提供。

使用 Python

上述两种方法都有一些局限性。因此,我使用 python 构建了一个实用程序库来处理从 CHRS 数据门户查询和下载降雨卫星数据。实用程序库 chrs-persiann-util 让您可以查询不同时间步长和文件格式的可用数据集。

https://github.com/samashti/chrs-persiann-util

要安装这个库,请将 GitHub 项目克隆到您的本地,并从您的终端的根目录运行以下命令;

python setup.py install

或者,您也可以直接从 Github 链接安装;

pip install git+https://github.com/samashti/chrs-persiann-util.git

安装完成后,您可以使用该库下载数据,如下所示:

from chrs_persiann import CHRSparams = {
    'start': '2021010100',
    'end': '2021010300',
    'mailid': 'test@gmail.com',
    'download_path': '~/Downloads',
    'file_format': 'Tif',
    'timestep': 'daily',
    'compression': 'zip'
}dl = CHRS()# PERSIANN
dl.get_persiann(**params)

在 Github 上阅读更多关于库和输入查询参数标准的用法。

下载和可视化降雨数据

让我们来看一下一月份的降雨量卫星数据。你也可以在 Google Colab 上找到这个例子。

https://colab.research.google.com/drive/1erI4OIrZZkqQfz5FEzmp_q4nxD7PcHnc?usp=sharing

让我们首先初始化所需的 python 模块。我们使用 rasterio 来读取下载后的栅格数据。

import rasterio
import zipfile
from chrs_persiann import CHRS

在这里,我们想下载 2022 年 1 月的个人数据。因此,我将相应的查询参数传递给实用程序库,并下载 zip 格式的降雨卫星数据。

params = {
    'start': '2021010100',
    'end': '2021013100',
    'mailid': 'test@gmail.com',
    'download_path': '/home/',
    'file_format': 'Tif',
    'timestep': 'monthly',
    'compression': 'zip'
}dl.get_persiann(**params)

您应该可以在日志中看到正在进行的查询和订购过程,如下所示;

Querying data & Placing the order...
Query Params:start date - 2021010100
end date - 2021013100
time step - monthly
data type - PERSIANN
file format - Tif
compression format - zip
download path - /home/Query complete.
Order Details - User IP: 108598346, File: 2022-03-10074331am
Generating Data url...
File url Generated - <https://chrsdata.eng.uci.edu/userFile/108598346/temp/PERSIANN/PERSIANN_2022-03-10074331am.zip>
Downloading compressed data file - /home/PERSIANN_2022-03-10074331am.zip
Download Complete ------------------------------------------

现在,我们检查下载的 zip 文件并查看可用的光栅文件。

file = '/home/PERSIANN_2022-03-10074331am.zip'
z = zipfile.ZipFile(file)
z.filelist

我们看到PERSIANN_1m202101.tif是 zip 文件内容的一部分,我们有兴趣使用 rasterio 读取这个文件。

rasterfile = z.filelist[0].filename
raster = rasterio.open(f'/vsizip/{file}/{rasterfile}')

成功读取栅格后,我们可以利用 rasterio 和 matplotlib 库快速可视化栅格。

from rasterio.plot import show
from matplotlib import pyplot as pltfig, ax = plt.subplots(figsize=(30,9))# use imshow so that we have something to map the colorbar to
image_hidden = ax.imshow(raster.read(1), cmap='viridis')# plot on the same axis with rio.plot.show
image = show(raster.read(1), transform=raster.transform, ax=ax, cmap='viridis')# add colorbar using the now hidden image
fig.colorbar(image_hidden, ax=ax)

2022 年 1 月全球 CHRS 降雨数据。图片作者。

摘要

在这个快速教程中,我们学习了如何通过多种方法从 CHRS 门户网站下载降雨卫星数据,包括使用 python 模块。chrs-persiann-util 将帮助您对数据集进行查询,并从您的代码中下载进行快速分析。如果您喜欢试验代码,您可以查看这个 Google Colab 笔记本上的代码。

https://colab.research.google.com/drive/1erI4OIrZZkqQfz5FEzmp_q4nxD7PcHnc?usp=sharing

如果你喜欢这个博客,喜欢&订阅博客,以获得关于未来博客帖子的通知。如有任何疑问或讨论,你可以在 LinkedIn 和 Twitter 上找到我。

阅读其他帖子:

https://www.samashti.space/articles/how-to-geocode-addresses-for-free https://www.samashti.space/articles/why-geospatial-data-is-the-way-forward-in-data-analytics

使用 PyTorch 下载和使用 ImageNet 数据集

原文:https://towardsdatascience.com/downloading-and-using-the-imagenet-dataset-with-pytorch-f0908437c4be

使用最流行的研究数据集训练您的影像分类模型

由 Unsplash 上的离子场效应晶体管拍照

ImageNet 是计算机视觉研究中最流行的数据集。图像数据集包含在 WordNet 层次结构中找到的所有种类的收集图像。168 GB 的大型数据集包含 130 万张图像,分为 1,000 个类别,具有不同的标签分辨率粒度。例如,它包含飞机和狗的类别,但也包含不同狗品种的类别,这些类别甚至很难对人类进行分类。ImageNet 可用于分类和对象检测任务,并在默认情况下提供训练、验证和测试分割。

你可能听过 ImageNet、ImageNet1k、ImNet、ILSVRC2012、ILSVRC12 等术语。被利用了。它们都引用了为 ILSVRC 2012 竞赛引入的相同数据集。但是,我应该提到,它只是完整 ImageNet 的一个子集,以“ImageNet21k”的名称存在。ImageNet21k 偶尔用于预训练模型。

最初,ImageNet 托管在 www.image-net.org 的,,然后数据集私有化,网站进入维护阶段,最后再次公开,但现在只能根据请求下载。在过去的几年里,我肯定申请了十几次,但都没有成功。下载 ImageNet 似乎是一次漫长的旅程。

最近,组织者举办了一场基于原始数据集的 Kaggle 挑战赛,增加了用于对象检测的标签。因此,数据集是半公开的:https://www . ka ggle . com/competitions/imagenet-object-localization-challenge/

要下载数据集,您需要注册一个 Kaggle 帐户并加入挑战。请注意,这样做意味着您同意遵守竞赛规则。特别是,您只能将数据集用于非商业研究和教育目的。

然后,安装 Kaggle CLI:

pip install kaggle

现在您需要设置您的凭证。这一步非常重要,否则,你将无法开始下载。请遵循官方指南:

要使用 Kaggle API,请在https://www.kaggle.com注册一个 Kaggle 账户。然后转到您的用户配置文件(https://www.kaggle.com/<username>/account)的“帐户”选项卡,并选择“创建 API 令牌”。这将触发下载kaggle.json,一个包含您的 API 凭证的文件。将这个文件放在位置~/.kaggle/kaggle.json(在 Windows 上的位置C:\Users\<Windows-username>\.kaggle\kaggle.json——你可以用echo %HOMEPATH%检查确切的位置,sans drive)。您可以定义一个 shell 环境变量KAGGLE_CONFIG_DIR来将这个位置更改为$KAGGLE_CONFIG_DIR/kaggle.json(在 Windows 上是%KAGGLE_CONFIG_DIR%\kaggle.json)。

完成后,您就可以开始下载了。请注意,此文件非常大(168 GB),下载将需要几分钟到几天的时间,这取决于您的网络连接。

kaggle competitions download -c imagenet-object-localization-challenge

下载完成后,你解压文件。对于 Unix,只需使用unzip。请注意,这也需要一段时间。

unzip imagenet-object-localization-challenge.zip -d <YOUR_FOLDER>

我们还需要两个小的辅助文件。您可以独立地重写下面的代码,但是简单地使用这些文件会更快更简单。因此,只需将它们下载到 ImageNet 根文件夹(包含 ILSVRC 文件夹的那个文件夹)中。如果你在 Unix 系统下,你可以使用wget:

cd <YOUR_FOLDER>
wget [https://raw.githubusercontent.com/raghakot/keras-vis/master/resources/imagenet_class_index.json](https://raw.githubusercontent.com/raghakot/keras-vis/master/resources/imagenet_class_index.json)
wget [https://gist.githubusercontent.com/paulgavrikov/3af1efe6f3dff63f47d48b91bb1bca6b/raw/00bad6903b5e4f84c7796b982b72e2e617e5fde1/ILSVRC2012_val_labels.json](https://gist.githubusercontent.com/paulgavrikov/3af1efe6f3dff63f47d48b91bb1bca6b/raw/00bad6903b5e4f84c7796b982b72e2e617e5fde1/ILSVRC2012_val_labels.json)

我们现在需要做的就是为 PyTorch 编写一个Dataset类。我认为实际的代码加载起来很无聊,所以我就不赘述了。

import os
from torch.utils.data import Dataset
from PIL import Image
import jsonclass ImageNetKaggle(Dataset):
    def __init__(self, root, split, transform=None):
        self.samples = []
        self.targets = []
        self.transform = transform
        self.syn_to_class = {}
        with open(os.path.join(root, "imagenet_class_index.json"), "rb") as f:
                    json_file = json.load(f)
                    for class_id, v in json_file.items():
                        self.syn_to_class[v[0]] = int(class_id)
        with open(os.path.join(root, "ILSVRC2012_val_labels.json"), "rb") as f:
                    self.val_to_syn = json.load(f)
        samples_dir = os.path.join(root, "ILSVRC/Data/CLS-LOC", split)
        for entry in os.listdir(samples_dir):
            if split == "train":
                syn_id = entry
                target = self.syn_to_class[syn_id]
                syn_folder = os.path.join(samples_dir, syn_id)
                for sample in os.listdir(syn_folder):
                    sample_path = os.path.join(syn_folder, sample)
                    self.samples.append(sample_path)
                    self.targets.append(target)
            elif split == "val":
                syn_id = self.val_to_syn[entry]
                target = self.syn_to_class[syn_id]
                sample_path = os.path.join(samples_dir, entry)
                self.samples.append(sample_path)
                self.targets.append(target) def __len__(self):
            return len(self.samples) def __getitem__(self, idx):
            x = Image.open(self.samples[idx]).convert("RGB")
            if self.transform:
                x = self.transform(x)
            return x, self.targets[idx]

现在,我们可以通过为预训练的 ResNet-50 模型运行验证时期来测试它。

from torch.utils.data import DataLoader
from torchvision import transforms
import torch
import torchvision
from tqdm import tqdmmodel = torchvision.models.resnet50(weights="DEFAULT")
model.eval().cuda()  # Needs CUDA, don't bother on CPUs
mean = (0.485, 0.456, 0.406)
std = (0.229, 0.224, 0.225)
val_transform = transforms.Compose(
            [
                transforms.Resize(256),
                transforms.CenterCrop(224),
                transforms.ToTensor(),
                transforms.Normalize(mean, std),
            ]
        )
dataset = ImageNetKaggle(<YOUR_FOLDER>, "val", val_transform)
dataloader = DataLoader(
            dataset,
            batch_size=64, # may need to reduce this depending on your GPU 
            num_workers=8, # may need to reduce this depending on your num of CPUs and RAM
            shuffle=False,
            drop_last=False,
            pin_memory=True
        )
correct = 0
total = 0
with torch.no_grad():
    for x, y in tqdm(dataloader):
        y_pred = model(x.cuda())
        correct += (y_pred.argmax(axis=1) == y.cuda()).sum().item()
        total += len(y)print(correct / total)

这应该输出 0.80342,这是模型的精度(80.342%)。

ImageNet 的替代产品

对于大多数人来说,使用 ImageNet 进行培训仍然过于昂贵。然而,有许多基于 ImageNet 的替代数据集,其分辨率和/或样本和标签数量有所减少。这些数据集可以用于训练,只需花费一小部分成本。一些例子有图像网、微型图像网、图像网 100 和 CINIC-10 。

参考

[1]邓,董,李,李,,,“ImageNet:一个大规模的层次图像数据库”, 2009 年 IEEE 计算机视觉与模式识别会议,2009,第 248–255 页,doi: 10.1109/CVPR.2009.5206848

该数据集是免费的,用于非商业研究和教育目的。

感谢您阅读这篇文章!如果你喜欢它,请考虑订阅我的更新。如果你有任何问题,欢迎在评论中提出。

为您的 ML 项目从 Kaggle 下载数据集

原文:https://towardsdatascience.com/downloading-datasets-from-kaggle-for-your-ml-project-b9120d405ea4

如何利用 Kaggle Python API 从他们的网站下载任何数据集

亚历山大·辛恩在 Unsplash 上的照片

这是怎么回事?

我最近想在我的一个 NLP 项目中使用 Arxiv 数据集(它是在 Creative Commons CC0 1.0 通用公共领域专用协议下许可的),并试图利用 HF dataset hub 下载数据集。在这样做的时候,我收到了这条消息:

作者图片

看起来我不得不从 Kaggle 的网站上手动下载数据。我可以这样做,然后把它上传到我正在开发项目的云环境中。但我认为尝试不同的方法并学习新的东西可能会很有趣:)

在这篇博文中,我想简单介绍一下官方的 Kaggle API 及其 Python 实现。这个 API 使我们能够只使用 Python 从 Kaggle 下载任何数据集。一旦我们完成了这些,我们就可以用 HF 的数据集库加载数据集了。

本教程的笔记本可以在这个 Github repo 中找到。

创建 Kaggle API 密钥

为了与 Kaggle API 交互,我们需要一个 API 密钥,我们可以在网站上创建它(注意,你需要一个免费的 Kaggle 帐户)。为此,我们可以转到我们的帐户网站(https://www.kaggle.com/<user_name>/帐户),在 API 部分下,我们可以创建这样一个密钥:</user_name>

作者图片

将会下载一个名为 kaggle.json 的文件,我们可以将这个文件存储在一个名为的文件夹中。kaggle 放在我们的主目录中,这样就可以用它来认证 API 服务。在本教程中,我们将使用操作系统环境变量直接在笔记本中执行身份验证,如下所示:

下载数据集

现在我们可以利用 Kaggle API 的 Python 实现。要做到这一点,我们只需查看一下源代码,这是有据可查的。

在那里,我们找到了一些与数据集相关的方法,例如dataset _ list _ files()方法。我们需要的只是我们感兴趣的数据集的标识符,我们可以从数据集的 URL 路径中提取这个标识符(https://www.kaggle.com/Cornell-University/arxiv):

作者图片

为了下载数据集,我们可以利用 download_files 方法:

这将下载与数据集相关的所有文件,作为一个 zip 文件,我们可以简单地解压缩它。

许多其他 API 函数

如果您经常与 Kaggle 交互,请注意这个 API 类中有许多其他方法可以让您做其他事情,例如与竞赛交互等。

奖金挑战

现在我们的环境中已经有了本地数据,我们可以返回到 HF dataset 类来加载我们的数据集。当尝试这样做时,我们会遇到另一个错误消息:

作者图片

出现此错误消息是因为当数据集在 HF Dataset Hub 上创建时,它预期有 176 万条记录,但数据集从那时起已经更新,现在有 199 万条记录。然而,我们可以通过添加 ignore_verifications 参数来规避这个问题:

结论

我们现在已经使用他们的 Python API 成功地从 Kaggle 网站加载了一个数据集。我希望这是有用的,请留下评论和/或问题,如果你有任何。

DRF 😦几乎)所有东西的随机森林

原文:https://towardsdatascience.com/drf-a-random-forest-for-almost-everything-625fa5c3bcb8

Geran de Klerk 在 Unsplash 上拍摄的照片

当 Breiman 在 2001 年引入随机森林(RF)算法时,他知道这会产生巨大的影响吗?如今,RF 是数据科学的许多领域中大量使用的工具。原因显而易见——RF 易于使用,并以其在极其广泛的任务中的高性能而闻名。这本身就令人印象深刻,但更有趣的是,获得这些结果通常不需要调优。

在本文中,我们讨论了原始 RF 的一个相当大的扩展,即我们最近在本文中开发的分布式随机森林(DRF ):

【分布随机森林:异质性调整和多元分布回归(jmlr.org)

与洛里斯·米歇尔的合作,米歇尔对本文也有贡献。其他代码和 python 实现可以在这里找到:https://github.com/lorismichel/drf

我们将从随机森林这个主题的简单介绍开始,然后逐步介绍开发 DRF 的步骤。最后有一个小例子列表,我们很乐意在将来扩展它。

在我们继续之前,我们首先需要了解一些符号:在本文中,我们将把 XY 称为随机向量,我们假设从这些向量中观察一个 iid 样本(yi, x i),i=1,…n。这在研究论文中很常见。如果我们改为处理随机变量(即单变量),我们只写 Y 或 X。数据科学的许多应用程序的主要目标是从一些特征中预测YX,假设我们想要从像素强度的向量( X )中预测标签“狗”(Y)。不太引人注目的是,预测实际上几乎总是条件分布 P(Y| X = x )的函数。所以我们问“如果向量 X 固定为一个值 x ,那么 Y 的某个分布方面是什么?”。最突出的例子就是条件均值或期望,即分布 P(Y| X = x )下的期望值。这是人们在要求预测时通常想要的。例如,如果我们使用线性回归进行预测,我们将一个值 x 代入线性公式,得到 Y 的期望值作为预测值。上面的图像分类示例已经不同了——这里我们可能要求最可能的值,即对于哪个标签lP(Y =l|X=X)最大化。长话短说:大多数预测都是条件分布的一部分,通常是条件期望。

有趣的是,人们后来发现 RF 不仅可以用于条件期望或均值预测,还可以预测(条件)分布的其他方面。例如,可以预测分位数,从而获得测量不确定性的预测区间。DRF 将这种方法提升到了一个新的水平:你可以向它提供一个多元响应 Y 以及特征的典型向量 X ,然后它会估计多元响应 Y整体条件分布给定任何(实现) x 。中给出了简单权重形式的估计值,便于从分布中模拟或计算感兴趣的量,即“预测”。

这里给出了对 RF 的全面解释,例如,,所以我们只是简单地触及一下:在 RF 中,安装了几个独立的决策树。每棵树只是得到变量的一部分,然后根据 X 中的特征分割结果空间。

行动中的随机森林。一个新的点 x 被放在每棵树上(红色),落在一个叶子或终端节点上。来源:使用 TikZ 代码从 s tackexchange 生成的图像。

因此,当我们“放下”一个新的点 x 时,它将在每棵树的一片叶子中结束。一片树叶是一组观察值 i 的集合,取该树叶中所有 yi 的平均值给出了对一棵树的预测。然后对这些预测进行平均,得出最终结果。因此,对于给定的 x 如果你想预测给定的xY 的条件均值,你:

1.“下拉”每棵树的 x (在上图中用红色表示)。因为分割规则是在 X 上制定的,所以你的新点 x 将安全地落在一个叶节点的某个地方。

2.对于每棵树,你平均该树叶中的响应 yi,以获得每棵树的条件均值的估计。

3.你在树上平均每个条件平均值来得到最终的预测。

重要的是,平均所有树的预测导致方差的显著减少。可以说,误差得到了“平均”。这就是为什么让树尽可能独立是很重要的。

我们现在致力于扩展这一思想,不仅进行平均预测,而且预测整个(条件)分布。也就是我们要预测一个测试点 x 的 P(Y|X=X)。如前所述,人们通常想要预测的许多东西都是这个条件分布的直接函数:条件均值、条件分位数、条件方差、协方差等等。事实证明,DRF 的形式也使它适合于因果分析,甚至超越了最先进的方法。我们在本文的最后给出了一个小例子,在以后的文章中可能会给出更多的例子。

现在,我们一步一步地推导如何到达分布式随机森林。第一步是得到重量。

该理论

第一步:增加体重

这其中的关键是获得射频提供的权重。首次介绍 RF 时,这一点通常会被忽略,但在这里却至关重要:

不是直接计算叶节点中的平均值,而是计算在进行平均值计算时隐含使用的权重。权重 wi( x )是(1)测试点 x 和(2)观测值 i 的函数。也就是说,如果我们把 x 丢下一棵树,我们会观察它最后落在哪片叶子上。该叶中的所有观察值都为 1,其他所有观察值都为 0。因此,如果我们最终在一片叶子中得到观察值(1,3,10),那么该树的观察值 1,3,10 的权重是 1,而所有其他观察值都是 0。然后,我们进一步将权重除以叶节点中元素的数量。在前面的示例中,我们在叶节点中有 3 个观察值,因此观察值 1、3、10 的权重都是 1/3,而所有其他观察值在该树中的权重仍然是 0。对所有树的这些权重进行平均得到最终的权重 wi( x )。

为什么这些重量有用?首先,可以看出,像我们在传统随机森林中所做的那样计算平均值,与对 wi( x )*yi 求和是一样的。这看起来有点难看,但基本上只是交换两个和。因此,如果这个估计是合理的,它应该是合理的,如果你取 yi 的其他函数,比如 yi,你得到给定的 Y 的平均值 X 。或者你,对于某个数 t,你可以使用 I(yi < t)如果 yi < t 为 1,否则为 0,并将 wi( x )I(yi < t)上的和视为 Y < t 的条件概率的估计,这样你就可以直接获得条件累积分布函数(cdf),它在理论上完全表征了条件分布。第二,这些权重实际上为您提供了在某种意义上与查询 x 相似的观察值的最近邻估计。正如我们将在下面看到的,这种相似性是以一种理想的方式来度量的,这种方式使得有可能将相关联的 yi 看作来自条件分布的 iid 样本。

这甚至可以更进一步。特别地,如果你用这些权重从 Y 中取样,你将得到一个条件分布的近似样本。在我们继续之前,让我们使用 r 中著名的 ranger 包做一个简单的例子。该包不直接提供这些权重,所以我们需要手动实现它们,这是一个很好的练习:

library(ranger)
library(ggplot2)
n<-1000## Simulate some data:
X<-matrix(rnorm(n*2),ncol=2)
Y=2*X[,1] + 0.5*X[,2]^2 + rnorm(n)
Y<-as.matrix(Y)## Get a test point
x<-matrix(c(1,-0.5),ncol=2)# Fit Random forest
RF<-ranger(Y~., data=data.frame(Y=Y, X=X),min.node.size = 10, num.trees=500)## Get the leaf/terminal node indices of each observation in the training samples
terminalX <- predict(RF, data=data.frame(X=X), type="terminalNodes")$predictions## Get the leaf/terminal node of the test point
terminalxnew <- predict(RF, data=data.frame(X=x), type="terminalNodes")$predictions## For the leafs in which x ends up, what are the number of observations (we need to normalize by that)
divid<-sapply(1:ncol(terminalxnew[1,, drop=F]), function(j) {sum(terminalX[,j]==terminalxnew[1,j])} )

# Average the weights over the trees:
weights<-rowSums(t(sapply(1:nrow(terminalX), function(j) as.numeric(terminalX[j,]==terminalxnew[1,])/divid )), na.rm=T)/length(terminalxnew[1,])## We can now sample according to those weights from Y
Ysample<-Y[sample(1:dim(Y)[1], prob=weights, replace = T),]## True conditional distribution
Ytrue<-2*x[,1] + 0.5*x[,2]^2 + rnorm(n) 
p1 <- hist(Ytrue, freq=F)                     
p2 <- hist(Ysample, freq=F)                     
plot( p2, col=rgb(0,0,1,1/4), freq=F)  
plot( p1, col=rgb(1,0,0,1/4), add=T, freq=F)## Plot the weights by looking at the point x and its nearest neighbors according to the weights
ggplot(data = data.frame(X=X), aes(x = X.1, y = X.2)) +
  geom_point(aes(alpha = exp(weights ))) + geom_point(data=data.frame(X=x), color = "red")## Get the estimated conditional mean:
mean(Ytrue)
mean(Ysample)
sum(weights*Y)

上面代码的结果:在左边,我们看到了一个 Xi (灰色点)和红色测试点 x 的图。观察点 Xi 越暗,RF 分配给它们的权重越大。在右边,来自真实条件分布(红色)的模拟与根据权重从 Y 提取的点进行比较。图片作者。

步骤 2:使用不同的分割标准

还有另一种方式来看待随机森林算法:它是一个同质机器。在树中的每个分裂中,选择在 X 中的分裂,使得结果节点中 Y 的两个样本尽可能“不同”。下图是单变量 X 和 y 的一个小例子。

RF 中完成的拆分的图示。图片作者。

在这样的例子中,一个给定的树很可能在 S 处分裂 X,如图所示。然后所有易与的< S will be thrown into node 1 and all Xi > = S 进入节点 2,从而识别数据簇。如果我们这样做足够长的时间,每个叶节点将有一个非常均匀的 Y 样本,或者换句话说,一个叶节点中的所有 yi 在某些方面将是相似的,因为所有“不相似的”观察值都被切掉了。因此,对于每棵树,您将数据分组到相似事物的桶中。

为什么这有意义?因为本质上,RF 是一种最近邻算法。如果你给它一个 x ,它会把它丢下树,直到它落在一个桶里或一片叶子上,观察结果“类似”。根据这些观察值,计算条件平均值。也就是说,在每棵树中,只考虑叶子中的观察值,其他都不考虑。所以它就像一个 k-NN,距离不是由欧几里得距离来衡量的,而是由森林来决定的。反过来,森林决定将这些 x i 标记为具有“相似”yi 的“相似”。因此, x i 的相似性是基于它们相关联的 yi 来决定的,如果你的目标是推断关于 Y 的事情,这就很有意义。事实上,即使是 k-NN 方法也假设了一些类似于“对于 x i 接近于 x 的条件分布 P( Y |X=XI,条件分布 P(Y)大致相同”的东西。下图说明了这一点:您可以看到样本中每个值 x i 的相关真条件分布,yi 就是从该分布中采样的。DRF 的完美版本将识别出( x 1, x 4, x 6)和( x 3, x 5, x 7)的条件分布是相似的(不管它们的欧几里德距离实际上是多少),并且将 yi,(y1,y4,y6)和(y3,y5,y7)的相应组分别视为

对于样本中的每个值 x i,显示了 Y| X = xi 的条件分布,Yi 是该分布的平局。可以看出,有些分布与其他分布更相似。图片作者。

理想情况下,这将意味着在实践中,我们在一个叶内最终得到的同质 yi 样本实际上大约是来自条件分布 Y| X=x 的 iid 样本。这就是采用(加权)平均值的理由。

不幸的是,在最初的 RF 中,除了条件均值预测之外,这种方法不能如预期的那样工作。同样,我们想要的是一个分裂标准,它使得 Y 在两个分裂中的分布尽可能不同。相反,在原始 RF 中,我们得到的只是一个分裂,使两个样本之间的均值差异尽可能大。在上图中,这样的方法可能会将除了 x 2 之外的所有人归为一组,因为 x 1、 x 3、 x 4、 x 6、 x 7 都有非常相似的含义。当然,正如上图所示,分布并不是通过平均值来定义的。一个正态分布可以有相同的均值,但有非常不同的方差或其他矩。一般来说,你可以有很多均值相同的分布,但在其他方面却非常不同。

均值相同的两个分布。如果这是两个不同国家的收入不平等,它们会被视为相同吗?图片作者。

关键在于,每次拆分都应该取决于两个结果节点之间分布差异的度量。因此,不仅检测均值或方差的差异,而且检测分布的任何差异。DRF 通过调整射频中通常采用的分裂标准来解决这个问题,以利用内核的理论和实际能力以及所谓的 MMD 标准。MMD 可以非常有效地近似,并且原则上能够检测分布中的任何差异。从理论上讲,我们从而把每一个点 yi 送入一个无限维的空间,再生核希尔伯特空间,实际上在那个空间比较均值。通过内核方法的魔力,这种均值之间的比较实际上是分布的比较!在这个特殊的空间中,平均值就是分布。这在实践中意味着如下:一个叶节点将包含相似的 x i,在这个意义上,yi 在那个桶中的分布是相似的。因此,如果给定的 Y 的条件分布 x i 和 x j 相似,则它们将被分组到相同的桶中。原则上这是正确的,即使 x i 和 x j 在欧几里德空间中相距很远(即,如果它们在 k-NN 意义上不是最近的邻居)。因此,如果我们使用这些权重来计算我们感兴趣的条件事物,我们使用最近邻方法,该方法认为 x i 和 x j 是相似的,当它们相关的 yi,yj 的分布是相似的。特别地,在一些平滑度假设下,叶节点 x 中的样本大约是来自分布 P(Y|X=X)的 iid 样本。

第三步:使用多元响应

这一步实际上很简单,因为 MMD 也允许比较多元分布。重要的是,区分不仅仅是平均值对于多变量响应变得更加重要,因为分布的差异可能更加复杂。例如,两个多元分布可以具有相同的均值和方差,但元素之间的协方差不同。

例子

我们来举几个小例子。这里的目标是提供非常简单的模拟例子来感受这种方法。首先,我们重复上面手动完成的操作:

library(drf)
# Fit DRF
DRF<-drf(X,Y)
weights<-predict(DRF,x)$weights[1,]### We can now sample according to those weights from Y
Ysample<-Y[sample(1:dim(Y)[1], prob=weights, replace = T),]## True conditional distribution
Ytrue<-2*x[,1] + 0.5*x[,2]^2 + rnorm(n) 
p1 <- hist(Ytrue, freq=F)                     
p2 <- hist(Ysample, freq=F)                     
plot( p2, col=rgb(0,0,1,1/4), freq=F)  
plot( p1, col=rgb(1,0,0,1/4), add=T, freq=F)ggplot(data = data.frame(X=X), aes(x = X.1, y = X.2)) +
  geom_point(aes(alpha = exp(weights ))) + geom_point(data=data.frame(X=x), color = "red")## Get the estimated conditional mean:
mean(Ytrue)
mean(Ysample)
sum(weights*Y)

现在产生了这些更好看的结果:

上面代码的结果:在左边,我们看到了一个 Xi (灰色点)和红色测试点 x 的图。观察点 Xi 越暗,DRF 赋予它们的权重就越大。在右边,来自真实条件分布(红色)的模拟与根据权重从 Y 提取的点进行比较。图片作者。

我们也可以预测条件分位数。例如,这样做给出了 Y| x 的值的预测区间,因此从该分布中得出的值应该大约是该区间中 95%的时间:

# Predict quantiles for a test point.
quants<-predict(DRF,x, functional = “quantile”, quantiles=c(0.025, 0.975))$quantile 
q1<-quants[1]
q2<-quants[2]mean(Ytrue >=q1 & Ytrue <=q2)

最后一行检查从条件分布模拟的新样本中有多少部分位于区间[q1,q2]内。在这种情况下,结果大约是 94%,接近我们希望的 95%。

二维响应

在这里,我们构建了一个具有二维响应的非常困难的示例,并计算了各种预测。我们首先模拟数据:

n<-5000
d<-2
p<-3## Simulate X and Y
X<-matrix( cbind(runif(n)*2, rnorm(n, mean = 1), rt(n, df=8)),nrow=n)Y<-matrix(NA, ncol=2, nrow=n)
Y[,1]<-X[,1]^2 + X[,2]*X[,1] + X[,3] + rnorm(n)
Y[,2] <- 2*Y[,1]*X[,2] + 0.1*X[,3] + rnorm(n)

对于非参数估计方法来说,这些是非常疯狂的关系,因为一个 X 的元素具有非常不同的分布。有一点要提的是 2*Y[,1]*X[,2],意思是当 X 的第二个元素为正时 Y 的第一个和第二个元素的相关性为正,而当 X 的第二个元素为负时相关性为负。 Y 整体看起来是这样的:

如上面代码中模拟的。图片作者。

我们现在选择两个测试点,做一些大胆的预测,因为我们可以:

library(drf)# Fit DRF
DRF<- drf(X=X, Y=Y, num.features=200)# Choose a few test point:
x= matrix(c(0.093, -0.5,  1.37, 0.093, 0.5,  1.37) , ncol=p, nrow=2, byrow=T)# mean prediction
(predict(DRF, newdata=x, functional="mean")$mean)# correlation prediction
matrix(predict(DRF, newdata=x[1,], functional="cor")$cor, nrow=d,ncol=d)
matrix(predict(DRF, newdata=x[2,], functional="cor")$cor, nrow=d,ncol=d)# Estimated probability that Y is smaller than 0:
weightstotal<-predict(DRF, newdata=x)$weights
p1<-sum(weightstotal[1,]* (Y[,1] + Y[,2]<= 0) )
p2<-sum(weightstotal[2,]* (Y[,1] + Y[,2] <= 0) )# Bootstrapping the estimated probability of the sum being <=0 for both points:
B<-100
pb1<-matrix(NA, ncol=1,nrow=B)
pb2<-matrix(NA, ncol=1,nrow=B)
for (b in 1:B){
  Ybx1<-Y[sample(1:n, size=n, replace=T, prob=weightstotal[1,]), ]
  Ybx2<-Y[sample(1:n, size=n, replace=T, prob=weightstotal[2,]), ]
  pb1[b] <- mean(Ybx1[,1] + Ybx1[,2] <= 0)
  pb2[b] <- mean(Ybx2[,1] + Ybx2[,2] <= 0)
}ggplot(data.frame(x=1:2, y=c(p1, p2)), aes(x = x, y = y)) +
  geom_point(size = 4) +
  geom_errorbar(aes(ymax = c(quantile(pb1,1- 0.025), quantile(pb2, 1-0.025)), ymin = c(quantile(pb1, 0.025),quantile(pb2, 0.025) )))

我们不详细描述结果,但有趣的是,当 x 的第二个元素为负时,DRF 设法正确地检测到负相关性,当 x 的第二个元素为正时,检测到正相关性。此外,我们还加入了一个新的方面:我们甚至可以为我们的估计做一个(有条件的)bootstrap。在这种情况下,我们将其应用于 Y 的元素之和小于或等于 0 的估计概率。这导致该量的以下置信区间:

两个测试点 P 的自举 CIs(Y1+Y2≤0 |X=X)。

从预测到因果效应

为了让事情变得更有趣,我们研究了一个医学例子,我们希望得到因果效应(它完全是由完全不切实际的数字组成的,尽管它是由真实的问题激发的——男性和女性对药物的反应不同)。

在这个例子中,我们模拟了一个结果,比如说应该通过某种药物调节的血液稀释效应(B)。我们还知道患者的年龄和性别,并且我们模拟以下关系:对于男性患者,与年龄无关,药物线性增加血液稀释效果。对于女性患者,药物治疗也会增加 B,但如果她们的年龄超过 50 岁,则增加的程度会高于男性。然而,如果低于 50,效果完全相反,药物导致降低血液稀释效果。确切的数据生成过程如下:

n<-1000# We randomly sample from different ages…
Age<-sample(20:70, n, replace=T)# and sexes
Sex <- rbinom(n, size=1,prob=0.6) # 1=woman, 0=man# W denotes the dosis of the medication, the causal effect we are directly interested in
W<-sample( c(5,10,50,100),n, replace=T)# B is the thing we want to understand
B<- 60+ (0.5*W)*(Sex==0) + (-0.5*W)*(Sex==1)*(Age<50) + (0.8*W)*(Sex==1)*(Age>=50) + rnorm(n)

首先说明这种关系(因为我们知道真相,所以我们可以这样绘制):

按年龄组和性别说明药物的模拟效果。图片作者。

DRF 的一种方法是(1)取 Y =(B,W)(所以我们的 Y 也是二维的)和 X =(年龄,性别),(2)得到给定的 x 的权重,然后(3)估计用这些权重加权的线性回归。这给出的是给定 X 固定为 x 时的效果估计值:

get_CATE_DRF = function(fit, newdata){
 out = predict(fit, newdata)
 ret = c()
 for(i in 1:nrow(newdata)){
 ret = c(ret, lm(out$y[,1]~out$y[,2], weights=out$weights[i,])$coefficients[2])
 }
 return(ret)
}

这里可以看到不同测试点的结果:

library(drf)# Construct the data matrices
X<-matrix(cbind(Age, Sex), ncol=2)
Y<-matrix(cbind(B,W), ncol=2)# Fit
DRF<-drf(Y=Y, X=X)# Get a test point (changing this test point gives different queries)
x<-matrix(c(40, 1), nrow=1)# Get the weights
weights <- predict(DRF, newdata=x)$weights[1,]# Study the weights
head(X[order(weights, decreasing=T),])# Result for given test point
(CATE_DRF = get_CATE_DRF(DRF, newdata=x))

可以看出,当运行 1000 个数据点的代码时,这些结果是相当准确的:在这个例子中,我们得到一个 40 多岁的女人的效应为-0.26(x=(40,1)),一个 60 多岁的女人的效应为 0.48(x=(60,1)),一个 30 岁的男人的效应为 0.28(x=(30,0))

在某些方面,这仍然是一个非常简单的例子,甚至以年龄和性别作为预测因素的线性回归可能也很有效。重要的是,DRF 在这里没有预先假设(例如线性),并且完全自己学习关系,即使当 X 的效应是非线性的。对于较小的样本量,估计这种影响要困难得多,但总的方向通常不会太差。

结论

本文解释了分布式随机森林方法(希望以一种可以理解的方式)。该方法是一个随机森林,其中每棵树根据 X 分割响应 Y ,以这种方式,具有相似分布的观察结果在一个叶节点中结束。如果一个新的点 x 被放在一棵树上,它将和其他具有类似条件分布 Yx i 一起到达一个叶子节点。这导致在所有树上平均的权重,以简单的形式给出条件分布的估计。这给出了 P(Y|X=X)的纯非参数估计,从中可以估计出许多有趣的量。

在本文的最后,我们只想提醒大家,非参数地估计多元条件分布是一项艰巨的任务。这是有意义的,尤其是当有大量的观察和复杂的关系是可疑的。然而,有时假设一个高斯分布的线性模型也可以。使 DRF 如此多才多艺的是,即使在参数模型更合适的情况下,权重对于半参数方法仍然是有用的,

大量额外的例子可以在原始论文中找到,或者在未来潜在的媒体文章中找到。我们希望 DRF 能在许多依赖数据的任务中提供帮助!

自动驾驶中的可驾驶空间:概念

原文:https://towardsdatascience.com/drivable-space-in-autonomous-driving-the-concept-df699bb8682f

可驾驶空间的内容和原因

你不会通过的(来源:罗伯特·林德在 Unsplash

可驾驶空间,也就是通常所说的**自由空间,**对于保证自动驾驶的安全性起着至关重要的作用。与自动驾驶中其他更知名的感知任务(如车辆检测和车道线检测)相比,可驾驶空间受到的关注要少得多。今天,让我们更仔细地看看这个安全至关重要的感知任务。

这是一个关于自动驾驶中可驾驶空间的三部分博客系列。今天我们将谈论可驾驶空间的概念和典型案例。然后在接下来的两篇博文中,我们将回顾学术界可驾驶空间的各种方法以及当前在工业中的应用。

背景

可驾驶空间,顾名思义就是确定自动驾驶车辆(ego vehicle)周围可行驶的区域。但是,对于具体的定义和覆盖范围,学术界和业界并没有统一的标准。让我们来看看一个相对常见的驾驶场景,尝试给出一个更清晰的可驾驶空间定义。

一般驾驶场景示意图(作者绘制的示意图)

覆盖范围

如上图所示,红色粗线代表物理道路边界(如路缘),黑色细线代表路面上的标线(车道线)。虽然大多数车辆在道路标线的实线内行驶,但在紧急情况下,它们也可以在实线和道路边界之间的路肩上行驶和停车。安全驾驶的底线是必须避开物理道路边界。

第一类:物理道路边界的样本图像(来源:知乎

在道路上,路面上会有动态物体(车辆、行人等主动交通参与者)和静态物体。动态对象可以分为已知类型和未知类型。使用动态对象检测网络可以检测已知类型的动态对象,例如普通车辆、行人、自行车和摩托车。但是路上经常会出现一些未知类型的动态物体,比如不太常见的三轮摩托车,改装过的重型车,赛格威滑板车上的行人。为了安全驾驶,我们还不得不避开这些未知的动态物体(UMO)。

更严格地说,这些类型应该是“不太为人所知”,但为了简单起见,我们称它们为“未知”。已知或未知的定义是相对的,取决于给定感知系统的进化。

第二类:未知动态对象的样本(来源:知乎

同样,静态对象也有已知和未知的类型。已知类型的静态对象是可数的(全景分割术语中的“事物”),具有明显的语义特征,比如交通锥。对于这些对象,可以使用对象检测网络(如 YOLO、CenterNet 等)进行实例检测。此外,还会有未知类型的静态物体,从地面上的街道标志到人工或自然的道路障碍物。这些静态障碍是不可计数的(在全景分割术语中是“东西”)或者没有明确的类别。翻车的车辆也可以算作未知类型的静态障碍物。为了安全驾驶,我们还必须避开这些未知的静态物体(USO)。

第三类:未知静态对象的样本(来源:知乎

总之,我们需要在没有明确语义类别的情况下识别物理道路边界和未知障碍,以确保驾驶安全。这些元素的检测包含在可驾驶空间感知任务中。可驾驶空间是作为辅助任务建立的,以支持已知类型的动态和静态对象的识别,这是一个“后退”任务。

不可否认,在众多合理的选择中,这只是一个关于可行驶空间范围的合理建议。另一种常见的做法是将物理道路边界的检测分离到单独的感知任务中。

双重回退系统

可驾驶空间作为一项感知任务,用于语义类别不明确的障碍物的后退检测。借助分类法中的这种概念后退,感知任务可以以互斥的集体穷尽(或 MECE)方式覆盖自动驾驶所需的所有类型的环境元素。

知觉的任务划分(图表由作者创建)

还有一层退路,比较实用。虽然动态对象检测任务被设计为检测具有清晰语义的已知对象,但是由于不完善的神经网络模型性能,经常会有漏检。在这种时候,我们需要使用可驾驶的空间来弥补错过的检测。

总而言之,两层回退是:

  • 未知对象,或者不能被动态和静态对象的已知类别语义覆盖的对象,将被可驱动空间语义覆盖。
  • 能够被已知类别的动态和静态对象语义覆盖,但实际上被相应的检测任务遗漏的对象,将被可驱动空间覆盖。

自我车辆周围的空间划分(图表由作者创建)

后处理

学术界通常不讨论的一个领域是与可驾驶空间相关的后处理。这一步涉及大量的工程实践,而且,不可否认的是,与神经网络任务本身相比,这一步并不那么有趣。然而,我们将看到为什么这一步是必要的,以及它通常是如何做的。

为了充当语义分类的后备,可驱动的空间任务必须在较低级的语义不可知方案中操作。只有这样,可驾驶的空间任务才能检测到车辆是一种类型的障碍,无论其类别是什么。这意味着这个任务的直接输出不加区别地对待所有障碍。这进一步意味着在可驾驶空间的输出和动态和静态物体检测的输出之间将不可避免地存在一些重叠。

这种检测结果的复制需要一个后处理步骤来将可驱动空间的输出与动态和静态物体检测的输出相融合。对于已经被动态和静态对象检测覆盖的对象,可驾驶空间输出将被抑制,并且不会被传递给感知的下游消费者。

可驾驶空间是自动驾驶不可或缺的安全网,其最大的效用是充当算法后备。在未来的博文中,我们将介绍学术界可驾驶空间的主流研究方向,然后介绍在行业中的应用。我们还将简要讨论如何将自动驾驶中的可驾驶空间扩展到通用机器人领域。

外卖食品

  • 可驾驶空间范围的一个合理建议包括物理道路边界、未知动态物体和未知静态物体。
  • 可驾驶空间是一个双重回退系统,覆盖语义间隙,还捕捉来自其他对象检测任务的遗漏检测。
  • 可驾驶空间不能替代动态物体感知或静态物体检测。它是对这些感知任务的补充。

参考

  • 全景分割,CVPR 2019

如何从 Pandas 数据框架中删除行列表

原文:https://towardsdatascience.com/drop-rows-pandas-d1772a054f0

用 Python 从 pandas 数据帧中删除多行

王禹在 Unsplash 上拍照

当处理 pandas 数据帧时,我们通常希望丢弃原始结构中的行。Pandas 提供了一个直观的 API,我们可以利用它来执行这样的操作。

在今天的文章中,我们将通过提供相应记录的索引列表来演示如何从 pandas 数据帧中删除行。此外,在处理大量数据时,我们将探索一些替代方法。

首先,让我们创建一个示例数据框架,我们将在整个教程中引用它来演示一些概念,并帮助您逐步完成这个过程。

import pandas as pd df = pd.DataFrame(
    [
        (1, 125, True, 'A'),
        (2, 222, False, 'A'),
        (3, 871, False, 'C'),
        (4, 134, False, 'D'),
        (5, 908, True, 'D'),
        (6, 321, False, 'E'),
        (7, 434, False, 'B'),
        (8, 678, True, 'C'),
    ], 
    columns=['colA', 'colB', 'colC', 'colD']
)print(df)
 ***colA  colB   colC colD*** *0     1   125   True    A
1     2   222  False    A
2     3   871  False    C
3     4   134  False    D
4     5   908   True    D
5     6   321  False    E
6     7   434  False    B
7     8   678   True    C*

删除带有索引列表的记录

上面输出中最左边的列(0–7)对应于我们的 pandas 数据帧中每个记录的索引。然后,我们可以创建一个列表,包含我们希望删除的记录的索引

drop_idx = [1, 3, 6]

然后利用[pandas.DataFrame.drop()](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.drop.html)方法直接指定要删除的索引或列名。最后,我们将索引列表分为一系列索引标签:

df = df.drop(df.index[drop_idx])print(df) ***colA  colB   colC colD*** *0     1   125   True    A
2     3   871  False    C
4     5   908   True    D
5     6   321  False    E
7     8   678   True    C*

请注意,如果您不执行就地更改,您将不得不将drop()方法的结果赋回您的df,如上例所示。要执行就地更改,您需要做的就是在调用drop()时传递相应的参数:

df.drop(df.index[drop_idx], axis=0, inplace=True)

处理大量数据

当处理大型数据帧时——或者甚至当需要删除大量记录时,上一节中介绍的df.drop()效率不会很高,并且可能会花费大量时间。

在按索引删除行时,处理大型数据帧的最有效方法是实际上反转问题。换句话说,我们不是找出需要删除的记录,而是处理我们实际上想要保留在结果数据帧中的行。

因此,我们从数据帧的所有索引中排除想要删除的索引,如下所示

drop_idx = [1, 3, 6]
keep_idx = list(set(range(df.shape[0])) - set(drop_idx))

最后,代替drop(),我们调用[pandas.DataFrame.take()](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.take.html)方法,该方法可以通过提供沿轴的位置索引来检索元素(在我们的例子中,这将是行轴)。

df = df.take(keep_idx)print(df)
 ***colA  colB   colC colD*** *0     1   125   True    A
2     3   871  False    C
4     5   908   True    D
5     6   321  False    E
7     8   678   True    C*

最后的想法

通常,我们希望通过为想要删除的相应行提供一个索引列表来删除特定的记录。在今天的简短教程中,我们演示了几种不同的方法,具体取决于您正在处理的数据的大小。

请注意,您可能希望选择满足(或不满足)特定条件的记录,而不是删除特定的记录。如果这是你正在寻找的,那么请随意阅读下面的文章,它将带你完成这个过程。

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

https://gmyrianthous.medium.com/membership

相关文章你可能也喜欢

神经网络中的辍学

原文:https://towardsdatascience.com/dropout-in-neural-networks-47a162d621d9

丢弃层是减少神经网络过拟合的常用方法。它是现代深度学习时代的地下规则之王。

在这个深度学习的时代,几乎每个数据科学家都必须在他们构建神经网络的职业生涯中的某个时刻使用过 dropout 层。但是,为什么辍学如此普遍?辍学层内部是如何运作的?它解决了什么问题?除了退学还有别的选择吗?

图 0:印度的 Jharokhe,去掉一些光(图片由作者提供)

如果您有关于辍学层的类似问题,那么您就来对地方了。在这篇博客中,你会发现著名的辍学层背后的错综复杂。完成这篇博客后,你会很舒服地回答与辍学有关的不同问题,如果你是一个更具创新精神的人,你可能会提出一个更高级版本的辍学层。

我们开始吧…:)

概述

本博客分为以下几个部分:

  1. 简介:它试图解决的问题
  2. 什么是辍学?
  3. 它是如何解决问题的?
  4. 辍学实施
  5. 推理过程中的遗漏
  6. 它是如何构思的
  7. Tensorflow 实现
  8. 结论

介绍

因此,在深入了解它的世界之前,让我们先来解决第一个问题。我们试图解决的问题是什么?

深度神经网络具有不同的架构,有时很浅,有时很深,试图在给定的数据集上进行概括。但是,在努力从数据集中学习不同特征的过程中,他们有时会学习数据集中的统计噪声。这无疑提高了模型在训练数据集上的性能,但在新的数据点(测试数据集)上却失败了。这就是**过拟合的问题。**为了解决这个问题,我们有各种惩罚网络权重的正则化技术,但这还不够。

减少过度拟合的最佳方式或调整固定大小模型的最佳方式是从所有可能的参数设置中获取平均预测值,并汇总最终输出。但是,这在计算上变得过于昂贵,并且对于实时推断/预测是不可行的。

另一种方法是受集成技术(如 AdaBoost、XGBoost 和 Random Forest)的启发,其中我们使用不同架构的多个神经网络。但这需要训练和存储多个模型,随着时间的推移,随着网络越来越深,这将成为一个巨大的挑战。

因此,我们有一个很好的解决方案,称为脱落层。

图 1:应用于标准神经网络的下降(图片由 Nitish 提供)

什么是辍学?

术语“丢失”是指在神经网络中丢失节点(输入和隐藏层)(如图 1 所示)。与被丢弃节点的所有前向和后向连接都被临时移除,从而在父网络之外创建新的网络架构。节点以 p 的丢弃概率被丢弃。

让我们用给定的输入 x: {1,2,3,4,5}来理解全连接层。我们有一个掉线层,概率 p = 0.2(或者保持概率= 0.8)。在从输入 x 向前传播(训练)期间,20%的节点将被丢弃,即 x 可能变成{1,0,3,4,5}或{1,2,0,4,5}等等。同样,它适用于隐藏层。

例如,如果隐藏层有 1000 个神经元(节点),并且以丢弃概率= 0.5 应用丢弃,则在每次迭代(批次)中将随机丢弃 500 个神经元。

通常,对于输入层,保持概率,即 1-丢弃概率,更接近于 1,0.8 是作者建议的最佳值。对于隐藏层,丢弃概率越大,模型越稀疏,其中 0.5 是最佳保持概率,表示丢弃 50%的节点。

那么辍学如何解决过度拟合的问题呢?

它是如何解决过拟合问题的?

在过拟合问题中,模型学习统计噪声。准确地说,在给定所有单元(神经元)的情况下,训练的主要动机是减少损失函数。因此,在过度拟合中,一个单元可能以修正其他单元的错误的方式改变。这导致了复杂的协同适应,这又导致了过拟合问题,因为这种复杂的协同适应不能在看不见的数据集上推广。

现在,如果我们使用 dropout,它会阻止这些单元修复其他单元的错误,从而阻止共同适应,因为在每次迭代中,一个单元的存在是非常不可靠的。因此,通过随机删除一些单元(节点),它迫使各层采取概率方法对输入承担或多或少的责任。

这确保了模型变得一般化,从而减少了过度拟合问题。

图 2: (a)无脱落的隐藏层特征;(b)隐藏的图层特征与丢失(图片由 Nitish 提供)

从图 2 中,我们可以很容易地看出,与没有丢失的层中的共同适应相比,具有丢失的隐藏层正在学习更多的一般化特征。很明显,辍学打破了这种单位间的关系,更注重一般化。

辍学实施

说够了!让我们来看看辍学的数学解释。

图 3: (a)训练期间的单元(神经元)以概率 p 存在,并以权重' w '连接到下一层;(b)推理/预测期间的单元总是存在的,并且通过权重连接到下一层,' pw '(图片由 Nitish 提供)

在丢弃层的原始实现中,在训练期间,以保持概率(1 丢弃概率)选择层中的单元(节点/神经元)。这就在给定的训练批次中创建了一个更薄的架构,而且每次这个架构都不一样。

在标准神经网络中,在前向传播期间,我们有以下等式:

图 4:标准神经网络的前向传播(图片由 Nitish 提供)

其中:
z:表示激活前层(l + 1)的输出向量
y:表示层 l 的输出向量
w:层 l 的权重
b:层 l 的偏差

此外,利用激活函数,z 被转换成层(l+1)的输出。

现在,如果有一个压差,正向传播方程会发生如下变化:

图 5:有缺失的层的向前传播(图片由 Nitish 提供)

因此,在我们计算 **z 之前,**对该层的输入进行采样,并按元素乘以独立的伯努利变量。 r 表示伯努利随机变量,每个伯努利随机变量具有为 1 的概率 p。基本上, r 充当输入变量的掩码,确保根据丢失的保留概率只保留少数单元。这确保了我们具有细化的输出“y(bar)”,其在前馈传播期间作为输入提供给该层。

图 6:前向传播期间给定层的压差网络与标准网络的比较(图片由 Nitish 提供)

推理过程中的遗漏

现在,我们知道辍学在数学上行得通,但是在推理/预测过程中会发生什么呢?我们是使用带有丢失的网络,还是在推理过程中移除丢失?

这是辍学最重要的概念之一,但很少有数据科学家知道。

根据推理过程中的原始实现(图 3b ),我们不使用漏失层。这意味着在预测步骤中会考虑所有单元。但是,由于从一个层中取出所有的单元/神经元,最终的权重将比预期的要大,为了处理这个问题,权重首先按照所选择的辍学率进行缩放。有了这个,网络将能够做出准确的预测。

更准确地说,如果在训练期间以概率 p 保留一个单元,则在预测阶段该单元的输出权重乘以 p。

辍学是如何形成的

《辍学:防止神经网络过度适应的简单方法》的作者之一杰弗里·辛顿(Geoffrey Hinton)表示,有一系列事件激发了根本性的辍学。

  1. 与谷歌大脑的类比是,它应该很大,因为它学习了大量的模型。在神经网络中,这不是一个非常有效的硬件使用,因为相同的功能需要由不同的模型分别发明。这是使用相同神经元子集的想法被发现的时候。
  2. 银行出纳员:在那个年代,出纳员会定期更换,这一定是因为需要员工之间的合作才能成功地欺骗银行。这植入了随机选择不同神经元的想法,使得每次迭代都使用不同组的神经元。这将确保神经元无法学习共同适应,并防止过度适应,类似于防止银行中的阴谋。
  3. 有性生殖:它包括谈论父母一方的一半基因和另一方的一半基因,添加非常少量的随机突变,以产生后代。这创造了基因的混合能力,使它们更加强壮。这可能与用于破坏共同适应的辍学有关(就像基因突变一样增加了随机性)。

整个旅程难道不令人着迷吗?

介绍辍学概念的主要动机是激励读者探索他们周围的世界,并将其与其他几个神经网络的工作原理联系起来。它肯定会产生许多这样的创新。

Tensorflow 实现

如果我们遵循最初的实现,我们需要在预测阶段将权重乘以丢弃概率。只是为了去除这个阶段中的任何处理,我们有一个被称为“反向丢弃”的实现。

将权重与丢失概率相乘的目的是确保最终的权重具有相同的尺度,因此预测是正确的。在反向辍学,这一步是在训练本身。在训练时,在丢弃操作之后剩余的所有权重乘以保持概率的倒数,即 w * (1/p)。

为了获得为什么两种操作在层权重上相似的数学证明,我推荐浏览一下毛蕾的博客。

结论

终于!!我们已经深入分析了几乎所有神经网络使用的漏失层。

辍学可以用于大多数类型的神经网络。这是减少模型过度拟合的一个很好的工具。它比可用的正则化方法好得多,并且还可以与最大范数归一化相结合,这比仅使用辍学提供了显著的提升。

在接下来的博客中,我们将会学到更多关于这些基本层的知识,这些基本层在几乎所有的网络中都有使用。仅举几个例子,批标准化、层标准化和关注层。

参考

[1] Nitish Srivastava,Dropout:防止神经网络过拟合的简单方法,https://jmlr . org/papers/volume 15/Srivastava 14 A/Srivastava 14 A . pdf

[2]杰森·布朗利(Jason Brownlee),对正则化深度神经网络的辍学现象的温和介绍,https://machine learning mastery . com/Dropout-for-regulating-Deep-Neural-Networks/

[3]毛蕾,Dropout Explained,https://lei Mao . github . io/blog/Dropout-Explained/#:~:text =期间%20 推断% 20 时间%2C%20dropout%20does,被% 20 乘%20pkeep%20 。

[4] Juan Miguel,Tensorflow 中的 Dropout explained and implementation,http://layed . delanover . com/Dropout-explained-and-implementation-in-tensor flow/

辍学是非常容易实现的

原文:https://towardsdatascience.com/dropout-is-drop-dead-easy-to-implement-67f08a87ccff

大概是 1 行 python…

图来自描述辍学的原始论文。

简介

我们都听说过辍学。从历史上看,这是正则化神经网络的最著名的方法之一,尽管现在它已经有些失宠,并被批量归一化所取代。不管怎样,这是一项很酷的技术,在 PyTorch 中实现起来非常简单。在这篇简短的博文中,我们将从头实现 dropout,并展示我们在 PyTorch 中获得了与标准 dropout 相似的性能。运行这个快速教程的所有实验的完整笔记本可以在这里找到。

什么是辍学?

退出是指在每个训练步骤中有效地随机删除神经网络的一些节点。这个想法是,通过不过度依赖任何一个节点,这将有助于网络变得更加健壮。

图来自最初描述辍学的论文。

实际上,我们忽略了每个训练周期中的一些随机节点集。很简单,对吧?

数学

因此,如果我们将网络中的每一层都视为一个矩阵,那么在每个训练步骤中,我们只需要将一组随机节点清零。这闻起来很像哈达玛产品。考虑一个单层神经网络,其中层由矩阵 A 表示。该网络将接受二维输入并输出三维结果,因此 A 是 2×3。

我们单层网络的可视化。

如果我们想将一些随机的节点集清零,我们可以创建一个二进制矩阵 D ,其中每一列都是零,概率为 p ,然后取元素乘积。我们可以通过创建一个具有与 A 相同列数的阈值化统一向量,然后在乘法运算中广播来轻松实现这一点。

让我们在 PyTorch 中实现它:

p = .5
A = torch.tensor([[1, 2, 3], [4, 5, 6]])
D = (torch.empty(A.size()[1]).uniform_(0, 1) >= p)
x = A.mul(D)====Output===
tensor([[0, 2, 3],
        [0, 5, 6]])

如您所见,上述计算将会遗漏一些随机的节点集。

另一种方法是使用 DropConnect,我们随机删除权重,而不是节点。这里唯一的区别是创建一个与大小相同的随机均匀矩阵,而不是进行广播。这看起来像这样:

p = .5
A = torch.tensor([[1, 2, 3], [4, 5, 6]])
D = (torch.empty(A.size()).uniform_(0, 1) >= p)
x = A.mul(D)====Output===
tensor([[1, 2, 0],
        [0, 5, 6]])

在 PyTorch 中实现一个层

有了最初的数学知识,让我们在 PyTorch 中实现一个 dropout 层。

第 6–7 行检查以确保传递给该层的概率实际上是一个概率。

第 10 行确定该层是处于训练模式还是测试模式。这很重要,因为我们不希望仅在训练期间在推断过程中遗漏节点。这个简单的 if 语句为我们解决了这个问题。

第 11 行完成了我们之前讨论的所有魔术,它创建了一个与 x 大小相同的二进制矩阵,其中有一个概率为 p ,任何节点都被遗漏了。

我们现在可以在一个简单的模型中使用这种下降。

如果我们用标准 PyTorch dropout 替换我们的自定义 dropout,我们会得到相同的结果。相当整洁!

最后一个音符

敏锐的读者会注意到,这并不是辍学者在实践中应该采取的方式。我们不是通过一个节点被训练的次数来标准化的。想一想这个。当我们丢弃一堆随机节点时,一些节点将比其他节点得到更多的训练,并且在最终预测中应该具有不同的权重。考虑到这一点,我们需要在推理期间通过保持概率1/(1-p)的倒数来调整每个节点的权重。但是在推理的时候这样做是很痛苦的。大多数实现在实践中所做的是在训练期间按这个量来缩放权重。所以真正的辍学层应该是这样的:

就是这样!感谢阅读!

DT 图:寻找二元分类器的最佳区分阈值

原文:https://towardsdatascience.com/dt-plot-finding-the-optimal-discrimination-threshold-for-binary-classifier-c3f326d6326f

学习如何使用一个鲜为人知但非常重要的诊断图

Alex Padurariu 在 Unsplash 上拍摄的照片

典型的机器学习任务的实质部分与训练算法相关,该算法将输入数据分配给两个预定义标签中的一个。这种算法通常被称为二元分类器。有多种方法可以直观显示这种分类器的性能,可以说最常用的工具是接收器操作特性(ROC)精确召回(PR) 曲线。

来自这两个图的洞察力几乎是相同的,但是有时一个比另一个更受青睐。根据经验,当具有真正阳性标记的观察值很少时,那么 PR 曲线是优选的。另一方面,ROC 曲线似乎在商业演示中更受欢迎,这可能是由于仅用一个度量来表达模型性能的直观吸引力:曲线下面积( AUC )。在任何情况下,这两个图,无论在选择最佳性能模型时多么有用,都不能决定性地回答随后的问题:我们应该将否定预测与肯定预测的分界点放在哪里?这种分界点的默认值是 0.5,这通常不是最佳值,尤其是在处理不平衡的数据集时。我们将在这里描述的可视化工具,称为辨别阈值 (DT)图,有助于找到该截止点的最佳值。

在本帖中,我们将:

  • 了解如何使用 DT 图找到二元分类器的最佳区分阈值(只是上述临界值的另一个名称)
  • 展示一个简单的交互式 DT 绘图版本,您可以下载并将其用作项目的模板。

这里我们将只检查关键的代码片段,但是你可以在 Github 上找到整个项目。

数据集和模型

在跳到情节和它的解释之前,让我们首先在 UCI 的信用卡客户数据集的违约上训练一个分类模型。由于相同的数据集也位于 OpenML 的存储库中,我们可以通过 scikit-learn 的 OpenML 接口轻松加载这些数据。

构建性能最佳的预测模型不是这篇文章的目标,所以我们将保持简单,坚持使用基本的随机森林分类器,对分类预测器进行顺序编码。

然而,我们必须记住,DT 图的静态和动态版本都是这样设计的,它们以模型本身而不是预测作为参数。此外,该模型将在数据集的不同子样本上进行多次训练和测试。这意味着我们必须以这样一种方式转换数据,即在每次拆分之后,训练集中的每个分类列都已经知道它可以在看不见的测试集中取的所有值。实现这一点的一种方法是应用分层随机分裂,但我们的数据集包含几个分类列,对所有这些列进行分层会很复杂(也可能不那么随机)。另一个策略是显式地将名义列转换成具有预定义无序值的 pandas 的 categorical type,这样,每当某个列的某个值在训练集中不存在时,在测试集中接收这样的值不会导致错误地分配标签或任何其他逻辑错误。下面的函数 transform_data() 就是这样做的。然而,要用第二种方法对数据进行编码,在继续建模之前,我们必须知道每个分类列可能取的所有值。

主要术语和定义

在深入研究之前,有必要用我们将使用的主要术语的非正式定义来刷新我们的记忆。

  • **精度:**具有预测阳性标签的真阳性观察值的比例。在我们的例子中,它是那些预测会违约的客户中实际违约的客户的比例。
  • **回忆:**也称敏感度,这是预测阳性病例在所有阳性病例中所占的比例。因此,在我们的数据环境中,召回率是预测违约的客户占实际违约客户的比例。
  • **F1 得分:**这是精确度和召回率的调和平均值,当我们有一个不平衡的数据集时,这变得特别方便。我向你推荐这篇简洁而写得很好的文章,让你了解更多 F1 分数背后的属性和直觉。下面的公式表明 F1 分数是精确度和召回率的单调递增函数(也是假阳性和假阴性的单调递减函数)。在其标准形式中,F1 分数假设精确度和召回率具有相同的权重(即从业务角度来看同等重要),但正如下一节所讨论的,它可以扩展为权重不同的形式。
  • **排队率:**这是样本中预测阳性标签的比例,即得分大于区分阈值的观察值的份额。

主要定义(图片由作者提供)

现有实施

在写这篇文章的时候,用 Python 绘制 DT 图最常见的方法似乎是一个名为 Yellowbrick 的包中的函数,它包含了一组非常有用(并且通常不常见和被低估)的可视化工具。如果您不熟悉这个包,我强烈建议您阅读它的文档。

下面的代码片段显示了如何绘制该图。如上所述,预测是在函数内部生成的,因此作为一个参数,它采用模型或以模型结尾的管道。

那么,什么是 DT 剧情呢?它是一个图表,显示了每个阈值和四个性能指标之间的关系:精确度、召回率、F1 值和排队率。从下面的图中,我们可以观察到提高精度会降低召回率,反之亦然(嗯,当阈值接近 1 时,精度有时会变得不稳定,但其总体趋势保持上升)。此外,我们可以看到对应于 F1 分数最大值的垂直虚线,即它是精确度的边际增加(F1 分数的导数 w.r.t .精确度)等于召回的边际减少(导数 w.r.t .召回)的点。

DT 图中最大化 F1 分数的垂直虚线是最佳辨别阈值。

在图中,低于最佳阈值的是 0.32,这将分数在前 25 个百分点中的标签标记为正(即,排队率是 0.25)。该阈值的精度和召回值大约为 0.47 和 0.53。DT 图还描述了曲线的可变性,即它们的下限和上限,这是多次运行模型的结果。相应地,边界的默认值是第 10 和第 90 个百分点,但是这些值可以用函数的分位数参数来修改。

使用默认值的 yellobrick DT 图(图片由作者提供)

虽然在上面的设置中,我们认为精度和召回同等重要(即同等重要),但我们可以想象一种方法优先于另一种方法的情况。一个典型的例子是脑肿瘤的分类,在某种程度上,尽管导致较低的精度,但具有大的召回率(即低假阴性)被认为优于任何其他配置。如果我们能够量化召回相对于精确度的重要性,我们可以相应地修改 F1 分数,这将导致不同的最佳阈值。举个例子,假设我们认为召回比精确重要 1.5 倍。我们要做的就是用参数 fbeta =1.5 调用函数 discrimination_threshold()

通过比较下面的 DT 图和原始图,我们立即注意到这里的最佳阈值更低了(现在是 0.16,而前面的图是 0.32),这也提高了队列速率(大约。现在是 50%,而不是之前图中的 25%。

当 F1 分数加权时,Yellobrick 的 DT 图(图片由作者提供)

仪表盘版

Yellowbrick 对 DT 情节的实现无疑是有用的,但也有几个小缺点,比如缺乏交互性和没有悬停注释。这就是为什么我们构建了一个带有输入部件的交互式仪表盘,它既可以在 Jupyter 环境中运行,也可以作为一个独立的应用程序运行。此外,仪表板可以在两种模式下获得最佳阈值:基本模式(即与 Yellowbricks 版本中最大 F1 分数对应的阈值)和约束模式,我们将在后面几段描述。

该应用程序是使用 Plotly Dash 构建的,因为我们希望它既可以在 Jupyter 笔记本上运行,也可以作为独立的应用程序运行。或者,我们可以使用 Panel ,但是 Plotly 的生态系统被认为更成熟,也更有据可查。 Streamlit 是另一个吸引人的选择,但不幸的是,在写这篇文章的时候,它不支持 Jupyter 笔记本。你可以在这里找到主要仪表板框架的详细对比。

下面的 gif 图示了仪表板的界面。如果您希望在本地计算机上运行它,可以从上面提到的 Github 库下载。

DT 绘图的仪表板界面(图片由作者提供)

虽然应用程序的默认基本模式很大程度上模仿了 Yellowbricks 实现的行为,但受约束模式的逻辑主要是受本文的启发。您可以通过勾选仪表板中的相应复选框来启用约束模式。简而言之,约束模式下的最优阈值取决于三个估计:
1。审查能力,即我们有能力审查以确定其是否为真正阳性的预测阳性标签的比例(即我们有能力审核并确定符合贷款条件的贷款申请人的比例);
2。审查一个案例(即一个贷款申请人)的成本
3。回报我们从每一次成功中获得的回报(即从识别通过门槛但不应获得贷款的申请人中获得的收益)。

在基本模式中,我们最大化 F1 分数,而在约束模式中,我们最大化支付函数(定义如下),假定最大化该函数的阈值低于审查能力。从形式上看,这种关系是这样的:

第一个等式计算每个阈值 t 的支出函数。参数 sc 通过输入小部件输入,而 n 是数据集的大小,因此这些可以被视为常数。在等式的右边,乘积 P(t) * s 表示每次成功的回报(即默认客户),经过精度调整(即所有预测阳性中真实阳性的比例),这使得术语 (P(t) * s - c) 成为每次成功的净回报。此外,由于我们没有将所有的情况都标记为正,我们还通过排队率 Q(t) 来调整净收益,并将乘积乘以观察次数 n.

第二个等式计算使支付函数PF(t;n,s,c) 鉴于其低于审查能力r;否则, r 成为最佳判别阈值。

调用交互剧情的脚本几乎和静态版一样短。

在附带的 Github 资源库中, 模块中定义了准备数据和调用绘图函数的专用方法的类,interactive _ discrimina tion _ threshold . py*。仪表盘的代码在 app.py 中。我试图用每个类属性和方法的详细描述来填充模块内部的文档字符串,所以在这里重复相同的文本会使这篇文章过长。简单地说,类InteractiveDiscriminationThreshold包含方法 prepare_data()、_append_metrics()、_get_metrics() 和 *plot()、其中:

  • prepare_data() 迭代地抽取子样本(带替换),在其上训练模型,获得测试集预测,然后为每次迭代调用方法*_ append _ metrics()*;
  • _append_metrics() 创建一个数组,包含所有可能的阈值以及每个阈值的真实标签和预测分数,调用方法*_ get _ metrics();*
  • _get_metrics() 给定阈值、真实标签和预测分数,计算并返回精度、召回率、F1 分数和排队率;
  • plot() 在我们用输入值准备好表格后,从 app.py 调用函数 build_plot()

函数 build_plot() 大约有 350 行长,理解它需要一些使用 Plotly Dash 框架的经验。幸运的是,Plotly 是一个文档丰富的库,有一个非常活跃的社区。也就是说,掌握 Plotly 生态系统需要一定的耐心、承诺和修改代码。

结论

总而言之,这篇文章有三个要点:

  • 在二元分类中,为模型性能选择最佳鉴别阈值与选择和微调最佳候选模型一样重要;
  • 如果你正在寻找一个快速和肮脏的方法来计算和绘制最佳的辨别阈值,那么 Yellowbrick 的专用功能是你的首选工具;
  • 作为一个更好看、功能更丰富、交互性更强的选择,您可以使用来自这个库的仪表盘,并根据您的需求进行定制。

感谢您的阅读!

Python 中的鸭式打字是什么?

原文:https://towardsdatascience.com/duck-typing-python-7aeac97e11f8

理解动态类型编程语言(如 Python)中鸭类型的概念

杰森·理查德在 Unsplash 上的照片

介绍

Duck Typing 是一个通常与动态类型化编程语言和多态性相关的术语。这一原则背后的想法是,代码本身并不关心一个对象是否是一只鸭子,而是只关心它是否嘎嘎叫

如果它走路像鸭子,叫起来像鸭子,那它一定是鸭子。

理解 Python 中的 Duck 类型

让我们考虑一下+ Python 操作符;如果我们对两个整数使用它,那么结果将是两个数的和。

>>> a = 10 + 15
>>> a
25

现在让我们考虑同样的字符串对象类型的操作符。结果将是两个对象相加在一起的连接。

>>> a = 'A' + 'B'
>>> a
'AB'

这种多态行为是 Python 背后的核心思想,Python 也是一种动态类型化的语言。这意味着它在运行时执行类型检查,而静态类型语言(如 Java)在编译时执行类型检查。

此外,在静态类型语言中,我们还必须在源代码引用变量之前声明变量的数据类型。

**// Python** a = 1**// Java**
int a;
a = 1

Python 本身会自动重载一些操作符,以便它们根据正在处理的内置对象的类型执行不同的操作。

def add_two(a, b):
    print(a + b)

这意味着任何支持+操作符的对象都可以工作。事实上,语言本身重载了一些操作符,因此所采取的操作依赖于所涉及的对象的特定数据类型。

Duck Typing 指的是不将代码约束或绑定到特定数据类型的原则

让我们考虑下面的两个示例类。

class Duck: 

    def __init__(self, name):
        self.name = name def quack(self):
        print('Quack!')class Car: 

    def __init__(self, model):
        self.model = model

    def quack(self):
        print('I can quack, too!')

由于 Python 是一种动态类型语言,我们不必指定函数中输入参数的数据类型。

def quacks(obj):
    obj.quack()

现在,如果我们用不同的对象调用同一个函数两次,所采取的动作将取决于输入对象的数据类型。

>>> donald = Duck('Donald Duck')
>>> car = Car('Tesla')
>>>
>>> quacks(donald)
'Quack!'
>>>
>>> quacks(car)
'I can quack, too!'

如果对象不支持指定的操作,它将自动引发异常。

>>> a = 10
>>> quacks(a)
AttributeError: 'int' object has no attribute 'quack'

因此,在 Python 中,我们通常避免强制进行这种手动错误检查,因为这会限制可能涉及的对象类型。在一些特殊情况下,你可能仍然想检查一个对象的类型(例如使用type()内置函数)。

但是请注意,您应该避免根据特定的数据类型来区分所采取的操作,因为这将降低代码的灵活性。但是在其他一些情况下,这可能表明问题出在设计层面,而不是代码本身。

最后的想法

在今天的文章中,我们讨论了 Duck 类型以及它与多态和方法重载的关系。此外,我们讨论了静态类型语言和动态类型语言之间的两个主要区别,以及这如何使 Python 代码能够应用于对象而无需关心它们的实际数据类型。

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

https://gmyrianthous.medium.com/membership

你可能也会喜欢

DVC + GitHub 动作:自动重新运行修改过的管道组件

原文:https://towardsdatascience.com/dvc-github-actions-automatically-rerun-modified-components-of-a-pipeline-a3632519dc42

快速迭代 DS 项目的完美组合

动机

假设您的数据管道看起来类似于下图。

作者图片

粉色方框代表一个阶段,这是一个单独的数据过程。依赖项是阶段所依赖的文件,如参数、Python 脚本或输入数据。

现在想象一下Dependencies 2的变化。标准的方法是重新运行整个管道。

作者图片

这种方法可行,但效率低下。只运行依赖关系改变了的阶段不是更好吗?

作者图片

这时,DVC 和 GitHub 操作的结合就派上了用场。在本文中,您将学习如何:

  • 推送提交时,使用 GitHub 操作运行工作流
  • 使用 DVC 运行具有修改相关性的阶段

最终,结合这两个工具将帮助减少摩擦时间来试验不同的参数、代码或数据。

作者图片

本文中使用的代码可以在这里找到:

https://github.com/khuyentran1401/prefect-dvc/tree/dvc-pipeline

使用 DVC 管道运行修改后的数据流程

DVC 是数据版本控制系统。它本质上类似于 Git,但用于数据。

DVC 管道允许你指定产生最终结果的单个数据过程(称为阶段)。

流水线阶段

让我们通过在文件dvc.yaml中创建两个阶段来创建一个 DVC 管道。总而言之,

  • process_data阶段处理原始数据
  • train阶段训练处理后的数据
stages:
  process_data: # process raw data
    cmd: python src/process_data.py
    params: 
        - config/process/process_1.yaml:
    deps:
    - data/raw
    - src/process_data.py
    outs:
    - data/intermediate

  train: # train processed data
    cmd: python src/segment.py
    params:
        - config/main.yaml:
    deps:
    - data/intermediate
    - src/segment.py
    outs:
    - data/final
    - model/cluster.pkl
    plots:
    - image

上述代码的详细信息:

  • cmd指定运行舞台的命令
  • deps指定阶段所依赖的文件
  • 指定了一种特殊的依赖:参数
  • outs指定阶段输出的目录
  • plots指定一种特殊的输出:plot

繁殖

要在dvc.yaml中运行管道,键入:

dvc repro

输出:

Running stage 'process_data'                                                                        
Updating lock file 'dvc.lock'                                                                         

Running stage 'train':
Updating lock file 'dvc.lock' 

第一次运行这个命令时,DVC:

  • 运行管道中的每个阶段
  • 缓存运行结果
  • 创建dvc.lock文件。该文件描述了要使用的数据和生成管道结果的命令。

作者图片

现在让我们说我们改变了依赖于train阶段的src/segment.py文件。当您再次运行dvc repro时,您将看到以下内容:

Stage 'process_data' didn't change, skipping                                                                                                                               

Running stage 'train':
Updating lock file 'dvc.lock' 

从输出中,我们可以看到 DVC 只运行train阶段,因为它:

  • 检测train阶段的变化
  • 不检测process_data阶段的变化。

作者图片

这可以防止我们在不必要的重播上浪费时间。

要使用 Git 跟踪管道中的变化,运行:

git add dvc.lock

要将更新发送到远程存储,请键入:

dvc push

用 GitHub 动作推送提交时运行管道

GitHub Actions 允许你自动化你的工作流程,从而更快地构建、测试和部署你的代码。

https://pub.towardsai.net/github-actions-in-mlops-automatically-check-and-deploy-your-ml-model-9a281d7f3c84

在向 GitHub 提交更改时,我们将使用 GitHub 操作来运行 DVC 管道。

首先在.github/workflows目录下创建一个名为run_pipline.yaml的文件:

.github
└── workflows
    └── run_pipeline.yaml

这是run_pipeline.yaml文件的样子:

name: Run code
on:
  push: 
    branches:
     - dvc-pipeline
    paths:
      - config/**
      - src/**
      - data/*
jobs:
  run_code:
    name: Run code
    runs-on: ubuntu-latest
    container: khuyentran1401/customer_segmentation:dvc
    steps:
      - name: Check out the current repository
        id: checkout
        uses: actions/checkout@v2

      - name: Pull data from DVC
        run: |
          dvc remote modify origin --local auth basic
          dvc remote modify origin --local user ${{ secrets.DAGSHUB_USERNAME }}
          dvc remote modify origin --local password ${{ secrets.DAGSHUB_TOKEN }}
          dvc pull

      - name: Run the pipeline with DVC
        run: dvc repro

      - name: Push the outcomes to DVC remote storage 
        run: dvc push

      - name: Commit changes in dvc.lock
        uses: stefanzweifel/git-auto-commit-action@v4
        with:
          commit_message: Commit changes in dvc.lock
          branch: dvc-pipeline
          file_pattern: dvc.lock

让我们通过分解来理解上面的文件。

文件的第一部分指定了导致工作流运行的事件。这里,我们告诉 GitHub Actions 在以下情况下会触发Run code工作流:

  • 提交被推送到dvc-pipeline分支
  • 推送包括对configssrcdata目录中文件的更改
name: Run code
on:
  push: 
    branches:
     - dvc-pipeline
    paths:
      - config/**
      - src/**
      - data/*

工作流运行由一个或多个作业组成。作业包括一组按顺序执行的步骤。文件的第二部分列出了run_code任务中的步骤。

jobs:
  run_code:
    name: Run code
    runs-on: ubuntu-latest
    container: khuyentran1401/customer_segmentation:dvc
    steps:
      - name: Check out the current repository
        id: checkout
        uses: actions/checkout@v2

      - name: Pull data from DVC
        run: |
          dvc remote modify origin --local auth basic
          dvc remote modify origin --local user ${{ secrets.DAGSHUB_USERNAME }}
          dvc remote modify origin --local password ${{ secrets.DAGSHUB_TOKEN }}
          dvc pull

      - name: Run the pipeline with DVC
        run: dvc repro

      - name: Push the outcomes to DVC remote storage 
        run: dvc push

      - name: Commit changes in dvc.lock
        uses: stefanzweifel/git-auto-commit-action@v4
        with:
          commit_message: Commit changes in dvc.lock
          branch: dvc-pipeline
          file_pattern: dvc.lock

写完工作流后,把文件推送到 GitHub。

让我们通过更改文件src/segment.py并将其推送到 GitHub 来尝试工作流。

git add .
git commit -m 'edit segment.py'
git push origin dvc-pipeline

当您单击存储库中的 Actions 选项卡时,您应该看到一个名为edit segment.py的新工作流运行。

作者图片

点击运行以查看关于哪个步骤正在运行的更多细节。

作者图片

恭喜你!我们刚刚成功地使用 GitHub Actions 和 DVC 来:

  • 当更改被推送到 GitHub 时运行工作流
  • 仅重新运行具有已修改相关性的阶段

下一步是什么

如果您是一名数据从业者,正在寻找一种更快的方法来迭代您的数据科学项目,我鼓励您尝试一下。通过一些初始设置,从长远来看,您将为您的团队节省大量时间。

我喜欢写一些基本的数据科学概念,并尝试不同的数据科学工具。你可以在 LinkedIn 和 Twitter 上联系我。

如果你想检查我写的文章的代码,请点击这里。在 Medium 上关注我,了解我的最新数据科学文章,例如:

</4-pre-commit-plugins-to-automate-code-reviewing-and-formatting-in-python-c80c6d2e9f5>

DX 是新的 UX

原文:https://towardsdatascience.com/dx-is-the-new-ux-1565304a4c82

数据体验的兴起

DX 是新的 UX——图片由 Castor 提供

在过去十年中,数据生态系统中的大多数创新都集中在产生更多数据的**。它成功了,正如 UX 随着数字产品的激增变得重要一样,DX 也随着数据产品的蓬勃发展占据了重要的位置。**

事实上,20 年前,数据是 IT 团队和少数数据奇才的领域。即使在 5 年前,它仍然主要由数据团队所有。如今,数据驱动着公司内的所有运营职能:销售、财务、营销、运营等。多亏了、反向 ETL 、BI 工具和自助服务,业务团队将数据作为日常运营的一部分。

简而言之,业务用户变成了数据用户,他们的体验变成了数据体验。数据体验是这些领域专家每天使用数据来增强工作能力时的感受。

****数据体验并不新鲜。业界已经谈论它有一段时间了。它也接近去年每个人都想到的数据网格和数据产品的概念。

达成共识很容易:数据体验被破坏并且需要修复。事实上,数据生态系统是分散的,很难统一工作流并在工具之间提供流畅的体验。

坏消息是,如果我们等待生态系统提出解决方案,我们将会在很长一段时间内默默忍受。生态系统不太可能汇聚成一个统一的解决方案,突然提供跨整个堆栈的良好数据体验,从数据接收和仓库一直到转换和可视化。在那之前我们做什么?

我们的挑战是从我们现有的地方开始,利用我们现有的人员和工具,让数据体验更好。

本文旨在定义什么是良好的数据体验**。经验远不止是工具和组织框架。对我们来说,良好的数据体验意味着在以下三个领域实现卓越:发现、社区和健康。我们将在下一节深入探讨这三个领域的卓越之处。**

数据体验的三大支柱——由卡斯特提供的图像

良好的数据体验是什么样子的?

我们对良好数据体验的看法基于三大支柱:发现、社区和健康。这三个要素及其相互作用的产物构成了数据体验的主体。每个类别都封装了许多重叠的工具和概念。出于本文的目的,我们避免进入我们为后面的系列保留的繁琐细节。让我们更详细地看看这些支柱。首先,您需要找到&并理解您所拥有的。然后,随着你的成长,分享&和围绕它交流一定很容易。一旦事情被发现&可以作为一个团队使用,您现在就可以改善健康状况因为您可以有效地发现数据资产&在问题出现时进行沟通。这是数据体验的马斯洛金字塔。

支柱 1:发现

数据体验的第一个支柱是数据发现**。解锁数据发现意味着您组织中的人员可以查找理解使用他们的数据资产,同时最大限度地减少不同团队之间不必要的交互。其思想是,体验是一个有几个步骤的工作流程。改善这种体验归结于在过程的每一步都移除阻断剂。**

数据发现工作流程-图像由 Castor 提供

发现

当数据工程师不再被视为数据目录时,数据就“可被发现”了。也就是说,人们不再懈怠地询问在哪里可以找到特定的数据集,以及在给定的报告中使用该数据集是否可靠。

这意味着公司里的每个人都知道在哪里以及如何为他们的特定项目找到最好的数据。即使数据很混乱。即使有 20 张几乎同名的桌子。

那么“好”是什么样子的呢?当团队可以轻松地在混乱中导航,毫不费力地确定哪些是最流行和最新的表格,而无需询问他们的同事或老板时,数据是可以找到的。改善数据体验的数据发现支柱需要消除所有与知道使用哪些数据相关的摩擦点。

同样,这可以通过很多方式实现:废弃无用的表格或记录数据。不管通过什么途径到达那里,你都应该追求一种体验,在这种体验中,人们永远不会费力去寻找一个数据集。

明白;理解

当人们意识到数据将满足的需求**、其内容和位置时,他们就理解了数据集。没有上下文的数据毫无价值&危险。一旦你找到了相关的数据集,你就完成了 10%的工作。现在,您需要仔细阅读一份包含 10 多个问题的清单,以确保您了解您使用的是什么数据。如果你不能回答下面的问题,说明你不了解你的数据。**

  • 数据从哪里来?
  • 流向哪里,向下游馈给哪些表?
  • 谁拥有它/谁对它负责?
  • 我的领域中给定字段的含义是什么?
  • 为什么重要?
  • 这个表最后一次更新是什么时候?
  • 这些数据的上游和下游依赖关系是什么?
  • 这是生产质量数据吗?

所有相关知识都与数据联系在一起时,人们才能真正理解数据。理解是主观的。ML 工程师处理数据集的方式与数据分析师不同。这就是为什么所有的理解都需要将所有相关的知识层与一个数据集联系起来。

使用

人们使用和利用数据有两个必要条件。人们需要访问数据,并围绕数据收集足够的上下文,以知道它适合于哪个用例。

过去,访问很简单。不再是了。GDPR 或 HIPAA 等严格的法规要求严格控制数据访问。对于我们今天处理的数据量,很难在数据治理和数据可访问性之间找到合适的平衡。很难在保护信息的同时确保人们能够在需要的时候访问他们需要的数据集。

****查询您的数据。在几秒钟内获得您需要的答案。良好的数据体验使得任何人查询数据都非常容易,不管有没有代码。浏览领域专家已经做过的工作,开始你的分析。重用团队中有经验的数据人员编写的强大查询。告别重复工作。不管人们的背景如何,查询数据应该变得非常简单。查询允许人们利用数据并获得问题的答案。

支柱 3:社区

数据社区的四块砖—图片由 [Castor](/Find A good indication that data is “findable” is when data engineers stop being treated like a data catalog. That is, people stop pinging them on slack asking where to find a specific dataset, and whether it is reliable to use for a given report. This means everyone in the company knows where and how to find the best data for their specific project. Even if data is messy. Even if there are 20 tables bearing the almost same name. So what does “good” look like?%20Data%20is%20findable**%20when%20teams%20can%20easily%20navigate%20across%20the%20mess,%20and%20identify%20effortlessly%20which%20are%20the%20most%20popular%20and%20up-to-date%20tables%20without%20asking%20their%20colleagues%20or%20boss.%20Improving%20the%20data%20discovery%20pillar%20of%20the%20Data%20Experience%20goes%20through%20removing%20all%20friction%20points%20related%20to%20knowing%20which%20data%20to%20use.%20%20Again,%20this%20can%20be%20achieved%20in%20a%20lot%20of%20ways:%20deprecating%20useless%20tables%20or%20documenting%20your%20data.%20Regardless%20of%20the%20path%20taken%20to%20arrive%20there,%20you%20should%20be%20aiming%20for%20an%20experience%20where%20people%20NEVER%20struggle%20to%20find%20a%20dataset.%20%20%20Understand%20%20People%20understand%20a%20dataset%20when%20they%20are%20aware%20of%20the%20needs%20this%20data%20will%20satisfy,%20its%20content,%20and%20its%20location.%20Data%20without%20context%20is%20worthless%20&%20dangerous.%20Once%20you%20found%20the%20relevant%20dataset,%20you%20did%2010%%20of%20the%20job.%20Now%20you%20need%20to%20go%20through%20a%20checklist%20of%2010+%20questions%20to%20make%20sure%20you%20understand%20what%20data%20you%20are%20using.%20If%20you%20can%E2%80%99t%20answer%20the%20following%20question,%20you%20don%E2%80%99t%20understand%20your%20data.%20%20%20-%20Where%20does%20the%20data%20come%20from?%20-%20Where%20does%20it%20flow%20and%20which%20tables%20does%20it%20feed%20downstream?%20-%20Who%20owns%20it%20/%20who%20is%20responsible%20for%20it?%20-%20What%20is%20the%20meaning%20of%20a%20given%20field%20in%20my%20domain?%20-%20Why%20does%20it%20matter?%20-%20When%20was%20the%20last%20time%20this%20table%20was%20updated?%20-%20What%20are%20the%20upstream%20and%20downstream%20dependencies%20of%20this%20data?%20-%20Is%20this%20production-quality%20data?%20%20People%20can%20truly%20understand%20the%20data%20when%20all%20the%20relevant%20knowledge%20is%20tied%20to%20it.%20Understanding%20is%20subjective.%20An%20ML%20engineer%20will%20approach%20a%20dataset%20differently%20than%20a%20data%20analyst.%20This%20is%20why%20all%20understanding%20goes%20through%20tying%20all%20the%20relevant%20knowledge%20layers%20to%20a%20dataset.%20%20%20Use%20%20There%20are%20two%20necessary%20conditions%20for%20people%20to%20use%20and%20leverage%20data.%20People%20need%20to%20access%20the%20data%20and%20gather%20enough%20context%20around%20it%20to%20know%20which%20use%20case%20it%20is%20good%20for.%20%20%20Access%20used%20to%20be%20straightforward.%20Not%20anymore.%20Tight%20regulations%20such%20as%20GDPR%20or%20HIPAA%20require%20data%20access%20to%20be%20firmly%20controlled.%20With%20the%20data%20volumes%20we%E2%80%99re%20dealing%20with%20today,%20it%20has%20become%20hard%20to%20find%20the%20right%20balance%20between%20data%20governance%20and%20data%20accessibility.%20It%E2%80%99s%20hard%20to%20protect%20information%20while%20ensuring%20that%20people%20can%20access%20the%20dataset%20they%20need,%20at%20the%20exact%20moment%20they%20need%20it.%20%20Query%20your%20data.%20Obtain%20the%20answer%20you%20need%20from%20it%20in%20seconds.%20A%20good%20Data%20Experience%20makes%20it%20super%20easy%20for%20anyone%20to%20query%20the%20data,%20with%20or%20without%20code.%20Kickstart%20your%20analysis%20by%20browsing%20through%20what%20domain%20experts%20already%20did.%20Reuse%20the%20powerful%20queries%20written%20by%20experienced%20data%20people%20in%20your%20team.%20Say%20goodbye%20to%20duplicate%20work.%20Querying%20the%20data%20should%20be%20made%20an%20incredibly%20easy%20step,%20regardless%20of%20people%E2%80%99s%20backgrounds.%20Queries%20allow%20people%20to%20leverage%20the%20data%20and%20obtain%20answers%20to%20their%20questions.%20%20%20##%20Community) 提供**

社区是数据体验的基本支柱。社区被定义为“一种与他人相交的感觉,是分享共同兴趣和目标的结果”。不管在你的组织中社区采取什么形式,创造这种感觉是关键。

事实上,在数据团队中没有竖井的空间。筒仓让你走上了失败之路。数据工程师、分析工程师、数据科学家、数据分析师和业务分析师都有相同的目标:利用数据帮助他们的组织蓬勃发展。他们在同一条船上,这就是为什么对他们来说感觉到他们在同一条船上是很重要的。

数据团队的解决方案社区包含四个组成部分:

  1. 内部沟通协调。在现代组织中,度量标准和业务定义的不一致性仍然是一个令人头疼的问题。很难就对每个人都重要的 KPI 达成一致,定义存在于我们分散的数据堆栈的不同工具中。团队应该寻求内部数据实践 100%符合指标、KPI 和仪表板的体验。在这个世界里,数据资产是经过认证的,你对“活跃用户”只有一个定义(我知道,对吗?).即使你的团队使用几十个数据工具,每个人都应该配备相同的信息。
  2. 对外交流。数据知识往往不会离开数据团队。我们应该致力于构建一种数据体验,让数据在数据团队和其他利益相关者之间无缝流动。运营团队应该能够在其日常工具中访问数据知识的非技术概述。无论部门、角色、任期和数据素养水平如何,员工都必须理解数据才能高效工作。社区确保数据知识不会停留在数据团队中。
  3. ****用法和团队。目前,组织中的数据使用缺乏透明度。不可能看到人们如何转换、查询和使用给定的数据集。这导致了大量的重复工作,通过让人们先睹为快可以很容易地避免这些重复工作。让你的团队明白他们并不孤单。良好的数据体验能让员工看到其他人如何使用数据。它允许每个人重用和利用他们团队成员已经完成的工作。意识到他人的消费正在激起一种友谊的感觉,这种感觉是社区的特征。
  4. ****讨论和反馈。团队将从轻松交流和表达想法的体验中受益。目前,回答与数据集相关的问题的唯一方法是 ping slack 上的 10 个同事,希望有人会回复。分散化和远程工作应该使我们更加意识到需要创建接口,以允许数据团队内部以及数据团队和其他数据利益相关者之间的顺畅通信。例如,这可能采取附加到每个数据集的聊天的形式。

支柱 3:健康

健康的数据系统——图片由 Castor 提供

良好的数据体验始于健康的数据环境。这样,我们并不意味着你的数据应该遵循酮饮食和从事每天 18 小时的间歇性禁食。

健康的数据应该是发现、社区和强大治理框架的自然结果。原因很简单。数据健康描述了组织的数据如何支持其业务目标。健康数据是容易被发现、理解并对需要使用它的人有价值的数据。

健康的数据意味着组织中的每个人都可以在他们需要的时候访问他们需要的信息,并且使用它而不用担心它的有效性。健康还意味着您知道您的数据资产是如何关联的**。如果你对资产之间的关系没有一个清晰的认识,你甚至可以在没有意识到的情况下,贬低为你的 CEO 最喜欢的仪表板提供信息的表格。**

健康的数据还应该在整个数据生命周期中保持这些属性。这远非简单明了。现代数据管道非常复杂,并显示出黑盒特征。你知道进去的是什么,出来的是什么,但你不知道中间发生了什么。

只要出现想要的结果就好。但如果没有,那就非常令人沮丧。当数据集从管道中出来时,通常会留下奇怪的值、缺失的列、本应是数字的字段中的字母等等。

因此,健康数据是可观察的数据。它的状态应该始终是明确的**:您应该知道上游流程是否运行不正常、是否过时或者是否只是被破坏。 数据可观察性 在监控数据系统的健康状况方面,工具可以做很多事情。它们允许您快速发现事件,并在数据损坏时进行干预。**

健康的数据环境具有以下特征:

  • 清楚地了解哪些数据可用,以及如何利用这些数据为您的组织带来好处。
  • 参与数据管理的各方之间的信任文化。
  • 一个强大的安全系统,以防止未经授权的访问或滥用所述数据。
  • 适应新技术的计划。

碎片化生态系统中的数据体验

现在的问题是:你如何让自己做到这一点?答案不在于等待,直到生态系统弄清楚事情,并最终决定整合。我们需要利用我们拥有的:我们拥有的人员、工具和数据。这个系列是关于利用我们现有的生态系统来改善我们团队的数据体验。同样,良好的数据体验可以采取多种形式,只要它建立在坚如磐石的发现支柱、数据团队中强烈的社区意识以及健康的数据生态系统之上。

最初发表于T5【https://www.castordoc.com】

Power BI 中带场参数的动态轴

原文:https://towardsdatascience.com/dynamic-axes-with-field-parameters-in-power-bi-fc3403d7dcf2

没有其他方法可以在度量之间切换

图片来自黛安·皮凯蒂诺

直到最近,还很少有方法可以让用户更改度量或权力的轴心 BI 可视化。

我们要么受困于复制图表和创建大量书签,要么不得不采取变通办法,用汇总表格预先计算度量值,在模型中创建冗余或笨拙的新维度。它们都不容易维护或修改。

不再是了!在 5 月份的更新中,PBI 获得了一个名为字段参数的新功能。

本文将探讨如何使用它们,什么时候它能拯救世界,什么时候它能让我们期待更多。

X 轴和 Y 轴的场参数可视化—图片由作者提供

要求

在我们开始之前,您可能需要更新您的 Power BI 桌面并启用现场参数。

要启用此功能,您需要进入:
文件—选项和设置—预览功能—字段参数

选项菜单—作者图片

添加字段参数

选中复选框并重新启动应用程序后,我们应该会在 Home-Modeling-New parameter 上看到新的字段选项。

“新参数”下拉菜单-作者图片

单击它后,会出现一个窗口提示我们选择想要使用的度量或字段。

该操作将在我们的模型中创建一个新的计算表,该表将保存参数的显示名称、对字段/度量值的引用以及带有显示顺序的整数。

添加参数窗口-作者提供的图像

除了选择度量之外,我们还可以为新表设置一个名称,重命名我们的参数,并选择是否要为它们自动创建一个切片器。

带参数的切片器—图片由作者提供

酷,我们有一个带有参数的计算表,现在我们需要将它们添加到一个可视化中,这与任何其他度量或字段的工作方式相同。

y 轴上有字段参数的视觉图像—作者提供的图像

厉害!现在,我们的用户可以动态地选择他们想要看到的度量。

切换图表 y 轴的字段参数—图片由作者提供

使用相同的步骤,我们还可以创建一个参数来更改 X 轴:

切换图表 x 轴和 y 轴的字段参数—图片由作者提供

出于某种原因,默认情况下,条形图使用 y 轴的值进行排序。我找不到禁止这种行为的方法;即使您更正了排序,当我们更改选择时,它也会回到默认状态。

这有点令人沮丧,因为我们的约会被打乱了。

我也错过了过滤器控制。当我们在 x 轴上的不同字段之间切换时,我们可能会发现没有完全填充的类别。在这个数据集中,“Promotion”有空值,我不想显示这些值。

如果我使用书签,我可以过滤掉促销画面中的空白,继续我的一天。有了参数,我需要向 DAX 公式添加一个条件,检查 Promotion 是否在范围内,如果是,则过滤掉空白。

编辑参数表

我们看到字段参数存储在一个计算表中,这意味着我们可以编辑它的 DAX 并添加新列。

要查看代码,我们可以单击参数字段。

该公式包含一个用括号括起来的列表;这个列表中的每一行都代表我们表中的一行。我们看到每条记录有三个值,一个字符串、一个函数和一个整数。

第一个值对应于我们的第一列 name,第二个值是检索我们的度量的函数,第三个值定义排序顺序。

Parameter = {("Sales", NAMEOF('Sales'[.SalesValue]), 0),
("Costs", NAMEOF('Sales'[.CostsValue]), 1),
("Profit", NAMEOF('Sales'[.ProfitValue]), 2),
("Production", NAMEOF('Sales'[.ProductionTimeliness]), 3),
("Packing", NAMEOF('Sales'[.PackingTimeliness]), 4),
("Shipping", NAMEOF('Sales'[.ShippingTimeliness]), 5),
("Delivery", NAMEOF('Sales'[.DeliveryTimeliness]), 6),
("Order to Delivery", NAMEOF('Sales'[.TotalTimeliness]), 7)}

如果需要更改任何名称、显示顺序、添加新参数或列,我们可以编辑这段代码。

例如,我们可以添加一个字符串来定义参数组。

Parameter = {("Sales", NAMEOF('Sales'[.SalesValue]), 0**, "Financials"**),
("Costs", NAMEOF('Sales'[.CostsValue]), 1**, "Financials"**),
("Profit", NAMEOF('Sales'[.ProfitValue]), 2**, "Financials"**),("Production", NAMEOF('Sales'[.ProductionTimeliness]), 3**, "Timeliness"**),
("Packing", NAMEOF('Sales'[.PackingTimeliness]), 4**, "Timeliness"**),("Shipping", NAMEOF('Sales'[.ShippingTimeliness]), 5**, "Timeliness"**),("Delivery", NAMEOF('Sales'[.DeliveryTimeliness]), 6**, "Timeliness"**),("Order to Delivery", NAMEOF('Sales'[.TotalTimeliness]), 7**, "Timeliness"**)}

具有层次级别的字段参数—作者提供的图像

总的来说,这张桌子和其他桌子一样好用。我们不仅可以编辑它的内容,还可以创建与其他表的关系。

与参数表的关系—图片由作者提供。

除此之外,我们可以使用这些关系连接到一个带有定义的表,并动态地描述所选的度量。

带有动态测量描述的报告-图片由作者提供

最后的想法

总的来说,字段参数为 Power BI 增加了很多功能;与以前的解决方案相比,重用可视化来显示不同的度量和字段使得开发速度更快,并且报表更易于维护。

综上所述,我认为还有改进的空间。在我看来,当我们需要更精确的可视化时,书签仍然是一个不错的选择。当我们需要一个特定的视觉配色方案,一个不同的排序,或者甚至当一些设计选择不能很好地与所有措施配合时,它们就非常有用。

Power BI 社区在提出变通办法或扩展工具的可用性时非常有创造力。我很兴奋地想看看场参数会带来什么样的可能性。

本例中使用的数据是用 Mockaroo 生成的,可在这里获得。

感谢阅读我的文章!

如何使用 Plotly 进行更深入和互动的数据探索

原文:https://towardsdatascience.com/dynamic-eda-for-qatar-world-cup-teams-8945970f16be

案例研究:卡塔尔世界杯球队的动态 EDA

世界杯球队的动态 EDA(图片由作者提供)

本文将详细介绍工具[1],它将数据可视化和探索性数据分析(EDA)带到了一个新的高度。无论您是 Python 用户还是 R 用户,您都可以使用这个开源图形库来使您的笔记本更加美观和具有交互性。要安装 Plotly,使用命令!pip install — upgrade plotly

我们就用“历史世界杯胜散比数据【2】”来分析参加卡塔尔 2022 世界杯的国家队。数据集包含每个“国家 1-国家 2”对之间的赢、输和平局比率,如下所示。例如,第一行给我们的信息是,在阿根廷和澳大利亚之间的 7 场比赛中,阿根廷赢、输和平的比率分别是 0.714286、0.142857 和 0.142857。

df = pd.read_csv('/kaggle/input/qatar2022worldcupschudule/historical_win-loose-draw_ratios_qatar2022_teams.csv')

df 预览

在本练习中,我们将利用箱线图、条形图、choropleth 图和热图进行数据可视化和探索。此外,我们还将介绍与这些可视化技术密切相关的高级 Pandas 功能,包括:

  • 聚合:*df.groupby()*
  • 排序:*df.sort_values()*
  • 合并:*df.merge()*
  • 旋转:*df.pivot()*

箱线图—按国家列出的胜率

箱线图—按国家/地区列出的胜率(按作者列出的图片)

第一个练习是想象每个国家与其他国家比赛时的胜率。为了实现这一点,我们可以使用箱线图来描绘每个国家的胜率分布,并进一步用该国的大洲来着色。将鼠标悬停在数据点上以查看详细信息,并放大方框图以查看最大值、q3 值、中值、q1 值和最小值。

让我们一步一步地分解我们是如何构建盒状图的。

1.获取大陆数据

从原始数据集中,我们可以使用字段“wins”并按“country1”进行分组,来研究一个国家内的值与国家间的值相比如何变化。为了进一步探究胜率是否受洲的影响,我们需要引入 plotly 内置数据集px.data.gapminder()中的“洲”字段。

geo_df = px.data.gapminder()

geo_df(图片由作者提供)

(这里我使用“大陆”作为例子,也可以随意使用“lifeExp”和“gdpPercap”)

由于只需要洲信息,我们使用drop_duplicates()删除其他列来选择不同的行。

continent_df = geo_df[['country', 'continent']].drop_duplicates()

然后,我们将 geo_df 与原始数据集 df 合并,以获得大陆信息。如果您以前使用过 SQL,那么您将熟悉表连接/合并。df.merge()的工作方式相同,它将 df (即“国家 1”)和continental _ df(即“国家”)中的公共字段组合在一起。

continent_df = geo_df[['country', 'continent']].drop_duplicates()
merged_df = df.merge(continent_df, left_on='country1', right_on='country')

merged_df(图片由作者提供)

2.创建箱形图

我们应用 px.box 函数,并指定以下参数,这些参数描述了馈入盒图的数据。

fig = px.box(merged_df, 
             x='country1', 
             y='wins', 
             color='continent',
...

3.格式化绘图

以下参数是可选的,但有助于格式化图并在视觉效果中显示更多有用的信息。

fig = px.box(merged_df, 
             x='country1', 
             y='wins', 
             color='continent',
# formatting box plot
             points='all',
             hover_data=['country2'],
             color_discrete_sequence=px.colors.diverging.Earth,
             width=1300,
             height=600
            )
fig.update_traces(width=0.3)
fig.update_layout(plot_bgcolor='rgba(0,0,0,0)')
  • points = ‘all’ 表示除了方框图之外的所有数据点都显示出来。将鼠标悬停在每个数据点上以查看详细信息。
  • hover_data=[‘country2’]在悬停框内容中增加了“国家 2”。
  • color_discrete_sequence=px.colors.diverging.Earths指定颜色主题。请注意,当用于着色的字段是离散的分类值时,应用*color_discrete_sequence*。或者,当字段是连续的数值时,应用*color_continuous_scale*
  • width=1300height=600指定图形的宽度和高度尺寸。
  • fig.update_traces(width=0.3)更新每个方框图的宽度。
  • fig.update_layout(plot_bgcolor=’rgba(0,0,0,0)’)将图形背景颜色更新为透明。

条形图—按国家列出的平均胜率

条形图—按国家/地区列出的平均胜率(按作者列出的图片)

第二个练习是可视化每个国家的平均胜率,并按降序排列,以便查看表现最佳的国家。

首先,我们使用下面的代码进行数据操作。

average_score = df.groupby(['country1'])['wins'].mean().sort_values(ascending=False
  • df.groupby([‘country1’]) : 将 df 按字段“country1”分组。
  • [’wins’].mean():取“赢”值的平均值。
  • sort_values(ascending=False):按降序排列数值。

然后我们使用pd.DataFrame()average _ score(Series 数据类型)转换成类似表格的格式。

average_score_df = pd.DataFrame({'country1':average_score.index, 'average wins':average_score.values})

average_score_df 传递给 px.bar 函数,遵循与 px.box. 相同的语法

# calculate average wins per team and descending sort
fig = px.bar(average_score_df,
             x='country1',
             y='average wins',
             color='average wins',
             text_auto=True,
             labels={'country1':'country', 'value':'average wins'},
             color_continuous_scale=px.colors.sequential.Teal,
             width=1000,
             height=600
            )
fig.update_layout(plot_bgcolor='rgba(0,0,0,0)')

为了更进一步,我们还可以使用下面的代码,根据洲对条形图进行分组,以显示每个洲中表现最好的国家。

条形图—按洲分组的国家/地区的平均胜率(图片由作者提供)

# merge average_score with geo_df to bring "continent" and "iso_alpha"
geo_df = px.data.gapminder()
geo_df = geo_df[['country', 'continent', 'iso_alpha']].drop_duplicates()
merged_df = average_score_df.merge(geo_df, left_on='country1', right_on='country')
# create box plot using merged_df and colored by "continent"
fig = px.bar(merged_df,
             x='country1',
             y='average wins',
             color='average wins',
             text_auto=True,
             labels={'country1':'country', 'value':'average wins'},
             color_continuous_scale=px.colors.sequential.Teal,
             width=1000,
             height=600
            )
fig.update_layout(plot_bgcolor='rgba(0,0,0,0)')

Choropleth 地图—按地理位置划分的平均胜率

Choropleth 地图—按地理位置划分的平均胜率(图片由作者提供)

我们要探索的下一个可视化是通过地图显示国家的平均胜率。上图让我们更清楚地看到世界上哪些地区的表现相对较好,例如南美和欧洲。

ISO 代码用于识别国家的位置。在前面按洲进行着色的平均胜率代码片段中,我们将 geo_df 与原始数据集合并,以创建带有字段“洲”和“iso_alpha”的 merged_df 。在这个练习中,我们将继续使用 merge_df (如下图所示)。

merged_df(图片由作者提供)

然后我们使用px . choropleth函数,将参数locations定义为“iso_alpha”。

*fig = px.choropleth(merged_df, 
                    locations='iso_alpha',
                    color='average wins',
                    hover_name='country',
                    color_continuous_scale=px.colors.sequential.Teal,                
                    width=1000,
                    height=500,
                   )
fig.update_layout(margin={'r':0,'t':0,'l':0,'b':0})*

热图—国家对之间的胜率

热图—国家对之间的胜率(图片由作者提供)

最后,我们将引入热图来直观显示每个国家对之间的胜率,其中密集区域显示 y 轴上的国家胜率更高。此外,将鼠标悬停在单元格上以动态方式查看胜率。

我们需要使用df.pivot()函数来重建数据帧结构。下面的代码指定数据透视表的行为“country1”,列为“country2”,并将“wins”作为透视值。结果,左边的桌子变成了右边的桌子。

*df_pivot = df.pivot(index = 'country1', columns ='country2', values = 'wins')*

***

df 到 pivoted_df(图片由作者提供)*

然后我们使用 pivoted_dfpx.imshow 通过下面的代码创建热图。

*# heatmap
fig = px.imshow(pivoted_df, 
                text_auto=True,
                labels={'color':'wins'},
                color_continuous_scale=px.colors.sequential.Brwnyl,
                width=1000,
                height=1000
               )
fig.update_layout(plot_bgcolor='rgba(0,0,0,0)')*

感谢到达终点。如果你想阅读我更多关于媒介的文章,我将非常感谢你的支持,注册成为媒介会员。

带回家的信息

Plotly 为我们提供了创建动态可视化的能力,并产生了比静态图形更多的洞察力。我们利用世界杯趋势数据探索了以下 EDA 技术:

  • 箱形图
  • 条形图
  • 等值区域图
  • 热图

我们还解释了一些用于数据操作的高级 Pandas 函数,这些函数已在 EDA 过程中得到应用,包括:

  • 聚合:df.groupby()
  • 排序:df.sort_values()
  • 合并:df.merge()
  • 旋转:df.pivot()

更多这样的文章

* Destin Gong

德斯坦贡

EDA 和特征工程技术

View list9 stories

参考

[1] Plotly。(2022).Plotly 开源 Python 图形库。从 https://plotly.com/python/[取回](https://plotly.com/python/)

[2]卡格尔。(2022).卡塔尔 2022 年足球世界杯【CC0:公有领域】。检索自https://www . ka ggle . com/datasets/amine teffal/Qatar 2022 world cupschudule?select = historic _ win-loose-draw _ ratios _ Qatar 2022 _ teams . CSV

原载于 2022 年 12 月 10 日 https://www.visual-design.nethttps://www.visual-design.net/post/semi-automated-exploratory-data-analysis-process-in-python*

动态编程:框架

原文:https://towardsdatascience.com/dynamic-programming-the-framework-7af71604cd78

你在编码面试中需要知道的

图一。图标取自 Freepick

编码面试中最具挑战性的话题之一是动态编程。特别是在用动态规划将问题识别、处理和发展为优化任务的过程中。

在这篇博客中,我们将看到识别什么时候可以用动态编程解决问题的关键,以及如何一步一步地提出解决方案。你准备好了吗?让我们去吧!

如何识别一个问题可以用动态规划来解决?

动态规划范例指的是一个优化过程,其目的是有效地探索所有可能的解决方案,直到找到最佳结构。

通常,动态规划问题在其方法中需要计算"某事"的最大值或最小值,做"某事"的不同可能性,状态k中进程的结果值,等等。

比如斐波那契数列的nth数是多少?寻找斐波纳契数列的nth数变成了一个动态规划问题,因为本质上,第 n 个数是由数字n-1n-2决定的,而这两个数字又分别由n-2n-3以及n-3n-4决定。换句话说,为了找到状态k的解,我们需要知道其解递归相关的前k-1状态的解。

在图 2 中,我们可以看到斐波纳契数列对循环关系的依赖性的图形表示。

图二。斐波那契数列|作者图片示例

值得一提的是,基于 动态编程 的解决方案的方法可能与基于 分治技术 的解决方案相混淆。区别在于,与动态编程解决方案相比,基于分而治之的解决方案不代表递归依赖关系。

简而言之,确定您的代码访问问题是否可以用动态编程解决的关键是:

  • 确定问题是否可以分解为子问题(思考基本情况是什么在这一点上将是关键)。
  • 识别每个子问题之间是否有任何循环依赖关系(例如,子问题的解决方案是否影响后续子问题的解决方案)。
  • 依靠关键词:寻找*“某事”的最大值或最小值、寻找在一定限制下做“某事”*的n种可能性等。

一旦你确定手头的问题可以用动态规划来解决,你现在就需要一个策略来制定和开发解决方案。在下一部分,我们将看到提议和开发您的解决方案的三个基本组件。

让我们去吧!

框架

开发基于动态编程的解决方案的基本组件包括:

  1. 对每种状态之间的递归关系进行建模的函数或数据结构。
  2. 记忆和制表。
  3. 基本案例

让我们详细看一下每个元素。

1.函数或数据结构

对所有状态的探索需要一种数据结构,这种数据结构允许跟踪每个状态的解决方案。通常,使用用于迭代扫描的数组(基于自下而上的方法)或用于递归扫描的函数(基于自上而下的方法)。

代码片段 1 展示了迭代关系函数和递归关系函数之间的比较。

代码片段 1。Fibonacci 序列中第 n 个元素的自底向上和自顶向下方法的比较。

1.a .基于自上而下和自下而上的方法

top-down方法意味着从后向前处理问题的递归函数。另一方面,bottom-up方法使用一个数据结构(通常是一个数组)迭代地进行状态依赖建模。

top-down方法从状态n开始,直到到达基本情况,而bottom-up方法从基本情况开始,直到到达情况n

2.记忆和制表

记忆和列表是指使用数据结构来跟踪和追踪每个状态的解决方案。

记忆化通常与top-down方法一起使用,其中最常用的数据结构是散列表。制表通常与数据结构是数组的bottom-up方法一起使用。两种策略都允许跟踪每个状态的子问题的解决方案。

3.基础案例

基本情况决定了过程的开始(对于bottom-up方法)或结束(对于top-down方法)。

基本上,基本情况是不需要应用动态编程就可以定义的情况,换句话说,它是我们开始的情况或我们最终将达到的情况。

Fibonacci 数列的top-downbottom-up方法的基本情况在代码片段 2 中指出。

代码片段 2。斐波纳契数列中第 n 个元素的自下而上和自上而下方法的基本情况。

既然我们已经知道了如何确定一个问题是否可以用动态编程来解决,以及构建一个解决方案的基本组件是什么,那么让我们继续看一个例子,在这个例子中我们将应用到目前为止所学的内容。

让我们去吧!

示例:查找第 n 个斐波那契数列

在我们开始解决方案之前,让我们一步一步来。首先,我们需要确定这个问题是否可以用动态编程来解决,所以让我们分析一下斐波那契数列是如何表现的。

图 3。斐波纳契数列计算的可视化描述。|作者图片

如图 3 所示,对于每个数字i,需要预先知道数字i-1i-2的值,也就是说,问题可以分解为子问题,这些子问题在各自的解决方案中具有依赖关系。因此,我们可以说这个挑战可以作为一个动态规划问题来处理。

现在让我们应用上一节中看到的框架。第一部分指的是检测将保持每个状态的解的函数或数据结构,其中该函数可以处理bottom-uptop-down方法。

出于解释的目的,让我们解决这两种方法。对于bottom-up方法,我们需要一个迭代函数,对于top-down方法,我们需要一个递归函数。

在代码片段 X 中,展示了这两种方法的原型。

代码片段 3。斐波纳契数列第 n 项的自下而上和自上而下原型。

现在我们需要考虑记忆制表。在这种情况下,出于解释的目的,我们将解决这两个问题。对于bottom-up方法,我们将使用列表,即包含每个状态的解决方案的数组,对于top-down方法,我们将使用记忆化,即包含每个状态的解决方案的散列表。

在代码片段 4 中,我们可以看到每种方法的列表和记忆的实现。

代码片段 4。展示列表和记忆。

最后,我们需要解决基础案例bottom-up方法以基础案例为起点,直到到达状态ktop-down方法从案例k开始,直到找到基础案例为止。

代码片段 5 分别显示了bottom-uptop-down方法的基本情况。

代码片段 5。用自下而上和自上而下的方法完整实现斐波那契数列中的第 n 项。

仅此而已。寻找斐波纳契数列中的nth数的问题已经用基于动态编程范例的解决方案开发出来了。

结论

在这篇博客中,我们看到了如何确定一个问题是否可以用动态编程来解决,如果可以的话,提出和开发一个解决方案需要考虑哪些因素。最后,我们展示了一个示例,展示了如何构建一个基于动态编程的解决方案来解决寻找斐波那契数列的第 n 个数的问题。

DAX 中的动态时间智能变得简单

原文:https://towardsdatascience.com/dynamic-time-intelligence-in-dax-made-easy-640b4e531ca8

当你的客户要求你创建一个动态时间智能测量。根据所选期间,该度量应返回不同的值。让我们看看你如何做到这一点。

克劳迪奥·施瓦兹在 Unsplash 上的照片

介绍

几周前,一位客户向我们提出了以下问题:是否可以根据 Power BI 报告中所选的时间段显示之前时间段的值?

假设他在查看月份级别。然后,他希望看到前一个月的值。在季度级别,他希望看到前一季度,在年度级别,前一年。

见下图,看看我们的客户描述的要求:

图 1 —目标结果(作者提供的图)

在我们找到解决办法之前,有一些令人挠头的时刻。

我的同行考虑使用标准的 DAX 函数来获取以前的周期,如 PARALLELPERIOD()、SAMEPERIODLASTYEAR()、DATEADD()等。

但是它们都是基于特定的时间段(年、月、日等)获得值的。).因此,它们都无助于满足这一特定要求。

因此,我们必须创建自定义逻辑来满足这一需求。

获取所选期间

第一步是确定哪个是当前期间。

首先使用的方法是 FILTERED()、ISINSCOPE()和类似的函数。但是这些功能并没有提供所需的结果。

然后有人问我什么是正确的方法。我建议使用函数 HASONEVALUE()。

我们从获取实际日历级别(日、月、季度或年)并根据所选级别返回值的方法开始:

Dynamic Time Int. =
VAR SelectedPeriod = IF(HASONEVALUE(‘Date’[Date])
                     ,1
                     ,IF(HASONEVALUE(‘Date’[MonthKey])
                       ,2
                       ,IF(HASONEVALUE(‘Date’[QuarterKey])
                         ,3
                        ,4
                        )
                       )
                      )RETURN
    SelectedPeriod

结果是:

  • 1 在日常水平
  • 每月 2 次
  • 3 在季度一级
  • 每年 4 次

你可以在下图中看到结果:

图 2—中间结果(作者提供的图)

如您所见,该度量返回每个选定期间的正确值。

有趣的一点是,我可以使用我的日期表中与一个被检查的级别相关的任何属性,并且我将总是得到正确的结果。

稍后我会解释这种方法的工作原理。

计算前期

现在,我必须添加逻辑以获得基本度量,并添加基于正确时间段的时间智能逻辑:

Dynamic Time Int. =
VAR SelectedPeriod = IF(HASONEVALUE(‘Date’[Date])
                     ,1
                     ,IF(HASONEVALUE(‘Date’[MonthKey])
                       ,2
                       ,IF(HASONEVALUE(‘Date’[QuarterKey])
                         ,3
                        ,4
                        )
                       )
                      )RETURN
    SWITCH(SelectedPeriod
          ,1, CALCULATE([Sum Online Sales]
             ,DATEADD(‘Date’[Date], -1, DAY)
                      )
          ,2, CALCULATE([Sum Online Sales]
             ,DATEADD(‘Date’[Date], -1, MONTH)
                      )
          ,3, CALCULATE([Sum Online Sales]
             ,DATEADD(‘Date’[Date], -1, QUARTER)
                      )
            ,CALCULATE([Sum Online Sales]
              ,DATEADD(‘Date’[Date], -1, YEAR)
                      )
           )

当然,我可以在 IF 函数中添加 CALCULATE()代码部分。

但是这将导致复杂和混乱的代码,难以理解。
这样,所选期间的选择与计算部分是分开的,两部分都简单易懂。

下图显示了结果:

图 3—结果(作者提供的数据)

如您所见,该措施如预期一样有效。

但是为什么呢?

说明

在你继续之前,试着找出你自己的原因。

.

.

.

现在,让我们来看看这个措施为什么有效。

这里的关键概念是“Filter-context”:当过滤一个表中的一个或多个列时,所有其他列也会受到影响。

请看下面从一个简单的日期表中摘录的内容:

图 4—摘自日期表(作者提供的图表)

当你选择月=一月,年= 2012 时会发生什么?
当这两个值过滤这两列时,对这两列的过滤也会影响所有其他表列。

因此,列 MonthKey 只有一个不同的值:201201

图 5—选定时间段的数据表摘录(作者提供的图表)

当您选择“季度= 2”和“年份= 2012”时,也会发生同样的情况。

列 QuarterKey 也包含一个不同的值。

因此,我们可以在键列上使用 HASONEVALUE()来确定所选的周期:

HASONEVALUE('Date'[MonthKey])

使用 HASONEVALUE()的查询既高效又快速,而且整个度量几乎完全可以在存储引擎中计算:

图 6—测量的服务器计时(由作者提供)

结论

理解 DAX 的所有含义和复杂性以及表格模型中的筛选器上下文对于解决此类挑战至关重要。

有时,它是关于连接你的知识点,以找到正确的解决方案。

在这种情况下,我们需要意识到选择年份和月份会将 MonthKey 列限制为只有一个值。剩下的就简单了。

最初的方法并非完全错误。但是它们太复杂了,不能在所有情况下都提供正确的结果。

这个解决方案的美妙之处在于,您可以轻松地将这个逻辑添加到计算组中,并在其他度量中重用这个逻辑。

这里我想强调的另一个主题是如何构建解决方案。

我们从第一个版本开始,它只返回我们用来标记所选时间段的标志。
这种方法遵循我构建复杂度量的一种常见模式:

  1. 构建中间版本,计算可理解且易于验证的值
  2. 向代码中添加更多的逻辑,并检查每一步是否有错误或不想要的结果
  3. 完成代码

这种方法帮助我根据需求和期望不断地验证结果。

由朱尼尔·费雷拉在 Unsplash 上拍摄的照片

参考

我使用 Contoso 样本数据集,就像我以前的文章一样。你可以从微软这里免费下载 ContosoRetailDW 数据集。

Contoso 数据可以在 MIT 许可下自由使用,如这里的所述。

我扩大了数据集,使 DAX 引擎工作更努力。
在线销售表包含 6300 万行(而不是 1260 万行),零售表包含 1550 万行(而不是 340 万行)。

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

使用正则表达式分词器进行动态单词分词

原文:https://towardsdatascience.com/dynamic-word-tokenization-with-regex-tokenizer-801ae839d1cd

关于用正则表达式单步预处理文本的简短教程

图片由阿玛多·洛雷罗在 Unsplash 上拍摄

在本教程中,我们将引入正则表达式来为 NLP 任务定制单词标记化。通过主动选择标记或单词,您可以快速预处理您的文本,而无需大量的文本清理。

在机器学习工程领域,界定数据处理建模部署是项目生命周期的主要递归过程。值得注意的是,数据清理和准备被认为是任何数据科学项目管道的早期阶段,但它们对模型的准确性至关重要。简单来说:

垃圾进,垃圾出。

图来自 DeepLearning.ai 的 MLOps Specialization 的讲座幻灯片(来源)

对于结构化表格数据,数据预处理可能采取缺失数据插补或某些类别的标准化值的形式(例如,引用相似类别的字符串的小写)。然而对于本教程,我们将触及另一个子领域的非结构化数据的数据预处理方法,自然语言处理(NLP)——文本数据

1.文本预处理—标记化

如果图像(另一种非结构化数据)被认为是空间数据,那么文本应该被认为是顺序数据,在记号(单词或字符)被完全按顺序处理之后,文本的信息被导出。

每一个文本标记都可以是单词、数字、符号、标点符号等等,它们承载着一定的意义,因而可以被看作是语义的一个要素。

从文本中获取标记列表的过程是一个称为标记化的预处理步骤,在此之后,标记被转换为一个热点向量,以馈入任何下游模型,例如用于 NLP 任务的转换器或双向 LSTM,例如机器翻译、摘要、情感分析和共指消解等。(然后,在训练过程之后,可以为每个标记导出 n 维向量嵌入,其封装了特定的含义。)

如果 NLP 任务在字符级别处理文本,标记化非常容易,如下面的代码片段所示:

字符级标记化。图片作者。

尽管如此,大多数 NLP 任务通常在单词级别上处理文本。使用 Python 中一些流行的 NLP 库,如 NLTK 或 spaCy,可以很容易地完成单词标记化,如下所示:

单词级标记化。图片作者。

上述记号化方法的一个问题是记号化方法要么是固定的,要么不容易定制。当文本混乱时,例如包含 HTML 标签,或者包含您希望省略的文本,如数字、网络链接、电子邮件甚至符号诅咒,这个问题会进一步加剧。

典型的单词分词器不会自动清除文本。图片作者。

第二个问题可以通过手动文本清理来解决,用空字符串替换掉不需要的文本。这很好,只要你能考虑到所有不需要的文本的变化。然而,这是乏味的,特别是如果你有一个巨大的语料库,包括数百万个文本文档。因此,这样的话,有时我们可能会得到未清除的令牌,并将其传递给下游模型。

如果我们可以在一个步骤中将文本清理和标记化结合在一起会怎么样?换句话说,除了在标记化之前过滤掉不想要的文本,我们是否可以只基于我们想要包含的文本来实现基于规则的标记化?

输入正则表达式(regex)标记符!但在此之前,让我们看看正则表达式是如何工作的。

2.按文本模式搜索—正则表达式

正则表达式(regex)在通过搜索特定搜索模式的匹配从文本中提取字符时非常有用。搜索模式的语言,表示为另一个文本字符串,称为正则表达式。对于每个特定的用例,regex 中都有几个特殊的字符,但是在本教程中,为了便于说明,我们将只简要介绍其中的一些:

锚——^和美元

^The:匹配字符串开头的“The”。

end$:如果它在字符串的末尾,则匹配“end”。

hello20:如果字符序列出现在字符串中的任何位置,则匹配“hello20”。

量词— * +?

love*:匹配包含“lov”后跟零个或多个“e”的字符串

love+:匹配包含“lov”后跟一个或多个“e”的字符串

爱情!:匹配包含后跟零或一个“e”的“lov”的字符串

空格— \s,\s

\s:匹配空格

\S:匹配非空格

括号表达式— [ ]

【a!?:]:匹配为' a ','!'的字符串, '?'或者':'

[a-zA-Z0–9]:匹配字母表中的任何字母(小写或大写)或任何数字 0–9。

捕捉,不捕捉 OR 运算符—(),?:和|

(roar)ing:匹配并捕获后面有“ing”的字符串“roar”。

(?:([0–9]+)|([#@!])) : ' ?: ‘通常否定捕获,当您想要将表达式与 OR 运算符'|’组合在一起,但不想将其保存为字符串的捕获部分时使用。

向前看,向后看——(?=)和(?regex101.com< =)

[0–9-]+(?=[.]) : Matches a telephone number, for instance, that ends with a full-stop.

(?<=^)[a-z@.]+ : Matches an email, for instance, that begins at the start of the string.

The above tutorial on regular expressions is non-exhaustive and there are several other regular expression use cases and rules, and I will leave this to your exploration. I have also collated some good resources for further learning here:

https://medium.com/factory-mind/regex-tutorial-a-simple-cheatsheet-by-examples-649dc1c3f285 https://stackoverflow.com/questions/2973436/regex-lookahead-lookbehind-and-atomic-groups

There are also a couple of handy websites to easily test out regex on text strings. One of my favorite is this:

https://regex101.com/

3. The NLTK Regex Tokenizer

Now we have mastered regular expressions, we can easily search for and customize text patterns that we wish to tokenize. Now say for instance, we only wish to capture all meaningful words, excluding all external punctuations, numbers, HTML tags, websites and what not. To do this, we can make use of the regex tokenizer in the NLTK library to tokenize text according to a search pattern. Consider the following text, which is a movie review, we see that tokens can be captured with clear precision without needing prior text cleaning.

'OK, so the FX are not high budget. But this story is based on actual events. Not something thrown together to make a couple of rich actors, even richer!! As most movies that are based on books, there are somethings that just don\'t fit. Only a couple of people have stated that this movie was based on real events, not a knock-off as most people believe it is!! This movie is in no way related too TWISTER! Other than both movies are about tornadoes.<br /><br />For those of you who have problems with the science of the tornadoes and storms in the movie, there are a couple of things you need to remember... The actual "night of the twisters" was June 3, 1980\. So this movie was released 16 years after the actual events. Try think how far storm research has advanced in that time. It happened in a larger town; Grand Island, Nebraska is the third largest city in the state. Even though the movie calls the town something else, and says it\'s a small town. For the real story check out: [http://www.gitwisters.com/'](http://www.gitwisters.com/')

Code snippet in applying NLTK regex tokenizer.

Screenshot from 。图片作者。

应用的正则表达式允许我们捕获任何单词(一个或多个带撇号和连字符的字母)的标记,这些单词前面有:

  • 字符串开头
  • 空白
  • 类似[> "]的字符

并且还成功地通过以下方式之一:

  • 字符串结尾
  • 空白
  • 像[:]这样的字符。!;"]

因此,正则表达式能够捕获所有有意义的单词,除了不需要的文本,如网页链接、电子邮件、HTML 标签等。出于好奇,我们应用的 regex 字符串如下所示,您可以随意定制以适应其他上下文。

“(?:(?<=\s)|(?<=^)|(?<=[>\”]))[a-z-’]+(?:(?=\s)|(?=\:\s)|(?=$)|(?=[.!,;\”]))”

4.最后的想法

正则表达式标记化是一种基于规则的动态标记化。尽管近年来算法逐渐转向基于模型或使用数据来驱动标记化,但正则表达式仍然是一个强大的工具。事后看来,在另一个应用中,在标记化之前,例如通过使用 regex 将网页链接转换成标记(例如),甚至可以进一步预处理文本。

如果杂乱的文本能够被容易地和清楚地描述,那么在 MLOps 生命周期的地平线上,可以为任何 NLP 模型提供强大的基础。

感谢阅读!如果你喜欢这些内容,可以在媒体上阅读我的其他文章,并在 LinkedIn 上关注我。

支持我! —如果你没有订阅 Medium,并且喜欢我的内容,请考虑通过我的推荐链接加入 Medium 来支持我。

https://tanpengshi.medium.com/membership

向 Argparse | Python 模式动态添加参数

原文:https://towardsdatascience.com/dynamically-add-arguments-to-argparse-python-patterns-a439121abc39

如何使用 argparse.ArgumentParser 根据用户输入指定不同的参数。

由 Unsplash 上的 Shubham Dhage 拍摄的照片

介绍

当数据科学家的需求超出 Jupyter 笔记本电脑所能提供的范围时,命令行界面(cli)工具就是他们的面包和黄油。Python 的来自标准库的 argparse 是我们在 Python 旅程中遇到的第一个相对容易地构建这种接口的工具。然而,尽管只使用 ArgumentParser 类的三个方法就可以很容易地构建一个带有 argparse 的小型易用 cli,但是当接口增长并变得更加复杂时,就需要进行一些额外的规划。在本文中,我们探索了将 cli 划分为单独的子命令的方法,这些子命令带有可以在运行时加载的参数,以及如何将它们与设计模式结合起来,以便更容易地扩展它。

多个子命令

大多数 cli 工具都提供了多个命令,每个命令都有自己独特的一组参数。让我们以 git 为例,下面是您可以运行的所有 git 命令的列表:

$ git --help
[...]
These are common Git commands used in various situations:

start a working area (see also: git help tutorial)
   clone     Clone a repository into a new directory
   init      Create an empty Git repository or reinitialize an existing one

work on the current change (see also: git help everyday)
   add       Add file contents to the index
   mv        Move or rename a file, a directory, or a symlink
   restore   Restore working tree files
   rm        Remove files from the working tree and from the index

examine the history and state (see also: git help revisions)
   bisect    Use binary search to find the commit that introduced a bug
   diff      Show changes between commits, commit and working tree, etc
   grep      Print lines matching a pattern
   log       Show commit logs
   show      Show various types of objects
   status    Show the working tree status

grow, mark and tweak your common history
   branch    List, create, or delete branches
   commit    Record changes to the repository
   merge     Join two or more development histories together
   rebase    Reapply commits on top of another base tip
   reset     Reset current HEAD to the specified state
   switch    Switch branches
   tag       Create, list, delete or verify a tag object signed with GPG

collaborate (see also: git help workflows)
   fetch     Download objects and refs from another repository
   pull      Fetch from and integrate with another repository or a local branch
   push      Update remote refs along with associated objects

这些是其中一些的论据:

$ git add --helpSYNOPSIS*git add* [--verbose | -v] [--dry-run | -n] [--force | -f] [--interactive | -i] [--patch | -p] [--edit | -e] [--[no-]all | --[no-]ignore-removal | [--update | -u]] [--sparse] [--intent-to-add | -N] [--refresh] [--ignore-errors] [--ignore-missing] [-renormalize] [--chmod=(+|-)x] [--pathspec-from-file=<file> [--pathspec-file-nul]] [--] [<pathspec>…​]$ git commit --helpSYNOPSIS*git commit* [-a | --interactive | --patch] [-s] [-v] [-u<mode>] [--amend]
           [--dry-run] [(-c | -C | --squash) <commit> | --fixup [(amend|reword):]<commit>)]
           [-F <file> | -m <msg>] [--reset-author] [--allow-empty]
           [--allow-empty-message] [--no-verify] [-e] [--author=<author>]
           [--date=<date>] [--cleanup=<mode>] [--[no-]status]
           [-i | -o] [--pathspec-from-file=<file> [--pathspec-file-nul]]
           [(--trailer <token>[(=|:)<value>])…​] [-S[<keyid>]]
           [--] [<pathspec>…​]

你可以看到它们重叠但不相同。如果您尝试将一个命令与另一个命令的参数一起使用,显然会失败:

$ git add --reset-author
error: unknown option `reset-author'
usage: git add [<options>] [--] <pathspec>...

假设你正在用 Python 为你的数据科学工作编写一个 cli 工具,也许你正在用深度学习编写一个工具来解决你领域中的问题

然后你很可能用标准库中的 argparse 编写你的 cli,因为它可能不是最好的,但它肯定是你学习的第一个。

构建一个参数解析器来使用子命令非常简单,我们将用一个例子来展示它。我们有一个示例应用程序,命令 train 和 *infer,*各有不同的参数,可以是强制的,也可以是可选的。示例代码可在https://github.com/mattiadg/example-cli获得,为方便起见在此复制:

# src/sub_commands.pyimport argparse

from commands import train, infer

if __name__ == "__main__":
    parser = argparse.ArgumentParser("Example v2")
    subparsers = parser.add_subparsers(help="Sub-commands help")

    parser_train = subparsers.add_parser("train", help="Train a model")
    parser_train.add_argument(
        "--model",
        "-m",
        required=True,
        help="name of the deep learning architecture to use",
    )
    parser_train.add_argument(
        "--save_model_path",
        required=True,
        help="Path to the directory where to save the model",
    )
    parser_train.add_argument(
        "--dropout",
        type=float,
        default=0.1,
        help="Dropout value, equal for each value",
    )
    parser_train.add_argument(
        "--batch_size", type=int, help="Batch size during training"
    )
    parser_train.set_defaults(func=train)

    parser_infer = subparsers.add_parser("infer", help="Use a model for inference")
    parser_infer.add_argument(
        "--model_path", required=True, help="Path to the model to use for inference"
    )
    parser_infer.add_argument(
        "--batch_size", type=int, help="Batch size during inference"
    )
    parser_infer.set_defaults(func=infer)

    args = parser.parse_args()
    args.func(args)

argparse 中的子参数将完成这项工作。我们首先需要声明我们想要使用子参数:

subparsers = parser.add_subparsers(help="Sub-commands help")

然后,我们用 add_parser()方法为命令“train”和“infer”声明子参数:

parser_train = subparsers.add_parser("train", help="Train a model")
parser_infer = subparsers.add_parser("infer", help="Use a model for inference")

然后,子解析器的行为将与任何其他解析器完全一样。让我们测试一下我们的 cli:

$ python .\src\sub_commands.py train -m transformer --save_model_path $HOME/my_model_path/
Training model with:
model=transformer
save_model_path=/home/me/my_model_path/
dropout=0.1
batch_size=None
func=<function train at 0x000001F9433493A0>

它不接受特定于推断的参数:

$ python .\src\correct.py train -m transformer --save_model_path $HOME/my_model_path/ --model_path .
usage: Example v2 [-h] {train,infer} ...
Example v2: error: unrecognized arguments: --model_path .

但是—当使用“推断”命令时,模型路径可以正常工作

$ python .\src\correct.py infer --model_path $HOME/my_model_path/
Inferring with model with:
model_path=/home/me/my_model_path/
batch_size=None
func=<function infer at 0x000001A1881AD1F0>

动态参数

现在,我们想要为我们想要训练的模型指定一些参数。在我们的例子中,我们有两个不同的模型,transformer 和 lstm。Lstm 将输出向量的大小和状态向量的大小作为参数。变压器具有子层的大小,并且对于大的前馈子层具有不同的大小。两种模型类型都将层数作为参数。

我没有找到将子解析器附加到命名参数(如 model)的方法,所以我们必须遵循不同的路线。

首先,为了保持解析器代码的可管理性,我们不希望所有的参数都出现在同一个主文件中。我们将把新的参数保存在文件中,在文件中我们使用一个函数来定义各自的模型,该函数将解析器作为输入并添加新的参数。

Lstm 看起来是这样的:

# src/models/lstm.pydef add_arguments(parser):
    parser_lstm = parser.add_argument_group("lstm")
    parser_lstm.add_argument("--num_layers", type=int, help="Number of LSTM layers")
    parser_lstm.add_argument("--forward_size", type=int, help="Number of units in the forward propagation")
    parser_lstm.add_argument("--state_size", type=int, help="Number of units for the state vector")

以下为变压器

# src/models/transformer.pydef add_arguments(parser):
    parser_trafo = parser.add_argument_group("transformer")
    parser_trafo.add_argument("--num_layers", type=int, help="Number of Transformer layers")
    parser_trafo.add_argument("--forward_size", type=int, help="Number of units in the forward propagation")
    parser_trafo.add_argument("--hidden_size", type=int, help="Number of units in the hidden FF layers")

现在,我们不能在启动时添加来自不同模型的所有参数,因为它们有冲突的名称(— num_layers),这会使解析器崩溃。在 duplicate.py 文件中,我们复制了上一节中的代码,并添加了来自两个模型的参数,您可以在https://github . com/matti adg/example-CLI/blob/main/src/duplicate _ arguments . py找到:

# src/duplicate_arguments.pyimport argparse

from commands import train, infer
import models.lstm
import models.transformer

if __name__ == "__main__":
 .
 .
 .models.lstm.add_arguments(parser)
models.transformer.add_arguments(parser)

args = parser.parse_args()
args.func(args)

如果我们现在跑

$ python .\src\duplicate_arguments.py infer --model_path $HOME/my_model_path/

我们得到预期的误差

argparse.ArgumentError: argument --num_layers: conflicting option string: --num_layers

很明显,我们需要一种方法来动态地向我们的解析器*,添加参数,也就是说,在运行时根据用户的输入。然而,ArgumentParser 的任何方法都不允许我们直接这样做,我们需要利用一点小技巧。*

我们需要解析参数两次,第一次获取模型值,然后加载相应的参数,第二次解析我们可以获取特定于命令的参数。

为此,我们需要解析器忽略用户插入的、尚未作为参数添加的参数。幸运的是,parse_known_args()恰恰做到了这一点!

*# src/model_loader.pyimport argparse

from commands import train, infer

# src/model_loader.pyfrom commands import train, infer
from models.loader import load_model_args
.
.
.args_, _ = parser.parse_known_args()

load_model_args(parser_train, args_.model)

args = parser.parse_args()
args.func(args)*

其中 parser_train 是 train 命令的子参数,如前所述,而游戏规则的改变者是这一行:

*args_, _ = parser.parse_known_args()*

它需要两个返回值,因为 parse_known_args 返回一个元组,在第一个位置包含已解析的参数,在第二个位置包含所有其他的参数。这是我们通过打印 parser.parse_known_args()的结果得到的结果:

*$ python .\src\model_loader.py train -m transformer --save_model_path $HOME/my_model_path/ --num_layers 6 --forward_si
ze 512 --hidden_size 2048(Namespace(model='transformer', save_model_path='/home/me/my_model_path/', dropout=0.1, batch_size=None, func=<function train at 0x000001E0125DA3A0>), ['--num_layers', '6', '--forward_size', '512', '--hidden_size', '2048'])*

通过最新的修改,我们最终得到了预期的结果:

*$ python .\src\model_loader.py train -m transformer --save_model_path $HOME/my_model_path/ --num_layers 6 --forward_si
ze 512 --hidden_size 2048Training model with:
model=transformer
save_model_path=C:\Users\matti/my_model_path/
dropout=0.1
batch_size=None
num_layers=6
forward_size=512
hidden_size=2048
func=<function train at 0x000001E0125DA3A0>*

缺少的步骤只有 load_model_args()函数,它为正确的模型加载参数。这是:

*# src/models/loader.pyimport importlib

def load_model_args(parser, model):
    module = importlib.import_module("."+model, "models")
    module.add_arguments(parser)*

这是一个基本的实现,它只接受模型名,在“model”包中导入同名的模块,然后在作为输入接收的 parser_train 上调用其中的 add_arguments 函数(如上所示)。

这里缺少的是可用模型的列表。如果给定一个随机的模型名,我们的代码就会失败,因为它找不到相应的模块。另一种方法是预先将所有模型的所有 add_arguments()函数和它们相应的名称添加到注册表中。然后,我们可以在— model 参数中提供这些选项作为“选择”。使用 Register 模式可以很容易地做到这一点,我在上一篇文章中描述过:

*

为什么我们要使用这种似乎会增加代码复杂性的模式呢?答案是,这里的代码非常简单,但是当您有几个模型时,它会变得越来越复杂,并且还希望为不同的优化器、数据加载器、搜索算法和代码中需要参数化的任何东西提供特定的参数。然后,代码变得固有地复杂,最好通过为每个类别设置一个单一的入口点(注册表)来隔离更改,并使特定的代码只与通用代码接口。此外,主函数将只与通用代码(load_model_args、load_optimizer_args 等)通信,代码库变得更容易推理。

结论

在本文中,我们已经看到了如何使用 Python 标准库中的 argparse 构建越来越复杂的 CLI。我们从简单地使用子参数向程序添加子命令开始,然后我们看到了如何使用 parse_know_args 根据用户的选择加载新的参数。最后,我们讨论了 Register 模式如何帮助我们的解析器实现关注点隔离。

作为最新的评论,如果你对开发 cli 工具感兴趣,考虑使用提供比 argparse 更多特性的库,比如 cloup 。

中等会员

你喜欢我的文章吗?你是否正在考虑申请一个中级会员来无限制地阅读我的文章?

如果您决定通过此链接订阅,您将通过您的订阅支持我,无需为您支付额外费用【https://medium.com/@mattiadigangi/membership*

DynamoDB Go SDK:如何有效地使用扫描和批处理操作

原文:https://towardsdatascience.com/dynamodb-go-sdk-how-to-use-the-scan-and-batch-operations-efficiently-5b41988b4988

使用 DynamoDB Go SDK 进行并行扫描(图片由作者提供)

通过实际的代码示例学习

DynamoDB 扫描 API 访问表中的每一项(或二级索引)。它相当于一个select * from查询。我将在这篇博客中讨论的事情之一是如何将 Scan API 与 DynamoDB Go SDK 一起使用。

要扫描一个表,我们需要一些数据开始!所以在这个过程中,我还将深入研究如何使用Batch API 在DynamoDB中写批量数据。您可以使用 BatchWriteItem API 来批量(25 个)创建或删除项目,并且您可以跨多个表组合这些操作。

我们将从简单开始,逐步改进我们的方法来有效地使用 API。我还将回顾我运行的一些基本测试,以展示增量改进。最后,我将强调使用这些操作时的一些注意事项。

可以参考 上的代码 GitHub

在您继续之前…

…确保创建一个名为usersDynamoDB表,其中包含:

  • 分区键email(数据类型String)和
  • On-Demand容量模式。

DynamoDB 表(图片由作者提供)

此外,我还想称一些事情为背景:

  • 该表是在us-east-1中创建的,测试也是从us-east-1中的EC2实例中执行的
  • 因为这些是一般的测试,而不是专门的基准测试,所以我没有做任何特殊的调整(在任何级别上)。这些只是用不同的输入执行的 Go 函数,尽可能保持简单。
  • 测试包括BatchWriteItem操作的编组(将 Go struct转换为DynamoDB数据类型)和Scan操作的解编组(从DynamoDB数据类型转换回 Go struct)。

让我们从探索BatchWriteItem API 开始。这样我们也将有数据来处理Scan操作。

双赢!

批量导入数据

由于您可以在一次调用中组合 25 项,因此与在循环中(甚至并行)调用 PutItem 相比,使用批处理方法进行批量数据导入要好得多。

下面是一个如何使用BatchWriteItem的基本示例:

func basicBatchImport() {

 startTime := time.Now()

 cities := []string{"NJ", "NY", "ohio"}
 batch := make(map[string][]types.WriteRequest)
 var requests []types.WriteRequest

 for i := 1; i <= 25; i++ {
  user := User{Email: uuid.NewString() + "@foo.com", Age: rand.Intn(49) + 1, City: cities[rand.Intn(len(cities))]}
  item, _ := attributevalue.MarshalMap(user)
  requests = append(requests, types.WriteRequest{PutRequest: &types.PutRequest{Item: item}})
 }

 batch[table] = requests

 op, err := client.BatchWriteItem(context.Background(), &dynamodb.BatchWriteItemInput{
  RequestItems: batch,
 })
 if err != nil {
  log.Fatal("batch write error", err)
 } else {
  log.Println("batch insert done")
 }

 if len(op.UnprocessedItems) != 0 {
  log.Println("there were", len(op.UnprocessedItems), "unprocessed records")
 }

 log.Println("inserted", (25 - len(op.UnprocessedItems)), "records in", time.Since(startTime).Seconds(), "seconds")
}

使用 BatchWriteItemInput ,我们可以定义我们想要在批处理中执行的操作——这里我们将执行 PutRequest s(它封装在另一个名为 WriteRequest 的类型中)。

我们将WriteRequest组装到一个切片中,最后将它们放在一个map中,key 是表名——这正是BatchWriteItemInput中的RequestItems属性所需要的。

在这种情况下,我们处理的是单个表,但是您可以在多个表上执行操作。

在本例中,我们只处理了一批 25 记录(最大允许批量)。如果我们想要导入更多的记录,我们需要做的就是将它们分成 25 的批次,并且一次执行一个(子)批次。很简单,下面是一个例子:

func basicBatchImport2(total int) {

 startTime := time.Now()

 cities := []string{"NJ", "NY", "ohio"}
 batchSize := 25
 processed := total

 for num := 1; num <= total; num = num + batchSize {

  batch := make(map[string][]types.WriteRequest)
  var requests []types.WriteRequest

  start := num
  end := num + 24

  for i := start; i <= end; i++ {
   user := User{Email: uuid.NewString() + "@foo.com", Age: rand.Intn(49) + 1, City: cities[rand.Intn(len(cities))]}
   item, _ := attributevalue.MarshalMap(user)
   requests = append(requests, types.WriteRequest{PutRequest: &types.PutRequest{Item: item}})
  }

  batch[table] = requests

  op, err := client.BatchWriteItem(context.Background(), &dynamodb.BatchWriteItemInput{
   RequestItems: batch,
  })

  if err != nil {
   log.Fatal("batch write error", err)
  }

  if len(op.UnprocessedItems) != 0 {
   processed = processed - len(op.UnprocessedItems)
  }
 }

 log.Println("all batches finished. inserted", processed, "records in", time.Since(startTime).Seconds(), "seconds")

 if processed != total {
  log.Println("there were", (total - processed), "unprocessed records")
 }
}

我用 50000 个记录(这意味着 2000 个批次)进行了尝试,花费了大约 15 秒。但是我们可以做得更好!

平行批量导入

我们可以为每一批增加一个goroutine,而不是顺序处理每一批:

func parallelBatchImport(numRecords int) {

 startTime := time.Now()

 cities := []string{"NJ", "NY", "ohio"}
 batchSize := 25

 var wg sync.WaitGroup

 processed := numRecords

 for num := 1; num <= numRecords; num = num + batchSize {
  start := num
  end := num + 24

  wg.Add(1)

  go func(s, e int) {
   defer wg.Done()

   batch := make(map[string][]types.WriteRequest)
   var requests []types.WriteRequest

   for i := s; i <= e; i++ {
    user := User{Email: uuid.NewString() + "@foo.com", Age: rand.Intn(49) + 1, City: cities[rand.Intn(len(cities))]}

    item, err := attributevalue.MarshalMap(user)
    if err != nil {
     log.Fatal("marshal map failed", err)
    }
    requests = append(requests, types.WriteRequest{PutRequest: &types.PutRequest{Item: item}})
   }

   batch[table] = requests

   op, err := client.BatchWriteItem(context.Background(), &dynamodb.BatchWriteItemInput{
    RequestItems: batch,
   })

   if err != nil {
    log.Fatal("batch write error", err)
   }

   if len(op.UnprocessedItems) != 0 {
    processed = processed - len(op.UnprocessedItems)
   }

  }(start, end)
 }

 log.Println("waiting for all batches to finish....")
 wg.Wait()

 log.Println("all batches finished. inserted", processed, "records in", time.Since(startTime).Seconds(), "seconds")

 if processed != numRecords {
  log.Println("there were", (numRecords - processed), "unprocessed records")
 }
}

结果大大改善了。这是我得到的。平均而言:

  • 插入 50000 条记录花费了~ 2.5
  • 在~ 4.55 秒内插入 100000 记录
  • 在不到 9.5 秒的时间内插入 150000 记录
  • 在不到 11.5 秒的时间内插入 200000 记录

批量中可能存在未处理的记录。这个例子检测这些记录,但是为了简单起见,已经跳过了重试逻辑。理想情况下,您还应该有一个(基于指数回退的)重试机制来处理未处理的记录。

为了插入更多数据,我循环运行了parallelBatchImport函数(如上)。例如:

for i := 1; i <= 100; i++ {
    parallelBatchImport(50000)
}

好吧,我们继续。现在我们有了一些数据,让我们试试…

…扫描 API

基本用法如下:

func scan() {
 startTime := time.Now()

 op, err := client.Scan(context.Background(), &dynamodb.ScanInput{
  TableName:              aws.String(table),
  ReturnConsumedCapacity: types.ReturnConsumedCapacityTotal,
 })

 if err != nil {
  log.Fatal("scan failed", err)
 }

 for _, i := range op.Items {
  var u User
  err := attributevalue.UnmarshalMap(i, &u)
  if err != nil {
   log.Fatal("unmarshal failed", err)
  }
 }

 if op.LastEvaluatedKey != nil {
  log.Println("all items have not been scanned")
 }
 log.Println("scanned", op.ScannedCount, "items in", time.Since(startTime).Seconds(), "seconds")
 log.Println("consumed capacity", *op.ConsumedCapacity.CapacityUnits)
}

只需提供表(或二级索引)名称,就可以开始了!但是,由于 API 限制(每次调用相当于 1 MB 的数据),您可能无法获得所有项目。在我的例子中,大约花费了 0.5 秒来处理大约 15000 条记录——其余的项目被跳过,因为超过了 1 MB 的限制。

使用分页

为了处理数据的限制,Scan API 在其输出中返回LastEvaluatedKey,指向最后处理的记录。您需要做的就是再次调用Scan,将ExclusiveStartKey属性的值设置为LastEvaluatedKey的值。

使用分页扫描方法花了我大约 100 秒来扫描~750 万条记录。

平行扫描

分页很有帮助,但它仍然是一个连续的过程。有很大的改进余地。幸运的是,Scan允许您采用并行化的方法,也就是说,您可以使用多个 workers(在本例中是goroutine s)来并行处理数据!

func parallelScan(pageSize, totalWorkers int) {
 log.Println("parallel scan with page size", pageSize, "and", totalWorkers, "goroutines")
 startTime := time.Now()

 var total int

 var wg sync.WaitGroup
 wg.Add(totalWorkers)

 for i := 0; i < totalWorkers; i++ {
  // start a goroutine for each segment

  go func(segId int) {
   var segTotal int

   defer wg.Done()

   lastEvaluatedKey := make(map[string]types.AttributeValue)

   scip := &dynamodb.ScanInput{
    TableName:     aws.String(table),
    Limit:         aws.Int32(int32(pageSize)),
    Segment:       aws.Int32(int32(segId)),
    TotalSegments: aws.Int32(int32(totalWorkers)),
   }

   for {
    if len(lastEvaluatedKey) != 0 {
     scip.ExclusiveStartKey = lastEvaluatedKey
    }
    op, err := client.Scan(context.Background(), scip)

    if err != nil {
     log.Fatal("scan failed", err)
    }

    segTotal = segTotal + int(op.Count)

    for _, i := range op.Items {

     var u User
     err := attributevalue.UnmarshalMap(i, &u)
     if err != nil {
      log.Fatal("unmarshal failed", err)
     }
    }

    if len(op.LastEvaluatedKey) == 0 {
     log.Println("[ segment", segId, "] finished")
     total = total + segTotal
     log.Println("total records processsed by segment", segId, "=", segTotal)
     return
    }

    lastEvaluatedKey = op.LastEvaluatedKey
   }
  }(i)
 }

 log.Println("waiting...")
 wg.Wait()

 log.Println("done...")
 log.Println("scanned", total, "items in", time.Since(startTime).Seconds(), "seconds")
}

SegmentTotalSegments属性是Scan API 如何实现并行的关键。TotalSegments只是需要产生的线程/工作进程的数量,而Segment是每个线程/工作进程的唯一标识符。

在我的测试中,对于大约 750 万条记录(我尝试了各种页面大小和goroutine组合),性能(几乎)保持在 37-40 秒(平均)不变。

我需要配置多少个 **TotalSegments** ???

要调优适当数量的并行线程/工作线程,您可能需要做一些实验。这很大程度上取决于您的客户端环境。

  • 您有足够的计算资源吗?
  • 一些环境/运行时可能有托管线程池,所以您必须遵守这些规则

因此,您需要不断尝试,为您的找到最佳的并行性。考虑这个问题的一种方法是为每个数据单元选择一个段(单个工作线程/线程/ goroutine)。

总结— API 考虑事项

BatchScanAPI 都非常强大,但是有些细微差别你应该注意。我的建议是通读 API 文档。

**Batch**API:

  • 一批不超过 25 个请求
  • 一批中的个别项目应而不是超过 400KB
  • 单个BatchWriteItem中项目的总大小不能超过 16MB
  • BatchWriteItem 无法更新物品
  • 不能指定单个putdelete请求的条件
  • 它不而不在响应中返回已删除的项目
  • 如果有失败的操作,您可以通过UnprocessedItems响应参数访问它们

明智地使用扫描

由于一个Scan操作遍历整个表(或二级索引),它很可能会消耗一大块提供的吞吐量,尤其是如果它是一个大表的话。话虽如此,Scan应该是你的最后一招。检查查询 API (或 BatchGetItem )是否适用于您的用例。

同样适用于平行*Scan*

通过使用一个过滤表达式、一个Limit参数(如前所述)或一个ProjectionExpression来进一步缩小结果的范围,只返回属性的一个子集。

这个博客到此为止。希望你觉得有用。

下次见,编码快乐!

E-DALL-E:用不同的纵横比创建数字艺术

原文:https://towardsdatascience.com/e-dall-e-creating-digital-art-with-varying-aspect-ratios-5de260f4713d

如何使用 VQGAN 和 CLIP 修复侧面来扩展 DALL-E Mini 生成的图像

图片来自 DALL-E Mini (左),放大到 16:9,边缘像素重复(中)和 E-DALL-E (右),图片由作者提供

你可能见过一些使用 OpenAI 的 DALL-E 2 [1]从文本生成的图像。尽管该系统令人印象深刻,结果令人难以置信,但它目前只在封闭测试版中提供等候名单。然而,你可以访问和运行一个独立的文本到图像系统,名为 DALL-E Mini [2],由开发者 Boris Dayma 和 Pedro Cuenca 领导。虽然结果没有 DALL-E 2 生成的图像那么壮观,但仍然非常优秀,源代码和训练好的模型都是免费开源的。你可以在他们广告支持的演示中尝试一下。

您可能已经注意到,两种 DALL-E 型号生成的图像都使用 1:1 的纵横比;图像总是死方的。该系统不能产生横向或纵向格式的图像,限制了它们的实用性。

但是,我注意到 DALL-E Mini 的图像生成器使用了 VQGAN 模型[3],这一点我从我写的几篇关于图像生成的文章中非常了解。我还知道 VQGAN 可以渲染不同纵横比的图像。所以我写了一点代码来获取 DALL-E 模型的输出,或者任何图像,并使用 OpenAI [4]的 CLIP 引导的 VQGAN 来扩展纵横比。我称这个系统为 Expand-DALL-E,简称 E-DALL-E。你可以在这里运行它。请务必查看附录中的图片集。

系统概况

这是 E-DALL-E 系统的示意图,其中简要描述了流程。系统组件的完整描述如下。

**E-Dall-E 组件,**作者提供的图表

该系统有两个主要组成部分:用于图像生成的 DALL-E Mini 和用于扩展纵横比的 E-DALL-E。

图像创建过程从用户的文本提示开始,就像“在海滩上戴着太阳镜的哈巴狗的砖块上涂鸦墙”DALL-E Mini 系统经过 1500 万对图像/字幕的训练,可以将文本转换为内部表示。然后,它将结果解码并采样为潜在向量,用作 VQGAN 图像生成器的输入,作者使用 ImageNet 数据集对其进行了训练[6]。VQGAN 为每个样本渲染 256x256 的图像,用户选择一个。

首先,用户向 E-DALL-E 提供所需的纵横比,如 16:9。然后,它通过重复原始边缘像素来填充所选图像,作为进一步迭代的初始图像。系统将文本提示输入剪辑文本编码器,用作指导。然后,它开始在生成过程中迭代 N 步,比如 100 步。系统使用 Adam 优化器[7]来改变 VQGAN 向量,以创建与文本提示最匹配的图像。然而,在每一步之后,系统将原始图像中心部分的矢量复制回来,因此它将只更新图像的边缘。

在完成迭代之后,系统显示扩展的图像,在侧面具有新添加的细节。

**DALL-E Mini 的原始 1:1 图像,具有重复边缘像素的初始 16:9 图像,使用 E-DALL-E 扩展的 16:9 图像,**作者提供的图像

仔细观察,您会发现右侧扩展图像的中心部分与左侧的原始图像略有不同。这是 VQGAN 渲染图像的一个有意的方面。我将在下面的图像拼接部分描述这种效果。

组件详细信息

达尔-E

2021 年 1 月,OpenAI 发布了一篇论文和他们的 DALL-E 文本到图像系统的演示[8]。这个名字是一种文字游戏。这是画家萨尔瓦多·达利的姓氏和迪士尼动画电影《瓦力》的结合

DALL-E 模型是一个巨大的变压器。它有 120 亿个参数,并使用来自互联网的 2.5 亿对图像/字幕进行训练。以下是查询结果,“一只手风琴做的貘。有手风琴纹理的貘。”以及“一只穿着圣诞毛衣的小刺猬遛狗的插图。”

来自 DALL-E 的输出来自 OpenAI 的论文零镜头文本到图像生成

DALL-E 的结果非常好。该系统在解释文本和渲染图像方面做得很好,既有创造性又很逼真。一个限制是输出相对较小,为 256x256 像素。OpenAI 没有提供 DALL-E 源代码或训练模型的访问权限。但 14 个月后,情况发生了变化。

达尔-E 2

2022 年 4 月 13 日,OpenAI 发布了名为 DALL-E 2 的更新版本[1]。它为文本编码器使用了他们的剪辑模型的变体,并使用了他们的 GLIDE [9]图像解码器模型的变体,具有 35 亿个参数。OpenAI 使用 6.5 亿张图像训练了 DALL-E 2 系统。该系统以 1024x1024 像素的高分辨率渲染图像。这是他们论文中的一些样本图片。

OpenAI 论文中 DALL-E 2 的输出,带剪辑潜在时间的分层文本条件图像生成

这些成绩都很优秀!正如我在本文开头提到的,DALL-E 2 只提供封闭测试版。

达尔-E 迷你

开发人员 Boris Dayma 和 Pedro Cuenca 带领一个团队创建了一个免费的开源文本到图像生成器,名为 DALL-E Mini [2]。该系统使用一对经过训练的 BERT 变换器[10]将文本转换为潜在向量,这些潜在向量可以使用 VQGAN 渲染图像。顾名思义,DALL-E Mini 型号比较小。它“只”有 4 亿个参数,并且“只”在 1500 万张图像上进行训练。

这是 DALL-E Mini 的推理管道图。

DALL-E Mini 的推理管道,来源: DALL-E Mini 解释

文本提示被输入 BART,然后被解码以产生 VQGAN 的潜在向量样本,从而呈现候选图像。请注意,系统不会迭代生成图像。它转换成 VQGAN 用来直接渲染图像的矢量。DALL-E Mini 如何工作的完整解释是这里。

这里有一些提示的示例图像,“一幅起伏的农田的画”、“一幅带有橙色三角形的抽象画”和“一碗水果的静物画”

DALL-E Mini的输出样本,图片由作者提供

虽然它们不如 DALL-E 2 的图像好,但 DALL-E Mini 的输出还不错。这些图像有很大的变化,虽然缺乏细节,但每幅作品总体来说都很好。

接下来,我将向您展示如何扩展输出以获得不同的纵横比。

伊达尔伊

E-DALL-E 系统从用户指定的纵横比开始。例如,如果我们有一个 256x256 的图像,并想将其拉伸到比如说 16:9,我们需要在左侧添加 96 个像素,在右侧添加 96 个像素。这将产生大约为 16:9 的合成图像 448x256。

接下来,系统用重复的像素填充图像的边缘。这将有助于 VQGAN 模型在生成扩展图像的侧面时领先一步。重复像素是一个简单的编程技巧,不需要任何机器学习。

对于图像中的每一行,系统计算最后 8 个像素的平均值,并复制它们以制作水平颜色恒定的子图像。它还对原始图像执行 32 像素的线性混合以掩盖过渡,因此左右子图像的宽度必须为 96+32 像素。

这是三幅图像在 16:9 格式下的样子,有重复的边缘像素。

**具有重复边缘像素的 DALL-E Mini 的输出,**作者的图像

好吧,它们不能作为成品图像,但它们是下一步过程的良好起点。重复边缘像素的源代码在这里是。

使用 VQGAN 拼接图像

在我开始渲染扩展图像的侧面之前,我将讨论 VQGAN 的一个有趣的方面,据我所知,它还没有被写出来。)虽然 VQGAN 的作者创建它是为了生成新图像,但它在将相似图像拼接在一起方面做得非常好。

VQGAN 本质上是一个编解码器。编码器获取图像并生成潜在向量。解码器获取潜在向量并生成图像。在训练期间,系统更新模型的参数,以使输出图像尽可能接近地匹配输入图像。

与大多数 GANs 中的潜在向量不同,VQGAN 使用的潜在向量有一个空间方面。对于输入中每 16x16 块 RGB 像素,解码器会创建 256 个浮点数。因此,256x256 RGB 图像的潜在尺寸为 16x16x256。在 VQGAN 论文[4]中,256 个数字的组被称为“码本”。

当我在潜在向量空间中编辑图像时,系统会在解码结果图像时平滑结果。

例如,这里有两幅来自艺术家古斯塔夫·克里姆特和阿美迪欧·莫蒂里安尼的肖像。最上面一行显示了从中间开始拼接 RGB 图像的结果。左半部分来自克里姆特,右半部分来自莫迪利阿尼。底部一行显示了拼接 VQGAN 潜在向量和解码结果图像的结果。

顶行: WikiArt 的古斯塔夫·克里姆特的 Amalie Zuckerkandl ,作者的混合像素拼接, WikiArt 的阿美迪欧·莫蒂里安尼的 Marie,人民的女儿,底行: Amalie Zuckerkland“通过 VQGAN,混合矢量拼接”,“通过 VQGAN 的 Marie,人民的女儿,作者的图片

这里有几件事需要注意。首先,VQGAN 模型不是一个完美的编解码器。通过模型传递的图像与原始图像并不完全匹配。例如,左上和左下肖像中的眼睛看起来不同。但是,您可以看到在潜在向量空间中拼接图像是如何非常自然地混合图像部分的。尽管中下方的这张脸显然是由不同的两半组成的,但很难找到两者之间的接缝。这是因为每个 VQGAN 码本条目在解码时不仅会呈现其空间区域,还会影响其邻居基于训练数据创建内聚图像。

当渲染扩展图像的侧面时,我使用 VQGAN 的这个特性。

使用 E-DALL-E 扩展图像

这是组件图,只显示了用于扩展图像的过程。

E-DALL-E 组件细节,作者提供的图表

该过程从输入图像和指定的纵横比开始。如上所述,系统重复边缘像素以拉伸图像。然后,它使用 CLIP 对提示进行编码,以指导优化过程。对于每次迭代,系统用 CLIP 对图像进行编码。它使用文本编码和图像编码之间的差异,通过 Adam 优化器来修改 VQGAN 潜在向量。在每次迭代之后,修改的图像向量的中心部分被来自输入图像的向量的中心替换,以保持中间部分相对恒定。只是侧面会有很大的变化。在 N 次迭代之后,系统显示具有新纵横比的最终图像。

以下是使用 E-DALL-E 的一些结果。

**来自 E-DALL-E 的结果,**作者提供的图片

相当不错!该系统似乎在扩展区域中很好地弥补了新的细节。而且很难看到原始图像和新生成的部分之间的接缝。但你也可以看到 VQGAN 有时如何改变图像的中心部分,以使新的部分更好地适应。例如,在右上角的图像中,天空的色调似乎在中心部分变成了更深的蓝色。右下角图像中心的橙色三角形的纹理似乎与边上新生成的三角形的表面相匹配。

文化偏见

像大多数基于互联网上发现的大量数据进行训练的神经网络模型一样,该项目中使用的模型具有内在的文化偏见,这些偏见会在数据中得到体现。

视频作者研究了他们系统中存在的文化偏见。

CLIP 是在互联网上与图像配对的文本上训练的。这些图像-文本对未经过滤和切割,导致剪辑模型学习许多社会偏见。…例如,我们发现…‘保姆’和‘管家’等标签开始出现在女性身上,而‘囚犯’和‘暴徒’等标签开始出现在男性身上。…此外,CLIP 还贴上了一些标签,这些标签更多地描述了男性的高地位职业,如“高管”和“医生”。——亚历克·拉德福德等人

DALL-E Mini 的作者发现了以下情况。

总的来说,由于生成的人和脸的质量低,很难详细调查模型偏差,但很明显,偏差是存在的。表现出较高教育水平的职业(如工程师、医生或科学家)或高体力劳动(如建筑业)大多由白人男性代表。相比之下,护士、秘书或助理通常是女性,通常也是白人。生成的人大部分是白人。只有在具体的例子中,比如运动员,我们才会看到不同的种族,尽管他们中的大多数仍然没有得到充分的代表。该数据集仅限于带有英语描述的图片,这使得来自非英语文化的文本和图像无法呈现。 - Boris Dayma 和 Pedro Cuenca 等人

E-DALL-E 在渲染扩展图像的新部分时可能会延续这些偏见。

最后的想法和未来的步骤

DALL-E 迷你文本到图像模型的结果看起来非常好。VQGAN 是一种多功能的图像渲染模型,有许多意想不到的用途,如扩展图像以改变纵横比。

在未来的项目中,我可能会尝试使用 VQGAN 作为一个通用的修复工具。尽管系统将被掩蔽的区域量化为 16×16 的像素块,但是有可能混合回原始潜在向量和被掩蔽区域之外的原始像素。并且使用 CLIP 作为一个指导性的文本编码器,有可能执行类似于“在哈巴狗上画一顶派对帽”的功能。😀

源代码

这个项目的源代码可以在 GitHub 上找到。我在 CC BY-SA 许可下发布源代码。你可以使用谷歌眼镜创建和扩展你自己的图像。

知识共享署名共享

感谢

我要感谢詹尼弗·林对这篇文章的帮助。

参考

[1] A. Ramesh 等人, DALL-E 2 带剪辑潜在时间的分层文本条件图像生成 (2022)

[2] B. Dayma 和 P. Cuenca, DALL E mini —从任何文本提示生成图像 (2021)

[4] VQGAN 作者:P. Esser、R. Rombach 和 B. Ommer,驯服变压器实现高分辨率图像合成 (2020)

[5] 剪辑由 a .拉德福德等著,从自然语言监督中学习可转移的视觉模型 (2021)

[6] J .邓等, ImageNet :一个大规模的层次化图像数据库 (2009)

[7] D. P .金马和 j .巴雷,亚当 : 随机优化的一种方法 (2015),国际学习表征会议2015

[8]a . Ramesh 等人的 DALL-E ,零镜头文本到图像生成 (2021)

[9] A. Nichol 等人, GLIDE :利用文本引导扩散模型实现照片级真实感图像生成和编辑 (2022)

[10] J. Devlin,M.W. Chang,K. Lee,K. Toutanova, BERT :语言理解的深度双向转换器的预训练 (2018)

附录

左边是 DALL-E Mini 的结果,右边是 E-DALL-E 的结果。

一幅带有蓝色、绿色和紫色漩涡的彩色抽象画

**“蓝色、绿色和紫色漩涡的彩色抽象画,”**作者图片

一幅吉娃娃冲浪的画

“一只吉娃娃在冲浪”,作者图片

一幅梵高《星夜》风格的埃菲尔铁塔画

**“梵高《星夜》风格的埃菲尔铁塔画”,**作者图片

一幅色彩缤纷的新英格兰风景画

**“色彩缤纷的新英格兰风景画”,**作者图片

为了无限制地访问 Medium 上的所有文章,成为会员,每月支付 5 美元。非会员每月只能看三个锁定的故事。

早期数据科学职业生涯:帮助你走向成功的 6 条原则

原文:https://towardsdatascience.com/early-data-science-careers-6-principles-to-set-you-up-for-success-da5ac724d6f9

一些提示可以帮助你在早期将你的数据科学/数据分析事业引向正确的方向。

Javier Allegue Barros 在 Unsplash 上拍摄的照片

请注意,在下面的文章中,我使用“数据科学”作为包罗万象的术语,代表所有数据科学、数据分析、商业分析、应用数据科学、研究数据科学和其他相关领域。

你在人们津津乐道的迷人的数据科学领域找到了一份工作,并且对未来的前景非常兴奋。(好吧,至少这是我 12 年前开始旅行时的感觉。)

开始任何职业都可能有点让人不知所措因为当你加入一个组织时,你会接触到丰富的资源、流程和知识库。**数据科学职业也不例外。如果你和我一样,你会有很多问题,比如你的工作中什么是好的,你应该做什么,在什么时候做什么,你不应该做什么。**对于初学者来说,开始数据科学职业生涯并在其中导航可能会成为一项艰巨的挑战。下面的帖子简要描述了一些原则,在您开始数据科学之旅时,您可以遵循这些原则来帮助自己走向成功。对于你可能开始的任何职业来说,这些都是有效的。

这些年来,我仔细看了无数人走过的数据科学家职业道路;在某些情况下,他们自己铺陈,而在另一些情况下,组织为他们有机地铺陈。考虑到这一点,我想写一些原则(应该做的和不应该做的),这些原则是我在推进数据科学事业中看到的..

1。学习,学习,学习。

如果今天你需要带走一样东西,那就是你必须在你的职业生涯中继续学习。这一点怎么强调都不为过。

学习可以用你想定义的方式来定义;这可能意味着学习分析方法、数据科学算法、编码平台、可视化工具、商业敏锐度、管理利益相关者..任何事!

诀窍是学习并不断提升自己,以便在不断发展的数据科学领域保持相关性。

  • 在早期阶段,你可以专注于数据科学的基础知识。目标是掌握项目中使用的工具、编码语言、简单的分析和统计方法。你的目标应该是成为做好工作所需的基础知识的大师。
  • 慢慢地,你开始培养信心,获得书面和口头沟通技巧,并开始管理利益相关者或客户
  • 在牢牢掌握了基础知识之后,你可以开始展开翅膀学习更复杂的机器学习方法。网上有一些资源,包括培训和课程,您可以使用它们来了解不断发展的数据科学领域的最新动态。

小心!
当你开始你的职业生涯时,你可能会有一个陡峭的学习曲线(因为你是从零开始)。当你进入数据科学领域几年后,学习曲线会开始变平,这是时候做出额外的努力来跟上步伐

2.不要一开始就太挑剔

一些数据科学家倾向于发展对某种工作的偏好。不用猜,大多数情况下,这是每个人都想得到的“科学”工作。

在这种情况下,科学工作指的是复杂的统计、数学机器学习技术在项目中的应用。
—我们经常阅读和谈论的数据科学中“酷”的部分。

由于我们对什么是数据科学*(基于我们所阅读和看到的)*的感知形象,人们形成了这样一种观念,即一个“复杂”的工作应该比其他“简单”的工作“更好”。这意味着做复杂的机器学习建模项目对他们来说比“更简单”的分析项目“更好”
→在这里我可以诚实的告诉你;这个 绝对不是 的情况。

由于这种错误的观念,初露头角的数据科学家通常希望获得“特定”类型的工作,有时会变得过于挑剔,导致没有灵感和动力从提供给他们的东西中学习。在早期,你必须欢迎你正在得到的工作,想法应该是完全掌握你的工作,然后要求额外的责任或复杂的工作

任何类型的工作(无论是科学类的还是非科学类的),只要是解决商业需求的,都会有大量的机会让你去学习,掌握,然后提高。

小心!
在早期阶段过于挑剔可能会导致你错过很多机会,并对你的职业生涯产生不利影响。

3.准备好离开你的舒适区

我们都喜欢安定的感觉。在职业环境中,这意味着对工作和与你一起工作的人感到舒适

如果你不喜欢这份工作或和你一起工作的人,那么你肯定需要考虑换一个角色。 这是一个不用动脑筋的问题。

然而,万一你确实热爱你正在做的工作和与你一起工作的人;然而,在某个时刻,改变对你有好处。当我们喜欢某样东西并通过努力变得擅长时;我们都倾向于对此感到有点舒服*(也许太舒服了)*。在这个地方,我们不需要延伸,我们不需要做任何超出的事情来做好我们的工作。
→虽然这是一个可以到达的好地方,但是长时间呆在你的舒适区会导致学习瘫痪

小心! 过得舒服是好事,过得太舒服是陷阱。离开它!

总是想办法挑战自己做更多的事情,让自己参与不同的项目,在不同的团队中工作,制定不同的解决方案,或者与不同的人一起工作。

每一个挑战都会带来一系列新的知识。所有这些都增加了你的经历。

4.忠于你的面包和黄油

摆弄数据以获得有意义的业务成果是数据科学家的‘面包和黄油’——你的工作存在的核心原因。

尽可能长时间地接触数据科学至关重要。

一些人在他们的数据科学职业生涯中犯的一个常见错误是不再亲力亲为,脱离实际的日常数据科学工作(编码、可视化、数据操作、见解、模型等)。)早年。如果你在最初几年表现出色,并且抓住机会过早进入管理岗位,这种情况就会发生。尽管没有预想到,但这总是会导致你与你的实践失去联系。

许多刚进入管理层的人认为,他们会密切关注实际的数据科学工作,并保持动手能力。然而,团队领导已经是茶余饭后的事了,没有留下任何真正动手的余地。这加速了您与核心基础数据科学概念,即您的“面包和黄油”失去联系的过程

小心! 在很多组织中,从数据科学的个人贡献者进入管理层被视为一种晋升——这不一定是真的。因此,鼓励许多数据科学家这样做,并最终在他们职业生涯的早期与数据科学失去联系。请记住,你的职业不是一场赛跑,而是一场马拉松!

5.回馈社会

在任何职业生涯的早期,你都依赖很多人来训练、帮助和支持你,让你达到一个让你做好工作的水平。换句话说,你从帮助你自立的社区中获得了很多。随着你在任何职业中的成熟,你开始拿的越来越少,但有更多的机会为之做出贡献。也就是回馈社会。数据科学职业也不例外,同样的原则也适用。随着职业生涯的成熟,回馈社会是非常重要的。

你获得的经验,*是你的社区帮助你获得的,*一定对你和社区都有好处。

有几种方法可以做到这一点— 与他人分享你的知识和经验,创建他人易于理解的可重复的解决方案,培训和指导初级成员,向同事和高级提供可操作的反馈,参与公司范围内的活动等。
—做一切能帮助别人做好本职工作的事。

小心! 很容易忽略知识分享。但是请记住,知识共享=知识平方
——这将有助于你提升自己在行业内的专家形象。

6.拓展人脉

人际关系是一项被低估且经常被忽视的技能。

一个强大的关系网会帮助你一起成长。

在你职业生涯的早期,你的全部精力应该放在学习上。做太多事情可能会适得其反。然而,随着时间的推移,当你掌握了你的领域、你的角色和你的团队;你可以开始拓展业务了。你可以开始投入很少的时间来沉迷于各种活动,如与组织内的其他团队合作,参加行业活动和会议,参加黑客马拉松和数据科学会议等。→所有这些都会给你提供社交机会

网络是让你在数据科学职业生涯中获得成功的头号不成文规则。

你会遇到你所在领域的专家,你会慢慢培养与他们的关系,反过来从他们的专业知识中学习。你可以了解这个领域的最新情况,了解每一个细节,这可以带来学习和成长的机会。
→这将最终帮助你推进你的数据科学事业。

小心!社交更多的是一门艺术,你不想在这上面花太多时间,只要能保持领先就好。

摘要

让自己在数据科学领域取得成功应该比数据科学本身更简单,但不幸的是很少如此!遵循下面的 6 条戒律,成功永远不会太远:

  1. 不断学习,你就会不断成长。
  2. 不要在项目初期过于挑剔。
  3. 不要太舒服。
  4. 在数据科学领域,永远不要手软。
  5. 为你所在社区的进步做出贡献,社区也会为你的进步做出贡献。
  6. 扩大你的关系网,以便与你的关系网一起成长。

保持联系..

如果你喜欢这篇文章并且对类似的文章感兴趣 在 Medium 上关注我加入我的邮件列表 和*(..如果你已经不是了..)跳上成为媒体家族的一员,获取数以千计的有用文章。*(如果你使用以上链接,我将获得你 50%的会员费)**

..不断学习,不断成长!

及早发现信用卡欺诈

原文:https://towardsdatascience.com/early-detecting-credit-card-frauds-38db7c190e44

应用机器学习模型来主动测试交易并将其分类为有效或无效

作者图片

介绍

信用卡技术背后的想法实际上可以追溯到 19 世纪晚期,来自爱德华·贝拉米(维基百科)写的乌托邦小说《回望过去》。然而,我们在 20 世纪才开始看到类似的东西,但与我们今天所拥有的相比,什么都不是。

事实是,信用卡已经彻底改变了我们购物和生活的方式,而不必随身携带大量现金。据估计,2018 年,仅在美国就有 12 亿张信用卡在流通,72%的成年人至少拥有一张信用卡。

照片由来自 Pexels 的 Tara Winstead 拍摄

不幸的是,这项技术为诈骗和欺诈打开了一个全新的可能性。这些类型的犯罪大多发生在通过各种渠道非法获取你卡上的数据时,但大多是由于数据库泄露或身份盗窃计划( FBI )。

然而,你可以采取很多措施来防止你的数据被盗。仅举几个例子:

  • 确保您正在访问的网站具有有效的安全证书;
  • 不要把你的信息透露给任何你不认识的人;
  • 不要相信你通过电子邮件或网站收到的每一个产品或投资提议。

来自 Pexels 的 Anete Lusina 摄影

为了避免这种欺诈,银行公司总是试图早期识别这些事件,以便立即阻止卡和交易失败。

考虑到这一点,我们将利用 Kaggle 上提供的一个数据集,该数据集是一家欧洲银行 2013 年两天的交易量,我们将开发一个模型来将交易分类为欺诈与否。

关于我们的数据集

原始数据集由 31 个属性(列)组成,考虑了关于时间、金额和交易类型(欺诈与否)的数据,这将是我们的目标变量。出于隐私原因,其余属性采用主成分分析( PCA )方法进行降维处理,并隐藏描述。至于行,我们总共有 284407 个条目

作者图片

这个数据集的一个重要方面是它的自然不平衡。正如预期的那样,我们应该会看到比欺诈交易更多的真实交易,这可以从我们的数据中看出。事实上,只有 0.173% (492 个条目)被归类为欺诈。

这实际上是我们分析的一个问题,但我们稍后会处理它。

分析分布

我们现在来看看两个主要的(已知的)属性:数量和时间,关于交易的类型,并开始分析我们的数据。

作者图片

通过查看 Amount 属性,我们已经可以开始看到一些特征,例如欺诈在较小的值中更常见。

作者图片

经过进一步分析,可以发现欺诈的平均值122.21 欧元,但中位数仅为 9.25 欧元,也就是说,所有交易的 50%实际上小于或等于后者。

中值和平均值之间的差异实际上是由于存在异常值,这些异常值不符合相应的分布,导致平均值更高。记录在案的最大诈骗实际金额为 2125.87 欧元

作者图片

我们知道,时间属性与 48 小时的事务相关。尽管我们没有每笔交易发生的实际时间,但通过观察分布情况,我们可以得出一些结论。我们看到较低价值的时刻可能是在黎明前,那时我们预计人们不会四处购物。

但是,对于欺诈性交易,我们没有观察到完全相同的模式,因为许多交易实际上都是在一天的这些时段注册的。

准备数据集

尽管我们不知道大多数数据的含义,但是这些列出现在各种范围内,所以第一步将是调整这些范围。为此,我们将标准化时间和数量变量,因为其他属性已经被处理过了。

下一步将是在训练和测试数据之间,以及在 X (独立变量)和 y (目标类)中分割我们的数据集。为此,选择的测试比例为 20%,剩余的 80%分配给训练集,然后随机分配值。

我们仍然有不平衡的问题要处理,但我们将稍后处理它,以便进行比较。

构建随机森林分类器

作者图片

这个项目选择的机器学习模型是随机森林分类器,来自 Scikit-Learn Python 库中的。当我们试图根据不同的特征和一系列对或错的陈述做出选择时,随机森林是我们在日常生活中直观使用的常见决策树的升级。

决策树倾向于创建一系列规则,并一次处理整个数据集。然而,随机森林增加了一点(你猜对了)随机性,为构建的许多决策树中的每一个选择不同的随机特征和条目,然后平均结果。理论上,模型的这种可变性会产生更准确的预测,因为许多树倾向于减弱每一棵树的单独误差。

但是,我们应该如何评估我们模型的性能呢?

这是一个极其重要的问题,没有一个真正的全球性结论性答案。它总是取决于我们使用的数据的模型和特征。

对于我们的具体情况,即我们有一组高度不平衡的数据并在寻找二进制分类(有效或无效),最合适的方法是 AUC-ROC (接收器工作特性曲线下的区域),这是一种处理真阳性率(TPR)和假阳性率(FPR)的方法。您可以在这里更多地了解它。

但是,简单解释一下,我们的 AUC-ROC 评分将取 0 到 1 之间的值,其中较大的值意味着模型在正确识别所需类别方面更好。我们还将使用预测召回参数进行比较。

训练原始数据

所选超参数为模型的标准值(仅为再现性设置了 random_state ),共有 100 个估计值(决策树)。

在将模型与训练数据拟合之后,我们继续根据测试数据预测类。

作者图片

第一个模型的数据处理不当,返回的最终评分为 0.89 ,作为预测因子,假阳性率基本较低(精度为 0.92 ),假阴性率轻微(召回率为 0.78 )。

由于问题的性质,我的方法是尽量减少假阴性率,但代价是最终增加假阳性结果的数量。假设是预防性封锁(最终的社会公害)比通过的欺诈性交易更受青睐,这将导致报销必要性等问题。

处理失衡问题

正如我们所看到的,我们的原始数据集非常不平衡,我们有一些技术来减少这个问题。这些技术可分为过采样或欠采样方法。在本分析中,我们将使用两者,方法来自不平衡学习 Python 库。

顾名思义,这些技术要么增加要么减少我们的数据集上的观察数量。我们首先使用 SMOTE ( 合成少数过采样技术)进行过采样,目标比例为 1:10(总计 10%),这实质上是通过生成符合原始观察值的属性值,为较小的类(欺诈)创建新条目。

对于欠采样,我们将使用随机欠采样器方法,比例为 5:10(少数类的两倍),随机挑选出一些最大的类(有效)条目,并将其从数据集中删除。

作者图片

有了这个,我们现在有整组的三分之一是诈骗。需要指出的重要一点是只有训练集经历了这种转换。我们希望测试数据尽可能真实,以便正确评估我们的模型。

下面我们可以看到治疗失衡前后分布的对比。

作者图片

我们现在继续创建一个新的模型,这次使用更平衡的数据集。

训练新处理的数据

作者图片

保留相同的超参数进行比较,现在我们能够检索到 AUC-ROC 评分 **0.94,**比之前的模型高 0.5 分。达到了预期的结果,实现了更低的假阴性代表更多的假阳性。

结论

在这个项目中,有可能将随机森林算法识别为对欺诈性信用卡交易进行分类的有效方法。从一个庞大且不平衡的数据集中,我们可以在处理数据之前和之后测试模型的准确性。

为了处理不平衡,对训练集应用了两种技术: SMOTERandom Under Sampling 。有了它们,欺诈交易的最初不平衡 0.17% 变成了类别之间的比例 66/33

从原始模型到处理后的模型,评估模型性能的主要选择指标 AUC-ROC 得到了显著改善:分别为 0.890.94 分。

不平衡处理有效地提高了模型的性能,但也增加了假阳性率。由于问题的性质,这个结果是合理的,因为它是可取的,以更好地检测欺诈,代表一些更多的误报。

感谢支持!

你可以在这里访问整个笔记本。

作为一名程序员挣更多的薪水——更高的学位还是更多年的经验?

原文:https://towardsdatascience.com/earn-more-salary-as-a-coder-higher-degree-or-more-years-of-experience-68c13f73a557

在 Python 中使用可视化和贝叶斯推理的分析

动机

作为开发人员或数据科学家,您可能想知道:

  • 随着你获得更多的经验,你会挣更多的薪水吗?如果是,多多少?
  • 其他因素,如以前的学位、职位类型和公司的规模会影响你的薪水吗?

作者图片

在本文中,我们将使用可视化和贝叶斯推理来回答这些问题。

检索数据

我们将使用 Kaggle 上的 Stack Overflow 2018 开发者调查。该数据收集了 2018 年开发者调查中由 Stack Overflow 填写的个人回复。

首先将数据下载到当前目录,然后运行:

由于不同的国家和不同的就业类型的工资是不同的,我们只选择在美国,有全职工作,不是学生的开发人员。

我们还将过滤掉超过 30 万美元的工资极值:

可视化薪资范围:

作者图片

看起来大多数开发人员的年收入在 75,000 美元到 100,000 美元之间。对于美国的开发人员来说,这听起来很合理。

编码年工资

我们最感兴趣的是编码年限如何影响工资。让我们用箱线图来想象一下。

作者图片

由于YearsCoding是字符串类型,我们将把它转换成pandas.Interval:

可视化数据:

作者图片

太好了,似乎平均工资随着编码年限的增加而增加!

注意,上面的数据只是开发者的样本。我们如何确定 3-5 年和 0-2 年工作经验或 6-8 年和 0-2 年工作经验之间的平均工资有显著差异?我们可以用 Bambi 的双样本贝叶斯 t 检验来验证这一点。

斑比贝叶斯 t 检验

斑比是什么?

Bambi 是用 Python 编写的高级贝叶斯建模接口。它构建在编程框架 PyMC3 之上。因此,Bambi 类似于 PyMC3,但是更容易使用。

要安装 Bambi,请键入:

pip install bambi

基于 2 年不同经验的贝叶斯 t 检验

在一次性比较多年工作经验之前,让我们先来比较两年不同工作经验的平均工资:0-2 年工作经验和 3-5 年工作经验。

作者图片

我们表示:

因此,我们可以这样写:

从上面的等式中,我们可以看到,如果两组之间的平均工资没有差异,那么𝛽 = 0。

我们将使用斑比来绘制 4000 个𝛽样本,并找出𝛽.的分布我们将假设 0-2 年和 3-5 年的工资分布是正态的。

在上面的代码中,ConvertedSalary ~ YearsCoding告诉斑比YearsCoding影响了ConvertedSalary

总结结果:

作者图片

在上表中,YearsCoding[(3.0, 5.0)]是上式中指定的𝛽。我们可以看到,𝛽94%的最高密度区间(HDI)在 8418.925 和 14348.040 之间。

让我们想象一下𝛽:的分布

作者图片

从上面的分布,我们可以说:

  • 两组的平均工资差为 11,400 英镑。
  • 这两个群体之间工资差异的 94%在 8418.925 英镑和 14,348.040 英镑之间。

由于𝛽的所有值都远远高于 0,我们可以肯定地说,有 0-2 年经验的开发人员和有 3-5 年经验的开发人员的平均工资有很大的差别。

让我们仔细检查一下𝛽的所有值是否都大于 0:

1.0

酷!他们都是。

基于多年经验的贝叶斯 t 检验

现在,让我们将其他年份的经验与 0-2 年的经验进行比较。

作者图片

从上表中,我们可以看到平均工资随着编码年限的增加而增加。随着编码年限变长,编码每多一年平均工资的增长变小。

影响工资的其他因素

我们知道经验年限影响薪资,但是正规教育、公司规模、开发者类型等其他因素呢?

让我们用可视化来找出答案。你可以在本笔记本中找到创建以下情节的代码。

正规教育工资

正规学历影响你挣多少钱吗?我们可以用一个方框图来找出答案,它的方框是根据教育水平的提高来排序的。

作者图片

在上面的图中,那些没有受过正规教育的人似乎和那些有硕士学位的人挣得一样多,并且平均比那些有学士学位的人挣得更多。因此,我们可以说,正规学位的水平和工资之间几乎没有关联。

按公司规模分类的工资

公司规模如何影响薪水?从下面的方框图来看,大公司的工资中位数似乎比小公司的工资中位数要大。

作者图片

按开发人员类型列出的薪金

某些类型的开发人员比其他人挣得多吗?下图显示了工程经理、首席执行官、首席技术官等管理职位的平均工资高于其他职位的平均工资。然而,差异很小。

学生的薪水似乎明显低于其他全职职位。

作者图片

首席执行官、首席技术官等高管的分布。)比其他发行版传播更广。不同规模的公司,高管薪酬可能会有很大差异。

总结和下一步

摘要

从上面的分析,我们可以说

  • 经验年数少的开发人员和经验年数多的开发人员在平均薪资上有显著差异。
  • 正式学位对薪水的影响很小,甚至没有影响。
  • 当公司规模扩大,职位更高时,工资中位数会略有增加。

那么你应该获得更高的学位还是获得更多的经验来挣更多的薪水呢?从上面的数据分析来看,更好的投资是在你感兴趣的领域获得更多年的经验。

下一步

能否使用贝叶斯 t 检验来确定不同公司规模之间或不同职位类型之间的平均工资是否存在显著差异?

在这里随意发挥和分叉本文的代码:

https://github.com/khuyentran1401/Data-science/blob/master/statistics/stackoverflow_survey/analyze_salary.ipynb

我喜欢写一些基本的数据科学概念,并尝试不同的数据科学工具。你可以在 LinkedIn 和 T2 Twitter 上与我联系。

星这个回购如果你想检查我写的所有文章的代码。在 Medium 上关注我,了解我的最新数据科学文章,例如:

参考

堆栈溢出。2018–05–15.堆栈溢出 2018 开发者调查,第 2 版。数据库内容许可证。检索自https://www . ka ggle . com/stack overflow/stack-overflow-2018-developer-survey。

用熊猫和地质熊猫在世界地图上绘图的最简单方法

原文:https://towardsdatascience.com/easiest-way-to-plot-on-a-world-map-with-pandas-and-geopandas-325f6024949f

使用 Python 中的 Pandas 和 GeoPandas 读取、清理和绘制地理空间数据的综合指南

报道的火球撞击能量[由作者创造]

学习如何用 Python 创建世界地图可能需要一点时间来弄清楚,但是一旦你知道如何做,你就可以很容易地复制它。假设您有想要绘制的地理数据;你可以用一个带有国家名称的条形图,把你的数据绘制成一个条形图,但是这很无聊。一种更具视觉吸引力的数据呈现方式是将其叠加在地图上,以物理方式显示数据的交互方式。这可能是一个具有挑战性的努力,但我在这里提供帮助。按照这个例子,你应该开始创造惊人的地理空间视觉效果。

照片由锡德·巴拉钱德朗在 Unsplash 上拍摄

在本文中,我将假设您对如何使用 Python 有一个基本的了解,但是如果您在浏览代码时有任何问题,请在评论中告诉我。我非常乐意帮忙。对于本文,我们将使用来自近地天体研究中心(NASA 喷气推进实验室的一部分)的数据集。如果你想重现本文中的形象,你应该从这个链接下载。将文件下载为*。csv* 文件并保存在方便的位置。现在,让我们进入代码:

导入库

以下是绘制数据所需的库的列表:

  • Matplotlib 用于导入 pyplot 包(为方便起见定义为plt),用于绘图目的
  • Pandas (为方便起见定义为pd)用于从读取和操作数据集。csv 文件
  • GeoPandas (为方便起见定义为gpd)用于创建我们的世界地图
# Importing libraries
import matplotlib.pyplot as plt
import pandas as pd
import geopandas as gpd

我看过很多论坛和文章,都是关于人们努力安装 GeoPandas 的。我自己也有点纠结,但是这个教程很有帮助,解决了我遇到的问题。如果你还没有安装 GeoPandas ,我强烈建议你遵循那个教程。

读取数据文件

接下来,我们将使用 Pandas (as pd)从cneos _ fireball _ data . CSV文件中读取数据。在read_csv函数中,我们使用文件的标题名来提取所需的数据列。这些头文件的格式并不总是最容易阅读的,所以我们可以使用如图所示的rename函数来重命名它们。

# Reading cvs file using pandas
df = pd.read_csv('cneos_fireball_data.csv', 
                 usecols=["Peak Brightness Date/Time (UT)", 
                 "Calculated Total Impact Energy (kt)", 
                 "Latitude (deg.)", "Longitude (deg.)"])
df = df.rename(columns={"Peak Brightness Date/Time (UT)": 
                        'Datetime',
                        "Calculated Total Impact Energy (kt)": 
                        'Impact Energy [kt]',
                        "Latitude (deg.)": 'Latitude',
                        "Longitude (deg.)": 'Longitude'})

# Showing raw data and data types
print(pd.DataFrame(df))
print('\n')
print(df.dtypes)
print('\n')

导入数据后,我们可以显示数据集的一部分,并查看有哪些数据类型。下面是这段代码的输出:

 Datetime Latitude Longitude  Impact Energy [kt]
0      1/11/2022 3:33    58.4S    160.2W               2.900
1      1/1/2022 20:23    66.1N    152.6W               0.420
2     12/29/2021 3:15    69.7S    115.0E               0.073
3    12/23/2021 21:27     4.9S     29.6W               0.076
4    12/20/2021 23:15    62.7N     60.3E               0.110
..                ...      ...       ...                 ...
881  11/29/1993 17:48    26.5N     78.3E               0.092
882   10/31/1993 3:39    51.3N    100.9W               0.130
883    10/4/1991 9:22    78.7N      6.3E               1.400
884    10/1/1990 3:51     7.5N    142.8E               5.200
885    4/15/1988 3:03     4.1S    124.3E              14.000[886 rows x 4 columns]Datetime               object
Latitude               object
Longitude              object
Impact Energy [kt]    float64
dtype: object

注意,DatetimeLatitudeLongitude都是对象数据类型。在我们绘制数据之前,需要对这些进行修正。

清洗数据集

清理该数据集的第一步是使用 PandasDatetime列转换为 datetime 数据类型。接下来,我们还需要将LongitudeLatitude列转换为 float 数据类型。这包括删除字母 N、E、S 和 W,并将这些方向转换为正确的正值或负值。此外,我们可以将我们的Impact Energy [kt]列限制在 20 kt 以下,以消除一些异常值。

# Converting to a datetime datatype
df['Datetime'] = pd.to_datetime(df['Datetime'], errors='coerce')

# Applying +/- based on direction and converting to numeric datatype
for x in range(len(df['Longitude'])):
    if str(df.loc[x, 'Longitude'])[-1] == 'E':
        df.loc[x, 'Longitude'] = str(df.loc[x, 'Longitude'])[:-1]
    if str(df.loc[x, 'Longitude'])[-1] == 'W':
        df.loc[x, 'Longitude'] = \
            '-' + str(df.loc[x, 'Longitude'])[:-1]

for x in range(len(df['Latitude'])):
    if str(df.loc[x, 'Latitude'])[-1] == 'N':
        df.loc[x, 'Latitude'] = str(df.loc[x, 'Latitude'])[:-1]
    if str(df.loc[x, 'Latitude'])[-1] == 'S':
        df.loc[x, 'Latitude'] = \
            '-' + str(df.loc[x, 'Latitude'])[:-1]

df['Longitude'] = pd.to_numeric(df['Longitude'], errors='coerce')
df['Latitude'] = pd.to_numeric(df['Latitude'], errors='coerce')

# Converting to numeric datatype
threshold = 20
df = df[df['Impact Energy [kt]'] < threshold]
df['Impact Energy [kt]'] = pd.to_numeric(df['Impact Energy [kt]'], 
                                         errors='coerce')

清理数据集的最后一步是消除在数据类型转换过程中出现错误的行。当出现错误时,error='coerce'代码将引入一个NaN(意味着当一个值不能被转换成正确的数据类型时),因此我们可以使用dropnareset_index来消除那些错误并重置我们的数据集索引。

# Dropping the errors from data conversions and resetting index
df.dropna()
df = df.reset_index(drop=True)

# Showing cleaned data and data types
print(pd.DataFrame(df))
print('\n')
print(df.dtypes)
print('\n')

以下输出显示了清理后的数据集和更正后的数据类型。

 Datetime  Latitude  Longitude  Impact Energy [kt]
0   2022-01-11 03:33:00     -58.4     -160.2               2.900
1   2022-01-01 20:23:00      66.1     -152.6               0.420
2   2021-12-29 03:15:00     -69.7      115.0               0.073
3   2021-12-23 21:27:00      -4.9      -29.6               0.076
4   2021-12-20 23:15:00      62.7       60.3               0.110
..                  ...       ...        ...                 ...
876 1993-11-29 17:48:00      26.5       78.3               0.092
877 1993-10-31 03:39:00      51.3     -100.9               0.130
878 1991-10-04 09:22:00      78.7        6.3               1.400
879 1990-10-01 03:51:00       7.5      142.8               5.200
880 1988-04-15 03:03:00      -4.1      124.3              14.000[881 rows x 4 columns]Datetime              datetime64[ns]
Latitude                     float64
Longitude                    float64
Impact Energy [kt]           float64
dtype: object

创建世界地图和绘制数据

最后,我们可以利用 GeoPandas 库导入一张世界地图。为了绘制worldmap数据,我们需要创建一个图形。然后,我们可以调用worldmap变量的plot方法。这将在我们的地图上创建世界地图,但我们也想包括我们的火球数据。为了包含它,我们调用scatter并为我们的点定义一些绘图参数。最后,没有标题和轴的情节是不完整的,所以我们也创造了它们。

# From GeoPandas, our world map data
worldmap = gpd.read_file(gpd.datasets.get_path("naturalearth_lowres"))

# Creating axes and plotting world map
fig, ax = plt.subplots(figsize=(12, 6))
worldmap.plot(color="lightgrey", ax=ax)

# Plotting our Impact Energy data with a color map
x = df['Longitude']
y = df['Latitude']
z = df['Impact Energy [kt]']
plt.scatter(x, y, s=20*z, c=z, alpha=0.6, vmin=0, vmax=threshold,
            cmap='autumn')
plt.colorbar(label='Impact Energy [kt]')

# Creating axis limits and title
plt.xlim([-180, 180])
plt.ylim([-90, 90])

first_year = df["Datetime"].min().strftime("%Y")
last_year = df["Datetime"].max().strftime("%Y")
plt.title("NASA: Fireballs Reported by Government Sensors\n" +     
          str(first_year) + " - " + str(last_year))
plt.xlabel("Longitude")
plt.ylabel("Latitude")
plt.show()

如果操作正确,您的绘图应该如下所示:

报道的火球撞击能量[由作者创造]

感谢您阅读文章!给我一个关注,看看我关于 Python、空间和轨道力学的其他文章!如果您有任何意见或顾虑,请告诉我!

承认

这里使用的数据集是由美国宇航局 EOSDIS 提供的。由于美国宇航局是一个政府实体,它不许可其材料,包括数据集。你可以在这里找到更多关于 NASA 许可的信息:https://earth data . NASA . gov/earth-observation-data/data-use-policy

轻松制作 Matplotlib 图形动画

原文:https://towardsdatascience.com/easily-animate-your-matplotlib-graphs-99b62db63697

让 Matplotlib 动画更容易理解

由卢卡斯·布拉塞克在 Unsplash 上拍摄

将数据可视化制作成动画可以增加可视化的整体深度。例如,下面的示例将时间维度添加到数据可视化中。你可以很容易地看到不同年龄组的人口随着时间的推移是如何变化的。通过动画可视化,我们可以很容易地看到趋势随时间的变化,在详细的组。

考虑到 Matplotlib 中可用选项的广度,学习如何制作图形动画似乎是一项艰巨的任务。本教程旨在解决这个问题!

请看下图,看看我们今天要创造什么:

你将学会创造什么(来源:Nik Piepenbreier)

激动吗?让我们开始吧!

你可以在这里下载数据集。它基于加拿大统计局免费提供的数据,描述了加拿大人口按年份、年龄组和性别的细分。

创建基础可视化

Matplotlib 动画通过不同的可视化效果循环工作。因此,我们可以设置一个基本的可视化,然后创建一个 for 循环,根据数据变化修改可视化。

让我们先创建一个我们满意的基础可视化:

创建我们的基础可视化

代码太多了!让我们来分析一下我们在这里做了什么:

  1. 我们导入了项目所需的库
  2. 我们使用read_csv()函数读入数据
  3. 我们应用了一些数据清理来使我们的数据达到最佳状态。我们向前填充缺失的年龄类别,将我们的人口数转换为整数,并将我们的女性人口数乘以-1,这样她们就出现在我们视觉的左侧
  4. 然后,我们创建了一个图形和轴对象来保存我们的可视化
  5. 然后,我们过滤我们的数据,使之可视化
  6. 然后,我们使用barh()函数创建两个相互叠加的可视化效果,并添加我们的值作为标签
  7. 最后,我们通过移除脊柱等来自定义我们的可视化。最后,我们设置一个标题来表示年份。

这将返回以下可视化结果:

您将创建的基本图像(来源:Nik Piepenbreier)

现在我们已经建立了基础,让我们创建我们的动画!

创建可视化

为了动画化我们的可视化,我们将使用FuncAnimation类。顾名思义,这个类使用函数来创建动画。在我们进一步讨论之前,让我们看一下类的定义:

了解 FuncAnimation 类

从上面的代码块中我们可以看到,我们需要传入三个关键参数:

  1. 要使用的数字
  2. 修改图形的功能
  3. 对于每个帧,将什么数据传递到函数中

您已经做了大量定义图形外观的艰苦工作。很容易把它转换成一个函数!让我们看看如何做到这一点:

创建我们的动画功能

我们在上面的代码中所做的只是简单地将之前的代码转换成一个函数。该函数接受一个参数,即年份,稍后我们将使用我们的frames=参数填充它。

这里需要注意的是,我们还在函数中添加了第一行。ax.clear()调用清除了我们的 axes 对象,并允许我们使用函数重新创建它。

把所有的放在一起

让我们看看现在如何把这些放在一起。我们可以通过用我们的轴、函数和一组框架实例化它来创建一个FuncAnimation对象。

我们可以通过创建一个捕捉最小值和最大值的范围,使我们的框架对数据是动态的:

加入我们的动画(终于!)

在上面的代码中,我们首先创建我们的动画对象。然后,我们使用PillowWriter类将我们的动画保存为 GIF 文件。这允许我们自定义动画运行的速度。在上面的代码中,我们将其设置为每秒 5 帧。

结论

厉害!您已经创建了您的动画!创建动画数据可视化可让您以全新的方式浏览数据。在这种情况下,我们能够看到人口如何随着时间的推移而变化。添加动画并不总是一个好主意,但确实可以使数据交流更容易。

轻松自动化您的文档,再也不用碰它了

原文:https://towardsdatascience.com/easily-automate-and-never-touch-your-documentation-again-a98c91ce1b95

使用 MkDocs 的完全自动化的 Python 文档过程

作为开发人员,每个人最喜欢的方面是:维护文档化的代码,并在 GitHub 上为他们的开发伙伴托管文档。

当然,我是在开玩笑。文档常常是一项被忽视的任务,这使得新成员接管过时的代码库成为一项浪费且痛苦的任务。我们都经历过——在我之前的开发者在这里做什么?还有……这到底是怎么回事?

不会了。在 Mkdocs 、 Mkgendocs 、我写的一个自定义脚本和 GitHub 动作的帮助下,我们可以自动维护像这样的华丽文档!

照片由西格蒙德在 Unsplash 上拍摄

第一步——确保你的代码库有谷歌风格的 python 文档串

自动化的第一步只是将 google 风格的文档字符串添加到 python 文件中。对于 atom 文本编辑器用户,我推荐使用 docblock atom 扩展来自动完成这项工作!

这一步并不是绝对必要的,但是以这种方式添加的任何文档字符串都将在接下来的步骤中被删除并添加到我们的站点中!这一步也可以在闲暇时逐步完成。您添加的文档越多,您的自动文档就越有成效!

步骤 2—安装必要的软件包

安装这两个包就这么简单!

mkgendocs==0.9.0
mkdocs==1.2.3

步骤 3——下载启动代码并将其添加到您的项目根目录中

点击下载启动代码。这提供了三个有助于自动化的文件!

mkgendocs.yaml 该文件是 python 文件(例如 main.py)到其关联的文档文件输出(例如 docs/modules/main.md)。它还包含了我们希望包含在文档中的所有类和文件的列表。我们将自动创建这个映射,以及降价文件本身。

这个文件获取我们的文档文件(例如 docs/modules/main.md),并将它们组织到站点文件夹中,以便创建站点地图。这也将由我们的脚本自动完成。

automate _ mkdocs . py——这个脚本受 Louis de Brujin 的工作的启发,但我自己针对更多情况进行了进一步的扩展和优化,填充了 mkgendocs.yaml 和 mkdocs.yaml 文件。将包括所有存在且不包含语法错误的文件。目录结构的样式将反映您的软件包文件夹的设置方式。

花点时间填写 mkgendocs.yaml 和 mkdocs.yaml 的顶部,让它们成为您的项目所独有的!

第 4 步—立即创建文档!

运行以下命令:

python automate_mkdocs.py 

这将自动填充 mkdocs.yaml 和 mkgendocs.yaml 文件。

gendocs --config mkgendocs.yml

这个命令获取我们的 mkgendocs 文件,并生成我们的 markdown 文件!注意:您可能需要在根目录下创建 docs 文件夹。

我们现在可以使用以下工具测试和查看我们的文档:

mkdocs serve

当您对它在本地的外观感到满意时,我们可以用

mkdocs gh-deploy

就是这么简单!刚刚创建了一个新的分支来保存您的文档和自动生成的站点地图!如果您喜欢在每次更改文档时都运行这些命令,那么到此结束就好了,但是,我们还可以做一个进一步的优化,那就是设置 Github 操作,以便在每次我们推送到我们的主(或任何)分支时更新和部署我们的文档!

步骤 5——使用 GitHub 动作自动部署文档

如果你以前从未使用过 GitHub actions,我推荐你先熟悉一下这里的!并创建基本 yaml 文件。从那里,我们将添加命令到:

  1. 设置我们的 python 版本并检查我们的代码
  2. 安装需求并更新 mkdocs 和 mkgendocs
  3. 建立或更新我们的降价文件
  4. 部署我们的网站
  5. 提交可能已经发生的任何更改
  6. 将这些更改推送到关联的分支

这可能看起来很多,但一旦做到了,它会让生活变得容易得多!

注意:你的 GitHub actions 文件很可能是相似的,但是会根据你使用的 python 版本,选择的主题,以及你是否有额外的需求比如自定义站点或者 GitHub 推送限制而有所不同!

设置我们的 Python 版本并检查我们的代码。这相当简单!

- name: Checkout
        uses: actions/checkout@v1- name: Set up Python python-version
        uses: actions/setup-python@v1
        with:
          python-version: 3.7

安装需求并更新 mkdocs 和 mkgendocs——requirements . txt 文件应该包含项目的所有文件,包括在步骤 2 中安装的文件。

- name: Autogenerate new documentation
        continue-on-error: true
        run: |
          pip install -r requirements.txt
          python automate_mkdocs.py
          git add .

构建或更新降价文件——我为安装添加了一些额外的 pip 文件,尽管这些文件可能会被排除!我个人对 jinja2 包有问题。

- name: Update and Build GH Pages
        run: |
          python -m pip install --upgrade pip
          pip install mkdocs==1.2.3
          pip install mkgendocs==0.9.0
          pip install jinja2==2.11
          gendocs --config mkgendocs.yml

部署我们的站点——它使用了一个非常酷的自定义 GitHub 动作,并且有大量可选参数,包括设置自定义域!

- name: deploy docs
        uses: mhausenblas/mkdocs-deploy-gh-pages@master
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          #CUSTOM_DOMAIN: optionaldomain.com
          CONFIG_FILE: mkdocs.yml
          EXTRA_PACKAGES: build-base
          # GITHUB_DOMAIN: github.myenterprise.com
          # REQUIREMENTS: docs/docs_requirements.txt, separate requirements file to install any themes you may want on your site 

提交任何更改—我们使用“出错时继续”,因此如果没有更改,它不会失败!

- name: Commit any changes to docs
        continue-on-error: true
        run: |
          git config --local user.name "github-actions[bot]"
          git add ./docs
          git commit -m "Auto-updating the docs"

推送我们的更改—注意:您可以选择将这些更改推送至哪个分支

- name: Push the changes to master
        continue-on-error: true
        uses: ad-m/github-push-action@master
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}
          branch: master
          force: true

仅此而已!一旦您解决了任何部署难题,您现在就有了一个完全自动化的文档工作流!如果这真的对你有帮助,这里有一个链接指向 mkgendocs 捐赠页面的创建者。我给他寄了一笔小小的捐款,以表达我对制作这个包裹的感激之情!

我希望这篇文章对您的文档之旅有所帮助!这篇文章是我最喜欢写的文章之一。如果您认为需要回来参考,请务必保存/标记该故事!如果你喜欢这篇文章,请随意关注我,阅读我写的更多内容,或者将我作为推荐人,这样我就可以继续制作我喜欢的内容。

轻松采用时间序列的 Theta 模型

原文:https://towardsdatascience.com/easily-employ-a-theta-model-for-time-series-b94465099a00

M4 竞赛中的最佳基准模型使用 Python 轻松训练、调整和测试

作者图片

与 ARIMA 等经典技术相比,Theta 不太为人所知,它是一种时间序列模型,可以产生准确的结果,并且易于理解和应用。如果你是时间序列从业者和预测者,这是一个很好的工具。

它的工作原理是从潜在的时间序列中提取两条“θ线”。第一条线是时间序列的线性趋势,可以通过对使用时间趋势作为输入的数据运行简单的线性回归来提取。这条θ线可以非常简单地通过无限期地继续其线性趋势而推断出未来。

第二条θ线可以看作是级数的曲率。它是系列的第二个差值乘以一个因子,默认情况下为 2。小于 1 的值抑制曲率并强调长期趋势,大于 1 的值强调曲率并强调短期趋势。通过使用指数平滑向前外推第二条θ线。

这两条θ线然后在加法或乘法过程中结合。为了说明季节性,在提取 theta 线之前,该模型还使用乘法或加法季节性分解方法对数据进行去季节性处理。在θ线合并后,这种季节性会重新应用到预测数据中。

提出这种方法的论文还提到,进一步的研究可能包括提取两条以上的θ线,但据我所知,没有这样的模型发现任何有前途的东西,但思考起来很有趣(Assimakopoulos & Nikolopoulos,2000)。

很简单吧?让我们看看如何使用 Python 来实现它。

Python 应用程序

飞镖游戏

Darts 是一个用户友好的时间序列包,它使用了一个名为 FourTheta 的 Theta 模型的实现,这是上面解释的思想的衍生物,可以对第一条 theta 线应用指数变换(而不是使用简单的线性趋势)。这款衍生车型是 2020 年 M4 竞赛中表现最佳的基准车型。

要安装省道:

pip install darts

这里有一个链接到 darts 中的模型文档。

规模预测

Scalecast 将 darts 的 theta 模型移植到一个通用的时间序列框架中,该框架易于实施,并可与其他几种经典的时间序列方法、scikit-learn 的机器学习模型以及其他技术进行比较。我将演示 theta 模型的 scalecast 实现,因为我是 scalecast 的作者,并且希望展示这个框架如何能够非常容易地为任何用户实现。也就是说,如果你想直接使用 darts 的模型,它也提供了一个用户友好和舒适的框架。

要安装 scalecast:

pip install scalecast

你可以在这里找到本文中使用的完整笔记本。数据来自 M4 竞赛的开放访问,可在 GitHub 上获得。我们将使用 H7 每小时时间序列。

代码实现

在代码中应用这个模型非常简单。我们首先将数据加载到预测器对象:

train **=** pd**.**read_csv('Hourly-train.csv',index_col**=**0)
y **=** train**.**loc['H7']**.**to_list()
current_dates **=** pd**.**date_range(
    start**=**'2015-01-07 12:00',
    freq**=**'H',
    periods**=**len(y)
)**.**to_list()
f **=** Forecaster(y**=**y,current_dates**=**current_dates)

我们可以绘制这个系列,以便更好地了解我们在做什么:

f**.**plot()
plt**.**show()

作者图片

让我们留出 25%的数据进行测试,并预测未来的 48 个时间段:

f**.**set_test_length(.25)
f**.**generate_future_dates(48)

现在,我们可以指定一个超参数网格来找到调优该模型的最佳方式。这个网格在大多数情况下都能找到一个很好的模型,但是你也可以考虑给它增加更多的θ值。

fromdarts.utils.utils import (
    SeasonalityMode, 
    TrendMode, 
    ModelMode
)theta_grid **=** {
    'theta':[0.5,1,1.5,2,2.5,3],
    'model_mode':[
        ModelMode**.**ADDITIVE,
        ModelMode**.**MULTIPLICATIVE
    ],
    'season_mode':[
        SeasonalityMode**.**MULTIPLICATIVE,
        SeasonalityMode**.**ADDITIVE
    ],
    'trend_mode':[
        TrendMode**.**EXPONENTIAL,
        TrendMode**.**LINEAR
    ],
}

现在,让我们使用三重时间序列交叉验证来寻找最佳的超参数组合。这将基于我们的训练集创建 3 个数据段,其中每个验证集的长度为 131 个观察值,并且具有所有上述超参数组合的模型根据每个验证集之前的数据进行训练。基于哪个模型返回所有褶皱的最佳平均 MAPE 值来选择最终模型。

f**.**set_validation_metric('mape')
f**.**set_estimator('theta')
f**.**ingest_grid(theta_grid)
f**.**cross_validate(k**=**3)

从交叉验证中选择的最佳参数是:

>>> f**.**best_params
{'theta': 1,
 'model_mode': <ModelMode.ADDITIVE: 'additive'>,
 'season_mode': <SeasonalityMode.MULTIPLICATIVE: 'multiplicative'>,
 'trend_mode': <TrendMode.EXPONENTIAL: 'exponential'>}

然后,我们使用选择的模型预测我们的测试集和 48 期预测范围:

f**.**auto_forecast()

我们现在可以看到可视化的测试结果:

f**.**plot_test_set(ci**=**True)
plt**.**show()

作者图片

以及预测结果:

f**.**plot(ci**=**True)
plt**.**show()

作者图片

这返回了 5.5%的测试集 MAPE 结果。交叉验证过程中的平均验证 MAPE 为 7.5%。验证 MAPE 稍微差一点是有道理的,因为它在每次验证迭代中要学习的训练集更少。

假设一段时间过去了,我们现在有一些新的数据要引入到这个模型中,我们可以衡量它在 48 期预测中的表现。让我们看看效果如何。

test = pd.read_csv('Hourly-test.csv',index_col=0)
y_test = test.loc['H7'].to_list()
future_dates = pd.date_range(
    start=max(current_dates) + pd.Timedelta(hours=1),
    freq='H',
    periods=len(y_test),
).to_list()fcst = f.export('lvl_fcsts')
mape = np.mean(
   [np.abs((f - a) / a) for f, a in zip(fcst['theta'],y_test)]
)

这返回了 6%的值,正好在我们的测试集和验证度量之间,这正是我们所期望的!

结论

theta 模型是时间序列分析师的强大工具,概念简单,易于调整,易于评估。希望你觉得这个教程有用!如果是的话,请考虑以后使用 scalecast,为其成长做点贡献!

https://github.com/mikekeith52/scalecast

参考

动词 (verb 的缩写)Assimakopoulos,K. Nikolopoulos,theta 模型:预测的分解方法,国际预测杂志,第 16 卷,2000 年第 4 期,第 521-530 页,ISSN 0169-2070,https://doi . org/10.1016/s 0169-2070(00)00066-2。
(https://www . science direct . com/science/article/pii/s 0169207000000662)

使用 SentenceTransformers 轻松获得高质量的嵌入!

原文:https://towardsdatascience.com/easily-get-high-quality-embeddings-with-sentencetransformers-c61c0169864b

介绍向量表示的概念,并比较 TF-IDF 向量和 SentenceTransformers 向量!

图片作者。

背景

在我加入 HK01 之前,它的数据团队已经利用大量的文本数据建立了几个数据项目。虽然能够将 NLP(自然语言处理)技术应用于真实世界的数据以对业务产生影响是件好事,但我注意到这些数据项目都在使用 TF-IDF 来学习 HK01 上发布的内容的嵌入(向量表示)。这些嵌入是这些数据项目的核心,因为它们在机器学习模型中用于进行预测。这种方法有几个问题:

  1. 性能欠佳 虽然 TF-IDF 做得很好,但它是一种相对较老的计算文本嵌入的方法。最近有很多关于 NLP 的研究,现在变形金刚模型(例如伯特、罗伯塔、 GPT-3 )是 NLP 任务的最新模型。
  2. 难以维护
    升级或调试效率低下,我们需要对这些项目中的每一个都进行更改。
  3. 高成本
    由于这些数据项目中的每一个都是独立计算嵌入,因此其成本远远高于由一个集中式服务来计算全部嵌入。

我们为什么要关心这些嵌入呢?

嵌入只是一些东西的表示,可以是文本、图像,甚至是语音,通常是矢量形式。计算文本嵌入的最简单方法是使用单词袋(BOW)表示法。

假设你有很多关于你在网上销售的产品的用户评论。要获得 BOW 表示或用户评论,您需要做的就是将这些评论分解成单词。然后创建一个表格(或者更像一个矩阵),它的列是注释中的单词。索引将是用户评论的 id。该值是该单词是否出现在用户评论中。看起来是这样的:

现在每一行都是一个注释的向量表示,所以注释 ID 1 的嵌入向量是[1, 0, 1, 1, 0, ...]。由于第一行在单词“好”、“爱”和“令人惊叹”中的值为 1,我们已经可以看出这个评论在情感方面是积极的。所以嵌入向量告诉我们注释的上下文含义。

一旦我们有了所有用户评论的嵌入,我们就可以做许多不同的事情。例如:

  1. 我们可以训练一个分类器来预测每个评论的情绪。
  2. 我们可以通过计算余弦相似度或欧氏距离来找到上下文相似的评论。
  3. 我们可以将评论分组,然后找到这些组中出现的最常见的单词。例如,我们可能会在聚类中找到像'fast', 'delivery''overpriced'这样的词。这有助于我们了解需要改进什么。

想象一下,如果我们对 HK01 上发表的文章这样做,我们就可以做一些事情,比如主题建模(类似于第 3 点),推荐用户读过的类似文章(类似于第 2 点),等等!

旁注

在实践中,我们会将停用词(例如' the ',' a ',' and ')和词干词放入它们的基本形式(例如' flying '到' fly ',' cars '到' car ',' am '到' be ')。这里不解释涉及的许多数据预处理技术。

为什么弓不够好?

在这一点上,你可能会意识到我们的向量的维数很高,这是因为用户评论中可能出现的单词数量非常大。所以每个向量在维度上可以是1x10000甚至是1x100000。当我们使用这些向量时,这会降低计算速度!

此外,BOW(单词袋)表示法可能不是一个很好的表示法。如果我们有两个注释,例如Exactly what I wanted! 5 stars!Absolutely amazed by the product! great price!。虽然我们可以知道它们都是正面的评论,但是这两个评论的 BOW 表示没有相似之处,因为没有重叠的单词。这就是为什么我们需要更好的东西!

句子变压器

SentenceTransformers 是一个 Python 框架,用于最先进的句子、文本和图像嵌入。它的 API 使用起来非常简单:

就这么简单,这就是我们需要编码来获得任何文本的嵌入的全部内容!

[-5.09571552e-01  6.48085847e-02  7.05999061e-02 -1.10023748e-02
 -2.93584824e-01 -6.55062944e-02  7.86340162e-02  1.02539763e-01
 -3.80028449e-02  1.71354219e-01  1.69140086e-01 -9.65721607e-02
  2.04715624e-01  3.12998295e-01 -1.77713439e-01  1.53584480e-02
  9.74370390e-02  2.11779386e-01  1.24351427e-01 -1.38820678e-01
  4.35955316e-01 -1.17388457e-01 -3.58339213e-02 -1.36476666e-01
... # hidden by me as it's too long :)(1, 384)

与使用 BOW 得到的 1 和 0 不同,我们得到了浮点值和固定尺寸(本例中为 1 x 384)。这是因为嵌入是从变压器模型中的隐藏层提取的,维度与该隐藏层的神经元数量相同。因为嵌入是由 transformer 模型学习的,所以前一节中的两个示例注释现在是相似的。在这篇博文中,我不打算详细讨论这个问题。现在,只需要知道转换器是一个神经网络,它的本质是可以将高维数据压缩到低维。

它在幕后做什么?

为 SentenceTransformers 做出贡献的人们在 HuggingFace 模型中心上托管许多不同的预训练的变形金刚模型。托管预训练模型已经在大量数据(100 多万甚至 1B+训练对)上进行训练,因此被称为“预训练”模型。模型看到的数据样本量如此之大,以至于我们可以简单地使用它开箱即用来获得高质量的嵌入。当 API 被调用时,它从 HuggingFace Model Hub 下载所选择的预训练模型(或者如果给定了本地路径,则下载 load)。然后,它对你的输入句子进行标记,并将它们放入模型中计算它们的嵌入。

API 极大地简化了这个过程,以至于我们不再需要为标记化编写代码,改变 PyTorch 模型类中定义的predict()等等。如果你使用了 HuggingFace 甚至纯 PyTorch 来做这件事,你就会知道这种痛苦了。现在,它变成了一行代码!

embeddings = model.encode(sentences) # very simple, isn't it?

我的文字超级长怎么办?

考虑 SentenceTransformers 上可用的每个预训练模型的最大长度很重要。例如,paraphrase-multilingual-mpnet-base-v2型号的最大序列长度为 128。这意味着对于任何超过 128 个标记的输入句子,都将被修剪,即只有前 128 个标记将被放入模型。想象一下,如果我们在 HK01 上发表了一篇包含数千个汉字的文章。如果我们把它放到 API 中,我们将只能得到代表前几个句子的嵌入!

克服这一点的一个简单技巧是将文章分成一系列句子,然后取句子嵌入的平均值作为文章嵌入。像这样:

虽然这听起来可能太简单,但我们发现它工作得很好。让我们在下一节看看它的表现。

旁注

正如你所看到的,理解它是如何工作的非常重要。这正是为什么即使训练机器学习模型的 API 已经简化了这么多,公司仍然需要数据科学家和机器学习工程师的原因:)!

与 TF-IDF 相比,它的性能如何?

为了了解它如何优于 TF-IDF 矢量表示,我们:

  1. 随机抽样 10,000 篇发表在 HK01 上的文章。
  2. 使用句子变形器(paraphrase-multilingual-MiniLM-L12-v2和平均句子嵌入)和 TF-IDF 计算它们的嵌入。对于 TF-IDF,我使用sklearn.feature_extraction.text.TfidfVectorizerTfidfVectorizer(analyzer='word', min_df=0.001, ngram_range=(1, 3)来更好地捕捉汉字。
  3. 通过运行 t-SNE 将嵌入维数减少到 2, t-SNE 是一种降维算法,以防你不知道。
  4. 将文章类别映射到数据,并将结果可视化。

以下是可视化效果,您可以通过单击图例与图表进行交互以放大和过滤数据:

请注意,由于有太多不同的类别,一些不同的类别使用相同的颜色。

我们可以看到,在顶部(红色的)和底部(紫色的)周围只有一些小簇。这个中心根本没有清晰的星团。想象一下,如果我们完全没有类别,我们很难对同一主题的文章进行分组。现在让我们来看看句子变形器生成的嵌入:

请注意,由于有太多不同的类别,一些不同的类别使用相同的颜色。

At first glance, you can already see data points with the same category are sticking closer together. Not only that, categories that are somewhat related (e.g. movie (電影), games & anime (遊戲動漫) and entertainment (即時娛樂)) are also closer together at the bottom right.

想象一下,如果我们有一篇关于喜剧电影的文章,那么我们可以使用上述嵌入来找到最近的 N 个数据点,并将它们列在 HK01 上作为相关文章,最近的 N 个数据点也将与“电影”、“喜剧”或至少“娱乐”相关。

摘要

现在,我们已经看到 SentenceTransformers 非常容易使用,并且它生成高质量的嵌入。

为了克服 HK01 的问题,我们正在创建一个新项目,目的是使用 SentenceTransformers 计算 HK01 上发布的任何内容的嵌入。目前,我们正在将每一个数据源集成到这个新项目中,以建立一个 cronjob 来计算新内容或编辑内容的嵌入。我们期待看到我们的推荐系统和下游数据项目的改进!

如果你喜欢这篇博文,请点击下面按钮并鼓掌!👏🏻也在 Github 上关注我吧!

https://github.com/thomas-tf

参考

  • 变形金刚—https://www.sbert.net/index.html#
  • TF-IDF—https://en.wikipedia.org/wiki/Tf%E2%80%93idf
  • 鞠躬—https://en.wikipedia.org/wiki/Bag-of-words_model

在 pandas 和 parallel-pandas 中轻松并行计算

原文:https://towardsdatascience.com/easily-parallelize-your-calculations-in-pandas-with-parallel-pandas-dc194b82d82f

由菲利普·奥罗尼在 Unsplash 上拍摄的照片

介绍

Pandas 是最受欢迎的数据科学图书馆之一。来自官方文档:

pandas 是一个快速、强大、灵活且易于使用的开源数据分析和操作工具,构建于 Python 编程语言之上

而每一个熟悉熊猫的人都会很有信心地证实这些话。与此同时,他们管道中的许多人面临着这样一个事实,即 pandas 没有充分利用 CPU 的能力。换句话说,pandas 方法不支持并发。

考虑一个简单的例子:

synchronous describe time took: 37.6 s.

(图片由作者提供)

从上图中可以看出,100%时只使用了一个内核。其余的无所事事。但是如果你使用所有的处理器内核呢?你能多快得到同样的结果,最重要的是——如何实现?

所以我们先想想 describe()是怎么工作的?它处理这些列,并为每个列计算一些统计数据。我们有一个包含 1000 列的数据框架。沿着第一个轴(沿着列)将我们的数据帧分成几个更小的部分,分别计算每个部分的 describe,然后将结果组合回一个公共数据帧,怎么样?让我们看看如何沿着指定的轴将数据帧分割成多个部分。这可以通过**numpy**模块的array_split功能轻松完成。让我们看一个简单的例子:

[   cat  dog
 0    0    0
 1    1    1
 2    2    2,
    cat  dog
 3    3    3
 4    4    4
 5    5    5,
    cat  dog
 6    6    6
 7    7    7,
    cat  dog
 8    8    8
 9    9    9]

并按列拆分

[   cat
 0    0
 1    1
 2    2
 3    3
 4    4
 5    5
 6    6
 7    7
 8    8
 9    9,
    dog
 0    0
 1    1
 2    2
 3    3
 4    4
 5    5
 6    6
 7    7
 8    8
 9    9]

因此,我们有了一个算法,可以将一个大的数据帧沿着我们需要的轴分割成更小的部分。下一步是什么?如何让我们 CPU 的所有核心都工作起来?众所周知,pandas under the hood 使用[**numpy**](https://numpy.org/doc/stable/user/whatisnumpy.html)数组和方法来处理它们,这通常会移除全局解释器锁(GIL)。因此,我们可以使用线程池来并行计算。让我们转向[**concurrent.futures**](https://docs.python.org/3/library/concurrent.futures.html#module-concurrent.futures)模块的ThreadPoolExecutor类的map方法:

map ( funciterablestimeout=Nonechunksize=1 )
类似于[map(func, *iterables)](https://docs.python.org/3/library/functions.html#map)除了:
1。立即收集
可重复项*而不是延迟收集;
2。 func 异步执行,可以并发调用几次 func

在我们的例子中,describe()方法是函数,iterable 对象是数据帧列表。下面给出了实现管道的完整代码。

parallel desribe time took: 15.0 s.

(图片由作者提供)

所以我们将pandas.DataFrame.describe()方法的速度提高了两倍!类似地,您可以并行化其他的pandas方法。

平行熊猫简介

[**parallel-pandas**](https://pypi.org/project/parallel-pandas/)库在本地实现了上述pandas方法的并行化。首先,使用pip软件包管理器安装parallel-pandas:

pip install --upgrade parallel-pandas

只要两行就够入门了!

synchronous time took: 3.7 s.
parallel time took: 0.688 s. 

如你所见,p_quantile方法比快 5 倍

一旦parallel-pandas被初始化,你继续照常使用熊猫。pandas方法的并行模拟以来自单词 parallelp_为前缀。此外,parallel-pandas允许您查看并行计算的进度。为此,在初始化期间指定disable_pr_bar=False就足够了。

带有进度条并行描述方法

如您所见,parallel-pandas负责将原始数据帧分割成块,并行化并为您聚合最终结果。

更复杂的计算可以以类似的方式并行化。例如,让我们对数据帧的列进行 z 规范化。同样,为了比较,我们用daskdata frame 实现 z 归一化:

synchronous z-score normalization time took: 21.7 s.
parallel z-score normalization time took: 11.7 s.
dask parallel z-score normalization time took: 12.5 s.

注意内存消耗。parallel-pandasdask使用的 RAM 几乎是pandas的一半

RAM 使用

对于某些方法,parallel-pandas 比 dask DataFrame 更快:

dask nunique time took:42.5 s.
dask rolling window mean time took: 19.8 s.
paralle-pandas nunique time took:12.5 s.
parallel-pandas rolling window mean time took: 11.8 s.

parallel-pandas实现了许多熊猫方法。完整列表可在文档中找到。

总结一下:

  • 在本文中,我们简要回顾了并行化pandas方法的思想,并以describe方法为例实现了它
  • 我们还熟悉了parallel-pandas库,它使得基本pandas方法的并行化变得容易。
  • 我们还使用几个例子将parallel-pandas的工作与另一个著名的分布式计算库dask进行了比较。

希望这篇文章对你有帮助,祝你好运!

用内乌顿自动语言实现简单的机器学习

原文:https://towardsdatascience.com/easy-machine-learning-with-neuton-automl-881437a09061

内乌顿汽车公司房价数据的探索性数据分析。作者创造的形象。

在过去十年中,机器学习(ML)领域在应用科学、社会科学、商业和经济学的不同领域中的应用蓬勃发展。ML 是困难的,找到最佳算法需要用户大量的经验、精力和直觉。

由于多种因素导致 ML 的复杂性增加,在过去几年中,出现了自动 ML 的激增。自动 ML 的目标是尽可能简化用户与底层 ML 算法的交互。仅举一个例子,Tableau、Power BI 等几个 BI 应用。在许多情况下,通过最大限度地减少用户输入,只需很少的点击即可执行 ML 算法。

即使 Tableau 或者 PowerBI 可以进行回归、分类等 ML 算法。它们不是执行复杂 ML 算法的最佳选择。现在很多 ML 算法通常都是用 Mathematica,Python,Matlab,Octave 等来做的。当一个人必须执行复杂的 ML 算法时,这些软件通常是最好的选择。

然而,随着技术和人工智能的进步,商业领域的许多公司可能没有预算(或想省钱)来负担员工执行 BI ML 算法。在这方面,这种类型的公司可能会寻求能够通过最大限度地减少用户与底层 ML 算法的交互来几乎不用代码执行 ML 的软件。这个软件之一是内乌顿-AutoML 。在这篇文章中,我讨论了内乌顿-AutoML 的最重要的方面,以及为什么它在许多方面对那些不太了解 ML 但却不得不在业务中使用的大公司非常有用。

什么是内乌顿汽车公司,它做什么?

内乌顿是一个使用 ML 的神经网络框架,无需从用户端编写代码。它不是基于一个预先存在的框架,而是利用 TinyML 来解决用户可能遇到的不同的 ML 问题。

许多最大似然算法的一个关键问题是,由于它们的复杂性和在训练过程中使用的大量数据,这些算法在计算机云上运行并消耗大量能量。由于这个原因,在过去的几年里, TinyML 领域有了显著的发展。ML 的这一新领域的目标是在微控制器上使用 ML 算法,以尽可能减少执行算法时使用的能量。

内乌顿是一个获得专利的神经网络框架,不是基于预先存在的算法。它有四个主要特征,使得修剪、量化和提取变得不必要,也不需要最终的模型压缩。这四个主要特征是:

  1. 专利优化算法 *。*内乌顿算法使平台的计算不基于误差的反向传播和随机梯度下降。这使得遇到局部最小值的可能性最小化。
  2. 无需用户手动搜索神经网络参数。 该功能使用户无需随机搜索参数,如层数、批量、学习率。
  3. 逐神经元结构生长。 该功能可以从一般特征到最具体的特征进行学习,并选择解决问题所需的几乎任何模型精度和尺寸。
  4. 有选择地接近选中的特征。 内乌顿的这一特性有助于在创建模型时只建立必要的神经元连接,不允许结构随机增长。

内乌顿的实际方面

要使用内乌顿,你只需在内乌顿的官方网站注册。我将不描述这个过程的必要步骤。我在这篇文章中的重点是内乌顿的实践和技术方面。

与任何 ML 过程一样,第一步是获取数据集并清理它。在这方面,内乌顿对数据集的类型及其要素数量有一些限制。训练数据必须满足的一些数据集特征如下:

  1. 数据集必须是使用 UTF 8 或 ISO-8859–1 编码的 CSV 文件。
  2. 数据集必须至少有 2 列或 2 行。
  3. 数据集不能有任何空列。
  4. 注意重复行:在预处理阶段,将从训练集中删除重复行,这可能导致与数据集最小大小和样本数要求不一致。
  5. 数据集中的第一行必须包含列名,并且必须使用逗号、分号、竖线、插入符号或制表符作为分隔符。CRLF 或 LF 应该用作行字符的结尾。数据集中的分隔符和行尾字符应该一致。
  6. 所有列名必须是唯一的,并且只能包含字母(a-z、A-Z)、数字(0–9)、连字符(-)或下划线(_)。
  7. 所有空值都必须从目标变量中排除。
  8. 对于回归任务类型,目标变量必须只有数值。
  9. 对于分类任务类型,必须为每类目标变量提供至少十个样本。

其他细节可以在内乌顿的用户指南文件中找到。一个关键的方面是数据集文件必须是 CVS 格式。类似的信息可以在测试数据集中找到。

一旦选择了数据集,接下来的内乌顿最大似然算法步骤如下:

  1. 选择数据进行训练
  2. 训练选中的模型
  3. 做出预测

为了帮助您更清楚地了解内乌顿汽车公司是如何工作的,我将展示几幅房屋数据集训练测试程序的图像。注册内乌顿网站后,点击“添加新解决方案”按钮,将出现以下窗口:

图一。“新建解决方案”对话框。作者创造的形象

点击“下一步”后,您将看到一个新的对话窗口。通过单击预加载数据集选项卡,您将看到以下窗口:

图二。训练数据集选项。在本文中,我使用预先加载的房价数据集。

在图 2 中,我勾选了房价(回归)选项,然后单击 OK 继续。之后,出现以下对话框:

图 3。作者创造的形象。

点击“确定”按钮,将出现以下对话框:

图 4。选项来选择目标变量。作者创造的形象。

在图 4 中,可以选择将哪个特征用作目标变量 y 。在这个例子中,我选择 SalePrice 变量作为目标变量。单击“下一步”按钮,您将看到以下窗口:

图 5。开始训练程序

在图 5 中,对话窗口给予用户选择任务类型的可能性,例如回归、分类等。,以及度量的类型。在这种情况下,软件默认选择 RMSLE。这是因为在这个训练程序中,我使用了基本模式,这是新用户的默认计划,并且是免费的。详情可在内乌顿用户指南中找到。

培训结果

一旦在基础模式下开始训练,内乌顿默认获取训练数据集(由内乌顿或用户预加载)并将数据拆分成训练数据集验证数据集。如果用户选择高级模式计划,则可以选择加载验证数据集,而无需对原始数据集进行训练测试分割。

在培训过程结束时,内乌顿将为基本模式用户显示以下窗口

图 6。培训过程结束。作者创造的形象。

从图 6 中可以看出,在训练过程结束时,内乌顿向用户提供了所获得结果的详细信息。例如,训练模型大约需要 8 分 7 秒。如果点击图 6 中的“日志”按钮选项,将显示以下信息

图 7。内乌顿在培训过程中采取的步骤。作者创造的形象。

从图 7 中可以看出,内乌顿基本上是从创建一个虚拟机开始的,然后是预处理数据,然后是特征工程,等等。如果用户单击“Metrics”按钮,则会显示以下信息

图 8。培训过程的模型质量和度量指标。作者创造的形象。

在图 8 中,有训练测试分割过程的度量指标的总结。结果是通过将学习的函数应用于验证测试而获得的。可以看出,MSE 误差相当大,正如人们对房价数据集的预期。内乌顿默认选择非常小的 RMSLE 误差,RMSLE = 0.139326。

要查看模型是否运行良好,还可以使用决定系数 R =0.88,这是一个非常好的输出结果。所有这些指标给出不同的结果,这完全取决于用户使用哪一个以及如何解释它。

在图 8 所示的训练测试结果之后,可以使用训练模型来对训练测试过程中未使用的看不见的数据进行预测,如下图 9 所示

图 9。模型预测选项选项卡。作者创造的形象。

结论

在这篇文章中,我讨论了最重要的特点,内乌顿汽车用于 ML。作为一个例子,我使用了 房价 数据集来说明内乌顿如何在给定的数据集上执行 ML。

你或你的公司应该使用内乌顿汽车吗?这个问题的答案取决于几个因素,但从技术和实用的角度来看,我强烈推荐。正如我在本文开始时已经提到的,内乌顿 AutoML 的主要目标之一是尽可能地减少编写代码的用户算法。在这方面,内乌顿做得非常出色,因为几乎所有的 ML 流程都是自动化的,如上图所示。

有了内乌顿,人们根本不需要执行 EDA。唯一的要求是那些必须在 CSV 等格式的训练数据集。正如我上面讨论的。尽管执行 ML 解决方案不需要任何代码,但决定使用内乌顿的个人或公司需要了解一些基本的 ML。事实上,他们需要知道什么是特征变量,什么是输出。他们还需要知道如何解释图 8 所示的输出结果,以评估模型的准确性。

内乌顿在当前阶段需要改进的一点是,让用户不仅可以使用 CSV 格式的数据集,还可以使用其他格式的数据集。此外,我认为支持库不应该依赖 维基百科 链接来指引用户到特定的定义。事实上,维基百科是一个公共百科全书,不时会有关于 ML 度量等的定义。,可能会发生变化,可能与其他 ML 学习材料不一致。

如果你喜欢我的文章,请与你可能对这个话题感兴趣的朋友分享,并在你的研究中引用/参考我的文章。不要忘记订阅将来会发布的其他相关主题。

简单拼花教程和最佳实践

原文:https://towardsdatascience.com/easy-parquet-tutorial-best-practices-237955e46cb7

开始学习拼花地板的实践教程

杰瑞登·维勒加斯在 Unsplash 上的照片

Parquet file 是一个文件存储系统,它改变了任何与几个数据用户之间的日常数据操作有关的人的生活,例如数据工程师数据科学家分析工程师以及其他技术角色。

拼花的原理在于其面向列的存储,以及数据沿着比沿着行更加同质的事实,提供了数据的优化压缩,从而导致更小的存储大小增加的处理速度

在本教程中,我们将概述一些最佳实践,让你开始学习镶木地板。

加载数据

首先,我们将使用一个公开的信用卡应用数据集。数据集可在 Kaggle 上获得:信用卡审批预测| Kaggle 。

获取这些数据最简单的方法是在您的环境中安装Kaggle API,提取数据并将归档文件解压到您的工作文件夹中:

pip install kaggle
kaggle datasets download -d rikdifos/credit-card-approval-prediction
unzip credit-card-approval-prediction.zip

让我们加载教程所需的包。6.0.0 以上的 pyarrow 任何版本都可以。

import pandas as pd
import numpy as np
import pyarrow as pa

在 zip 存档中,您将拥有 credit_record.csv (关于客户每月信用状况的数据集)和 application_record.csv (关于客户的信息)。为了简单起见,我们只对 zip 存档中的应用程序记录. csv 文件感兴趣。

为了让事情变得有趣,我们将复制数据 10 次并重置 id,使数据帧大约有400 万行和 18 列。

applications = pd.read_csv('application_record.csv')
applications = pd.concat(10*[applications]).reset_index().drop(columns=['ID','index']).reset_index().rename(columns={'index':'ID'})

以下是数据帧前 5 行的概述(面向列):

applications.head(5).T

我们注意到名为 FLAG_X 的变量不共享相同的输出类型,将它们规范化为布尔值应该是一个合理的选择。

首先,让我们构建一些简单的功能,即家庭收入和申请人年龄的月度版本:

applications['MONTH_INCOME_TOTAL'] = applications['AMT_INCOME_TOTAL']/12
applications['AGE'] = - np.floor(applications['DAYS_BIRTH']/365)

现在,我们希望与其他数据用户共享这些数据。为此,我们将以 CSV 和 parquet 格式将数据保存到其他用户可以访问的一些路径中。但在此之前,我们先来看看模式的概念。

模式

对于 parquet 文件,一个非常有价值的实践是定义数据集的模式。原因是,这将显著提高您正在共享的数据的一致性和健壮性,在用户之间传输数据时,列上不会出现任何类型的模糊性。

要获得 pandas DataFrame 的模式,只需使用 pyarrow 的 from_pandas 。模式。在内部,该函数将 DataFrame 列的类型与 pyarrow 能够理解的类型进行匹配,以用于 Parquet 文件。

my_schema = pa.Schema.from_pandas(applications)
my_schema

从上面的模式中,我们注意到我们最好做两个操作:

flags 变量实际上是布尔值 (1/0),这样存储它们除了避免任何类型模糊性之外,还会节省我们的存储空间。

  • 出生天数年龄重复,可以删除。

Schema 可以轻松完成这两种操作(类型转换和变量过滤)。该方法集用于用第二个参数更新第 列,该参数应该是一个 pyarrow.field 对象。

my_schema = my_schema.set(12, pa.field('FLAG_MOBIL', 'bool'))
my_schema = my_schema.set(13, pa.field('FLAG_WORK_PHONE', 'bool'))
my_schema = my_schema.set(14, pa.field('FLAG_PHONE', 'bool'))
my_schema = my_schema.set(15, pa.field('FLAG_EMAIL', 'bool'))
my_schema = my_schema.remove(10)

现在让我们比较一下保存拼花CSV 文件的执行时间:

%%time
applications.to_parquet('applications_processed.parquet', schema = my_schema)

%%time
applications.to_csv('applications_processed.csv')

CSV 格式存储不允许任何类型声明,与拼花模式不同,并且在执行时间上有显著差异,以拼花格式存储比以 CSV 格式存储快 5-6 倍。

您刚刚见证了由拼花文件提供的处理速度。

为了减少存储大小,在本例中,拼花文件的存储差几乎是 20 乘以便宜(CSV 为 636MB,拼花为 39MB)。

总的来说,处理速度和存储减少是 Parquet 文件的主要优势,但不是唯一的优势。

创建分区

另外,关于 Parquet 非常有趣的一点是,您可以通过分区来分割数据,这意味着将与分区名称上的相同值相关的信息组合在一起。

您可以将数据分区视为将图书馆中相同类型的书籍排列在一起。就像整理书籍一样,它有许多优点:

  • 数据的用户可以访问指定的一组数据,显著提高了加载速度,降低了 RAM 消耗
  • 数据的生产者可以并行化处理,允许数据大小的可伸缩性和运行时间的可伸缩性减少

下面我将向您展示如何产生 Parquet 分区数据。

从列 *NAME_INCOME_TYPE,*中,我们观察到只有 5 个不同的值涉及客户的职业活动类别。

现在假设,我们作为数据的制作者,想要保存到拼花文件,但是在这个列上分区,因为数据的用户有兴趣分别查看那些专业活动:

applications.to_parquet('APPLICATIONS_PROCESSED', schema = my_schema, partition_cols=['NAME_INCOME_TYPE'])

注意,当我们保存到具有一个或多个分区列的 Parquet 时,我们必须提供一个文件夹路径而不是一个 Parquet 文件路径,因为方法 to_parquet 将创建关于 partition_cols 所需的所有子文件夹和 Parquet 文件。

生成的 APPLICATIONS_PROCESSED 文件夹现在根据信用申请人的 NAME_INCOME_TYPE 为每个信用申请人类别包含一个文件夹。

现在,对特定专业类别进行分析或决策选择感兴趣的最终用户,如*【国家公务员】*可以以很快的速度加载数据,并且只针对这群信贷申请人。

读取分区

我们将数据创建为分区的 Parquet 文件。

但是用户如何访问它们呢?这是我们从数据的用户的角度将要看到的。

有几种方法可以读取拼花文件。

如果它是由生成器生成的,没有分区列,并且假设我们,作为一个用户,对是“*工薪阶层”*的候选人感兴趣,我们必须写:

%%time
test = pd.read_parquet('applications_processed.parquet')
test[test.NAME_INCOME_TYPE=='Working']

这个操作花了将近 5 秒,仍然比在 CSV 中读取要好,但不是最佳的,因为用户正在加载所有数据并在那之后过滤它们。这意味着我们在浪费宝贵的内存和计算时间

我们刚刚看到了分区的存在,一个熟练的数据工程师生成了由 NAME_INCOME_TYPE 分区的数据,这样我们就可以通过简单地加载感兴趣的分区来加快读取时间并减少 RAM 消耗。

有两种方法可以在相似的执行时间内完成:

  • 我们可以直接将 NAME_INCOME_TYPE 的分区路径读作“Working”
  • 或者我们可以使用 filters list 参数以同样的方式到达分区。过滤器选项会查看文件夹中的所有分区,并选择符合您条件的分区,这里是NAME _ INCOME _ TYPE**=**‘正在工作’,而不是直接进入路径。

下面列出了两种可能性:

%%time
pd.read_parquet('APPLICATIONS_PROCESSED/NAME_INCOME_TYPE=Working/')
# OR (the run-time below corresponds to either one of way of reading)
pd.read_parquet('APPLICATIONS_PROCESSED', filters=[('NAME_INCOME_TYPE', '=', 'Working')])

你看到速度增加了吗?速度快了 3 倍,而且你不必加载全部数据,节省了你机器上的大量内存。

这两种读取分区数据的方法有一个区别,但在我们的例子中几乎察觉不到:使用过滤器读取数据取决于内部分区的数量。实际上,这里我们在 NAME_INCOME_TYPE,上只有 5 个分区,所以读取数据的路径和过滤器方法之间的运行时是相同的。然而,如果我们有 1000 个分区,运行时的差异将会很大,因为 Apache Parquet 必须发现所有的分区,并返回与您的过滤器匹配的分区。

然而,我强调这样一个事实,用过滤器读取在灵活性和容量方面要强大得多,如果运行时的权衡可以接受的话,我强烈建议您尝试一下。

一个简单的例子是,如果您想专门读取两个或更多的分区(但不是所有的分区),那么您无法使用路径读取有效地做到这一点,但是使用过滤器,您可以做到。

例如,如果我们不仅对标准的*【工作】申请人感兴趣,而且对【国家公务员】*申请人也感兴趣:

filters = [('NAME_INCOME_TYPE', 'in', ['Working', 'State servant'])]
pd.read_parquet('APPLICATIONS_PROCESSED', filters=filters)

您也可以通过给出文件夹路径 : 来加载整个数据,即使它是在 NAME_INCOME_TYPE 上分区的

pd.read_parquet('APPLICATIONS_PROCESSED')

请注意,在生成的数据帧上,列 NAME_INCOME_TYPE 是存在的,而如果您正在读取 NAME_INCOME_TYPE 的分区,则它是隐藏的。

这是正常的行为:通过简单地读取分区,分区数据上的Apache**Parquet假设您已经知道这个列是针对这个特定的已过滤分区值而存在的(因为您告诉他根据 NAME_INCOME_TYPE 进行过滤),所以它不会在输出数据帧中重复该列,因为它只是一个具有唯一值的 NAME_INCOME_TYPE 的列。

总之,我们概述了使用 Parquet 的最佳实践,包括定义一个模式和划分数据。我们还强调了使用拼花文件在处理速度存储效率方面的优势(在硬盘RAM 上)。此外,我们还考虑了数据用户的观点以及使用 Parquet 文件的相关性和简单性。

用我的其他文章继续学习拼花地板:

https://pub.towardsai.net/parquet-best-practices-the-art-of-filtering-d729357e441d

无需额外费用,您可以通过我的推荐链接订阅 Medium。

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

或者你可以在收件箱里收到我所有的帖子。做到这里

可解释的助推机器:弥合 ML 和可解释性之间的鸿沟

原文:https://towardsdatascience.com/ebm-bridging-the-gap-between-ml-and-explainability-9c58953deb33

什么是可解释性,为什么它很重要?

安德烈·德·森蒂斯峰在 Unsplash 上拍摄的照片

什么是可解释性,为什么它很重要?

人工智能在过去几十年中不断发展,已经在各个领域找到了应用,包括医疗保健、军事、银行和自动驾驶汽车等关键系统。然而,很多时候,许多机器学习模型的黑盒性质阻碍了它们的采用。例如,在商业中,机器学习的应用将是预测未来销售、预测客户流失、锁定客户等。黑箱模型或许能够准确预测未来的销售或客户流失,但它无法解释不同的因素如何影响产出。这在银行业等行业尤其重要,因为这些行业受到监管机构的监管,这些机构要求其模型透明、结构公正。此外,对模型决策的理解有助于企业理解不同因素如何影响其业务,更好地为不确定的未来做准备,并做出更好的战略决策。这是通过可解释的或玻璃盒子的 ML 模型提供给他们的。

机器学习中的可解释性指的是模型或建模技术解开模型内关系的能力。根据算法提供的可解释性水平,机器学习模型可以大致分为两类:玻璃盒模型和黑盒模型。本文探讨了什么是玻璃盒模型和黑盒模型,是什么赋予了玻璃盒模型的可解释性,以及一种称为可解释助推机(EBM)的玻璃盒模型。

玻璃盒型号:

这些都是固有解释的模型。属于这一类的两个最简单的模型是线性回归和逻辑回归。以逻辑回归为例,它将概率预测为一个或多个独立变量的线性组合的函数。这个模型的等式可以写成:

作者图片

其中 p 是事件发生的概率,log(p/(1-p))是事件的对数概率。这种将对数概率表示为独立变量的线性组合的能力使得该模型具有可解释性。对于这个逻辑回归模型,可以说变量 x1 的单位变化改变了事件的对数概率β1。注意,为了便于解释,因变量不需要与自变量具有线性关系。例如,即使是以下形式的“广义加性模型”

作者图片

是可以解释的,因为你可以估计任何变量 x 的变化是如何影响目标 y 的

黑盒模型:

在这些模型中,自变量和因变量之间的关系并不明显。诸如随机森林、梯度增强树和神经网络之类的算法是一些黑盒模型。

为了进一步说明黑盒的概念,考虑一个简单回归树的例子,它具有以下数学形式:

作者图片

其中,ki 是常数,I(。)是一个指示函数,如果其参数为真,则返回 1,否则返回 0。

和 Di 是训练数据的不相交分区。下面的例子说明了这个等式:

作者图片

使用上述等式的更简洁的表示,我们得到:

作者图片

然而,玻璃盒模型虽然可以解释,但与黑盒模型相比往往不够准确。EBM 试图通过提供一个与一些黑盒模型一样准确同时又保持相当可解释性的解决方案来弥合这一差距。

可解释增压机

什么是循证医学?

EBM 是一个广义的加法模型,它使用梯度推进和浅回归树的集合[1]。因此,简单地说,循证医学是以下形式的广义函数

作者图片

其中 g(。)是一个链接函数(类似于广义线性模型)。该模型使用非常低的学习率在“循环周期”中一次训练一个特征,因此特征顺序无关紧要[1]。

因此,在迭代 1 中:

作者图片

在迭代 2 中:

作者图片

这一直持续到迭代 r。每个特征的最终函数是通过将该特征的所有函数相加而获得的,即

作者图片

诸如此类。

对于每一个特征,EBM 计算一个 f(xi)对 xi 表,用它来产生得分对 xi 图,帮助理解 xi 和易之间的关系以及每一个特征对易预测的贡献。然而,循证医学并不止于此。它还包括变量之间的二维相互作用。由于二维交互仍然可以在二维平面上呈现为热图,因此包含二维交互的模型仍然是可解释的。因此,EBM 的最终形式可以表示为:

作者图片

传统上,确定交互项在所需的计算能力方面是复杂的,尤其是对于具有大量变量的大型数据集。EBM 通过提出两阶段构建方法和使用 FAST 有效地对成对交互进行排序来解决这个问题。这种方法的两个阶段是:

1.在第一阶段,仅使用一维组件构建最佳的附加模型。

2.在阶段 2 中,固定一维函数并为残差上的成对相互作用构建模型,即,使用 FAST 选择前 K 个相互作用对,并使用残差 R 上的对来拟合模型,其中 K 是根据计算能力选择的。[2]

由于 EBM 通过将每个特征的贡献相加来计算最终输出,因此很容易可视化和理解各个特征和交互项的贡献。然而,由于预测的这种模块化,EBM 必须支付额外的训练成本,这使得它比类似的方法要慢一些。但是这并没有使它在预测过程中变慢,因为进行预测涉及到简单的加法和特征函数内部的查找。事实上,这使得 EBMs 成为预测中执行速度最快的模型之一[1]。

循证医学实例:

在下面的例子中,我使用了来自 Kaggle [3]的信用卡欺诈检测数据集。根据 ODC ODBL 许可协议,该数据集可供用户自由共享、修改和使用。

数据集描述:

该数据集包含欧洲持卡人在 2013 年 9 月的信用卡交易。数据集高度不平衡,正类(欺诈)占所有交易的 0.172%。它包含从 V1 到 V28 的特征,这些特征是在 PCA 之后获得的。不使用 PCA 进行转换的唯一特征是时间(数据集中第一次和每次交易之间经过的秒数)、数量(每次交易中使用的数量)和类别(目标变量)[3]。

循证医学模式:

由于数据已经被处理,我们将直接进入建模部分。

作者图片

一旦我们有了模型,让我们看看模型是如何表现的。循证医学提供了两种解释:全局和局部。

全局解释:

全局解释有助于我们理解特性对模型的整体贡献,以及每个特性与模型的关系。

  1. 了解特征对模型的整体贡献

作者图片

还可以通过使用 ebm.feature_importances_ 和 ebm.feature_names 来获取特征和特征重要性

特征(x) v/s 目标(y)关系:

作者图片

局部解释:

局部解释有助于我们理解在每次预测中,即在局部水平上发生了什么。

作者图片

作者图片

从 EBM 获得预测:

由于数据集非常不平衡,我们使用“精确召回曲线下的面积”这一指标来测试模型。

作者图片

让我们比较一下 EBM 和 xg-boost 的竞争情况:

作者图片

很接近吧!

参考资料:

[1]https://interpret.ml/docs/ebm.html

[2]尹娄,丰富卡鲁阿纳,约翰内斯·盖尔克,和贾尔斯·胡克。具有成对交互的精确可理解模型。第 19 届 ACM SIGKDD 知识发现和数据挖掘国际会议论文集,623–631。2013.

[3]https://www.kaggle.com/datasets/mlg-ulb/creditcardfraud

计量经济学是原始的数据科学

原文:https://towardsdatascience.com/econometrics-is-the-original-data-science-6725d3f0d843

这就是你应该多了解它的原因

米克·豪普特在 Unsplash 上的照片

我记得开始我的第一门机器学习在线课程时,我意识到我已经知道了大部分内容。

我将在这篇文章的开头说,我是一个受过训练的、杂志发表的计量经济学家——我有偏见。你知道谁也有偏见吗?约书亚·安格里斯特——一位 2021 年诺贝尔奖获得者,我在为这篇文章做研究时发现他的视频说了同样的话。

如果你正在读这篇文章,我假设你对数据科学有些兴趣——你可以从计量经济学中学到很多东西,所以请系好安全带,认真听讲。

有什么区别?

总的来说,它们是一个硬币的两面。

数据科学和计量经济学的大部分课程都是从同一个地方开始的。计量经济学线性回归与数据科学线性回归完全相同。然而,你可能会学到不同的东西。例如,在计量经济学课程中,有相当多的关于“正规方程”的提及,这是一个代数方程,允许你解析地求解最优参数。从下面可以看出:

由作者创建— θ是参数权重的向量,X 和 y 分别是你的观测值和目标的矩阵。

我一直认为这是一个非常漂亮的等式,但在数据科学中经常被忽略。我认为原因是法线方程在处理少量数据时表现良好,不需要特征缩放,而梯度下降则相反。随着大数据的兴起,在数据科学课程中坚持梯度下降是有意义的。

你会注意到一些符号是不同的,这让我觉得非常讨厌。

计量经济学和数据科学都会教你很多相同的东西,因为两者都需要对统计学有很强的理解。然而,在讨论了线性和逻辑回归之后,课程往往会在最后有所不同,数据科学将继续谈论神经网络,而计量经济学将深入研究工具变量和回归不连续设计的主题。

它们的目标和结果确实不同

不过,这两者的不同之处在于它们创建的模型的结果和用途。计量经济学家和数据科学家可以制作完全相同的模型,并撰写非常不同的讨论论文。

我注意到,大多数数据科学家似乎只对他们的模型感到满意,如果它获得了高准确率的话。我们都知道这个问题——尤其是在试图预测罕见事件的模型中。计量经济学倾向于更深入地研究模型,并试图推断因果关系。

虽然数据科学只关注预测,但计量经济学试图实现高准确性,同时也寻求找到因果关系。然而,寻找因果关系是一种约束,这往往会损害你的准确性。

计量经济学用准确性换取理解。

数据科学用数据找关系,计量经济学用数据证明关系。计量经济学从一个理论开始,然后用一个模型来检验它的假设。

因此,根据项目的不同,您可能经常希望理解多于准确。我稍后会解释原因。

数据科学遗漏了什么?

计量经济学课程让学生更好地理解基本面

在我个人看来,计量经济学的课程提供了对基本面更好的理解,尤其是在回归这样的领域。有多少数据科学家知道并理解高斯-马尔科夫定理?我相信很多人都有,但我很少在课程中看到他们被提及。高斯马尔可夫定理告诉我们,如果满足某组假设,回归系数的普通最小二乘估计会给出可能的最佳线性无偏估计(蓝色)。像 Josh Angrist 一样,我觉得花时间在课堂上证明它是浪费时间,但对我来说,它肯定回答了很多关于我们为什么在回归中做某些事情的问题。在现实中,这些假设永远不会得到完美的满足,但它们肯定有助于作为基准来改进您的模型。这就引出了我的下一点。

因果关系

计量经济学家如此关心正确地描述他们的模型,有时为了做到这一点而放弃准确性的原因是,他们主要关心的是因果关系。

让我们忽略亚里士多德和休谟,采取实际意义上的因果关系。让我们看看维基百科的定义:

因果关系(也称为因果关系,或因果关系)是一个事件,过程,状态,或对象(一个原因)促成另一个事件,过程,状态,或对象(一个效果)的产生的影响,其中原因部分地对结果负责,结果部分地依赖于原因。一般来说,一个过程有很多原因,也可以说是这个过程的原因,都在于它的过去。一个效应可以反过来成为许多其他效应的原因或因果因素,这些都在于它的未来。

实际上,因果关系是一个物体对另一个物体的影响。

然而,因果关系不能与相关性相混淆。在计量经济学中,第一课是——“相关性并不意味着因果关系”。关于计量经济学因果关系的精彩阅读,请试试这个。

强烈的相关性可能表明因果关系,但它可能存在许多其他原因。这很可能是出于偶然——为了好玩,请看下面来自网站的一个例子。

https://www.tylervigen.com/spurious-correlations——https://creativecommons.org/licenses/by/4.0/

或者它很容易来自另一个我们没有包括在分析中的秘密变量。例如,想象你看到皮肤癌和锻炼之间有很强的相关性。你会很快得出结论,锻炼不会导致皮肤癌,但锻炼越多的人往往越活跃,因此更多地外出。

所以这是计量经济学真正试图解决的问题。作为一名数据科学家,我可以向墙壁扔东西,看看有什么粘在一起,但作为一名计量经济学家,我真的必须考虑我在扔什么(以及我没有扔什么)。

那么如何推导因果关系呢?

通过实验和传统数据科学技术的巧妙结合。

我不会详细介绍计量经济学家的所有不同技术,但这里有一个很好的例子——工具变量。

以线性回归为例,如果真实模型被认为在解释变量和误差项之间没有协方差(来自高斯-马尔可夫假设),那么由于任何原因,这是不真实的(例如,有一个被忽略的变量影响因变量和自变量),那么 OLS 将不会产生 X 对 y 的因果影响

基本上,除非模型是完美的,否则我们有将相关性视为因果关系的风险。

如果你担心错误指定的模型,工具变量是推断因果关系的一个很好的方法,特别是在随机对照试验不适合的领域。

工具变量是第三个变量,Z,当您有内生变量或不确定模型是否指定错误或缺少关键变量时,在回归分析中使用。

例如,让我们以一种降低血压的药物为例。我们想知道,假设这种药物是免费的,任何人都可以购买,这种药物是否有效(我们无法进行随机对照试验)。其他变量如锻炼和饮食也将发挥作用,我们不知道是锻炼越多的人服用药物的可能性越小,还是我们只是忽略了一些变量。

因此,我们必须找到一个仅通过服药途径影响血压的变量。一个我们确信对血压绝对没有影响的变量,但由于与服用药物相关,可能显示出一些相关性。

常用的例子是靠近药房。你离药店有多近绝对不会对你的血压产生影响,除非是因为你更有可能服药。因此,我们可以通过第三个变量来分离药物和血压之间的因果关系。

由作者创建。

然后你可以通过两阶段回归 /OLS 来解释结果。

通过这种实验和统计操作的巧妙结合,我们可以对药物的能力更有信心。

这只是计量经济学可以用来确定因果关系的许多技术之一。作为我最喜欢的另一个例子,这是我写的另一篇关于回归不连续设计的文章。

你为什么要在乎?

这篇文章的要点是因果关系很重要——大公司也知道这一点。正如乔希·安格里斯特所说,对于受过计量经济学培训的人来说,私营部门有一个非常大的市场。

他们在寻找能做一些统计的人,但这些公司感兴趣的很多问题都是因果问题。例如,改变价格的后果会是什么。'

在就业市场上,有能力确定因果关系是一个巨大的优势。

计量经济学也可以从数据科学中学到很多东西。

为了完善这一点,并确保我没有试图侮辱数据科学家——我就是其中之一——这里有几点我认为计量经济学可以从数据科学中吸取的。

探索性分析

通过学习许多数据科学课程,我也学到了许多可以应用于计量经济学的东西。

计量经济学家在探索性研究方面很糟糕,绝对糟糕。

显然,这并不适用于每个计量经济学家,但就教科书和课程而言,绝对没有强调理解你的数据。如果你只是绘制一些数据,你可以节省很多时间来决定在你的模型中放入什么。

准确(性)

当我学习计量经济学的时候,曾经困扰我的是对 p 值的依赖,以及对模型整体准确性的缺乏关注。对我来说,如果模型只解释了 4%的方差,那么吹嘘一个变量有多重要就没什么意义了。是的,这个变量可能是有趣的,但当我们只解释和理解图片的一部分时,这并不重要。

结论

归根结底,计量经济学可以从数据科学中学到很多东西,数据科学也可以从计量经济学中学到很多东西。两者之间的鸿沟当然也在缩小。

对因果影响的理解确实是所有数据科学家都应该具备的技能。

只要记住‘所有的模型都是错的,但有些是有用的。有时候理解一个更差的模型比不理解一个稍微好一点的模型更有用。

干杯,

詹姆斯

感谢阅读,我希望这能帮助你。

If I’ve inspired you to join medium I would be really grateful if you did it through this [link](https://jamesasher4994.medium.com/membership) — it will help to support me to write better content in the future.If you want to learn more about data science, become a certified data scientist, or land a job in data science, then checkout [365 data science](https://365datascience.pxf.io/c/3458822/791349/11148) through my [affiliate link.](https://365datascience.pxf.io/c/3458822/791349/11148) 

这是我写的其他一些东西:

EDA 与 Tableau: 2021 年 NYPD 停下来搜身的人口统计

原文:https://towardsdatascience.com/eda-with-tableau-2021-nypd-stop-and-frisks-by-demographics-e5e88eb43939

使用公共数据时制作可访问仪表板的案例—

(longislandwins的《无声行进到终点》被 2.0 的 CC 授权。)

上面这张照片是在一次结束截停搜身和种族歧视的无声游行中拍摄的,拍摄于 2012 年 6 月 17 日,在截停搜身被视为违宪的一年前。探索 NYPD 的拦截搜身数据符合公众的既得利益。去年在纽约,有将近 9000 次停车。

但是什么是拦截搜身呢?

NYPD 拦截搜身概述:

Dictionary.com 将 stop-and-frisk 定义为*短暂拦截某人以搜查其武器或违禁物品的警察行为*

NYPD 从去年开始称他们的项目为“拦截、询问和搜身”,以反映市长亚当对拦截和搜身的态度,亚当是前 NYPD 队长。

“我不断被追问我对被称为‘拦截搜身’的警务程序的立场——这在执法中实际上被称为‘拦截、询问和搜身’——以及为什么我相信,如果使用得当,它可以在不侵犯个人自由和人权的情况下减少犯罪,”—亚当斯市长【1】**

为什么这对纽约市的治安历史如此重要,是因为如果你在谷歌上搜索“停下来搜身+违宪”,你首先会看到以下内容,来自维基百科:

在 2013 年 8 月 12 日裁决的 Floyd 诉纽约市一案中,美国地方法院法官 Shira Scheindlin 裁定,拦截搜身检查的使用方式违宪,并指示警方采取书面政策,具体说明在哪些地方允许此类拦截。

纽约市警察局在 NYPD 的拦截搜身计划上立场明确。[4]

来自纽约市警察局:

年度拦截搜身数字:

NYCLU 的一项分析显示,自 2002 年以来,无辜的纽约人遭到警察拦截和街头审讯超过 500 万次,黑人和拉丁裔社区仍然是这些策略的主要目标。在 2011 年彭博政府时期的截停搜身高峰期,超过 685,000 人被截停。几乎 90%被拦截搜身的纽约人是完全无辜的。

…在 2021 年,记录了 8947 次停车。
5422 人是无辜的(61%)。5404 人是黑人(60%)。2457 人是拉丁裔(27%)。732 人是白人(8%)。192 人是亚洲/太平洋岛民(2%)
71 人是中东/西南亚人(1%)

然而,有一个问题阻止了大多数纽约人接近拦截搜身数据。正如我在关于 NYPD 拦截搜身数据的上一篇文章中提到的,这些信息对公众开放,但公众无法获取。NYPD 公布的文件仅以原始形式存在,它们没有被总结或汇总。文件的每一行代表一个站点的一个记录,查看原始文件有点像这样:

(视频由作者提供。youtube 上的视频片段链接如下:https://www.youtube.com/watch?v=illObkP3TLQ

对于需要公众访问的数据,Tableau Public 这样的工具是绝佳的匹配。它的点击式图形用户界面对于熟悉数据的人和数据新手来说都很直观。通过将 Tableau Public 用于我的 EDA,交互式可视化的好处有助于我自己对数据的理解,但更重要的是,我可能为普通纽约人构建了一些易于理解的东西,以理解去年的“拦截搜身”。

让我们看看我能做什么。然后,我将向后展示我的方法,这样您就可以理解我是如何构建这个仪表板并将其用于 EDA 的。

我的 EDA 将专注于理解人口统计学(种族、年龄和性别)与警察辖区之间的关系,在这些区域发生了拦截搜身,并阻止了涉嫌犯罪的人。我还会调查是否使用了任何形式的暴力,以及停车是否导致了逮捕。

结果:

https://public . tableau . com/views/stopandfrisk 2021 NYPD/stopandfrisk 2021 demographicoverview?:language = en-US&:display _ count = n&:origin = viz _ share _ link

这是我制作的一张仪表盘的静态图片,因为 Medium 不支持嵌入 Tableau 公共仪表盘。

(图片由作者提供)

数据:

NYPD 将其所有可用数据发布到纽约市开放数据网站,这是他们的拦截、询问和搜身数据。

纽约市在“学校、警察、健康和消防”【3】下面有 NYPD 分局的 geojson 档案。

代码:

我的 Github Repo 在这里清理了数据,并为聚合做好了准备。我不会回顾我所做的每一步,而是概述我所做的选择。

  1. 我将STOP_FRISK_DATESTOP_FRISK_TIME制作成每一站的日期时间列,并将文件重新保存为 csv.gz 文件以节省一些空间:

(图片由作者提供)

2.我分离出感兴趣的列,只保留那些:

(图片由作者提供)

3.我用完整的措辞替换了一些更复杂的犯罪描述:

(图片由作者提供)

4.我尽可能地将一些种族描述改为更微妙的语言。(Business Insider 很好地解释了为什么“中东”是过时的语言。[ 4 ]在SUSPECT_RACE_DESCRIPTION中将类似MALE(null)的值更改为UNKNOWN非常简单。我不想改变太多的这些价值观,因为我发现保持警察如何对人们进行种族侧写的精确性是相关的。

然而,可以将BLACK HISPANICBLACKWHITE HISPANICWHITE合并,或者将HISPANICLATINX单独归为一类。将ASIAN / PACIFIC ISLANDER更改为E. ASIAN是唯一一个我失去了一些细微差别的类别,以换取一个更简单易用的名称对象,这是我在 Tableau 中使用别名时解决的问题。

(图片由作者提供)

5.在关于使用体力的栏中,我将Y替换为1,将UNKNOWN替换为0。当我合计时,这将把所有的Y加在一起。

(图片由作者提供)

6.出于汇总和描述性统计的目的,我还制作了一个列,记录了一次遭遇中使用的所有物理力量(行。)

(图片由作者提供)

它返回给我们下表:

(图片由作者提供)

值得注意的是,在该数据代表的 8,947 行中,只有不到 100 行使用了UNKNOWN数量的体力。该数据集中的所有其他停止都有一个已知的因素,即至少使用了某种物理力的一个计数。当我们得到描述性统计数据时,我们将回到这个问题上来。

7.我做了一个布尔列来捕捉是否使用了任何形式的物理力量。请注意,当我在 Tableau 中为该列添加别名时,FALSE变成了UNKNOWN:

(图片由作者提供)

8.我将 DateTime 列转换为索引,并将STOP_LOCATION_PRECICNT列更改为 string 数据类型,因为它是分类信息,我们不想计算这些值。

(图片由作者提供)

9.我在做了一个data['SUSPECT_REPORTED_AGE'].value_counts()之后,发现了一些像 0 岁、120 岁这样不合逻辑的年龄值,就把SUSPECT_REPORTED_AGE中一些没有意义的值改成了UNKNOWN

(图片由作者提供。)

10.我从数据中切掉年龄是已知值的行,并将这些值转换成整数,这样我们就可以计算它们了。

(图片由作者提供)

我这样做是因为我想基于年龄的四分位数范围创建一个AGE_CATEGORY分类列。通过按四分位数范围划分年龄,我知道我可以在数据分布的地方最平均地划分数据。

(图片由作者提供)

这段代码向我们返回了与年龄层位置相关的数字。

(图片由作者提供)

11.所以我做了一个垃圾桶来捕捉 20 岁以下,21-28 岁,28-38 岁和 38 岁以上的人:

这段代码返回到我们的SUSPECT_REPORTED_AGE列,与我们刚刚创建的AGE_CATEGORY列进行比较。让我们看看它是否有效。

成功了!我可以说它工作了,因为我们的第一行,索引在2021-01-01 01:50:00被列为40岁,在Thirtyeight-Above类别等等。

从那里,我想把我们的年龄未知数混合回数据中,他们的年龄类别为UNKNOWN:

(图片由作者提供)

它返回以下内容:

(图片由作者提供)

好像花了!从那里,我想了解一下AGE_CATEGORY中年龄的总体分布情况

它返回了以下内容:

(图片由作者提供)

看起来我们的分位数成功地捕捉到了均匀分布,我们的UNKNOWN年龄类别比其他类别的一半要小。

11.当我查看像这样的SUSPECT_SEX发行版时:

(图片由作者提供)

它返回了以下内容:

(图片由作者提供)

使FEMALE成为这个数据集中的少数。让大多数人是一种性别没有太大意义。我决定将UNKNOWN改为MALE,因为我知道可能会有一些既不是女性也不是男性的人通过这种方式处理数据时会经历数据擦除。

(图片由作者提供)

12.我制作了一个列,仅仅是为了汇总任何给定类别中的停靠点总数。我会在 Tableau 中大量使用这个专栏。

(图片由作者提供)

13.我使SUSPECT_ARRESTED_FLAG列适合聚合,并使它的对应列SUSPECT_NOT_ARRESTED_FLAG显示相反的值,这样我就可以同时使用这两个列。

(图片由作者提供)

因此,如果有人被捕,它将显示值为SUSPECT_ARRESTED_FLAG1和值为SUSPECT_NOT_ARRESTED_FLAG0,这将在可视化过程中帮助我。

14.我使用data.describe()查看了描述性统计数据,以下是我的发现:

(图片由作者提供)

  • 总的平均比率是 37%被捕与 62%未被捕,平均标准偏差约为 50%,这意味着可变性高于实际被捕率。
  • 在停车期间,平均枪支收缴率不到 6%。
  • 在停车期间,大约有 20%的时间会强制使用手铐。

(图片由作者提供)

  • 根据数据,2021 年停车期间没有使用 OC 喷雾。
  • 在停车期间,大约 3%的时间使用体力“其他”。
  • 在停车期间,只有不到 3%的时间使用了约束。
  • 90%的时间都在使用体力口头指令,这使它成为大多数停车的常规部分。

(图片由作者提供)

  • 几乎没有使用过武器的记录。
  • 体力总量,也许是这组统计数据中最有趣的指标,约为 1.25%,这意味着如果我们将所有使用的各种体力计数相加,使用的体力计数比停止的多大约四分之一。这是一个非常有趣的统计数据。标准偏差约为 0.5 或所用物理力的一半,这意味着平均经验是物理力被用于止损,物理力的大小通常变化半个计数。

从这里开始,我使用data.to_csv('2021_data.csv')保存数据,并继续使用 Tableau 公开仪表板。

仪表板:

这是我第一次使用 Tableau Public,我花了一分钟才适应。这里是我的一般步骤,但对于更多细节,我鼓励您下载仪表板本身并开始使用它。

  1. precincts.json文件添加为Spacial文件,将2021_data.csv文件添加为文本文件,并将它们之间的关系定义为Precicnt1 = STOP_LOCATION_PRECICNT

(图片由作者提供)

2.通过将Geometry拖到空白页上制作分区结果图,使Stop Location Precicnt成为一个维度细节(不是按总和),允许我滚动每个分区并弹出该分区。从那以后,问题就变成了我想在选区展示什么。我选择显示该辖区内的总停靠次数,并选择显示我创建的名为Not-Arrested Rate的计算字段,有关我如何计算该字段的详细信息,请参见此处:

(图片由作者提供)

3.对于涉嫌犯罪被阻止的情节,我把Total Stops拖到列上,确定它正在取和。然后,我将Suspected Crime药丸拖到几排。

(图片由作者提供)

我决定将“大麻的销售”与“大麻的销售”混为一谈,因为我想消除说西班牙语的人的污名。更多来自 NPR 的消息。]

让数字在栏旁边弹出也很简单,只需将SUM(Total Stops)拖到文本框中,如下所示:

(图片由作者提供)

4.随着时间的推移制作种族差异剧情分两步走。首先,我将时间索引拖到列上,并选择了Month而不是Year.,然后我将Total Stops拖到行上,并确保它得到了总和。

(图片由作者提供)

然后我把Suspect Race Description药丸拖到 Marks,并使它成为一个彩色细节。

(图片由作者提供)

5.制作年龄图是类似的,我将Age Category拖到列上,将Total Stops拖到行上,确保它得到总和。

(图片由作者提供)

然后我同样将Suspect Race Description拖到颜色标记处。

(图片由作者提供。)

6.将所有这些都放在一个仪表板上,使每个情节相互作用,并设置所有的过滤器,这是一个有趣的过程。要看到我的整个过程,最简单的事情就是从 Tableau Public 下载仪表板,然后自己去找。Tableau 社区文档中有丰富的更多资源:https://help . Tableau . com/current/pro/desktop/en-us/filtering . htm[6]

注意:这个仪表板仍然可以看到一些变化或改进。举例来说,我还没有尝试使用集合功能将同一个区的所有选区组合在一起。我也没有连接一种方法来显示使用了两种或两种以上物理力的停止,这在分离出 PHYSICAL_FORCE_ 时可能是相关的。

为什么这比用 python 做我所有的 EDA 要好?

  1. 我可以用连珠炮似的问题来处理数据,而不会因为制作大量的静态表格和图表而慢下来。
  2. 我可以非常容易地与公众和我的利益相关者分享我的发现。

例如,如果我只想得到未逮捕率最高的统计数据的明细,该怎么办?在地图上,我可以很容易地将 75 区(东纽约)标记为最暗的红色,当我单击它时,我可以看到该区内涉嫌犯罪的分布明细,其中绝大多数是持枪犯罪。从这里我还可以看到按种族划分的年龄分布,以及按种族划分的被捕时间。一次点击为我节省了很多很多行代码!

(图片由作者提供)

当我们使用这些描述性统计数据深入了解该辖区时,我们可以了解到,平均而言,75 号辖区拦截的乘客年龄远低于所有车站的平均年龄(28 岁)。)我们还了解到,75 区的未逮捕率远高于全市平均水平,分别为 83%和 67%。如果我们看一下时间线,我会想到问“4 月份开始发生了什么来阻止止损,特别是当阻止黑人时?”

(图片由作者提供)

当我们使用Outcome过滤器比较我们的图表时,我们可以看到,去年在 75 区因涉嫌非法持有武器而被拦下的 330 人中,有 278 人没有被逮捕。

进一步的发现:

涉嫌非法持有武器并不导致逮捕:

在今年进行的 8,947 次拦截中,有 2,471 次是涉嫌非法持有武器,并没有导致逮捕。这仅占所有停靠站的 27%。通过查看年龄图,我们可以看到超过四分之一的停靠点都是 20 岁以下的人,或者他们的年龄没有被列出。我们也可以看到大多数黑人弥补这些停止。当我们查看种族差异随时间变化的图表时,我们可以看到一波从 9 月开始,在 11 月达到高峰,停留次数是 9 月的两倍多。这就引出了一个问题,9 月份开始发生了什么,为什么警方会阻止涉嫌非法持有武器的年轻黑人?

(图片由作者提供)

斯塔滕岛站:

当我们查看仅发生在斯塔滕岛的停靠点时,我们会得到不同的数据。我们看到了更多针对年轻人停车的证据,(但没有列出年龄的趋势),黑人年轻人占了 20 岁及以下类别停车的一半。

(图片由作者提供。)

最值得注意的是,在斯塔滕岛发生的停车事件中,绝大多数都使用了暴力。这两张照片显示了发生在斯塔顿岛的所有停靠站,然后我只分离出使用某种物理力量的停靠站。这两张照片几乎一模一样。

(图片由作者提供)

那是因为去年在斯塔滕岛只有 5 次停车,没有证实是否使用了某种暴力。其余的停留都涉及到体力。在未来,我想进行假设检验,看看斯塔滕岛的数据与纽约市其他地方的数据有多大差异,因为我们之前发现,去年全市 90%的车站中至少有一次使用了物理力量。

14 区的车站和妇女:

只要看看那些被拦下的人被列为女性的车站(记住,虽然大多数女性都自称为女性,但这是一种过于简单化的说法),我们就可以看到曼哈顿下城的一个区,那里的不逮捕率特别高(暗红色。)

(图片由作者提供)

在进一步调查中,我们可以看到这是 14 区,去年有 60 个由妇女组成的站点,其中 90%没有被逮捕。与我们全市所有车站 67%的不逮捕率相比,这是一个相当高的比率。

(图片由作者提供。)

在这 60 次拦截中,40 次(67%或三分之二)涉嫌非法持有武器。当我们查看她们的年龄时,我们可以发现超过一半的女性年龄在 28 岁以下,而大多数没有列出年龄的女性是东亚或太平洋裔。当我们查看我们的种族差异随时间变化的图表时,我们可以看到这些停止在 10 月和 11 月之间有一个很大的峰值。

当我们更仔细地观察时,我们可以看到这些拦截中的大多数并没有导致逮捕。通过比较这两张快照,我们可以看到,随着时间的推移,种族差异主要是由黑人女性构成的。重要的是,大多数导致这些黑人女性被捕的停车点并不是在 10 月至 11 月停车高峰时发生的。

通过使用 Tableau,我可以与更多的观众分享这些发现,并且我能够轻松地对数据快速提问。事实证明,Tableau 在帮助我探索数据以及找到我想要进一步查询数据的位置方面非常有用。

最后,我将把 Tableau 整合到我的 EDA 过程中,我鼓励你也考虑这样做。它节省了你询问数据问题的时间,你的利益相关者会感谢你能够理解数据并与数据本身互动。

[1] E. Adams,A. Wehenkel 和 G. Louppe,我们如何使纽约市变得安全:当选市长 Eric Adams 解释了我们为什么需要拦截搜身和积极主动的治安 (2021),纽约每日新闻

[2] NYPD,拦住、盘问和搜身的数据 (2021)

[3]纽约市,政治和行政区—下载和元数据 (2021)

[4]纽约市警察局,拦截搜身数据 (2021 年),纽约市警察局

EDN-GTM:具有用于单一图像去雾的引导传输图的编码器-解码器网络

原文:https://towardsdatascience.com/edn-gtm-encoder-decoder-network-with-guided-transmission-map-for-single-image-dehazing-78e8036bbaa3

当传统的计算机视觉和深度学习结合时。

由 Unsplash 上的 drmakete 实验室拍摄的照片

图像去雾

增强从自然场景捕获的数字图像的可见性的目的在许多现实世界应用中变得非常必要,因此图像去雾(或去雾)在几十年前已经成为计算机视觉和图像处理中的重要任务。

如果你想知道这个话题有多热,我想让你知道何,深度学习中各种经典理论如残差网络、更快 R-CNN、空间金字塔池、特征金字塔网络等的发明者在他的博士研究期间研究了这个主题,并在他的论文和IEEE Transactions on Pattern Analysis and Machine Intelligence中提出了之前的暗通道(DCP)。

去雾算法有两种范式:传统方法和基于深度学习的方法。许多传统方法已经使用纯计算机视觉技术将手工制作的图形模型应用于去雾(例如,DCP),而基于深度学习的方法已经采用卷积神经网络(CNN)来解决去雾问题。然而,这些方法仍然有它们的缺点,并且总是有改进的空间。

这篇文章回顾了使用导向传输图(EDN-GTM)实现有效的单幅图像去雾的编码器-解码器网络。EDN-GTM 是一种新的方案,它利用传统计算机视觉技术和现代深度学习算法的能力来执行图像去雾。具体地,利用通过采用暗通道先验估计的透射图作为 CNN 模型的指南来执行去雾。论文全文可在 arXiv (预印本)或Procedia Computer Science 204(已发表论文)上找到。

作为 CNN 指南的传输图

暗通道先验(DCP)的去雾结果:(a)输入模糊图像,(b)通过 DCP 的去雾图像,(c)地面真实图像,(d)通过 DCP 的反转透射图。(纸张中的图像)

DCP 是基于无薄雾的室外图像的统计而提出的,因此,它在室内场景中不太有效,并且当薄雾图像包含看起来类似于空气光的大区域时可能无效。在上图中可以看到一个例子,当 DCP 试图在看起来像空气光和薄雾的墙壁场景区域中去雾时,从而提出了比地面真实图像更暗的输出图像。

然而,当重新思考由 DCP 产生的倒置透射图时,它们可以被认为是一种注意力图,其中较亮的区域指示密集雾度的区域,而较暗的区域指示不太雾度的区域(除了墙壁场景区域)。现在的问题是如何找到墙景区域?

哦,CNN 刚刚举手了!由于具有提取和分析图像特征的能力,CNN 可能是一个潜在的候选者。

有了这些强有力的证据,由 DCP 和 CNN 模型获得的透射图可以被统一以形成有效的霾去除系统。传输图“告诉”CNN 关注哪里。从这些建议区域,CNN 可以通过监督学习知道它应该更加关注哪些区域(例如,在输入和输出图像中墙壁场景区域没有太大不同,但是模糊区域不同)。

网络架构

图表和网络架构:(a)EDN-GTM 方案的图表,(b) EGN-GTM 设计,以及(c)鉴别器设计。(纸张中的图像)

上图显示了 EDN-GTM 方案以及发生器和鉴别器的网络架构。

发电机设计(EDN-GTM)

作为语义分割和图像恢复中最流行和最强大的网络之一,U-Net 被选为 EDN-GTM 方案的基础网络。为了获得 EDN-GTM 的架构设计,作者进一步将以下主要修改添加到网络中:

  1. 输入通道:传输图与图像的深度信息有着密切的关系,在去雾方案中起着重要的作用,然后它被用作网络输入的附加通道(与传统的 RGB 图像一起)。
  2. 瓶颈:通过使用一组具有不同内核大小的池操作,空间金字塔池(SPP)模块能够分离出最重要的功能,它被插入到基础网络的瓶颈中(就像它在 YOLOv4 object detector 的颈部使用的方式)。
  3. 激活:ReLU 在最近的 CNN 模型中逐渐变得过时,因此,ReLU 被 Swish 函数所取代,该函数已经被证明在现代深度网络中始终优于 ReLU。
  4. 感受野:去雾网络的感受野应该足够大,这是由于在模糊图像中霾(或雾)的扩散分布,因此在基本网络的每个卷积级中增加一个 3×3 conv 层。

鉴别器的设计

该方案选择 U-Net 的编码器部分作为鉴别器的结构。鉴别器设计的这种选择可以帮助两个网络(发生器和鉴别器)具有提取和分析输入图像特征的竞争能力,从而两个网络可以相互“战斗”以获得它们的性能。

损失函数

EDN-GTM 应用积分损失函数,该函数是对抗性损失、MSE 损失和感知损失的加权和。

对抗性损失

其中 B 是批量,z 是模糊图像,G 是发生器,D 是鉴别器。

MSE 损失

其中 N 是输入(输出)图像中的像素数,I 是干净的图像。

知觉丧失

其中 M 是预训练 VGG16 模型的层 Conv3_3 的特征图φ中的元素数量。

整体损失

积分损失是上述所有相关损失函数的加权和。

基准测试的结果

提供了去雾任务的四个基准数据集上的实验结果,包括 I-HAZE、O-HAZE、Dense-HAZE 和 NH-HAZE。下图显示了各种方法的典型视觉去雾性能。EDN-GTM 已被证明在可见度方面始终优于其他现代去雾方法。

视觉去雾的结果是:(a) I 雾度,(b) O 雾度,(c)致密雾度,和(d) NH 雾度。(图片来自论文)

下表显示了 EDN-GTM 和其他最新去雾方法的定量结果(红色和蓝色数字分别表示最佳和次佳性能)

来自纸张的图像

应用于对象检测

EDN-GTM 作为预处理工具应用于目标检测任务。比较了有雾和去雾图像的检测性能。实验中使用的数据集是 WAYMO 数据集。WAYMO 数据集不提供模糊图像数据,因此,通过应用本文帖子中描述的方法合成模糊图像。

合成模糊 WAYMO 数据集上的视觉去雾结果。(图片来自论文)

在两组模糊和去雾图像上的对象检测性能(红色:地面实况框,绿色:预测框,蓝色:放大区域)。(图片来自论文)

图片来自纸张。

结论

在这篇文章中,我简要回顾了 EDN-GTM,一种新颖的单幅图像去雾方案。EDN-GTM 利用纯计算机视觉和深度学习方法来形成一个统一的网络,以实现最先进的去雾性能。EDN-GTM 利用 U-Net 作为基础网络,并对网络进行各种修改,以便能够实现最佳去雾性能。EDN-GTM 的有效性已经在基准去雾数据集上得到验证。论文全文可以在 arXiv (预印本)或Procedia Computer Science 204(发表的论文)上找到。

欢迎读者访问我的脸书粉丝页面分享关于机器学习的事情:投入机器学习。我的其他著名帖子也可以在这里找到:

  • 元格式器
  • 黑暗时代
  • EFPN:扩展特征金字塔网络
  • 数据扩充
  • 数据提炼
  • 而其他人在我的页面。

感谢您抽出时间!

教育是巴西人类发展的驱动力

原文:https://towardsdatascience.com/education-as-the-driver-of-human-development-in-brazil-e95f9f0124fe

巴西人口普查数据分析

图片: Freepik

T2010 年的上一次人口普查更新了衡量巴西各城市(MHDI)人类发展指数的数据。该国本应在 2020 年进行随后的人口普查,但主要是因为疫情,数据收集推迟了两年。疫情和经济危机的影响使人们对 2000 年和 2010 年人口普查中观察到的改善感到关切。虽然不可能与该国的现状进行比较,但如何从冰冷的数字和图形的视觉感受中更详细地了解过去的演变呢?

以下段落,尤其是下面的图片,对 1991 年至 2010 年间的变化进行了简要总结。这里我先做了 1991 年和 2000 年的比较,然后是 2000 年和 2010 年的比较。这个想法是通过 聚类 技术显示 MHDI 的变化之间的比较形成了哪三组城市,然后从组成 MHDI 的各种变量的变化中显示影响这三组城市框架的主要因素是什么。

1991 年和 2000 年的比较

下图显示了该算法如何在 1991 年至 2000 年间将巴西城市分布在 MHDI 的三个不同等级中。

MHDI 变差的分类。图片由作者提供。

在图表中,每个点都是一个自治市。在低变化等级中,紫色部分是 2167 个城市,它们的 MHDI 变化在 5.9%到 34.8%之间。浅绿色表示中等变化等级,集中了 2107 个 MHDI 在 34.81%和 53.7%之间变化的地点,在最后一个用黄色表示的类别中,其余 991 个城市的变化范围在 53.71%和 207%之间。

下面,我们可以看到 MHDI 三个不同等级的城市分布情况。

1991 年和 2000 年之间的地图和 HMDI 变化。图片由作者提供。

应用于地图的图例表明,自治市点的颜色越蓝,MHDI 越高,越红,值越低。颜色范围的变化发生在 0.5 的测量中,对应于我们开始考虑中等发展的 HDI 的值。

对地图的观察表明,MHDI 地区差异较小,同时 MHDI 值最高的城市集中在南部和东南部地区。另一方面,变化大的城市在 1991 年与非常低的 MHDI 联系在一起。2000 年,总的来说,这一阶层有所改善,一些城市甚至超过了中等发展人类发展指数点(人类发展指数> 5)。通过这种方式,可以看到一些带有蓝色阴影的城镇,这在 1991 年并没有出现。

MHDI 由 200 多个变量综合而成。一些因素可能对每个城市的指标演变产生了较大影响,而另一些因素则影响较小。因此,我使用了一个被称为 决策树 的程序,试图找出最相关的特征来确定上面显示的三组城市。

该算法指出了八个重要变量,它们都与教育有关。第一个是年轻人口的入学率。根据所使用的方法,这一变量比第二重要的变量,即 5 至 6 岁儿童的入学率,重要 2.28 倍。让我们来看图表。

年轻人口的入学率

使用四个指标来计算青年人口的入学率:5 至 6 岁儿童的入学率、11 至 13 岁儿童在小学最后几年的入学率、15 至 17 岁儿童完成小学教育的百分比以及 18 至 20 岁儿童完成高中教育的百分比。见下文该指标如何划分 1991 年至 2000 年 MHDI 的三类变化。

1991 年至 2000 年 MHDI 入学率变化的影响。作者图片

在上图中,我们可以看到,在参考年份 1991 年,三组的三种颜色在它们的位置上得到了很好的巩固。在他们的 MHDI 里,移动最少的城市,用紫色的点标出,在另外两个班级里,有着比其他城市高得多的入学率。更相关的是,运动最显著的城市,用黄色画的,占据了低 MHDI 和低入学率的空间。

另一方面,当我们看到 2000 年发生的情况时,黄色和浅绿色的点更接近紫色的点,从而表明这些群体中的城市在入学率指数方面取得了多大进展,以及这种进展对 MHDI 的改善产生了多大影响。

另一种观察这种运动的方式是通过下图。

1991 年至 2000 年 MHDI 入学率变化的影响。作者图片

人们可以在 1991 年观察到,黄点集中在一个象限,其特点是 MHDI 非常低,入学率很低。实际上,几乎没有一个城市的 MHDI 高于 0.4,学校出勤率高于 0.25。另一方面,在 2000 年,黄点很快出现在入学率高于 0.5 和 MHDI 高于 0.4 的象限中。还值得注意的是,在以高入学率和低 MHDI 率为标志的象限中,没有一个班级是他们的代表,这加强了这一组成部分在 MHDI 整体改善中的重要性。

5 至 6 岁在校人口

如前所述,衡量 5 至 6 岁儿童上学的百分比是青少年上学指标的一部分。根据我们的算法,这是通过 MHDI 的变化形成组的第二个最重要的变量。那么,让我们来看一个与这个指标相关的数字。

1991-2000 年间 MHDI 5-6 岁学生变化的影响。作者图片

很容易看到市政当局向右移动,特别是对于 MHDI 中高变化的城市。然而,我们也注意到,这种迁移对 MHDI 的改善并没有像青年人口频率指数那样产生强烈的影响。人们可以看到,所有群体都存在中等和高中入学率以及中等和低 MHDI 的城市。

2000 年和 2010 年的比较

十多年的文明进程改进带来了更多的蓝点和更少的关注点。但是,更重要的是,在 2000 年和 2010 年之间 MHDI 的变化所形成的群体中有一个区域性的重点。

2000 年和 2010 年之间的地图和 HMDI 变化。图片由作者提供。

上图显示,2010 年几乎没有 MHDI 点被归类为低发展。南部和东南部地区集中在两次人口普查之间差异较小的城市。最有可能的原因是,这些地区已经出现中高 MHDI 的频率更高,因此不会有更大的增长空间。另一方面,东北地区集中了 MHDI 变化最大的城市。

这种大约 20 年的转变促使我们将 1991 年与 2010 年进行比较,使颜色之间的对比更加强烈。我们会做这个比较,因为我们有数据。

1991 年至 2010 年间的地图和 HMDI 变化。图片由作者提供。

但是,2000 年到 2010 年之间的变化的重要变量是什么呢?同样,所有重要的因素都与教育有关。同样,年轻人口的入学率是最重要的,其次是 11 至 13 岁小学生的比率。让我们来看图表。

年轻人的入学率——第二部分

看看下面的点和颜色告诉我们什么。

2000 年至 2010 年 MHDI 入学率变化的影响。作者图片

不出所料,所有阶层的起点都远高于前十年的对比。我们再一次看到了所有不同班级的出勤率和 MHDI 之间高度相关的视觉亮点。

小学 11 至 13 岁学生的比例

同样,构成年轻人入学率的一个指标在人类发展指数变化组的定义中排在第二位。让我们看一下图表。

2000 年至 2010 年 MHDI 11-13 岁学生的影响变化。作者图片

当将 2000 年与 2010 年进行比较时,中低变化等级被压缩,对于中变化城市,可以清楚地看到 MHDI 向上移动。另一方面,对于高度变化的城市,点向右的位移与向上的位移一样大。这显示了适龄儿童接受初等教育对改善 2010 年观察到的 MHDI 的重要性。

该分析中使用的算法有助于发现构成 MHDI 数据库的近 17000 行和 230 列中的隐藏模式。这里我们只强调文本中最重要的变量的一个子集。

年轻人在学校的存在与年龄和学校阶段之间一致性的重要性之间高度相关的模式变得很明显。此外,在 2000 年和 2010 年的比较中,根据人类发展指数的变化划分的市镇群体的明显的区域成分也很突出。

总的来说,这些进步与其他几个变量有关。例如,一个更细心的研究人员可能想解释婴儿死亡率的大幅下降、收入的提高等等。仍有大量数据有待探索。恢复人口普查之前的这一时刻似乎是恢复巴西在 2010 年之前取得的进步并将其与极不稳定情况下的预期进行对比的大好时机。

如果对 MHDI 的数据感兴趣,非政府组织 Base dos Dados 可以从这个地址轻松获取这些数据。另一方面,如果你有兴趣知道我是如何使用算法或构建图形的,R 语言的代码可以在我的 GitHub 上找到。

使用 OpenBCI Ultracortex 的脑电图 101

原文:https://towardsdatascience.com/eeg-101-using-openbci-ultracortex-fbeb0202d0c5

使用open BCIultra cortex Mark IV EEG 耳机演示 EEG(脑电图)信号中的数据采集、数据滤波和去噪技术的教程。

图:1 (A)直接从 Ultracortex Mark EEG 耳机收集的未滤波 EEG 数据(B)带通滤波器(> 1Hz 和<50 Hz) ( C)Denoising with Fast Fourier Transform(FFT).

Modus Operandi

I have recorded live EEG※ from my own scalp using an Ultracortex Mark IV EEG 耳机 😃 Ultracortex 耳机共有 16 个通道,但在本教程中,我们将仅使用 8 个通道(图 2)。电极按照国际 10–20 系统放置,这使我们能够测量大脑皮层中潜在的电活动。

E 电极放置: Fp1 和 Fp2,测量额叶前部皮层的活动, C3C4 ,来自顶叶的 P7 / T5P8 / T6 ,颞侧的 O1O2

图 2:使用基于国际 10–20 系统的 Cyton 板(8 通道)收集 EEG 数据。

Ultracortex Mark IV※可用于湿电极和干电极。它也可以被配置成作为有源电极或无源电极工作。但是对于这个实验的范围,我使用了干电极和无源电极的组合以及 Cyton 生物传感板 ※以 *250 赫兹(采样频率)*采样信号。

数据收集

在 *Python (Python 3.8.0: CPython 实现)*中,我们将使用 BrainFlow 用户 API ※ (BoardShim 类)进行数据收集,使用 Scipy(信号类)进行数据过滤和去噪技术。这两个软件包都可以通过 pip 安装在终端中,如下所示:

pip install brainflowpip install scipy

让我们开始编码吧!!( Github: collection.py )

  1. 库导入
import time
import argparse
import numpy as np
import pandas as pdfrom brainflow.board_shim import BoardShim, BrainFlowInputParams

2.串行端口和板 ID 配置

parser = argparse.ArgumentParser()parser.add_argument('--serial-port', type=str,
        help='serial port', required=False, default='/dev/ttyUSB0')parser.add_argument('--board-id', type=int,
        help='board id, check docs to get a list of supported
        boards', required=False, default=0) ## Cyton board ID = 0)args = parser.parse_args()

3.用于加载配置的 BrainflowInput 参数 API

params = BrainFlowInputParams()
params.serial_port = args.serial_port
board = BoardShim(args.board_id, params)

4.记录实时脑电图数据流(时间间隔= 1 秒)

board.prepare_session()
board.start_stream()
time.sleep(1)
data = board.get_board_data(250*1) ## (250 Hz @ 1sec) ##
board.stop_stream()
board.release_session()

N 注意:get_board_data()方法获取最新的板卡数据,并从环形缓冲区中删除这些数据。其他方法如**get_current_board_data()** 如果没有足够的数据,则获取指定数量或更少的数据,并且不从环形缓冲区中移除数据。

5.获取 Cyton 板所有活动 EEG 通道的列表

eeg_channels = BoardShim.get_eeg_channels(args.board_id)
eeg_names = BoardShim.get_eeg_names(args.board_id)

注:Cyton 板有 24 个通道来捕捉所有生物传感活动(体温、心跳等)。但在我们目前的设置中,我们使用的是 8 通道 EEG 配置:Fp1、Fp2、C1、C2、P7、P8、O1 和 O2。

6.将脑电图数据存储到 CSV 文件中

df = pd.DataFrame(np.transpose(data[:,1:]))
df_eeg = df[eeg_channels]
df_eeg.columns = eeg_namesdf_eeg.to_csv('data.csv', sep=',', index = False)

图 3:熊猫数据框架的前 10 行数据。

数据分解

EEG 信号可以分解成多个频段,每个频段都有独特的功能特征,如图 4 所示。这些子带的范围从被称为以 0.1 赫兹振荡的德尔塔波的极低频到被称为以 40 赫兹振荡的伽马波的高频。我们过滤掉其余的频率。※

图 4:脑电图中感兴趣的频谱(频域)。

在本教程中,我们将使用带通滤波器对数据进行滤波,这也是信号处理中最常用的滤波器。重要的是要注意,在应用滤波器后,信号会被衰减,即当频率成分被移除时,信号强度会有强度降低。人们可以在图 1 中观察到同样的情况;原始 EEG 和带通数据之间的幅度差异(V)。

N 注:为了简化计算,我们将只对其中一个通道进行预处理,即使用带通滤波器对 Fp2(前额叶皮层—右侧)进行预处理,并将其分解为各种其他子带。

让我们开始编码吧!!( Github: bands.py )

  1. 库导入
import pandas as pd
import matplotlib.pyplot as pltfrom scipy.signal import butter, lfilter, lfilter_zi

2.定义带通滤波方法

def butter_bandpass(lowcut, highcut, fs, order=5):
    nyq = 0.5 * fs
    low = lowcut / nyq
    high = highcut / nyq
    b, a = butter(order, [low, high], btype='band')
    return b, adef butter_bandpass_filter(data, lowcut, highcut, fs, order=5):
    b, a = butter_bandpass(lowcut, highcut, fs, order=order)
    zi = lfilter_zi(b, a) * data[0]
    y, _ = lfilter(b, a, data, zi=zi)
    return y

3.分解频带(α、β、δ、θ、γ)

sampling_frequency = 250df = pd.read_csv('data.csv')delta = butter_bandpass_filter(data = df.Fp2, lowcut = 0.1, highcut
    = 4 , fs = sampling_frequency, order = 3)theta = butter_bandpass_filter(data = df.Fp2, lowcut = 4, highcut
    = 8, fs = sampling_frequency, order = 3)alpha = butter_bandpass_filter(data = df.Fp2, lowcut = 8, highcut
    = 13, fs = sampling_frequency, order = 3)beta = butter_bandpass_filter(data = df.Fp2, lowcut = 13, highcut
    = 32, fs = sampling_frequency, order = 3)gamma = butter_bandpass_filter(data = df.Fp2, lowcut = 32, highcut
    = 50, fs = sampling_frequency, order = 3)

4.数据可视化(图 5:脑电波分解)

fig = plt.figure(1)plt.subplot(6,1,1)
plt.plot(df.Fp2, linewidth=2)plt.subplot(6,1,2)
plt.plot(delta, linewidth=2)plt.subplot(6,1,3)
plt.plot(theta, linewidth=2)plt.subplot(6,1,4)
plt.plot(alpha, linewidth=2)plt.subplot(6,1,5)
plt.plot(beta, linewidth=2)plt.subplot(6,1,6)
plt.plot(gamma, linewidth=2)plt.show()

图 5:单个波形在不同频率下进行滤波,以展示其频率构成。

N 注:随着滤波器阶数的增加,滚降也会降低,从而大幅削减阻带频率,但更高的阶数也会在滤波数据中引入延迟。与当前值(即 3)相比,通过将上述代码中的顺序更改为 1,可以看到相同的情况。

用 FFT 对数据去噪

FFT 是信号处理中最受欢迎的算法之一,是数字通信、音频和图像压缩以及卫星电视中的一个重要组成部分。在本教程中,我们将利用快速傅立叶变换(FFT)算法从 EEG 数据的原始结构中提取噪声数据。

在收集 EEG 时,有许多假象频率被引入到波形中,这些假象频率不是由人脑活动直接产生的,因此降低了数据结构的锐度。FFT 帮助我们从草地(原始脑电图波形)中去除杂草(噪声)。由于数字(CPU、GPU)或生理假象(呼吸、脉搏和眨眼),这些微弱的频率很可能是在收集 EEG 时被拾取的。

F 人们也可以将 FFT 理解为信号从时域到频域的变换。

我们将通过 FFT 算法传递上一步过滤后的 EEG(带通滤波器),并希望找到 EEG 中最显著的频率成分。稍后,我们将过滤掉功率较低的频率(或“弱”频率)。我们将使用频率的功率谱密度(PSD)度量特定频率在给定 EEG 波形中对其形状的贡献有多重要。

让我们开始编码吧!!(Github:noise . py)

  1. 库导入
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from scipy.signal import iirnotch, freqz, filtfilt

2.使用带通滤波器(包括陷波滤波器)

df = pd.read_csv('data.csv')
band_pass_eeg = butter_bandpass_filter(data = df.Fp2, lowcut = 1,
                  highcut = 50, fs = 250, order = 3)b_notch, a_notch = iirnotch(w0=59.9250936329588, Q=20, fs=250)
filtered_eeg = filtfilt(b_notch, a_notch, band_pass_eeg)

3.计算傅立叶系数(复数值):

number_of_points = len(filtered_eeg)fhat = np.fft.fft(filtered_eeg, number_of_points)
PSD = fhat * np.conj(fhat) / number_of_points
freq = (1/(0.004*number_of_points))*np.arange(number_of_points)
L = np.arange(1,np.floor(number_of_points/2),dtype='int')

4.用 PSD 滤除噪声

indices = PSD > 150
PSDclean = PSD * indices
fhat = indices * fhat
ffilt = np.fft.ifft(fhat)

5.数据可视化(图 6:降噪和噪声数据的功率密度)

fig,axs = plt.subplots(3,1)data_points = np.arange(number_of_points)plt.sca(axs[0])
plt.plot(data_points,band_pass_eeg, color='k',linewidth=1.5,
               label='Bandpass filter')
plt.xlim(data_points[0],data_points[-1])
plt.legend()plt.sca(axs[1])
plt.plot(data_points,ffilt,color='b',linewidth=2,
           label='FFT Filtered')
plt.xlim(data_points[0],data_points[-1])
plt.legend()plt.sca(axs[2])
plt.plot(freq[L][3:75],PSD[L[3:75],color= 'r',linewidth=2,
            label='Noisy')plt.plot(freq[L][3:75],PSDclean[L][3:75],color='b',linewidth=1.5,
            label='Filtered')
plt.legend()
plt.xticks(freq[L][3:75:5])

图 6 —(A)来自带通滤波器的数据,( B)通过 FFT 后的数据,( C)噪声和干净数据的 PSD。

尽管我们有嘈杂的数据,但在θαβ光谱中有一些清晰的峰值,这是显而易见的,因为我在收集我的大脑数据时处于完全警觉状态:)(图 6 — (C))。

我们选择功率的截止值为 150,因此强度小于 150 的所有频率都将从信号中截止。去除噪底后,信号更加清晰锐利。

F 最后注意:预处理 EEG 数据时需要小心,因为它可能会改变事件相关电位的时间结构,可能无法绘制出准确的大脑反应。过滤会改变你的数据,因此,根据一般经验,过滤越少越好

我想衷心感谢 Titiksha Bhardwaj 在本教程中设计了以上所有的视觉效果。没有她,这样有见地的插图是不可能的。谢谢:)

※参考文献:

  1. 定义脑电图(维基)
  2. 10–20 脑电图采集国际系统(维基)
  3. OpenBCI — UltraCortex 耳机设置
  4. OpenBCI Cyton 生物传感板
  5. 人才流动—用户应用编程接口
  6. 脑电信号的频谱信息(EURASIP-信号处理进展杂志)
  7. 用 Python 去噪 (databook.uw — Steve Brunton —华盛顿大学)

Eeny Meeny Miny Moe,最好了解哪个数据科学平台?

原文:https://towardsdatascience.com/eeny-meeny-miny-moe-which-data-science-platform-is-best-to-know-28f101b72c73

研究不同的数据科学平台和 ide 以及何时学习它们

图片来自 Pixabay,作者 geralt

选择正确的平台来专注于您的数据科学教育是一项挑战,因为当今进行数据科学的平台无处不在。但情况并非总是如此。不久前,唯一可用于测试数据科学的是 IPython 或交互式 Python。命令行 shell 为不同的代码块提供即时反馈。

使用命令行进行数据科学的问题在于,数据科学活动需要能够看到输出,无论是数据本身、正在创建的变量还是分析结果。尽管 Python 作为一种编程语言很有用,但它还没有达到适用于典型数据科学家的可用性。

Python 作为一种编程语言诞生于 80 年代末,在 90 年代初开始普及,并随着 2000 年 Python 2.0 的发布开始被后端数据开发人员所采用。直到 2009 年,随着 Anaconda 和面向数据科学的“集成开发环境”(IDE) Spyder 的出现,Python 才真正开始成为数据科学的“语言”。

在短短的 12 年里,IDE 和数据科学平台的数量激增,以至于学习该领域的人很难知道应该关注哪个 IDE 或平台。在本文的剩余部分,我将回顾 IDE 和平台之间的区别,介绍不同的产品,并解释我认为每种产品在开发数据科学家的教育旅程中都属于什么位置。

它是一个平台还是仅仅是一个 IDE?

数据科学家花大量时间研究数据。在许多情况下,这些研究活动的结果会成为可交付成果(如幻灯片)的基础。因此,数据科学家要求他们的开发环境在视觉上对满足这些目标有用。

Spyder 是第一个在编程和视觉上都非常有用的 IDE。Spyder 是由科学家为科学家开发的,并成为与 Anaconda 打包在一起的默认 IDE(下面将详细介绍这个数据科学平台)。

但是 Spyder 等 ide 都不是平台。它们是图形用户界面(GUI ),帮助程序员和数据科学家开发解决 Python 代码问题的解决方案。

另一方面,平台是将多种服务集成到一个框架中的产品,该框架通过抽象或自动化用户可能需要的一些技术要求来处理复杂的任务,从而使用户能够实现这些不同的服务。

在数据科学中,最受欢迎的 ide 包括 Jupyter Notebooks、Spyder、PyCharm 和 Sublime Text(但在这里可以看到更多)。平台致力于与这些 ide 集成,以支持额外的数据科学需求,如包依赖性管理、计算资源、安全性和模型部署。例如,Anaconda 可以被认为是一个数据科学平台,因为它有助于管理包的依赖关系,提供了多种 ide 用于开发,并且包括对它们自己的包存储库的访问。

一些最大、最受欢迎的数据科学商业平台包括 DataBricks、Amazon Sagemaker、Dataiku 和 IBM 的用于数据的 CloudPak。

在接下来的几节中,我将典型的数据科学学生的学习之旅分为 3 个简化的关键时期,并讨论应该重点关注哪些 ide 和平台,以成功克服这个关键点并提高数据科学技能。

关键期#1:学习数据科学基础知识(Python,数据角力,&模型训练)

对大多数人来说,成为数据科学家的第一步需要学习如何使用代码来访问和操作数据。因为 Python 已经成为行业中最受欢迎的数据科学编码语言,并且代表了满足最大数量的职位空缺的一种技能,所以现阶段的重点应该是创造一个允许个人在数据环境中学习 Python 基础知识的环境。

最简单的平台是 Anaconda,它允许从您的笔记本电脑上最快速地访问 Python,包括公共数据科学库,并且包括基于 GUI 和基于浏览器的 ide。Anaconda 对个人使用也是免费的,因此对于学习数据科学的初级阶段来说,它是最容易访问的数据科学平台。我只希望在我刚开始的时候有人告诉我这些😉

为什么是 Anaconda 而不仅仅是 Python 的基础实现?

当我刚开始学习数据科学时,Anaconda 是全新的,人们对它的全部功能知之甚少。因此,我不得不遵循需要下载 Python 解释器的教程和建议,它也有自己的 IDE,名为 IDLE 。从命令行在 IDLE 和 Python 解释器之间工作很麻烦,经常导致包依赖冲突,并且很少提供可视化体验来快速观察我的代码如何影响我试图处理的数据。

Anaconda 通过帮助执行环境扫描来处理所有这些问题,环境扫描增加了包不冲突的可能性,并且提供了一个虚拟环境库,以防我们需要访问与主环境中安装的现有库冲突的包。尽管虚拟环境超出了本文的范围,但是要了解为什么虚拟环境有用的更多信息,请参阅这里、这里和这里。

此外,Anaconda 还附带了 Spyder 和 Jupyter IDEs。Spyder 对我来说更熟悉,我在学术界使用 SPSS 和 SAS,Jupyter 提供了更丰富的视觉体验,因为它是基于浏览器的,可以利用互联网浏览器的交互功能。

此外,Jupyter 也是最受欢迎的 ide 之一,它与 Sagemaker 和 DataBricks 等企业级数据科学平台相集成。

要点:Anaconda 是开始学习数据科学的最佳环境。我强烈建议学习 Jupyter 和像 Spyder 这样的 ide 的优点,因为它们提供的优点略有不同,正如我提到的,Jupyter 是主要企业数据科学平台的主要 IDE。

最后,Anaconda 预装了几个非常有用和常用的数据科学库,如 Pandas、Scikit-Learn、NLTK 和 Numpy。因此,作为一个学习平台,Anaconda 代表了从您的笔记本电脑开始学习数据科学基础知识的最佳场所之一。

关键时期#2:扩大计算资源以训练“更大”的模型

随着数据科学家学习数据访问、争论和模型训练的基础知识,下一步通常是希望用需要更多计算资源或 GPU 等新计算资源的数据来训练模型,这是用图像或文本训练深度学习模型时经常出现的情况。正是在这一点上,数据科学家认识到 Anaconda 的本地安装受限于他们本地笔记本电脑的处理资源。因此,提升我们的数据科学技能通常也意味着提升我们的计算需求。

正是在这一点上,世界变得更加复杂,可能也更加昂贵,尽管我将分享一些方法来将您的数据科学平台预算保持在最低水平。当然,您可以选择购买一台新的、功能更强大的笔记本电脑,但也有更便宜的替代方案,并且可以学习新技能,这些新技能通常与业务环境中的数据科学需求相重叠。

有几种解决方案允许数据科学家访问比大多数个人笔记本电脑计算能力更强的环境。例如,Google CoLab 提供对基于 Jupyter 笔记本的云环境的免费访问。免费层功能强大,用户可以访问 12 GB 的 RAM 和一个 GPU。在本文发布时,您可以分别以 9.99 美元和 49.99 美元的价格订阅 CoLab Pro 或 Pro+来提升计算能力。

CoLab 的一些限制包括非持久性磁盘,这意味着一旦笔记本电脑关机,数据就会被删除,有限的运行时间取决于订阅级别,以及当重新启动笔记本电脑时,任何新安装的库都需要重新安装。

用于扩展计算资源的其他基于平台的选项包括 AWS Sagemaker、微软 Azure 的 DataBricks 或 IBM 的 Watson Studio。但是请注意,其中每一项都与一些成本相关联,包括租赁虚拟机的成本、利用数据科学平台的成本、将数据存储在 it 可访问的位置的成本,或者以上所有成本。例如,对于 Sagemaker 平台,AWS Sagemaker 没有成本,但是如果您在计算量超过空闲层的虚拟机上启动该服务,您将会产生成本。根据分配给虚拟机的磁盘大小,您还会产生数据存储成本。或者,DataBricks 收取平台使用费,外加租用运行您正在使用的 DataBricks 机器的虚拟机的 Azure 成本。因此,管理实际成本对你来说是一个挑战。

到目前为止,我们一直专注于支持更多计算的平台,但我们注意到,每个平台都抽象出一些用于支持开发人员需求的服务,这对您理解成本带来了一些挑战。

但是平台不一定是你在这个阶段的唯一选择。

出于上述许多原因,我在自己的工作中经常使用的一种替代方法是从云提供商那里租赁自己的虚拟机,并启用远程桌面连接,这样我就可以像在自己的桌面环境中一样在该虚拟机上工作。虽然设置不像上面的平台提供的那样简单,但这确实意味着我的成本更加透明,我可以完全访问 VM 的操作系统,因此可以添加其他有用的软件来满足不同的开发需求,并且我可以学习一些关于网络的知识。

设置好之后,我就可以再次利用 Anaconda 来满足我的大部分开发需求,并且可以控制服务器的大小以及维护它的成本。例如,在 GCP,我可以以 0.067006 美元/小时的价格租用一台带有 2 个虚拟 CPU 和 8GB 内存的虚拟机。如果我选择使用现货虚拟机,成本是价格的 1/3。只要我不忘记在不使用时关闭虚拟机,我就能够控制成本,同时最大限度地访问强大的计算资源。我唯一需要支付的是我的数据的谷歌云存储费用。请注意,云平台也对数据传输收费,每个云提供商对收费有不同的规定,因此请确保监控您的数据传输需求。

如果您有兴趣了解更多关于使用云虚拟机设置自己的数据科学环境的信息,请查看我在这里整理的指南。

总之,使用云提供商构建您自己的虚拟机,同时学习云服务的工作方式,可以为您的数据科学知识增加显著优势,并最终使您对潜在雇主更具吸引力。简而言之,您将获得理解不同服务使用的成本后果的第一手经验。

关键点#3:获得数据科学工作并实现模型需要部署

假设您已经在上述 ide 和平台上进行了最大限度的实验,现在对您的数据科学技能非常有信心,并准备开始申请工作。或者你甚至找到了一份工作。当谈到数据科学的业务应用时,与数据科学平台相关的下一个考虑因素是什么?

在商业环境中,数据科学要产生影响,通常需要“生产化”我在这里的意思是,您的数据科学代码需要从研究和模型实验/培训阶段进入使用模型对新业务数据进行评分的阶段。换句话说,我们需要找出吸收和准备数据的部署选项,然后用我们的模型对数据进行评分,最终将这些结果公开给使用模型结果的下游流程。

正是在这种背景下,我们遇到了快速增长的 MLOps 领域,这是一种 DevOps,但特别适合数据科学任务和模型管理。这也是大多数年轻数据科学家经验最少的领域。这也是数据科学平台具有真正商业价值的地方,因为它们帮助数据科学和 MLOps 团队跟踪他们的实验,并将模型管道部署为计划任务或可按需调用的 API 服务。

无论是哪种情况,Sagemaker 和 DataBricks 等数据科学平台都提供了支持模型管道代码部署的简单工具。但是,每个平台在实现部署方面都有自己的细微差别,并且每个平台都有不同的相关成本。因此,选择一个来学习是不太有用的,除非你为已经使用该平台的公司工作。

如果您发现自己正处于数据科学学习之旅的这一阶段,我强烈建议您更多地关注学习 MLOps 的一些基础知识,例如构建逻辑有序、模块化、遵循良好编码实践并可通过 Github 共享的代码项目。

结论

总之,有几种不同的数据科学平台和 ide 可供年轻的学习数据科学家使用,知道将注意力集中在哪里可能是一个巨大的挑战,因为许多平台甚至提供“免费”的试用版本。请小心,即使平台可能是免费的,平台使用的虚拟机和存储也可能不是免费的。因此,我强烈建议专注于使用 Anaconda 平台构建您的基础,确保同时使用笔记本和 ide 进行实验。这样做可以让你为你可能接触到的平台做好准备,因为你的数据科学爱好会变成数据科学职业。

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

机器学习的有效测试(第三部分)

原文:https://towardsdatascience.com/effective-testing-for-machine-learning-part-iii-7bdb557711ab

测试 ML 系列

机器学习的有效测试(第三部分)

用于开发健壮的 ML 项目的渐进的、逐步的框架

图片作者。

在前两部分(第一部分和第二部分,我们描述了一个框架,通过逐步增加更全面的测试来增加我们项目的健壮性。从冒烟测试到集成测试,我们从一个基本项目过渡到一个确保生成高质量模型的项目。

这最后一部分总结了这个系列,有三个目标:

  1. 定义一个策略来决定每当我们遇到问题时添加什么测试。
  2. 描述加速测试执行的策略。
  3. 为选择开发可测试 ML 管道的工具提供建议。

测试的分类

让我们回顾一下我们在前两部分中介绍的测试类型:

1。集成(数据质量)测试

1.1.检查数据属性(即age列中没有NULL值)。

1.2.分布变化(即,确保我们的目标变量的分布不会发生剧烈变化)。

1.3.模型质量(即检测模型性能的突然下降/上升)。

2。单元测试

2.1 检查训练和服务管道之间的一致性(又名训练-服务偏斜测试)。

2.2 检查数据转换的正确性(给定一些有代表性的输入,测试数据转换的输出)。

2.3.检查模型文件和推理管道的兼容性。

工作流摘要

我们希望我们的测试快速失败,所以我们将首先运行单元测试(训练服务偏斜和数据转换)。如果它们通过了,我们继续运行带有数据样本的管道(集成测试);如果成功,我们使用生成的模型文件,并检查与推理管道的兼容性;我们在下图中描述了完整的流程:

图片作者。

请注意,我们建议每晚对整个数据集重复相同的过程;但是,时间间隔越短越好。

集成与单元测试

一个关键的区别是集成测试依赖于训练数据,因为它们评估其质量。相反,单元测试不会,因为它们评估我们代码的正确性。因此,我们可以用几个有代表性的例子来检验它们。

这种对训练数据的依赖对定义我们的测试策略有影响。理想情况下,我们希望我们的集成测试检查我们的整个数据集。然而,这是不可行的,所以我们求助于随机抽样(比如 1%)来快速测试数据质量。虽然有效,但这种随机抽样方法只是我们在整个数据集上测试所得的近似值。

另一方面,由于单元测试依赖于我们的训练数据,我们可以使用一些有代表性的输入进行测试;因此,预期的运行时间应该很短(不超过几分钟)。此外,由于单元测试运行速度很快,它们应该是您测试的第一件事,所以如果单元测试有问题,您不必运行昂贵的集成测试。

因此,总的来说,我们应该把测试套件(带有随机样本的集成测试和单元测试)的运行时间控制在 20 分钟以内。

现在让我们描述一个策略,当我们遇到一个错误的时候,决定执行什么测试。

未来测试的策略

我们的策略取决于具体情况;让我们来看看每一个:

当集成测试崩溃时

数据属性

假设数据属性失败(例如,一列突然有了NULL值)。在这种情况下,有两个选择:更新您的代码以过滤掉违规的记录(这将导致测试通过),或者放松测试(例如,删除测试以允许NULL值,或者允许某个百分比)。决定将取决于你的用例:也许你决定做数据插补,所以你决定允许一些NULL值;另一方面,您可能确定您不能估算数据,在这种情况下,更新代码以过滤掉违规记录。

分布变化

如果数据分布发生变化,您必须确定这种差异是由于数据生成过程中的实际变化,还是由于某些数据接收或数据转换错误。例如,假设您发现了age列中的差异:中位数age是 25,现在是 40。可能是目标人群变老了,你现在必须更新你的参考值。另一方面,也可能是上游数据转换发生了变化,它传递了您不应该使用的记录;如果是这种情况,您可能需要检查上游流程,以过滤掉改变数据分布的新记录。

模型质量

一旦你在生产中有了第一个模型,改进通常是小幅度的。因此,每当模型质量出现显著下降或上升时,调查它是很重要的。正如本系列的第二部分所提到的,您需要一个基准模型来评估当前模型的质量;这通常是生产中的当前模型。

性能的突然下降意味着丢失了一些集成测试(因为集成测试应该在进入模型训练任务之前检测低质量的数据)。相比之下,性能的突然显著提升可能表明存在泄漏等问题。

如果您的模型性能比基准差得多,请比较用于训练当前模型和基准的代码,以确定发生了什么变化(例如,删除了某个特征,更改了超参数)。另一方面,如果模型的性能比基准测试好得多,检查代码变更并确保没有任何问题,比如泄漏。如果您没有发现任何问题,那么恭喜您,您刚刚使您的模型变得更好了!接受变更并更新基准指标。

如果您在调查后发现培训管道有问题,请将其转化为集成测试。例如,如果您的模型变得更差,因为您在具有NULL值的列上对其进行了训练,那么为其添加一个集成测试。添加测试后,修复管道,并确保更改修复了性能问题。

请注意,我们建议使用数据样本在每个git push上测试您的管道,以使其切实可行;然而,这意味着输出训练集将变得更小,使得评估性能变得更具挑战性。如果可能的话,根据在相同样本大小上训练的基准模型,评估在数据样本上训练的模型的性能。然而,如果这样做很有挑战性(例如,不同实验之间的性能差异太大),您可能会决定只在夜间运行模型质量测试。

当单元测试失败时

训练-发球偏斜

如果您的训练-服务偏斜测试失败,比较您的训练和服务管道的输出,直到您发现结果不同的第一步。一旦您发现了问题,修复它并继续运行测试,直到它通过所有的样本输入。这种一步一步的调试过程是我们需要构建模块化管道的原因:如果我们在单个笔记本/脚本中编写整个项目,将很难发现这些问题。

例如,下图显示了以不同方式处理输入的管道(它们生成不同的特征向量)。因此,一旦您检测到问题,请向后检查输出,直到您发现差异为止;在这种情况下,问题在于Process input A步骤,因为它在训练(2)和发球时间(10)产生不同的结果。

图片作者。

数据转换

如果一个数据转换(通常是一个单一的函数)测试失败了,那一定是由于转换的源代码发生了变化。有时,我们在优化一个转换时会犯错误(例如,为了更有效地利用内存),单元测试允许我们检测它们。然而,其他时候,我们可能会改变转换的行为。因此,单元测试中的输入样本将不再具有代表性。在任何情况下,都要确保确定哪种场景适合您,并修复源代码或更改示例输入。

请记住,您的单元测试应该是不断发展的。因此,每当您发现一个边缘案例时,确保您添加了一个新的输入测试案例:单元测试应该覆盖您的转换应该考虑的所有代表性的输入案例。

模型文件和推理管道

您的推理管道捕获将原始数据转换为模型用作输入的特征向量所需的预处理逻辑;这两个元素可能会不同步。例如,你可能有一个特征训练的模型文件[A, B, C](按此顺序)。尽管如此,如果您最近更新了您的推理逻辑,它可能会以不同的顺序生成要素(比如说,[C, B, A]),这会中断您的推理过程。您通常可以通过使用相同的 git 提交生成模型文件来修复模型文件和推理管道之间的不兼容性;然而,有必要运行这个测试,以确保您不会部署不兼容的工件。

加速测试

单元测试应该运行得很快(几分钟),因为它们是用几个有代表性的输入运行的。然而,快速运行集成测试是具有挑战性的,因为它们依赖于训练数据。为了有助于这一点,我们用随机样本运行训练管道;但是,这可能无法检测出整个数据集中存在的问题。

例如,如果我们测试数据属性,比如没有NULL值,如果我们用 1%的数据对整个数据集进行测试,测试结果可能会改变。分发也受到影响;用较小的样本进行测试会增加假阳性的变化(在没有差异的情况下检测到差异)。此外,用数据样本评估模型性能几乎肯定会给出一个度量更差的模型。

为了平衡运行时间和测试健壮性,我建议如下:用最广泛的数据样本运行集成测试,这仍然给你一个合理的测试运行时间(我认为不超过 20 分钟)。最重要的是,尽可能频繁地安排完整数据集的运行。例如,如果使用整个数据集端到端地运行培训管道需要 2-3 个小时,则可以在夜间运行。

最重要的是,您可以利用增量构建:假设您已经计算并存储了来自管道的所有结果;如果只改变最后一步,就不需要从头重新运行一切。因此,相反,只执行自上次运行以来源代码已经更改的步骤。不幸的是,并不是所有的管道框架都支持这一点(但是 Ploomber 支持!).然而,增量构建极大地加快了开发和测试的速度。

处理昂贵的培训程序

在某些情况下,训练过程可能需要很长时间才能完成(例如,深度神经网络)。如果是这种情况,您可以使用代理模型进行测试(例如,如果您的神经网络有十个隐藏层,则使用其中三个的代理模型)。如果你的训练数据有问题,很有可能代理模型也会表现出较低的性能。

选择正确的工具

当测试我的 ML 项目时,我发现最大的挑战之一是缺少合适的工具。我们设计了 Ploomber 来支持这个测试工作流程(所以我们强烈建议您尝试一下!),但是这里有一些选择框架时的一般建议。

本地执行

通常,被设计成分布式运行的框架(例如,在 Kubernetes 上)没有在单节点环境中执行管道的简单方法;依赖外部基础设施使测试变得复杂。因此,最好使用允许您在单节点环境中运行代码的框架。测试应该像启动一台机器并调用:

可输入管道

测试需要一些配置和准备;例如,您可能需要创建一个临时目录来运行带有示例的管道。像 pytest 这样的测试框架允许你这么做。测试的典型结构是这样的:

要使用测试框架,您应该能够使用 Python 导入和运行您的管道,因此确保您将使用的库允许您这样做。测试可能是这样的:

参数化

您的培训管道必须公开参数,以允许您使用不同的配置运行它们。测试时,您希望使用数据样本运行测试,并将任何结果存储在单独的文件夹中,以防止覆盖您的结果,因此请确保您使用的框架允许您对管道进行参数化:

最后的想法

测试 ML 管道是一项艰巨的任务:大型数据集和长训练周期为确保测试在合理的时间内运行带来了巨大的挑战。然而,简单的测试策略,比如冒烟测试和用小的随机样本进行测试是有回报的,所以确保你实现了那些基本的策略,并且随着你的项目的成熟而转向更高级的策略。

开发可测试项目的一个基本要求是模块化您的工作。在单个文件中包含整个数据处理逻辑的单块笔记本是测试和维护的噩梦,所以请确保您使用的框架允许您将逻辑分解为小步骤,以便您可以单独测试每个步骤。

我作为数据科学家的经历启发了这些指南;然而,这是一个不断发展的领域,所以如果你有任何问题或者想聊聊关于 ML 测试的所有事情,加入我们的社区!

发现错误?点击这里让我们知道。

最初发布于ploomber . io

有效平衡客户和数据科学家之间的产品需求

原文:https://towardsdatascience.com/effectively-balance-the-product-needs-between-client-and-data-scientist-5cab9a7639ec

意见

共同管理如何帮助您的项目

照片由 Unsplash 上的 Aziz Acharki 拍摄

在项目管理中,有一个被称为合作经理模型的概念,它为客户和技术团队提供了管理项目的同等权力和责任。这意味着技术产品经理必须愿意与客户产品经理分担项目的责任。有了这些,花点时间思考一下,如果我的团队是数据科学/技术产品团队,那么谁是我的客户端产品团队?

在之前的一个角色中,我在一个客户的技术团队中工作,该客户了解如何进行数据分析,但需要一个技术团队来开发机器学习和分析,以推动他们的仪表板。为了管理这种约定,在运行项目时,在技术联合经理和客户联合经理之间形成平衡变得至关重要。我们的最终目标是为设备运行状况管理制作仪表盘,显示哪些设备存在高问题风险,哪些设备与可接受的设备相比需要关注。

为了处理这两个团队之间的联系,每周,我们都通过电话讨论项目状态、后续步骤和演示。开始时,会议双方关系紧张。客户觉得他们没有从产品中得到他们期望的东西,而技术团队觉得他们达到了他们的目标。当团队要求对正在完成的工作进行反馈时,这种冲突导致缺乏充分的参与。在认识到这些问题的几个月内,我们授权客户的产品经理在项目中承担更多的责任,并开始根据他们的业务案例和他们期望的结果做出决策。

我们通过分解我们的技术工作和术语方面的挑战来做到这一点,这些术语可能与客户的设备健康监控有关。本质上,我们遵循了可解释人工智能的四个原则:

知识 限制:系统仅在其设计条件下运行,或者当系统对其输出达到足够的置信度时运行。

我们创建的控制面板仅适用于特定的设备子集,分析师正在研究这些设备的运行状况管理。这缩小了项目范围,允许我们在已知的条件下操作来创建我们的模型。这项工作是事先商定的;我们只需要对客户所要求的这些条件进行解释。

解释:系统为所有输出提供附带的证据或理由。

我们创建了仪表板,显示关于模型如何到达的足够多的细节,以得出设备是否健康的结论。我们允许分析师向下点击底层数据,以查看维护活动用于达成模型的决策。通过允许分析师向下点击底层数据,他们得到了支持模型输出所需的证据。这些数据为他们看到的输出提供了解释。

有意义的:系统提供个人用户可以理解的解释。

允许分析师看到基础数据以及模型对健康状况好坏的预测是好的,但它需要对客户有意义。结合起来,不同屏幕的 UI 易于导航,每个级别都以分析师的术语向他们提供了详细的解释,说明分析是如何形成的,以及他们如何理解该输出以做出关于设备分组的决策。

说明 精度:说明正确反映了系统产生输出的过程。

伴随着解释和意义而来的是对准确性的需求。一旦我们产生了这些输出,我们就在每周的电话中演示结果。正是在这些演示中,客户反馈变得很重要。通过他们的领域专业知识和我们的模型,我们可以评估结果的准确性,并根据客户对他们所见的反应做出改变。此外,我们将他们的手动分析重新创建为可解释的机器学习模型,以提高生产率。他们对我们的建模理解得越多,反馈就变得越好,因为他们可以根据他们的领域知识提供特性请求和改进。此外,它允许团队之间更好的协作,以提高仪表板输出的整体可解释性。

在合同进行到一半时,我们的客户更好地理解了所展示的仪表板演示,以及它们背后的算法是如何做出决策的。通过更好的解释和沟通,我们可以使用客户的语言建立一个开放和诚实的沟通渠道。这种变化意味着客户对项目的方向承担了更多的责任,并提供了有价值的反馈,告诉他们什么工作符合他们的预期,什么工作不符合他们的预期。既然客户理解了我们所展示的内容,他们就可以根据他们的行业领域知识和经验提供意见。这个反馈允许我们产生一个实用的解决方案,为使用仪表板的分析师创造预期的业务价值。这种变化也使团队能够积极地参与所有的决策和需求变更,以实现这些目标。

最终想法

数据科学家经常与业务分析师和客户密切合作,他们需要了解他们的工作以及工作对他们的影响。有了这个,团队需要确保客户处于最佳位置,以创建有益于项目的有意义和及时的决策。通过用客户的语言解释您的数据科学流程,并确保他们理解您的算法如何预测事件,可以促进这些行动。通过提供所有这些信息,您可以帮助您的客户做出决策,并拥有他们所支持的产品。此外,它为两个团队创建了一定程度的所有权,并允许他们感觉他们为路线图的成功做出了贡献。

感谢阅读!我希望你喜欢阅读我所学到的东西。如果你愿意,你可以通过这个链接成为一名灵媒来支持我的写作。

有效界定数据科学的范围,并向决策者传达数据科学

原文:https://towardsdatascience.com/effectively-scoping-and-communicating-data-science-to-decision-makers-ab5a2bdc0e65

因为首席执行官不想看你的笔记本

在 Unsplash 上由 Carlos Muza 拍摄的照片

Metis 的数据科学和机器学习训练营的模块 3 已经结束了!对于这一部分,我们稍微改变了一些事情——从一个月的不间断编码中(相对)休息了一下,专注于业务基础、,它概述了我们将在其中实践新技能的专业环境,以及如何最好地将数据产生的见解传达给非技术利益相关者和决策者。

我们都是销售人员

十年来,我大部分时间都在从事面向客户的工作,因此对这类对话并不陌生。作为从云提供商到政治顾问和社交媒体平台等公司的销售人员和客户经理,我最基本的工作是找到潜在公司的决策者并与之联系,帮助他们了解我的产品如何帮助他们解决问题。在销售中,我们把这个向潜在客户推销的过程称为 制定价值主张的过程称为

虽然阐明产品的价值主张是成功销售的一个重要部分,但仅仅证明你的产品具有实用性并不足以促使决策者购买。顾客(像所有人类一样)主要是利己的生物。当你推销时,他们想知道一件事: **我有什么好处?**或者, **WIIFM ,**如果你喜欢缩写的话。

您如何为您的客户缓解一些棘手问题?让他们在老板面前看起来像摇滚明星?节省他们的时间?钱?减轻他们的工作量?这些是真正激励人们购买你的产品的东西。不仅仅是效用。

照片由 Cytonn 摄影在 Unsplash 上拍摄

作为数据从业者,同样的原则也适用。我们的客户是我们的利益相关者。利益相关者可以采取多种形式。你的利益相关者可能是你的咨询公司客户的主要联系人,一个寻找关于新功能的用户数据的产品经理,或者是你公司的销售负责人,他想要了解客户流失的情况。

无论我们在做什么项目,都需要用它能为我们的利益相关者提供的价值来表达,如果我们希望我们的提议“投入生产”,我们提供的见解或建议需要用它们可能带来的潜在利益来表达。

让我们回到销售主管的例子来做一个恰当的说明:为了帮助减少客户流失,你建立了一个逻辑回归模型,将客户标记为“流失”或“不流失”。该模型的准确率为 95.3%。太神奇了!但这个指标对销售主管来说毫无意义。他们想知道如何将这种模式应用于减少客户流失的问题。

完美不是在没有什么可以添加的时候,而是在没有什么可以拿走的时候

——安托万·德·圣埃克苏佩里

作为数据从业者,我们经常迷失在我们所做工作的技术细节中。当你大量生产可视化产品,用特征工程提高模型的准确性时,很难把它放回业务影响的环境中。但是,如果我们想说服我们的利益相关者接受我们的想法,我们需要超越评估指标和可视化,并考虑我们的发现如何在实际意义上影响业务成果。为了取得成功,我们需要既有完成工作的技术诀窍,又有以简洁、易懂、与利益相关者需求相关且禁止性的方式提出我们的想法所需的整体商业敏锐度。

品牌&人在 Unsplash 上拍照

剖析成功的数据科学项目:项目范围界定

识别

交付成功的数据科学项目的第一步是确定一个已经成熟的问题或解决机会。在识别问题时,请记住以下一些想法:

  1. 从问题中前进,而不是从解决方案中后退
  2. 从利益相关的各种团队/观点中征求意见。
  3. 想法应该以影响为中心,而不是以数据科学为中心。
  4. 产生许多想法,质量不是这里的衡量标准。

成功项目的下一步是获得决策者的认可。要做到这一点,我们需要采纳我们在识别步骤中产生的想法,并对它们做一些初步的范围界定。这意味着清楚地阐明问题/机会、解决这些问题的潜在商业影响,以及与将资源投入特定想法相关的后勤/风险/陷阱。

一旦我们收集了已经确定范围的想法,就该向我们的决策者推销了!当我们关注可能性时,推销项目想法应该是一个令人兴奋的时刻。在推销过程中,一些想法可能会有明显的问题,但我们应该在推销时努力保持乐观。这个过程的下一步**,**是这些问题得到解决的时候。

筛选是指决策者将我们的初步想法清单削减成那些应该彻底探索的想法。我们的最终清单应该包括雄心勃勃的、乏味的、但潜在影响大的、具有战略重要性的想法。根据您的组织,数据科学家在流程的这一部分可能有很多、很少或根本没有发言权。

范围

照片由杰森·古德曼在 Unsplash 上拍摄

有了我们新精简的想法列表,我们需要进行第二轮更彻底的范围界定。本次范围界定分为三个部分:

  1. 非技术范围界定
  2. 技术范围界定
  3. 协作范围界定

非技术范围主要关注我们问题的战略方面:

  • 障碍、机会或业务需求是什么?(例如,减少客户流失)
  • 解决这个问题的潜在影响是什么?
  • 这个想法的内部利益相关者是谁?外在?
  • 这个想法会面临什么限制?

技术范围是数据科学家熟悉的流程。在这里,我们想:

  • 定义潜在的解决方案路径(例如,预测客户是否会流失的分类模型)
  • 确定哪些数据是理想的,哪些数据是现实可用的?

协作范围界定是非技术范围界定和技术范围界定的结合,带有少量业务战略。这里,我们的目标是综合前两次范围界定会议的要点,并提出一个影响假设。

  • **业务需求:**减少客户流失。
  • **数据科学目标:**使用分类模型预测客户流失。
  • **影响假设:**通过外联、激励和促销来锁定潜在的流失客户,将会减少流失的数量。

除了定义我们的影响假设,协作范围界定还应该实现其他几个目标:

  • 定义当前状态(例如,没有采取任何措施来预测或防止客户流失)
  • 定义期望的业务成果(例如减少 X%的流失率)
  • 确定在项目期间应该探索的未知因素(例如,为什么客户会流失?)
  • 定义我们的项目将告知的行动(例如,营销部门将向被确定为潜在客户的客户发送促销信息)
  • 概述促进上述行动所需的技术后勤
  • 在项目时间线上对齐
  • 识别/量化项目的成功和失败
  • 定义数据科学解决方案的成功指标(例如,正确识别 70%以上的老客户)
  • 定义业务成果的成功指标(例如,预期节省 X 到 Y 美元,否则会因流失而损失)
  • 定义确认项目成功/失败的流程

活动发起人在 Unsplash 上的照片

剖析一个成功的数据科学项目:交流结果

一旦我们彻底地确定了项目的范围,完成了产生可交付成果所需的工作,项目最关键的部分就在眼前了:交流结果。

如果我们希望我们的工作有真正的影响,我们需要把我们投入的时间浓缩成一个容易理解的演示文稿。这绝非易事!也许我在这里只是为自己说话,但我喜欢上下文。我很难有效地沟通,因为我想深入工作的每一个细节,在这个过程中失去了我的观众。

最好的数据科学传播者将他们的受众从枯燥中抽象出来,只使用要点讲述一个引人注目的故事。在太少和太多的细节之间找到正确的平衡是很难掌握的,但是有一些最佳实践可以帮助指导你的思考。

观众

最好的演示是为他们的观众量身定制的,所以这是一个很好的开始:你将向谁展示你的发现?作为一名销售人员,了解你的潜在客户/客户是至关重要的。这里也没什么不同。请考虑以下情况:

  • 年龄、教育程度、宗教信仰等个人特征。
  • 角色、技术性、资历、决策权等职业特征。
  • 主题领域的专业水平

内容

一旦你对你的受众有了充分的了解,就该开始整理你的内容了。一般来说,在传达结果时,您应该包括以下内容:

  • 简介(动机、目标和目的)
  • 方法(数据、模型、指标和工具)
  • 结果(误差指标、预测、图表)
  • 结论(建议和见解)
  • 未来工作(如果你有更多的时间,你会做什么?)
  • 附录(其他所有内容)

就演示本身而言,最好记住以下几点:

  • 练习良好的公开演讲技巧
  • 了解内容并预测问题
  • 排练并在时间限制内控制自己
  • 乐观积极!
  • 保持简短(亲吻)
  • 留给你的听众不超过 3 个要点

带 Tableau 的示例项目

对于 Metis 训练营的第三个模块,我们的项目更加开放。目标是确定一个假设客户的业务需求,使用上述流程确定项目范围以解决他们的问题,并使用演示最佳实践交流项目的初始工作,着眼于后续步骤。

凯尔·格伦在 Unsplash 上的照片

我为我的客户**选择了 AirBnB 。**我想通过提出主机价格优化功能来帮助 AirBnB 增加平台参与度,作为我的可交付成果,我想对纽约市 AirBnB 房源的公开数据集进行 EDA,以确定最容易预测价格的变量,并就应该进一步探索的问题提出建议。

为了让这个项目更有趣,我们不得不使用 Python 之外的工具。这意味着 Excel、Google Sheets 和 Tableau 的某种组合。

Tableau 是企业数据可视化解决方案领域无可争议的领导者,也是各地高管和决策者的最爱。出于这些原因,我挑战自己去做我大部分的工作,包括用故事来搭建我的展示。

取决于你想做什么,Tableau 要么非常简单,要么不必要的难操作。我在整合这个项目的过程中经历了这两种情况,但我肯定会建议任何有抱负的数据专业人士花时间下载 Tableau Public,并对这种无处不在的工具有一个基本的了解。它可能非常强大,有时甚至很有趣!

使用 Tableau 作为我的演示媒介的另一个好处是它是交互式的,并且可以发布到互联网上。这意味着,如果 AirBnB 的团队想要参考我的项目,他们可以找到它,并在自己的时间里深入研究这些见解。就像你们一样!

查看下面的仪表板截图(非常小),你可以看到演示文稿,所有独立的可视化,并在这里下载整个公共工作簿。你也可以在这里抓取 GitHub 回购。好好享受,下次再见!

(图片由作者提供)

熊猫的高效数据操作

原文:https://towardsdatascience.com/efficient-data-manipulation-with-pandas-2cbc4e3824f9

停止用传统的方式使用熊猫,用“管道”代替

学习在熊猫中使用管道进行数据操作

资料来源:Unsplash,Lars Kienle

我们都在用熊猫。它是几乎每个使用 python 的分析师的首选工具。我们中的许多人已经掌握了数据处理的艺术。我对我所知道的关于熊猫的知识和我应用知识的方式非常满意,直到我看到了马特·哈里森写的一本书。这本书改变了我熊猫的生活。我觉得我一直以来都被背叛了😅在这篇文章中,我将分享几件我学到并立即爱上它们的事情。让我们开始吧。

一些我们喜欢的任务

在操作数据时,我们通常使用以下操作:

1️⃣:列选择
2️⃣:过滤数据
3️⃣:更改列
4️⃣:创建新列
5️⃣:应用自定义函数
6️⃣:聚合数据
7️⃣:连接数据
8️⃣:可视化数据

这绝对不是一个完整的列表,但现在足够了。你一定注意到了上面任务中的等级。通常,我们以有序的方式应用这些任务。到目前为止一切顺利。然而,我们通常倾向于单独执行这些任务,即使您将这些任务放在一个函数中。我们缺少的是“管道”。

“管道”的目的是将这些任务缝合在一起,并以一种内存高效的方式计算它们。这本身就是一个巨大的优势。然而,对我来说,管道最大的好处是代码的“可读性”。那么这个“管道”是什么呢?

最后有一个完整的可复制的代码示例。只需浏览流程的虚拟代码片段(灰色的)。

管道

要构建管道,您实际上不必去任何其他特定的库。我们可以通过将数据帧包装在一个元组中来开始使用管道,就像这样:

import pandas as pd# read the data
df = read_csv("some_data.csv")
# make a pipeline
( 
  df
)

如果您执行代码,这将显示df数据帧。没什么特别的。然而,这就是乐趣的开始。在圆括号内,在df下面,你可以开始调用所有你喜欢的方法,一个接一个,按照你想要的顺序。让我们试一试。

(
  df
  # select few columns
  [['column_a','column_b','column_c']]
  # filter the data where column_a's values are green & blue
  .query(" column_a == ['green','blue']")
  # check the first 5 rows of the data
  .head())

如果运行此代码,您将看到数据框的前五行,共三列,包含“column_a”值为“绿色”或“蓝色”的记录。这正是你点的。但是,如果我们运行并检查df,我们会发现df什么都没有发生,我们所做的所有更改都应用到内存中,并与df分开保存。太棒了😮。这种方法的一些好处是:

👉:代码可读性很强
👉:代码灵活,更改非常容易实现
👉:我们不需要创建修改数据帧的单独引用
👉:内存效率高
👉:原始数据帧保持不变

它是如何工作的

圆括号中的每一行都是管道中的一个“步骤”。流水线的第一步必须是数据帧。每一步都必须从单独的一行开始。你走的每一步都需要一个数据框架方法,比如.head() .query() .tail() .merge()等。每一步的输出都成为下一步的输入。在我们的例子中,步骤[['column_a','coumn_b'm'column_c']]的输出是包含三列的数据帧。这成为过滤数据的.query()步骤的输入。过滤后的数据成为.head()步骤的输入,最后的输出显示给用户。

重要的是保持这一势头。我的意思是,我们应该避免在第一步之后使用数据框的名称。例如,您想要对现有的列进行更改。我将使用.assign()方法,这是创建或更改现有列的方法。

这是你应该而不是做的:

(
df 
# apply a filter
.query("column_a == ['green','blue']")
# make a change to column_a
.assign(column_a = df['column_b'])
)

通过引用.assign()步骤中的df['column_b],我们实际上是在引用回df的原始状态(即它在第一步时的状态),这是我们不想要的。我们想要的是仅在我们将过滤器应用到column_a(过滤数据的.query()步骤的输出)之后改变column_a。为了做到这一点,我们将在assign()步骤中使用一个函数(比如 lambda)。这就是我们应该做的:

(
df 
# apply a filter
.query("column_a == ['green','blue']")
# make a change to column_a
.assign(column_a = lambda x: x['column_b])
)

在这种情况下,lambda 函数中的参数x引用的是.query()步骤的输出,而不是原来的df,正如我们所希望的那样。

最后一部分

在我们进行最后一个可重复的例子之前,我需要向您介绍一个重要的方法,.pipe()方法。如果您想要应用熊猫数据框固有的不可用方法(如自定义函数),此方法非常有用。.pipe()方法接受一个函数和该函数的参数。函数的第一个参数应该是数据框。函数的输出也应该是数据框。让我们看一个例子:

# define a custom function, first argument as a df. Function
# returns a df.
def some_function(df:pd.DataFrame,column_name:str)->pd.DataFrame:
  new_df = df[column_name]*4/df[column_name]^3
  return new_df# start the pipeline
(
  df
  .pipe(somefunction,"column_c")
  .head()
)

简而言之,.pipe()将帮助我们部署任何我们想要应用于我们的数据框架的定制解决方案/功能。

总结

Pandas piping 是一种优秀的、节省内存的方式,可以为数据操作编写清晰可读的代码。它简单直观。您还可以将最终输出分配给另一个变量,例如

df_1 = (
         df
         .query("column_a == 'blue'")
         )

我们也可以把管道包装成一个函数,然后一直使用函数进行重复使用。

最后,这里有一个可重复的代码,您可以使用它来进一步挖掘和实践。

作者代码

➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖
可以在 上关注我 &在LinkedIn&上联系我访问我的 GitHub ➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖

您可能还对以下内容感兴趣:

👉Docker
让您的数据科学生活变得简单👉使用 PyCaret 的自定义估算器,第 1 部分
👉使用 PyCaret 的自定义估算器,第 2 部分
👉轻松获得 Windows 内部的 Linux
👉使用 PyCaret 进行多重处理

高效的广义球形细胞神经网络

原文:https://towardsdatascience.com/efficient-generalized-spherical-cnns-1493426362ca

混合旋转等变球形 CNN

球形卷积的概念为释放深度学习的潜力提供了一条有前途的途径,以解决球形数据普遍存在的各种问题。然而,非线性的引入是一个挑战。在本帖中,我们将探索如何应用量子物理学中的思想来克服这一障碍。我们介绍了在实践中有效实现这些想法的新方法。(进一步的细节可以在我们相关的 ICLR 论文中找到关于 高效广义球形 CNN)。)

这篇博文由来自 Kagenova 的奥利弗·科布和奥古斯丁·马沃-帕克共同撰写。

照片由哈尔·盖特伍德在 Unsplash 上拍摄

任何跨越计算机视觉和自然科学的问题都需要对球形数据进行分析。通常,当模拟球形数据时,我们希望处理特征的方式不依赖于特征在球体上的取向。遵守这一原则的模型被称为旋转等变。通过只考虑满足该属性的模型,学习可以更有效地进行,正如在之前的帖子中所讨论的。

球面和旋转群上的卷积概念可用于构建球面数据的可学习的、线性和旋转等变变换。这些卷积的概念,当与一个非线性和旋转等变变换配对时,可以被顺序地应用以分级地学习球形数据的特征。

球体和旋转组上的信号

球体和旋转组上的信号可表示为谐波系数的集合,描述它们如何由一组谐波基信号组成(见下图)。

球体上的信号可以分解成球谐 Yˡₘ(ω).的线性组合ℓ = 0,1,2,…的每一度都有 2ℓ+1 谐波[图片来自维基共享资源。]

当以谐波形式表示时,球体和旋转群上的信号旋转以及它们之间的卷积具有相似的形式。

这种共享形式包括将谐波系数收集到矢量中。特别地,对于每个谐波模式ℓ,相应的系数被收集到矢量中,

t 索引不同的向量。旋转(通过ρ)可以通过线性变换向量来实现,如下所示

其中 D 被称为ρ的维格纳 D 矩阵表示。与可学习滤波器的卷积可以通过以下方式在每个谐波模式内采用可学习的向量线性组合来实现

广义信号

球体上的信号只需要一个矢量

而旋转组上的信号需要

然而,根据 Kondor 等人(2018),我们可以考虑更一般的集合,每个模式对应任意数量的向量。尽管该集合可能不再被解释为球体或旋转群上的信号,但它仍可以以完全相同的旋转等变方式进行旋转和卷积。这样的集合因此被称为广义(可旋转)信号,如下图所示。

广义球形信号的一个例子。当信号每度仅包含一个向量时,在球体上存在相应的信号。然而,在广义框架内,每度允许任意数量的向量。这里我们取了(2,1,3,2,0,0,…)。【原创人物由作者创作。]

为什么要一概而论?

卷积的概念提供了一种以可学习的、线性的和旋转等变的方式变换广义信号的方法。然而,为了顺序地应用这种变换并分层地学习复杂的特征,我们还必须在连续的线性变换之间非线性地变换信号。

对于限于球体或旋转组上的解释的信号,可以通过获得相应的基于样本的表示并应用样本方式的非线性函数,以近似旋转等变的方式引入非线性(如前一篇文章中进一步讨论的)。这类似于在平面 CNN 中如何逐点应用非线性。然而,与保持平移等变的平面情况相反,不能以统一的方式对球体或旋转组进行采样意味着在球体上应用非线性采样方式不是严格的旋转等变的。不仅旋转等方差只是近似的,而且转换到基于样本的表示和转换回来是一个昂贵的过程。

然而,还有一种引入非线性的替代方法,它直接作用于我们基于矢量集合的表示,同时保持精确的旋转等方差!Kondor 等人(2018)提出的关键思想如下。

是广义信号中的两个矢量。如果我们拿外面的产品

在两个向量之间,并投影合成结果

使用非常特殊的线性投影将维向量转换为 2ℓ+1 维空间,整个过程是旋转等变的(见下图)。这不是偶然的。线性投影是经过仔细选择的,因此这是正确的(更确切地说,它涉及如何分解张量积群表示),并且可以用 3D 张量来描述

的克莱布什-戈丹系数。当处理旋转对称的类似概念时,特别是在耦合角动量时,克莱布什-戈丹系数也被用于量子力学。

输入信号的两个组成向量如何组合形成输出的一个组成向量的例子。对于每一对输入向量,计算各种程度的输出向量。【作者创作的原创人物。]

这提出了一种非线性变换广义信号的方法:

对所有ℓ度执行此程序,并收集合成矢量,每个矢量可表示为

变成一个新的广义信号。因为每个输出向量是输入的旋转等变变换,因为克莱布什-戈丹系数满足

和旋转可以通过它如何变换各个向量来描述,但是广义信号的这种整体变换也是旋转等变的。此外,我们看到它是非线性的,因为外积在输入和输出之间引入了二次关系。

广义球形 CNN

有了以旋转等变方式对广义信号进行线性和非线性变换的方法,可以构建广义球形 CNN(Kondor 等人,2020)。

与通常 CNN 形成由卷积和非线性组成的层的惯例的唯一区别在于,在广义层中,基于外积的非线性应该在卷积之前应用。这是因为收集每一度的所有外积大大增加了信号中包含的向量的数量。通过在非线性之后执行卷积,它可以被用于向下投影到合理大小的表示上。

如果我们考虑采用线性→非线性→线性形式的稍微更一般的层,我们也将科恩等人(2018)和埃斯特韦斯等人(2018)的球形 CNN 构造包含在这个广义球形 CNN 框架内(科布等人,2021)。此外,我们可以在混合模型中利用这些不同的方法,如下图所示。

包含我们开发的高效层的混合体系结构示意图,这些层与𝕊和 SO(3)层结合在一个网络中。【原创人物由作者创作。]

利用基于外积的非线性的一般化层的问题在于,每度输出的向量数量与每度输入信号的向量数量成二次方比例,并且成五次方比例(5 次方!)就最大程度而言。虽然可以使用卷积进行向下投影到合理的大小,但是这样做需要大量的参数,并且没有首先解决计算所有这些向量的成本。作为合理分辨率(最大程度)和表示能力(每度向量)的非线性转换广义信号的一种方式,需要一些修改,这是我们在高效广义球形 CNN工作的重点(Cobb 等人 2020)。

高效的广义球形细胞神经网络

首先,我们引入一个通道式结构(见下图)。在 Kondor 等人(2018)的框架内,假设单独的向量包含单独通道的角色,因此网络内的表示采用一个大向量集合的形式。相反,如果我们将集合分成单独的通道(每个通道都有自己的广义信号),并将基于外积的非线性分别应用于每个通道,则需要计算的片段数量会大大减少(减少了所考虑的通道数量的一个因子)。

通过使用逐通道张量积,高效的广义球形 CNN 层减少了片段计算的计算足迹。【原创人物由作者创作。]

其次,我们将卷积分解为三个独立的步骤,这只有在采用通道式结构时才有可能。回想一下,卷积对应于对每个度数分别采用输入向量的线性组合。在我们的三步法中,第一步是收缩步骤,分别对每个通道进行相同的线性组合。第二步采用每个通道内的线性组合,第三步采用跨通道的线性组合。通过在收缩步骤之后执行后两个步骤,可以更有效地学习有意义的特征。

第三,我们注意到没有必要计算所有可能的输入向量对之间的外积来引入非线性。我们可以只计算一个子集,程序保持旋转等变。然而,重要的是选择子集,使得信息仍然混合在不同的谐波阶数之间。可以采用基于计算图的方法,该方法将实现给定混合量的最低成本子集标识为对应于最小生成树的边,如下图所示。

度混合集的图表示。【原创人物由作者创作。]

最后,对于依赖于基于样本的数据表示的操作,我们在球体和旋转组上采用最佳采样方案(McEwen & Wiaux 2011,McEwen 等人 2015)和相应的谐波变换,这进一步提高了效率。

实验

在广义球形 CNN 的层内进行这些修改允许我们训练比其他可能方式更具表达力的模型。我们在两个现实世界的问题上展示了这些有效层的性能,这两个问题乍看起来不一定是固有的球形问题。然而,对于这些问题,尊重旋转对称性是重要的,因此球形 CNN 可以被有效地利用。

三维形状分类

我们考虑的第一个问题是对 3D 对象的网格进行分类,如下所示。

我们的网络分类的 3D 对象类型的一个例子。[ 来源于维基共享资源的 3D 模型。]

乍一看,这似乎不是一个球面问题。然而,我们希望尊重旋转对称:网格的预测类别不应该取决于它的方向。因此,可以获得物体网格的球形表示(通过从边界球的光线投射),并且球形 CNN 可以应用到很大的效果。

我们利用类似于上面所示的混合架构。相对于以前的球形 CNN 结构,这实现了优异的性能,实现了五个性能指标中最高的三个(用于SHREC’17 竞赛的基于精度和召回的指标),同时使用了明显更少的参数。

SHREC'17 对象检索竞争指标(微扰全)。

雾化能量预测

我们考虑的第二个问题是,在给定每个原子的类型、位置和电荷的情况下,预测将分子(见下图)分裂成其组成原子所需的能量。

肾上腺素分子模型。[图片来源于维基共享资源。]

同样,这可能不是一个球面问题,但是我们希望模型的预测对于分子围绕每个组成原子的旋转是不变的。对于每个原子,这可以通过计算来自每个方向的排斥电荷来实现,从而产生模型应该旋转不变的球形信号。此外,该模型应该以这样一种方式构建,即它对于球面图的数量和排列是不变的。

为了处理这些球形地图,我们再次使用了类似于上述的混合架构。上述修改使大的表示能力成为可能,这使得在这个问题上最先进的性能真正从均方根误差 5.96 推进到 3.16,Cohen 等人(2018)和 Kondor 等人(2018)的球形 CNN 构造分别达到 8.47 和 7.97。这是在使用比类似方法少得多的参数的同时实现的。

原子化能量回归问题的检验均方根误差。

摘要

我们已经看到,通过形成球面表示和应用球面 CNN,最初可能不表现为固有球面的问题可以从编码旋转对称的理解中受益匪浅。然后,通过在一个更一般的框架内解释这些球形表示,其中非线性可以以严格等变的方式引入,并仔细考虑如何有效地引入这种非线性,可以在重要的现实世界问题上实现最先进的性能(Cobb 等人,2021)。

虽然我们已经讨论了有效的方法,但是所提出的技术仍然需要大量的计算。进一步扩展球形深度学习的技术将在接下来的帖子中讨论。

参考

[1] Cobb,Wallis,Mavor-Parker,Marignier,Price,d'Avezac,McEwen,高效广义球形 CNN,ICLR (2021), arXiv:2010.11661

[2]科恩,盖格,克勒,韦林,球形 CNN,ICLR (2018), arXiv:1801.10130

[3]埃斯特韦斯,艾伦-布兰切特,马卡迪亚,达尼利迪斯,学习 SO(3)与球形 CNN 的等变表示,ECCV (2018), arXiv:1711.06721

[4]康多尔,林,特里维迪,克莱布什-戈丹网:一种全傅立叶空间球形卷积神经网络,NeurIPS (2018), arXiv:1806.09231

[5] McEwen & Wiaux,一个新颖的球面上的采样定理,IEEE TSP (2012), arXiv:1110.6298

[6] McEwen,Büttner,Leistedt,Peiris,Wiaux,旋转群上的一个新颖的采样定理,IEEE SPL (2015), arXiv:1508.03101

具有最优迭代和执行时间的高效 K-均值聚类算法

原文:https://towardsdatascience.com/efficient-k-means-clustering-algorithm-with-optimum-iteration-and-execution-time-9358a794406c

高效 K-means 聚类算法的实现:研究成果

改进的 K-means 聚类算法与其他现有方法的比较[1]

动机

回到 2019 年,我在读研究生,教授 K-means 聚类算法,作为机器学习课程的一部分。我很快抓住了算法的基本主题。该算法很有趣,因为它为每个聚类随机假设质心,并迭代直到它收敛到最终的聚类。不管初始质心是什么!它总是落在同一个星团里。在常规过程中,迭代次数随机变化。从那时起,我开始思考,如果我能修正初始质心,算法的迭代和执行时间将大大减少。我做了很多探索来寻找一种方法来选择最佳的初始质心。我分析过很多类似的作品。并找到了一个名为 kmeans++的标准方法。不幸的是,n 方法之一提供了最佳常数迭代。我和两个朋友以及我的主管一起,开始想出不同的点子来寻找可能的解决方案。我们还用现有的方法测试了我们产生的想法。经过一年的研究,我们提出了一个想法,即在执行时间和迭代次数方面优于其他方法。我们刚刚使用了百分位和 PCA(主成分分析)来确定最佳初始质心。在接下来的部分中,我将通过实际操作来讨论所提出的方法。

****n . b .—**它已经由 Springer Nature 发表在 【数据科学年鉴】 期刊上。 全文在此处。 ]

目录

  1. [**Clustering Algorithm at a Glance**](#26c5)
  2. [**K-means Clustering Algorithm Overview**](#7bb5)
  3. [**How the Proposed Method Works**](#7382)
  4. [**Step By Step Implementation with Python**](#603e)
  5. [**Comparison with the Traditional Method**](#3e5b)
  6. [**Multidimensional Cluster Visualization with Parallel Coordinates**](#d0ac)

聚类算法一览

当“集群”这个词来的时候,让我想起了一件简单的事情:**“把相似类型的物体组合在一起*”*它是无监督学习的一部分。聚类问题是无监督的学习问题,因为这些算法对未标记的数据(无目标值)起作用。算法的主要任务是“根据相似的特性或特征对数据进行分组”

作者图片

看看上图就知道了。这是一个二维图像。假设虚线表示具有两个特征的每个实例( X,Y )。它清楚地显示了聚类是基于最小距离(相似类型的要素)形成的。存在许多聚类技术,包括 K-means 聚类、DBSCAN、凝聚层次聚类、高斯混合模型算法等。其中,K-means 聚类被广泛应用。

k-均值聚类算法概述

首先,k-means 聚类算法为每个聚类随机选择质心。然后计算每个点到质心的距离。基于最小距离创建聚类。然后计算每个聚类的平均点,并将其作为新的质心。重复相同的过程,直到质心收敛到一个固定点。

k 均值聚类算法[1]

我们来看看论文[1]中提到的算法。它非常精确地描述了整个过程。

提议的方法如何工作

主算法我们什么都没修改。我们所做的只是提出了一种有效选择初始质心的方法。让我们看看下面给出的流程图。

让我一步一步地解释方法。

  1. ***数据集读取:*对于每个机器学习模型,我们都需要读取数据集。所提出的方法需要相同的过程。当我们在下一步中应用 PCA 时,我们必须将所有的值转换成数字。
  2. ***主成分分析(PCA)*步骤都是关于降维的。这些特征应该归纳为两个部分。将使用 PCA 来完成这项工作。有了这两个特性,我们可以轻松地对数据进行水平或垂直分段。这就是为什么我们使用两种成分的 PCA。
  3. ***应用百分位数概念分离数据:*百分位数是一种统计技术,通过它我们可以将数据分成 100 个不同的部分。每个部分保存 1%的数据。要了解更多关于百分位的细节,你可以阅读以下文章— ( 数据科学统计终极指南 )
  4. ***数据集拆分和均值计算:*这一步是最重要的一步。在上一步中,我们只是应用了百分位数。现在,我们需要使用百分位数分割数据集。例如,我们希望使用 K-means 聚类算法创建 4 个聚类,因此 K=4。根据该方法,我们将根据第一部分 将数据集分成 4 等份(第一部分 0% — 25%,第二部分 25% — 50%,第三部分 50% — 75%,第四部分 75% — 100%)。 接下来我们将通过映射指标提取各部分的主要数据。之后,将计算每个部分的平均值。

作者图片

上图显示了一个 spit 零件的演示数据集。其中, X1,X2…代表特性,D11,D21…表示实例值。 意思是将计算如下——

平均值 X1=(D11+D12+D13+D14)/4

平均 X2=(D21+D22+D23+D24)/4

平均 X3=(D31+D32+D33+D34)/4

平均值 X4=(D41+D42+D43+D44)/4

平均值 X5=(D51+D52+D53+D54)/4

聚类的初始质心将是 的值(平均 X1,平均 X2,平均 X3,平均 X4,平均 X5)。 用同样的过程,将确定另外 3 个质心。

*5.**质心确定并馈入 K-means 算法:*我们在 数据集分割和均值计算 步骤中获得了最佳初始质心。是时候将质心提供给主 K-means 聚类算法了。其余的过程与传统的 K-means 聚类算法相同。为了方便起见,我还包括了该方法的算法。

高效 K 均值聚类的建议算法[1]

用 Python 逐步实现

  • 导入必要的 Python 库。

  • 读取数据集和一些预处理

出于演示目的,我使用了 cars.csv 数据集,可从Kaggle获得。您也可以使用其他聚类数据集。

让我们看看数据集的整体信息。

*上面的单元格清楚地显示了一些非数字列,如 ***cubicinches、heavy bs 和 brand。**品牌列保存分类值,如美国、欧洲和日本。我们将映射分类值以将其转换为数值。

现在,我们将删除包含分类值的**brand** 列。

关于数据的当前信息。

尽管如此,我们仍然有两个非数字的列cubic inch 和 weightbs*,它们是数值,但被指定为字符串。让我们把它转换成数值。*

数据集当前状态的概述。

我们可以看到所有的值都是数字,但是有一些丢失的值需要小心处理。

这段代码将处理丢失的值。

下图显示了数据的分布情况。

***Output***

  • 为数据集寻找 K 值的最佳数量

我已经用 肘法 找到了最佳 K 值。

最佳簇的数量是 3,因为肘部的弯曲从该点开始。

【注意——肘击法不是建议技术的一部分。我用它来寻找最佳聚类,因为我们正在处理一个随机数据集。而且我们不知道有多少个聚类适合这个数据集。】

  • 应用具有两种成分的主成分分析,并将数据可视化

  • 应用百分位数分离数据

我们将创建 3 个集群。因此,我们需要将数据集分成 3 个相等的部分。百分位计算在 100%以内。因此,每个群集中 100/3=33.3%的数据可能是相等的。值得一提的是,百分点将应用于第一个 PCA 成分 的 ,因为它保存了最多的信息。

让我们看看我是如何分割数据集的。

  • 从主数据中提取分离的数据

在上面的代码中,我根据 PCA 的第一个组成部分将数据分成 3 个相等的部分。但是我们不会从 PCA 分量中计算质心,因为可能会有巨大的信息丢失的可能性。因此,我们将数据合并到预处理的***car*** 数据框架中,以提取包含原始数据集所有特征的数值数据。上面代码的first, second and third 变量包含了每个分割的数据。

  • 平均值计算和质心选择

在这一步中,我们计算了每个数据分割部分的平均值,并将其视为质心。最后,我们在 K-means 聚类算法中加入了质心。出于测试目的,该过程已经执行了 10 次。我已经在 iteration and time_execution列表中记录了建议方法的迭代次数和执行时间。

与传统方法的比较

用传统的 K-means 聚类算法训练模型。

我已经在iteration_defaultexecution_time_default列表中记录了执行时间和迭代。

我们来画个对比图进行迭代。

它清楚地表明,我们提出的方法工作于常数迭代,因为我们的质心是固定的;另一方面,传统的 K-means 聚类算法表现出任意的迭代。并且在每种情况下,该方法的迭代次数都是最小的。

执行时间方面的比较。

实验结果表明,在大多数情况下,该模型的性能优于传统方法。

具有平行坐标的多维集群可视化

我们的数据集中有超过 3 个维度。实际上我们无法想象它。这就是为什么我会用平行坐标来绘制这些簇。

【解释平行坐标的概念不在本文讨论范围内。如果你想了解一下,点击 这里 就知道了。】

这里,***0, 1, 2***代表单个集群。

结论

机器学习模型很复杂,需要强大的计算能力。如果我们能找到任何方法来降低它的计算复杂性,它将发挥重要作用。由于所提出的方法优于其他方法,它也将节省计算成本。

【注意——你可以引用参考部分所示的方法。】

***Full notebook is available here.***

*https://deepnote.com/@md-zubair/Efficient-K-means-Clustering-for-data-driven-modelling-a6ca9f6e-5f62-4914-a16d-6ead5c57ae36

参考

  1. 祖拜尔,m .,伊克巴尔,M.A .,希尔,A. 一种面向高效数据驱动建模的改进 K 均值聚类算法。安。数据。Sci。 (2022)。https://doi.org/10.1007/s40745-022-00428-2* *https://mzh706.medium.com/subscribe https://mzh706.medium.com/membership *

在 Python 中训练深度学习模型时的高效内存管理

原文:https://towardsdatascience.com/efficient-memory-management-when-training-a-deep-learning-model-in-python-fde9065782b7

如何使用 Tensorflow、Python 和迭代器在小型计算机上使用大数据

西西弗斯的作品;由维基共享许可授权https://commons . wikimedia . org/Wiki/File:Friedrich _ John _ nach _ Matth % C3 % A4us _ Loder _ Sisyphus _ UBS _ G _ 0825 _ ii . jpg

当前商业世界中的数据量每天都在增加。有新的数据源要合并,有更多的行要追加,有新的列要连接。

不幸的是,对于典型的数据科学家或机器学习工程师来说,购买新笔记本电脑或计算机或扩展云服务的速度通常赶不上新数据进入的速度。一个人的硬件可能感觉像西西弗斯:试图保持岩石不压碎他(计算机中的内存不会填满),同时仍然保持他的工作(训练深度学习模型)。

在这篇文章中,我将提出一个关于如何考虑将大量数据放入少量 RAM 的逻辑。

所有的代码和例子都可以在我的回购中找到:

https://github.com/Eligijus112/big-data-ml

我们将尝试解决的目标是创建一个模型,使用以下功能预测纽约市出租车司机的车费金额

  • 拾取日期时间
  • 出租车里的人数
  • 上车点和目的地之间的距离

该数据已在 Kaggle 竞赛中提供,包含约 5500 万行。

数据片段;作者照片

我们将使用以下函数对此数据集进行一些特征工程:

提货日期转换;作者代码

距离计算;作者代码

虚拟变量创建;作者代码

将这些函数应用于数据框后,我们将使用以下公式对票价金额进行建模:

  • 乘客数量
  • 每周提货日的虚拟变量
  • 行驶距离
  • 拾取时一天中某小时的 Sin 和 Cos 循环转换
  • 拾取时一年中某一天的 Sin 和 Cos 循环转换

要了解更多关于周期性特征的信息,请访问以下资源:

https://feature-engine.readthedocs.io/en/1.3.x/user_guide/creation/CyclicalFeatures.html

模型中共有 18 个特征。

顺便说一句,要更好地理解数据并向伟大的数据科学家社区致敬,请访问本笔记本:

https://www.kaggle.com/code/breemen/nyc-taxi-fare-data-exploration

在这篇文章的标题中,有一个术语叫做内存管理。当谈到内存和深度学习时,人们要么指图形处理单元的内存( GPU) ,要么指随机存取存储器( RAM) 。我将探索 RAM 部分,以及如何使用大数据不堵塞计算机内存。

在使用 Tensorflow 的典型深度学习模型训练中,记忆方面的训练可以表示为:

记忆和深度学习;作者照片

当我们启动一个 Python 脚本并使用 TensorFlow 定义一个模型时,我们会立即占用 RAM 中的一些空间。这是我们不能走捷径的部分,因为为了让训练程序工作,整个模型对象需要存在于内存中,并且可以被 Python 的运行进程快速访问。

纽约市数据的深度学习模型;作者代码

使用内存分析器,我们可以运行上面的脚本:

python -m model

并得到如下细分:

内存使用细分;作者照片

甚至在调用函数之前,Python 已经通过加载函数 (Keras,TensorFlow,memory_profiler)上面定义的包在我们的系统中预留了 391 MB 的 RAM。

在第 38 行,当模型启动时,RAM 使用量增加了大约 600 MB。即使是这个简单的一个隐藏层模型也要占用超过半个 GB 的内存。

因此,即使在训练开始之前,没有数据被加载到存储器中,也需要至少 1 GB 的 RAM 来进行任何类型的训练。

让我们运行下面的代码,它将数据集的所需行加载到内存中,训练一个模型并返回它。运行包含 100k 行的脚本的命令是:

python -m train_whole_data --rows 100000

以直截了当的方式进行培训;作者代码

内存分析器返回以下结果:

100k 行的内存使用情况;作者图片

正如我们从第 71 行看到的,数据占用了大约 33 MB 的 RAM。模型训练需要额外的 74 MB。所有其他 RAM 的使用都是由于加载了额外的包。让我们看看一百万行会发生什么:

python -m train_whole_data --rows 1000000

使用 1000 000 行的内存使用量;作者照片;

增加 10 倍的行数会使整体 RAM 使用量增加 1.5 倍。让我们分析一下下面的情节:

RAM 使用与行数的关系;作者照片

当行数增加时,内存使用量呈线性增长。试图用所有数据(大约 5400 万行)来拟合一个模型会导致代码使用超过 12GB 的 RAM!

到目前为止,我们所做的过程可以总结在下图中:

填满羊肉饼;作者照片

RAM 空间是有限的,取决于机器的规格。当行数增加时,加载到 RAM 的数据和用于模型定型的 RAM 使用量( XY 变大)都会增加。

把所有东西都存储在 RAM 里最大的好处就是训练的整体速度快。这是因为运行数据加载和训练模型的 Python 进程获得了它自己的专用 RAM 空间,并且从那里向训练加载数据只需要几分之一秒的时间。

可以看到,我们最终将达到一个阈值,在该阈值处,训练脚本将被终止,因为我们将使用系统中的每一位 RAM。

为了用几乎任何数量的数据训练一个模型,我们将使用一个数据生成器序列(从这里开始,我将数据生成器序列简单地称为数据迭代器)

形式上,编程中的迭代器是一个有两种方法的对象:

  • hasNext() —返回一个布尔值,判断当前活动迭代项旁边是否有元素。表示迭代应该停止。
  • next() —返回迭代中使用的下一项。

在为 TensorFlow 定义数据生成器时,我们需要使用以下类:

需要在类中定义的方法有:

  • init() —对象构造函数。
  • len() —我们迭代器中的总项数。
  • getitem() —获取迭代中的下一项。

__ getitem__() 方法等价于形式定义中的 next() 方法。

在每次迭代结束时调用 __ len__() 方法,一个单独的规则或者停止迭代器或者继续它。这模仿了 hasNext() 方法背后的逻辑。

下面是这个项目中使用的数据迭代器:

纽约市数据的数据生成器;作者代码

构造函数中的第一个参数是使用 Pandas 库中的**read _ CSV(iterator = True)**方法获得的。这是一种内部 Pandas 数据框方法,可以在读取具有分区的数据时使用。在读取到计算机内存时,CSV 文件可以被拆分为单独的行,而无需将整个数据集加载到 RAM 中。

对块的引用保存在内存中;按作者分类的图表

每次调用 getitem() 方法时,都会从 csv_generator 对象中调用一个块到内存中。然后对块进行预处理,并从中创建用于深度学习的 xy 矩阵。

x 和 y 矩阵被馈送到 TensorFlow 模型,并且在用它们完成所有训练之后,它们被从存储器中删除。

用迭代器模式训练;按作者分类的图表

当数据迭代器停止时,训练完成。

使用迭代器训练模型的完整 python 代码:

使用迭代器的完整管道;作者代码

现在让我们试着运行有一百万行的代码:

python -m train_iterator --rows 1000000

用迭代器 1 百万行;作者图片

正如我们从第 126 行看到的,创建一个 CSV 生成器来遍历整个数据集只需要 6.4 MB 的 RAM。回想一下,将整个数据集加载到内存需要大约 12000 MB 的内存。内存的总使用量大约为 2100 MB。

使用整个数据集运行脚本:

python -m train_iterator 

使用迭代器对完整数据集进行训练;作者照片

令人惊讶的是,即使添加了 54 倍的数据,整体 RAM 消耗几乎保持不变(从 2191MB 到 2373MB)!这可以用图表来解释:

有效的语块训练;按作者分类的图表

SSD(或数据库或任何其他存储)中的数据需要分成分区(块)。有效的训练算法可以总结如下:

* Split the data into **M** chunks. * Initiate an empty model in memory. * For **m** in **M** chunks do: 1) Load the data of chunk **m** to memory  2) Train the model using that chunk 3) The model weights are saved and the chunk **m** is removed from memory. 

上面的算法让我们在相对低内存的设备上使用非常大的数据文件来训练模型。

这种方法的缺点是将数据块从本地存储转换到 RAM 会产生瓶颈,从而减慢整个训练过程。

总之,在训练神经网络的速度和将大量数据放入计算机内存的能力之间存在权衡:

  • RAM 中的数据越多,训练速度越快。
  • RAM 中的数据越少,训练模型所需的资源就越少。

在本文中,我展示了如何使用这两种方法,介绍了 TensorFlow 提供的数据迭代器的概念,并展示了所有代码示例。

编码快乐!

[1]纽约市出租车费用预测;
网址:https://www . ka ggle . com/datasets/harlfoxem/housesales prediction?资源=下载

执照:https://creativecommons.org/publicdomain/zero/1.0/

有效的风险规避强化学习

原文:https://towardsdatascience.com/efficient-risk-averse-reinforcement-learning-29fbd0c4a906

训练你的强化学习代理来处理不幸的场景和避免事故

在这篇文章中,我展示了我们最近的 NeurIPS 2022 论文(与 Yinlam Chow、Mohammad Ghavamzadeh 和阏氏·曼诺尔合著)关于风险厌恶强化学习(RL)。我讨论了风险厌恶为什么和如何应用于 RL,它的局限性是什么,以及我们建议如何克服它们。展示了在自动驾驶事故预防中的应用。我们的代码也可以在 GitHub 上获得。

TL;速度三角形定位法(dead reckoning)

在将 RL 应用于风险敏感的现实世界问题时,规避风险的 RL 至关重要。为了以规避风险的方式进行优化,当前的方法关注于与低回报相对应的数据部分。我们表明,除了严重的数据低效,这也导致不可避免的局部最优。我们建议关注环境的高风险条件,而不是直接关注低回报。我们设计了一种交叉熵方法(CEM)的变体,它学习并过采样这些高风险条件,并将该模块用作我们的交叉熵软风险算法的一部分( CeSoR )。我们在驾驶和其他问题上显示了冷静的结果。

我们用来对高风险条件进行过采样的交叉熵方法是一个 PyPI 包 。当然,它可以应用于 RL 的示例采样范围之外。我们还提供了一个关于 CEM 和包的 教程

3 名代理人(风险中性 PG;名为 GCVaR 的标准 CVaR-PG 算法;和我们的 CeSoR)应用于 3 个基准。顶部:代理回报的下分位数。下图:样片。图片作者。

背景(一):为什么要规避风险?

强化学习(RL)是机器学习的一个子领域,它支持从有限的监督和规划中学习。这些特性使得 RL 在需要决策的应用中非常有前途,例如驾驶、机器人手术和金融。最近几年,RL 在各种游戏中展示了有希望的成功,以至于有一部电影讲述了它在围棋游戏中的表现。然而,RL 很难找到进入现实世界应用的方法。

缩小视频游戏和机器人手术之间的差距的一个挑战是,后者对风险高度敏感:虽然允许游戏机器人偶尔出错,但像医疗设备这样的真实世界系统必须在任何情况下都能合理可靠地运行。换句话说,在现实世界中,我们通常对优化代理回报的风险度量感兴趣,而不是优化平均回报。要优化的一个常见风险度量是条件风险值(CVaR);本质上,随机变量(如收益)的 CVaR_ α 测量的是最低分位数 α 的平均值——而不是整个分布的平均值。 α 对应于我们感兴趣的风险级别。

CVaR 风险度量的一个例子:给定代理回报的分布,我们感兴趣的是分布尾部的平均值。图片作者。

背景(二):传统的风险厌恶型 RL

直观地说,CVaR 优化的标准策略梯度方法(CVaR-PG)考虑由代理收集的一批 N 集(轨迹),仅取收益最低的 αN 集,并对它们应用 PG 步骤。

下面我们讨论这种 CVaR-PG 方法的关键限制。在本文中,我们还为 PG 以外的其他方法中的类似限制提供了证据,例如,分布式 RL。

CVaR-PG 的局限性

**样本效率低下:**好吧,CVaR-PG 中的数据效率低下是相当直接的:CVaR-PG 实质上丢弃了我们的数据的 1-α ,通常是 95%-99%!相反,如果我们可以只对与环境的 α 最坏情况相对应的情节进行采样,并对其进行优化,那么很明显,我们可以恢复标准(风险中性)算法的采样效率,即,通过因子 1/α 提高数据效率。如下所述,这正是交叉熵方法的目的。

盲目走向成功: CVaR-PG 不仅丢掉了大部分数据;它扔掉了数据中所有成功的剧集!如果我们的代理碰巧探索了一个新的令人兴奋的策略来处理一个具有挑战性的场景——优化器将立即丢弃这一集,因为“高回报因此不相关”。我们把这种现象称为对成功的盲目。在我们的论文中,我们从理论上证明了在离散奖励的环境中,这不可避免地导致梯度消失——导致局部最优。

说明性例子——守卫迷宫:在守卫迷宫中,智能体需要尽快到达绿色目标(位置不变)。然而,最短的路径通过红色区域,这是有时被一个官员占据,他收取随机贿赂费(基于真实故事,来自一个国家,此处不具名)。平均来说,最短的路径仍然是最优的,尽管很少有负面的回报。然而,更长且更安全的路径是 CVaR 最优的(例如,对于 α=5% )。

守卫的迷宫:一个样本集。每个代理从相同的起点遵循不同的路径。图片作者。

我们实现了 GCVaR 算法,这是 CVaR-PG 的标准实现。如上面的示例中所示, GCVaR 学会了避免有风险的短路径,但未能学会替代的长路径:每次遇到长路径时,它的回报都很高,因此没有提供给优化器。它对长路径的成功策略视而不见——尽管它经常探索它!

CeSoR 呼叫救援

我们的方法 CeSoR (交叉熵软风险)使用两种机制解决了上述问题。

软风险:如上所述,CVaR-PG 使用每批 N 集的 αN 集。一方面,这导出了真实政策梯度的一致估计值。另一方面,对成功的盲目导致这种梯度进入局部最优。我们用一个简单的方案来解决这个权衡:我们用 α' 代替 α ,从 1 开始,逐渐减少到 α 。这样,在开始时,我们的梯度看起来超越了局部最优,朝向成功的策略;然而,在最后的训练阶段,它仍然是 CVaR 政策梯度的一致估计。

软风险计划:实际风险水平α' 开始时比目标风险水平 α *更保守,防止对成功的盲目。在最后阶段,α'=α提供了一个稳定的训练目标,保证了 CeSoR 的收敛。*图片作者。

交叉熵方法(CEM) :软风险还不够,我们还有两个问题。首先,如上所述,无论何时α’<1,我们都会丢弃数据并损失采样效率。第二,软风险本身可能会消除我们的预期风险厌恶:即使训练以 α'=α 结束,如果在此之前代理收敛到风险中性策略怎么办?

为了解决这些问题,我们假设对训练环境的某些条件进行控制。比如学车的时候,我们可以选择自己出卷的道路和时间,这些都影响着行车条件。在这种假设下,我们使用交叉熵方法(CEM)来了解哪些条件导致最低回报,然后对这些条件进行过采样。CEM 是一种非常酷的采样和优化方法,但并不常见。在的一个单独教程中,我展示了这种方法,并使用 cem 包演示了如何在 Python 中使用它。

一旦我们对高风险条件进行过采样,我们就不再需要像以前那样扔掉那么多的情节。特别是,CEM 的目标——从原始收益分布的 α- 尾部取样——将样本效率提高到 1/α 倍(如上所述)。在实践中,CEM 实现了较为适度的改善。

通过对高风险条件进行过采样,我们还保留了风险厌恶,中和了软风险的负面副作用:软风险允许优化器学习高回报的政策,而 CEM 采样器仍然保留了风险厌恶。

CeSoR 的主要原则可以表述为:为了规避风险,专注于高风险场景——而不是糟糕的代理策略。下图对此进行了说明。

训练批次的图解。每个点代表一集,具有回报 R 和“条件”C(例如,C 可以是迷宫中的守卫成本)。相同颜色的点对应于“相似”的代理策略(例如,迷宫中的短路径、长路径和无为路径)。Mean-PG 对整批进行平均,从而学习蓝色策略(类似于最短路径)。GCVaR 考虑左边部分(低收益),学习橙色策略(什么都不做)。我们的 CeSoR 对上部(高风险条件)进行过采样,并学习紫色策略(长路径)。图片作者。

上述现象在守卫迷宫的训练过程中得到了很好的演示,如下图所示:

GCVaR,SoR,CeSoR:%-没有到达目标(“停留”)或通过守卫迷宫中的短路径或长路径到达目标的剧集。右下角:%-馈送给优化器的剧集中的长路径。图片作者。

  1. 标准 CVaR-PG (GCVaR) 确实探索了长路径(左上图),但是从不将它提供给优化器(右下图)。因此,它最终学会了什么也不做。注意,单独使用 CEM(没有软风险)不能解决这个限制。
  2. 单独的软风险 ( SoR ,没有 CEM)消除了对成功的盲目,并为优化器提供了一条漫长的道路(右下角)。然而,它开始时是风险中性的,因此更喜欢走捷径(右上角)。当它再次变得厌恶风险时,参与者已经收敛于短路径政策,而不再探索长路径。
  3. 只有 CeSoR 观察到“好的”策略(由于软风险)并在“坏的”环境变化下判断它(由于 CEM),收敛到长路径(左下角)。

学习成为一名安全的司机

我们在一个驾驶基准上测试了 CeSoR,我们的代理人(蓝色)必须尽可能从后面跟着一个领导者(红色),但不能撞到它。领路人可以直行、加速、刹车或变道。

CeSoR 关于驾驶游戏基准。作者 GIF。

如本文第一张图所示,CeSoR 将代理的 CVaR-1%测试回报在该基准上提高了 28%,特别是消除了风险中性驾驶员造成的所有事故。更有趣的是, CeSoR 学会了与安全驾驶相对应的直觉行为:如下图所示,它使用油门和刹车的频率略低(右图),与领先者保持较大的距离(左图)。

在驾驶游戏的所有测试情节中,每个代理人在所有时间步的统计数据。图片作者。

最后,我们注意到 CEM 采样器本身的表现符合预期。在驾驶游戏中,我们让 CEM 控制领导者的行为(注意领导者是环境的一部分,而不是代理)。如下图所示,CEM 增加了领队在训练中转弯和紧急刹车的相对比例。这些领导者行为的频率以可控的方式增加,以使代理体验与真实回报分布的 α- 尾部保持一致。

CEM 学会了在驾驶游戏中过度模仿具有挑战性的领导者行为。图片作者。

摘要

在这篇文章中,我们看到 RL 中的风险厌恶目标比期望值的标准目标更难训练——这是由于对成功的盲目和样本的低效率。我们引入了 CeSoR ,它结合了软风险以克服对成功的盲目,并结合了 CEM 采样器以提高采样效率和保持风险厌恶。在驾驶基准测试中,CeSoR 学会了直观的安全驾驶政策,并成功防止了所有发生在替代代理身上的事故。

这项工作只是一个更有效率和更有效的风险规避风险的起点。未来的研究可能会直接改善 CeSoR(例如,通过软风险调度),或者将其扩展到政策梯度方法和 CVaR 风险度量之外。

高效地迭代熊猫数据帧中的行

原文:https://towardsdatascience.com/efficiently-iterating-over-rows-in-a-pandas-dataframe-7dd5f9992c01

不再使用 iterrows 和 itertuples

图片由作者,表情符号由open moji(CC BY-SA 4.0)。

当我开始机器学习时,我遵循这些准则,并通过组合我的数据集中的多个列来创建自己的特征。这一切都很好,但我做这件事的方式非常低效。我必须等几分钟才能完成最基本的操作。

我的问题很简单:我不知道在 Pandas 中迭代行的最快方法。

我经常在网上看到有人使用我曾经用过的技术。不优雅但是数据不多也还行。然而,如果您处理超过 10k 行的数据,这很快就会成为一个明显的性能问题。

在本文中,我将向您介绍在 Pandas DataFrame 中迭代行的最佳方法,不需要额外的代码。这不仅仅是关于性能:这也是关于了解在引擎盖下发生了什么,以成为更好的数据科学家。

让我们在 Pandas 中导入一个数据集。在这种情况下,我选择了我开始时所做的:是时候修正我过去的错误了!🩹

可以用下面的 Google Colab 笔记本运行代码。

该数据集有 22k 行和 43 列,包含分类值和数值。每行描述两台计算机之间的连接。

假设我们想要创建一个新特性:连接中的总字节数。我们只要总结两个现有的特征:src_bytesdst_bytes。让我们看看计算这个新特性的不同方法。

❌❌ 1.Iterrows

根据官方文档,iterrows()迭代“熊猫数据帧的行作为(索引,序列)对”。它将每一行转换为一个系列对象,这导致了两个问题:

  1. 它可以改变你数据的类型(dtypes);
  2. 转换大大降低了性能

出于这些原因,不恰当的iterrows()是实际迭代行的最差方法。

10 loops, best of 5: **1.07 s** per loop

现在让我们看看稍微好一点的技术…

❌ 2.For 循环 with。loc 或。iloc(快 3 倍)

这是我开始时经常做的:一个循环的基础,通过索引选择行(用.loc.iloc)。

为什么不好?因为数据帧不是为此目的而设计的。与前面的方法一样,行被转换成 Pandas 系列对象,这会降低性能。

有趣的是,.iloc.loc更快。这很有意义,因为 Python 不必检查用户定义的标签,直接查看行在内存中的存储位置。

10 loops, best of 5: **600 ms** per loop
10 loops, best of 5: **377 ms** per loop

甚至这种用.iloc的基本 for 循环也比第一种方法快 3 倍!

❌ 3.应用(速度提高 4 倍)

apply()方法是另一种流行的行迭代方法。它创建了易于理解的代码,但这是有代价的:性能几乎和前面的 for 循环一样差。

这就是为什么我强烈建议您为了这个特定的目的避免这个函数(对于其他应用程序也可以)。

注意,我使用to_list()方法将 DataFrame 转换成一个列表,以获得相同的结果。

10 loops, best of 5: **282 ms** per loop

这个apply()方法是一个伪装的 for 循环,这就是为什么性能没有提高那么多的原因:它只比第一种方法快了 4 倍

❌ 4.Itertuples(快 10 倍)

如果你知道iterrows(),你大概也知道itertuples()。根据官方文档,它“遍历数据帧的行,命名为值对”。实际上就是把行转换成元组,元组是比熊猫系列轻得多的对象。

这就是为什么itertuples()iterrows()的更好版本。这一次,我们需要访问带有属性(或索引)的值。如果您想用一个字符串来访问它们(例如,如果字符串中有一个空格),您可以使用getattr()函数来代替。

10 loops, best of 5: **99.3 ms** per loop

这开始变得更好了:现在iterrows()快 10 倍。

❌ 5.列表理解(快 200 倍)

列表理解是作为一行程序迭代列表的一种奇特方式。

例如,[print(i) for i in range(10)]打印从 0 到 9 的数字**,而没有任何显式 For 循环**。我说“显式”是因为如果我们看字节码,Python 实际上将它作为 for 循环处理。

那么为什么会更快呢?很简单,因为在这个版本中我们不调用.append()方法。

100 loops, best of 5: **5.54 ms** per loop

的确,这种技术比第一种技术快 200 倍!但是我们仍然可以做得更好。

✅ 6.熊猫矢量化(速度提高 1500 倍)

到目前为止,所有使用的技术只是简单地将单个值相加。与其将单个值相加,为什么不将它们组合成向量来求和呢?两个数字或两个向量相加的差别对于 CPU 来说并不重要,这应该会加快速度。

最重要的是,Pandas 可以使用所有可用的 CPU 内核并行处理系列对象

语法也是最简单的:这个解决方案非常直观。在引擎盖下,Pandas 使用连续的内存块,通过优化的 C 代码对我们的数据进行矢量化处理。

1000 loops, best of 5: **734 µs** per loop

这段代码比 T2 快 1500 倍,而且写起来更简单。

✅✅ 7.NumPy 矢量化(速度提高 1900 倍)

NumPy 被设计用来处理科学计算。它比 Pandas 方法有更少的开销,因为行和数据帧都变成了np.array。它依赖于与熊猫矢量化相同的优化。

有两种方法将一个系列转换成np.array:使用.values.to_numpy()。前者已经被废弃多年,这就是我们在这个例子中使用.to_numpy()的原因。

1000 loops, best of 5: **575 µs** per loop

我们用比第一个竞争对手快 1900 倍的技术找到了我们的赢家!让我们把东西包起来。

🏆结论

数据集中的行数会极大地影响某些技术的性能(图片由作者提供)。

不要像我一样:如果您需要迭代数据帧中的行,那么矢量化是一个不错的选择!你可以在这个地址找到重现实验的代码。矢量化不会更难阅读,也不会花费更长的时间来编写,而且性能提升令人难以置信。

这不仅仅是关于性能:理解每个方法是如何工作的帮助我写出更好的代码。性能提升总是基于相同的技术:将数据转换成向量和矩阵,以利用并行处理。唉,这通常是以牺牲可读性为代价的。但不一定非要这样。

对行进行迭代只是一个例子,但它表明,有时,你可以拥有蛋糕并吃掉它。🎂

如果你喜欢这篇文章,在 Twitter 上关注我@ maxime labanne了解更多关于数据科学和机器学习的技巧!

EfficientNetV2:比视觉变压器更快、更小、精度更高

原文:https://towardsdatascience.com/efficientnetv2-faster-smaller-and-higher-accuracy-than-vision-transformers-98e23587bf04

关于 EfficientNetV2 模型的详细说明,及其架构和培训方法的开发

(图片来源:克里斯里德(Chris Ried)在Unsplash—https://unsplash.com/photos/ieic5Tq8YMk拍摄的照片)

EfficientNets 是目前最强大的卷积神经网络(CNN)模型之一。随着视觉变压器的兴起,它实现了比 EfficientNets 更高的精确度,出现了 CNN 是否正在消亡的问题。EfficientNetV2 不仅提高了准确性,还减少了训练时间和延迟,从而证明了这一点。

在这篇文章中,我已经详细讨论了这些 CNN 被开发出来,它们有多强大,以及它对 CNN 在计算机视觉中的未来意味着什么。

内容

  1. 简介
  2. EfficientNetV2

………….2.1 efficient net(版本 1)的问题

………….2.2 EfficientNetV2 —为克服问题和进一步改进所做的更改

………….2.3 结果

3。结论

1.介绍

使用神经结构搜索来设计高效网络模型。第一个神经架构搜索是在 2016 年的论文中提出的—‘具有强化学习的神经架构搜索’。

其思想是使用一个控制器(一个网络,如 RNN)和来自概率为“p”的搜索空间的样本网络结构。然后,通过首先训练网络,然后在测试集上验证它以获得准确度“R”来评估该架构。“p”的梯度通过精度“R”计算和缩放。结果(奖励)被反馈给控制器 RNN。控制者充当代理,网络的训练和测试充当环境,结果充当报酬。这是常见的强化学习(RL)循环。这个循环运行多次,直到控制器找到给出高回报(高测试精度)的网络架构。这如图 1 所示。

图一。神经架构搜索概述(来源:图片来自神经架构搜索论文

控制器 RNN 对各种网络架构参数进行采样,例如每层的过滤器数量、过滤器高度、过滤器宽度、步幅高度和步幅宽度。对于网络的每一层,这些参数可以是不同的。最后选择奖励最高的网络作为最终的网络架构。这如图 2 所示。

图二。控制器在网络的每一层中搜索的所有不同参数(来源:图片来自神经架构搜索论文

尽管这种方法效果很好,但这种方法的一个问题是需要大量的计算能力和时间。

为了克服这个问题,2017 年,论文中提出了一种新的方法——‘学习可扩展图像识别的可转移架构’。

在这篇论文中,作者研究了以前著名的卷积神经网络(CNN)架构,如 VGG 或 ResNet,并指出这些架构在每一层中没有不同的参数,而是有一个具有多个卷积和池层的块,并且在整个网络架构中,这些块被多次使用。作者利用这一想法,使用 RL 控制器找到这样的块,并重复这些块 N 次,以创建可扩展的 NASNet 架构。

这在 2018 年的“ MnasNet:面向移动设备的平台感知神经架构搜索”论文中得到进一步改进。

在这个网络中,作者选择了 7 个区块,并对每个区块的一层进行采样和重复。这如图 3 所示。

图 3。MnasNet 架构中的采样参数。所有用蓝色书写的内容都用 RL 搜索(来源:图片来自 MnasNet 论文)

除了这些参数之外,在决定进入控制器的奖励时,还要考虑一个非常重要的参数,那就是“等待时间”。因此,对于 MnasNet,作者同时考虑了准确性和延迟,以找到最佳的模型架构。这如图 4 所示。这使得架构很小,可以在移动或边缘设备上运行。

图 4。寻找模型架构的工作流,同时考虑准确性和延迟以决定对控制者的最终奖励(来源:图片来自 MnasNet 论文)

最后,在论文中提出了 EfficientNet 架构——2020 年‘efficient net:反思卷积神经网络的模型缩放’。

寻找 EfficientNet 架构的工作流程与 MnasNet 非常相似,但没有将“延迟”作为奖励参数,而是考虑了“FLOPs(每秒浮点运算次数)”。这个标准搜索给了作者一个基础模型,他们称之为 EfficientNetB0。接下来,他们扩大了基本模型的深度、宽度和图像分辨率(使用网格搜索)以创建另外 6 个模型,从 EfficientNetB1 到 EfficientNetB7。这种缩放如图 5 所示。

图 5。缩放深度、宽度和图像分辨率,以创建不同的 EfficientNet 模型(来源:图片来自 EfficientNet 论文)

我已经写了一篇关于 EfficientNet 版本 1 的文章。要详细了解这个版本,请点击下面的链接—

https://medium.com/mlearning-ai/understanding-efficientnet-the-most-powerful-cnn-architecture-eaeb40386fad

2.高效网络 V2

论文-efficient net v2:更小的模型和更快的训练(2021)

EfficientNetV2 比 EfficientNet 更进一步,提高了训练速度和参数效率。该网络通过使用缩放(宽度、深度、分辨率)和神经架构搜索的组合来生成。主要目标是优化训练速度和参数效率。此外,这次搜索空间还包括新的卷积块,如 Fused-MBConv。最终,作者获得了 EfficientNetV2 架构,它比以前和更新的最新模型快得多,而且体积也小得多(高达 6.8 倍)。这如图 6 所示。

图 6(b)清楚地显示了 EfficientnetV2 有 2400 万个参数,而 Vision Transformer (ViT)有 8600 万个参数。V2 版本也有原始 EfficientNet 的将近一半的参数。虽然它确实显著减小了参数大小,但它在 ImageNet 数据集上保持了与其他模型相似或更高的精度。

图 6。与其他先进模型相比,EfficientNetV2 模型的训练和参数效率(来源: EfficientNetV2 论文)

作者还进行了渐进式学习,即一种逐渐增加图像大小以及正则化(如删除和数据增加)的方法。这种方法进一步加快了训练速度。

2.1 efficient net(版本 1)的问题

EfficientNet(原始版本)有以下瓶颈—

a.效率网络通常比其他大型 CNN 模型训练得更快。但是,当使用大图像分辨率来训练模型(B6 或 B7 模型)时,训练是缓慢的。这是因为更大的 EfficientNet 模型需要更大的图像大小来获得最佳结果,当使用更大的图像时,需要降低批处理大小以适应 GPU/TPU 内存中的这些图像,从而使整个过程变慢。

b.在网络架构的早期,深度方向的卷积层(MBConv)速度很慢。深度方向卷积层通常比常规卷积层具有更少的参数,但问题是它们不能充分利用现代加速器。为了解决这个问题,EfficientNetV2 结合使用了 MBConv 和 Fused MBConv,在不增加参数的情况下加快了训练速度(本文稍后将对此进行讨论)。

c.从 B0 到 B7,高度、宽度和图像分辨率都采用了相同的比例来创建各种高效网络模型。所有层的这种等比例缩放并不是最佳的。例如,如果深度被缩放 2 倍,网络中的所有块被放大 2 倍,使得网络非常大/深。将一个块缩放两次,将另一个块缩放 1.5 倍(非均匀缩放)可能更好,这样可以在保持良好精度的同时减小模型大小。

2.2 EfficientNetV2 —为克服问题和进一步改进所做的更改

a .添加 MBConv 和融合 MBConv 模块的组合

如 2.1(b)中所述,MBConv block 通常无法充分利用现代加速器。融合 MBConv 层可以更好地利用服务器/移动加速器。

MBConv 层最初是在 MobileNets 中引入的。如图 7 所示,MBConv 和 Fused-MBConv 结构的唯一区别是最后两个模块。MBConv 使用深度方向卷积(3x3 ),后跟一个 1x1 卷积层,而 Fused-MBConv 用一个简单的 3x3 卷积层替换/融合这两层。

融合的 MBConv 层可以使训练速度更快,只需增加很少的参数,但如果使用许多这样的模块,就会因添加更多的参数而大大降低训练速度。为了克服这个问题,作者在神经架构搜索中通过了 MBConv 和 Fused-MBConv,该搜索自动决定这些块的最佳组合,以获得最佳性能和训练速度。

图 7。MBConv 和融合 MBConv 模块的结构(来源: EfficientNetV2 paper

b .优化准确性、参数效率和培训效率的 NAS 搜索

*进行神经结构搜索是为了联合优化准确性、参数效率和训练效率。*efficient net 模型被用作主干,搜索是在各种设计选择下进行的,如卷积块、层数、过滤器尺寸、扩展比等。将近 1000 个模型作为样本,训练 10 个时期,并比较它们的结果。在准确性、训练步骤时间和参数大小方面优化得最好的模型被选为 EfficientNetV2 的最终基础模型。

图 8。EfficientNetV2-S 的架构(来源: EfficientNetV2 论文)

图 9。EfficientNet-B0 的架构(来源: EfficientNet 论文)

图 8 显示了 EfficientNetV2 模型(EfficientNetV2-S)的基本模型架构。该模型开始时包含融合 MBConv 层,但后来切换到 MBConv 层。为了比较,我还在图 9 中展示了之前 EfficientNet 论文的基本模型架构。以前的版本只有 MBConv 层,没有熔断 MBConv 层。

与 EfficientNet-B0 相比,EfficientNetV2-S 的膨胀率也较小。EfficeinetNetV2 不使用 5x5 滤镜,只使用 3x3 滤镜。

c .智能模型缩放

一旦获得了 EfficientNetV2-S 型号,就可以按比例增加以获得 EfficientNetV2-M 和 EfficientNetV2-L 型号。使用了一种复合缩放方法,类似于 EfficientNet,但是做了更多的改变,使模型更小更快——

I .最大图像大小被限制为 480x480 像素,以减少 GPU/TPU 内存的使用,从而提高训练速度。

二。更多的层被添加到后面的阶段(图 8 中的阶段 5 和阶段 6),以在不增加太多运行时开销的情况下增加网络容量。

d .渐进式学习

较大的图像尺寸通常倾向于给出更好的训练结果,但是增加了训练时间。一些论文先前已经提出了动态改变图像尺寸,但是这经常导致训练准确性的损失。

EfficientNetV2 的作者表明,由于在训练网络时图像大小是动态变化的,因此正则化也应该相应地改变。改变图像尺寸,但保持相同的正则化会导致精度损失。此外,较大的模型比较小的模型需要更多的正则化。

作者使用不同的图像尺寸和不同的放大来测试他们的假设。如图 10 所示,当图像尺寸较小时,较弱的放大会产生较好的结果,但当图像尺寸较大时,较强的放大会产生较好的结果。

图 10。使用不同的图像大小和不同的增强参数测试 ImageNet top-1 准确性(来源: EfficientNetV2 论文

考虑到这一假设,EfficientNetV2 的作者使用了带有自适应正则化的渐进学习。想法很简单。在前面的步骤中,网络在小图像和弱正则化上被训练。这允许网络快速学习特征。然后图像尺寸逐渐增大,正则化也是如此。这使得网络很难学习。总的来说,这种方法具有更高的精度、更快的训练速度和更少的过拟合。

图 11。具有自适应正则化的渐进学习算法(来源: EfficientNetV2 论文)

初始图像尺寸和正则化参数是用户定义的。然后,在特定阶段(M)之后,应用线性插值来增加图像大小和正则化,如图 11 所示。这在图 12 中有更好的直观解释。随着历元数的增加,图像尺寸和放大倍数也逐渐增加。EfficicentNetV2 使用三种不同类型的正则化— Dropout、RandAugment 和 Mixup。

图 12。具有自适应正则化视觉解释的渐进学习(来源: EfficientNetV2 论文

2.3 结果

  1. EfficientNetV2-M 实现了与 EfficientNetB7(以前最好的 EfficientNet 型号)相似的精度。此外,EfficientNetV2-M 的训练速度比 EfficientNetB7 快近 11 倍。

图 13 a .与其他先进模型的参数效率比较(来源: EfficientNetV2 论文)

图 13 b. FLOPs 与其他先进模型的效率比较(来源: EfficientNetV2 论文)

图 13 c .与其他先进模型的延迟比较(来源: EfficientNetV2 论文)

如图 13 a、13 b 和 13 c 所示,EfficientNetV2 模型优于所有其他最先进的计算机视觉模型,包括视觉变压器。

要了解更多关于视觉变形金刚的信息,请访问下面的链接

[## 变形金刚在图像识别方面比 CNN 强吗?

towardsdatascience.com](/are-transformers-better-than-cnns-at-image-recognition-ced60ccc7c8)

图 14 显示了在 ImageNet21k 上预训练有 1300 万张图像的 EfficientNetV2 模型和在 ImageNet ILSVRC2012 上预训练有 128 万张图像的一些模型与所有其他最先进的 CNN 和 transformer 模型的详细比较。除了 ImageNet 数据集,模型还在其他公共数据集上进行测试,如 CIFAR-10、CIFAR-100、Flowers 数据集和 Cars 数据集,在每种情况下,模型都显示出非常高的准确性。

图 14。EfficientNetV2 模型与其他 CNN 和变压器模型在精度、参数和 FLOPs 方面的比较(来源: EfficientNetV2 论文

3.结论

EfficientNetV2 型号比大多数最先进的型号更小、更快。这个 CNN 模型表明,即使视觉变形金刚已经席卷了计算机视觉世界,但通过获得比其他 CNN 更高的精度,具有改进训练方法的更好结构的 CNN 模型仍然可以获得比变形金刚更快更好的结果,这进一步证明了 CNN 将继续存在。

参考文献—

EfficientNetV2 纸张—

谭,明星&乐,郭。(2021).EfficientNetV2:更小的模型和更快的训练。arXiv,doi:10.48550/arXiv . 2104.00298 https://arxiv.org/abs/2104.00298

特征直觉:理解特征向量和特征值

原文:https://towardsdatascience.com/eigen-intuitions-understanding-eigenvectors-and-eigenvalues-630e9ef1f719

理解所有事物“本征”的直观基础

动机

我们通常希望转换数据以减少特征的数量,同时尽可能多地保留方差(即样本之间的差异)。通常,你会听到人们提到主成分分析(PCA)和奇异值分解(SVD),但如果不首先了解什么是特征向量和特征值,我们就无法理解这些方法是如何工作的。

语源

“特征向量”是一个非常奇怪的词。就像很多怪异的词(想想幼儿园)一样,我们可以责怪德国人。我听过的最有用的翻译来自 Coursera 课程“机器学习专业化的数学”:“eigen”的意思是“特性”。

“特征向量”是“表征”线性变换的向量。

视觉直觉

让我们看看任意线性变换下的两个向量,如平移、缩放、旋转和剪切。我们的大部分矢量都被移动了。不过,有些在转换前后指向相同的方向。

让我们来看一个简单的水平缩放!我们可以用线性变换矩阵[[2,0],[0,1]]来实现这一点。

图 1 :通过水平缩放可视化三个矢量。图片作者。

如果我们绘制三个单位长度向量——一个在 0 °,一个在 45 °,一个在 90°—并想象应用变换矩阵后会发生什么,我们会看到一些向量仍然指向与之前相同的方向(0°和 90 °),而其他向量则不指向相同的方向(45°)。有趣的是,这两个向量前后都指向同一个方向。在线性变换下,这些向量仅由一个标量项进行缩放。我们在 90°处的单位矢量没有改变,即缩放 1,而我们在 0°处的单位矢量加倍。这些向量就是我们的特征向量!

线性变换的特征向量是那些保持指向相同方向的向量。对于这些向量,变换矩阵的作用只是标量乘法。对于每个特征向量,特征值是向量在变换下缩放的标量。

数学

绘制一堆矢量并等待动画渲染并不是一个非常有效的方法。幸运的是,我们需要做的只是将我们已经建立的直觉形式化。有些方程式看起来有点吓人,但是一旦我们理解了它们的来源,它们就没那么糟糕了。

虽然数学可以扩展到任意维数的矩阵,但我们将坚持使用 2x2 矩阵进行演示。

让我们考虑一个线性变换矩阵 A. 如我们所见,矩阵的特征向量是刚刚缩放的向量。这些标量是特征值,我们称它们为 λ 。我们称我们的特征向量为 x

现在一起…特征向量 x 被我们的特征值 λ 缩放,被我们的矩阵 A 缩放。

我们可以用图 2 中的顶部等式来形式化。

图 2 :特征向量和特征值的基本形式化。图片作者。

让我们移动一些术语!减去 λx 并分解出 x 给出了一个很好的零值等式。为了从矩阵 A 中减去一个常数( λ ,我们需要将它乘以一个与 A 维数相同的单位矩阵。

让我们求解我们的特征向量和特征值!我们对这些方程的“琐碎”解不感兴趣,在这些解中, x 向量的值为零。相反,我们想知道什么时候项 (A-λI )等于零。我们可以通过检查行列式(图 3 )的值为零来实现这一点!

图 3:2 x2 矩阵行列式的定义。图片作者。

现在让我们展开我们的矩阵 A ,这样我们就可以看到矩阵中的每个值(图 4 )。

图 4 :展开矩阵 a .作者图片。

将这些东西拼凑在一起,我们得到了图 5 所示的等式。

图 5 :检查 det( A-λI)=0。图片作者。

使用我们从图 3 中定义的行列式,我们可以代入我们的值。

图 6 :将矩阵中的值代入行列式的定义中。图片作者。

最后,乘以各项,我们恢复出一种叫做“特征多项式的形式

图 7 :“特征多项式”的定义图片作者。

理论上我们只能做到这一步了!现在,让我们应用这个“特征多项式”,求解我们的特征值( λ )。

图 8 :样本矩阵 a .作者图片。

将矩阵中的值代入我们的特征多项式…

图 9 :求解矩阵 a 的特征多项式,作者图片。

我们得到我们的特征值( λ )。现在,我们可以代入我们的特征值,来求解我们的特征向量。

图 10 :根据特征值确定我们的特征向量。图片作者。

这是一个古怪的结果……@λ= 2*,* [0,-x₂] = 0。我们的 x₁似乎已经消失了。这是什么意思?

这意味着对于 λ = 2,只要 x₂为零,x₁可以等于任何值。

  • 例如[5,0]、[1,0]和[-3,0]

同样,对于 λ = 1,只要 x₁为零,x₂就可以等于任何东西。

  • 例如,[0,2],[0,-1],[0,8]

我们通过用占位符变量 t 代替可以取任何值的项来表达这种不变性。

图 11 :定义我们空间的特征向量。图片作者。

这正是我们的视觉直觉告诉我们的!我们空间的所有水平向量都是本征向量,它们由本征值 2 缩放。我们空间的所有垂直向量都是本征向量,它们由本征值 1 缩放。

自己图谋试试!

我发现为自己策划事情很有价值。如果你想试试,看看下面的来源!

承认

重要的是在最明确的地方给予信任!虽然文章中的代码是我的,但是用于可视化的包( manim )肯定不是!可视化库和解释的方法都是无耻的从 3blue1brown 偷来的。

文章前面提到过,但是我爱这个 Coursera 系列:机器学习专精数学!

我很欣赏你的阅读!我希望这有助于解释一个复杂的概念。如果我犯了什么错误或者有什么不清楚的地方,请告诉我!

为数据科学选择数据存储时的八个考虑因素

原文:https://towardsdatascience.com/eight-considerations-when-choosing-a-data-store-for-data-science-c71ce72b05de

选择合适的技术,使数据科学家能够专注于数据科学而不是 IT 基础设施,这将有助于企业获得其在数据科学和机器学习方面投资的收益

法比奥在 Unsplash 上的照片

这里有一个悖论,它绊倒了许多扩展数据科学运营的企业:当他们意识到他们需要积极主动地组装合适的基础架构,以将数据科学置于尽可能多的业务运营的核心时,在不招致一点痛苦的情况下进行新的基础架构投资已经太晚了。

但是,无论您的组织刚刚开始扩展其数据科学运营,还是您正在努力将数据科学置于尽可能多的业务流程的核心,您都需要考虑支持强大的数据科学实践的要求。对于所有企业来说,这将是你的组织未来生存的基础。

在本次讨论中,我们将重点关注数据存储和支持整个企业大规模数据科学的功能。如果你想让你的公司走上成功之路,你需要考虑收集和组织数据的最佳方式。此外,您需要利用所有对您的 MLOps 计划有用的数据;您不希望使用因数据存储无法捕获或管理某些数据馈送而受到损害的数据集。

记住,在机器学习和人工智能中,垃圾入/垃圾出( GIGO )效应极其强烈。如果缺少存储平台,您就无法获得具有可靠访问和可用性能的高质量数据。

因此,需要考虑八个因素:

1。可扩展性:更多的数据胜过更好的算法,我们已经看到了大量令人信服的证据。在 Halevy、Norvig 和 Pereira 的《数据的不合理有效性》一书中,作者认为“……简单的模型和大量的数据总是胜过基于更少数据的更复杂的模型。”因此,当您的数据存储无法扩展以容纳更多数据,并且在项目进行过程中,您发现由于这种限制,您需要进行数据平台迁移时,您的项目就注定要失败。

今天的神经网络能够做出惊人的事情!这并不是因为这些架构自 20 世纪 60 年代开发以来已经有所改进。相反,这是因为我们现在有能力存储和处理海量数据。非常聪明的算法无法弥补数据的缺乏。这根本不是一个选项。

每个行业都变得由数据驱动。但是,想想因无法扩展数据存储而失去的机会,就令人难以置信。以医疗保健行业为例:Statista 报告称,到 2020 年,医疗保健数据生成量超过数据存储能力的比例超过 2 比 1。当超过一半的生成数据因为组织没有存储这些数据的方法而被丢弃时,这意味着大量情报的丢失,而这些情报本来可以很好地用于改善患者的结果。请这样想:这个问题的答案,*“我们到底该不该储存它?”*应该基于数据是否有用,而不是基于容量限制。

此外,可伸缩性不仅仅意味着容纳大量数据的能力。当您处理这些数据时,系统还必须能够保持良好的性能和响应能力。大量的机器学习算法被迭代训练,这意味着要对数据进行成百上千次的检查。如果您正在操作一个大型数据集(不能固定到内存中),数据存储的访问时间和速度将成为一个重要的瓶颈。

数据科学家通常喜欢开源工具,喜欢 PostgreSQL、MongoDB 等。例如,它们远没有雪花的大规模并行处理(MPP)能力。当考虑将开源工具用于小规模数据操作时,它们很有吸引力。但是,当您转向企业范围的 MLOps 计划时,您会很快发现依赖这些开源解决方案并在内部维护它们变得完全不可行。

2。灵活性:关系数据库为王的日子已经一去不复返了。关系数据库非常适合处理结构化数据。然而,在许多机器学习领域,如计算机视觉或自然语言处理(NLP),对半结构化和非结构化数据的支持是必不可少的。

企业数据库对非结构化数据的支持有限。这不是它们的设计初衷,因此它们在 MLOps 中的作用并不明显。在为您的数据操作选择数据存储时,您不仅需要考虑您当前的需求,还需要尽可能考虑您将在两年、三年或五年内运行的模型。支持机器学习工作负载的数据存储系统在格式方面必须灵活。它应该很容易处理表格数据和其他格式,如 JSON、Avro、ORC、Parquet、XML 等等。

3。混合工作负载:一些数据存储擅长处理事务性工作负载,这些工作负载只需要在一两个数据行上执行计算,并以亚秒级响应时间执行。其他人擅长管理分析工作负载,这些工作负载需要处理数百万行数据,并且响应时间相对宽松。出于数据操作的目的,数据科学家需要在这两方面都出色的数据存储。

雪花的建筑真的很有趣。他们采用压缩的列方法来存储数据,这允许大规模地高性能处理分析和事务性工作负载。雪花的“虚拟仓库”,本质上是 MPP 计算集群,具有内在的灵活性,因为它们可以随着资源需求的变化而动态地创建、调整和删除。这些微分区支持高效扫描各个列,以支持所需的分析和事务查询的执行。

4。可靠性:当停电导致公司数据不可用时,所有数据操作会突然停止;对于您的数据科学家来说,除了等待 it 团队纠正这种情况之外,别无他法。从财务角度来看,让您的数据操作闲置一段时间已经够糟了,但在停机期间无法接收新数据很可能会加剧这一问题。

数据是组织可以拥有的最大资产。不要误解我——人力资本也非常重要。数据科学人才需求量很大。有大量的报道称,在一个继续快速增长的领域,数据科学家持续短缺。如果你失去了整个数据科学/机器学习团队,你将会经历一段痛苦的旅程。但是可以雇佣新员工,对现有员工进行再培训。是的,这将是昂贵的,对企业来说将是一个挫折,但公司仍然可以恢复。另一方面,如果你丢失了所有的数据,很可能几个月后你的公司将不复存在。

数据存储的可靠性是绝对必要的。在内部运行数据库的单个实例很容易,但是如果您需要在集群中运行多台服务器,并提供负载平衡、灾难恢复和其他服务,那么管理起来就要复杂得多,成本也高得多。在大多数情况下,最好使用云提供商的服务来进行数据存储操作。像雪花,GCP,AWS 和其他供应商有专门的团队来照顾基础设施的可靠性,从可用性和安全性的角度来看。这是他们每周 7 天、每天 24 小时都在做的事情,他们积累的经验让他们比内部团队更有优势。

**5。云原生存储:**这在某种程度上是上面讨论的可靠性考虑的扩展。利用云原生存储资源可以获得多项重要优势:

  • 灵活的容量:利用云资源允许您的数据科学团队根据需求调整分配的资源。如果您的系统完全是内部部署的,您将不得不投资昂贵的硬件来进行扩展。然后,一旦需求下降,缩小规模就更成问题了。
  • 维护和安全性:如上所述,将这些服务卸载给供应商几乎总是有利的。他们通常会比内部团队做得更好,因为这是他们的主要关注点;他们以此为生,每天应对威胁会让服务提供商比您的内部团队更有经验。
  • 地理恢复能力—这不仅涉及通过冗余实现的群集可靠性,还涉及在特定区域隔离数据以符合区域法规的能力。

处理敏感数据的公司通常会有多个禁止相互连接的网络。他们可能有专门的内部环境来存放敏感数据,以符合当地或区域的数据治理要求。其他不受限制的数据可以存储在任何地方,因此经常被发送到云。数据科学家面临的问题是,当我们处理两个(或更多)截然不同的孤立环境时,我们如何进行协作?

当数据不能跨越国界时,你需要对数据进行计算,而不是反过来。但是,如果您有云数据存储支持的分布式数据操作,您可以在您最好的数据科学家居住的任何地方开发和试验模型(只要您只使用样本/匿名数据)。借助云原生存储,您可以在世界任何地方构建和训练这些模型。一旦远程数据科学家调整了模型,他们可以轻松地将它们导出到敏感数据所在的区域,本地数据科学家可以在那里部署模型并针对实际的敏感数据执行操作。

**6。易用性:**这里的关键思想是让数据科学家做数据科学。数据存储必须易于从任何语言和工具(Python、R、MATLAB 等)访问。)你的数据科学家更喜欢。同样重要的是,要有一个开放的数据科学平台,可以轻松地与各种数据存储集成。没有必要经历大量的数据存储选择过程,而只是意识到当前的 DS 堆栈不支持它。

此外,使用数据存储的学习曲线不应该太陡。如果您的数据科学团队有自我改进的时间预算,他们应该花时间学习新的算法和技术,获取更多的领域知识,或者更加精通他们日常使用的语言和框架。他们不应该花费分配的时间学习晦涩的专有 API 或 SQL 语法,仅仅是为了获得他们需要的数据。如果给定的解决方案要求用户开发大量的专有知识,例如,开发人员认证途径包括五门培训课程(每门 3-5 天)和五场认证考试,那么这可能不是您的数据科学团队可以依赖的理想系统。

您所使用的技术工具应该尽可能对您的数据科学家不可见。您的数据科学家已被聘用,并根据他们所带来的深厚专业知识获得报酬。因此,他们的时间是非常宝贵的;他们应该把钱花在开发、培训、部署和监控模型上,而不是浪费在 it 基础设施上。

考虑一个医院环境:我们不希望看到外科医生花费时间来确保初级保健医生或急诊室人员在电子健康记录(EHR)中捕获的笔记是可访问的和完整的。毫无疑问,外科医生获得这些信息对患者的结果至关重要,但是外科医生需要将他们的时间和精力花在他们唯一胜任的活动上。在数据科学运营中,我们不希望数据科学家必须管理他们用于开发、培训和部署模型的基础架构。或者,更糟糕的是,我们不希望看到他们调整他们的流程来适应或解决他们的技术工具带来的限制。

7 .**。数据版本化:**数据科学中的再现性极其重要。如果您不想手动处理数据版本控制,支持这种现成功能的数据库可以让事情变得非常简单。雪花时间旅行和零拷贝克隆是这种重要能力的极好例子。

假设以下情况:为一家金融机构工作的数据科学家使用机器学习开发和训练一个评分模型,以批准或拒绝贷款申请人。该模型已部署,并在前两年在整个企业中运行良好。但随后,该银行受到了该模型存在偏见的指控。数据科学团队在审核期间必须回答的第一个问题是他们如何训练模型。他们需要访问两年前使用的培训数据。

为了重现性,公司需要他们的原始数据。一些系统很好地自动化了这一点;Oracle 拥有“闪回”技术,可以提供特定时间段的数据。它自动跟踪一段时间内数据的所有更改,并返回查询中请求的日期之后的数据。并非所有数据存储都以这种方式工作,而是需要数据科学家手动跟踪更改或手动在不同的时间点拍摄快照。

**8。未来焦点:**这是一个长期的数据运营策略。您的数据存储的潜在供应商是否具有前瞻性?他们的路线图是什么?他们懂机器学习和数据科学吗?他们是否提供(或考虑)对 Python/R 的数据库内执行的支持?他们能利用 GPU 吗?他们可以部署模型进行数据库内评分吗?他们会考虑 Kubernetes 的支持吗?诸如此类的问题将有助于您了解数据存储提供商在未来几年的发展前景。

了解您的数据操作中使用的工具和产品在多大程度上符合供应商的产品战略,以及他们的路线图的哪一部分是以机器学习和数据科学为导向的,这一点非常重要。简而言之,寻找一家了解数据科学和机器学习的数据存储供应商,其对该学科在五年内的发展前景的愿景与您的数据科学团队的愿景相吻合。

结论

几乎在所有情况下,数据存储的购买决策都取决于企业内部的购买委员会。组织数据运营的成熟度将决定委员会的组成人员。那些没有深入到将数据模型置于其业务运营核心的组织可能会将决定权交给 IT 领导层。那些在成为模型驱动型企业的道路上走得更远的公司可能会有一位首席数据分析官(CDAO)或同等职位的人来做出最终决定。但是,最终,IT 人员和数据科学领导者和实践者应该根据上述八个考虑因素,共同决定一个能够提供最佳功能组合的解决方案。

无论您的组织是否比您所希望的晚一点认识到数据存储的功能对数据操作的成功至关重要,或者您是否能够选择理想的数据存储来发展您的数据操作,所有人员都需要了解选择满足您现在和未来需求的最佳解决方案有多重要。

每个数据科学家都应该知道的 8 种数据结构

原文:https://towardsdatascience.com/eight-data-structures-every-data-scientist-should-know-d178159df252

从基本数据结构到抽象数据类型

克林特·王茂林在 Unsplash 上拍摄的照片

作为一名数据科学家,工作的一个关键部分是能够理解组织和结构化数据的最佳方式,以便根据任务有效地存储或访问数据。这可能是为了将数据输入到模型中,存储模型实现的结果,或者能够在以后可视化数据。因此,我们需要知道我们可以使用什么样的数据结构,以及它们的优缺点。下面列出了八种数据结构/类型,对于了解和实施数据科学家工作的任何部分都很有用。

内置 Python 数据结构

首先从内置的 Python 数据结构开始,在任何数据科学家的旅程和与 Python 的交互开始时,都可能会遇到这种数据结构。这些是 Python 中内置的数据结构,以后可以在其上实现抽象数据类型或更复杂的数据结构。

目录

该列表是您在 python 编程之旅中可能遇到的第一批数据结构之一。本质上,它们就像一个现实生活中的列表,您可以在一个结构(在本例中是一个变量)中存储多个数据点。它们是可变的(一旦被定义就可以被改变)、有序的(除非被明确改变,否则它们保持它们的顺序)、可索引的(我们可以通过它们的索引来访问项目)并且它们还可以包含重复的记录。列表的好处是,如果您知道各个数据点的索引,就可以很容易地访问它们,因为顺序是保持的,但是如果您不知道位置,那么查找项目的成本会很高。

词典

字典是另一种常见的数据结构,您在 Python 之旅的早期经常会遇到(甚至在其他语言中也是如此)。它们的形式类似于实际的字典,在键:值结构中,键(单词)与值(描述)成对出现。它们的关键特征是可变的、有序的和可索引的(如果您知道 items 键),但是它们的键中不能包含重复的记录(值可以是重复的)。字典的主要区别在于它们的键:值结构允许用户基于键而不是数字索引来访问值。这意味着,由于这种配对,它们比其他数据结构占用更多的空间,但如果您知道这些键,它可以允许更有效的搜索(如果您不知道,这将成为一个问题)。

罗布·霍布森在 Unsplash 上拍摄的照片

一组

集合是 Python 中的另一种数据结构,但很少遇到或使用。同样,单个变量可以用来存储多个信息点,但是它们是唯一的,因为它们是无序的,不能存储重复的。这种结构的关键特征是它们是无序的、不可索引的,不能包含重复的值,但是它们仍然是可变的。当您希望只存储唯一值或者希望检查不同数据源之间的重叠时,这样做的好处就显现出来了。当您关心项目顺序或想要重复值时,您不希望使用这些。

元组

最后,我们有元组,这也是不太常见或使用。像列表一样,它们是有序的和可索引的,但是主要的区别是它们不能被改变(它们是不可变的)。这意味着,当您希望确保信息不会被意外更改(例如通过用户交互或编程过程)时,它们是有用的,但是您仍然希望以后以某种顺序访问信息。这种用法的一个例子是存储来自模型的输出、起始值或者即使用户可能与它们交互时也要保持的值。

抽象数据类型

除了上面的四种内置数据结构之外,学习和理解其他几个数据结构也很重要,但它们都是可以用 Python 实现的抽象数据类型。这些是对数据结构的广泛描述,我们可能希望在 Python 中实现这些数据结构来存储具有特定功能的数据。您可能会遇到一些不同的抽象数据类型,但您需要了解的四种主要类型是堆栈、队列、链表和图形。

长队

队列抽象数据类型的目的是像现实生活中的队列一样工作,因为添加的内容只在后面添加,而您只能从前面删除项目。这意味着它遵循先进先出(FIFO)结构,并保持数据点的顺序。应用这种数据结构的常见例子包括为 CPU 调度作业、为打印机排队作业或广度优先搜索算法。当您希望确保第一个添加到结构中的是首先移除的结构时,这很有用。

Giphy 的 GIF

与队列类似,堆栈是一种抽象数据类型,它存储项目添加到结构中的顺序,但与队列不同,它只允许对堆栈顶部进行添加和删除。这意味着这遵循后进先出(LIFO ),就像在餐馆里叠盘子或吃一堆煎饼一样。当我们希望程序或用户只访问添加到结构中的最新内容(与队列相反)但必须保持顺序时,可以使用这种方法。常见的例子包括解释器读取代码的方式或计算机上的撤销按钮(ctrl + z)。

giphy 的 Gif

链表

链表是一个包含信息的节点集合,以线性方式指向另一个节点(例如 A → b → c →d)。这种情况有两种主要形式,一种是双向链表(链接到上一个和下一个节点),另一种是单向链表(只指向下一个节点)。这允许容易地从列表中插入或删除项目,因为只需要改变受影响的节点之间的链接。这意味着与传统列表的相同操作相比,它的计算量要小得多。当我们不确定最终项目集合的长度,我们不关心随机访问或者我们想要快速插入时,这可能是有用的。

图表

我们所关心的最后一个抽象数据结构是一个可以用来存储项目及其关系的图。这通常用大写字母 G 来表示,它包含顶点(包含信息)和边(顶点之间的关系)。后者可以包含关于是否存在关系的信息以及该关系的潜在权重/强度,例如距离或值。这方面的例子包括道路网络表示棋子可以进行的不同移动,并为社交网络中使用的基于图形的数据库奠定基础。

结论

您在工作中可能会遇到许多不同的数据结构和类型,根据您计划使用数据的目的,了解使用其中一种来存储数据之间的权衡是很重要的。这里介绍的只是您将遇到的不同类型的数据结构的一个子集,但是理解这些数据结构通常可以作为理解许多其他数据结构的基础,例如 Numpy 数组或 Pandas 数据帧。数据结构和算法在软件工程和数据科学面试中出现也是很常见的,因此值得将这些知识留在脑海中以备将来使用。

如果你喜欢你所读的,并且还不是 medium 会员,请使用下面我的推荐链接注册 Medium,以支持我和其他了不起的作家

https://philip-wilkinson.medium.com/membership

或者随时查看我在 Medium 上的其他文章

[## scikit-learn 决策树分类器简介

towardsdatascience.com](/introduction-to-decision-tree-classifiers-from-scikit-learn-32cd5d23f4d)

弹性网回归:从 Sklearn 到 Tensorflow

原文:https://towardsdatascience.com/elastic-net-regression-from-sklearn-to-tensorflow-3b48eee45e91

如何在 Python 中进行 sklearn 和 Tensorflow 之间的等价弹性网回归

迈克·考克斯在 Unsplash 上的照片

这篇文章是为那些想要比较弹性网回归的 sklearn 和 Keras 实现的从业者准备的。主要是如何从 Sklearn 损失函数到 Keras (Tensorflow)损失函数。

文章的主要部分:

  • 回归中的正则化简介。
  • 弹性网的 Sklearn 实现。
  • 弹性网的张量流实现。
  • 从一个框架到另一个框架。
  • 编写自定义损失函数。
  • 比较结果。

所有的代码都在我的仓库里:【https://github.com/Eligijus112/regularization-python

回归是机器学习中确定响应变量的平均值 Y 和特征 X 之间关系的过程。

简单回归方程;作者图片

模型的预测用带帽的 y 表示,并通过从数据中估计系数β来计算:

预测方程;作者图片

不带帽子的 beta 表示理论模型,带帽子的 beta 表示实际模型,使用可观测数据获得。我们如何计算系数β?

计算从定义一个错误开始。误差显示了预测值与真实值的差异。

观察值 I 的误差;作者图片

很明显,我们希望误差尽可能小,因为这将表明我们找到的系数接近基本因变量 Y 给出我们的特征的最佳值。此外,我们希望对负误差和正误差(以及其他原因)给予相同的权重,因此我们将引入平方误差项:

观察值 I 的平方误差;作者图片

在标准线性回归中,我们的目标是将所有观测值的平方误差降至最低。因此,我们可以定义一个称为均方误差的函数:

MSE 函数;作者图片

x 和 y 数据是固定的——我们不能改变我们观察到的东西。我们拥有的唯一杠杆是尝试将不同的贝塔系数与我们的数据相匹配,以获得尽可能低的 MSE 值。这是线性回归的总体目标— 仅使用β系数将定义的损失函数降至最低。

为了最小化 MSE 值,我们可以使用各种优化算法。最流行的算法之一是随机梯度下降或者简称为 SGD

梯度部分是我们根据所有系数计算偏导数:

所有 I 的偏导数;作者照片

下降部分是我们迭代地更新每个系数β:

下降部分;作者照片

M 是迭代次数。

α常数是一个正值,称为学习率。

随机部分是我们不在一次迭代中使用数据集中的所有样本。当更新系数β时,我们使用数据的子集,也称为小批量。

回归中的正则化是一种避免建立更复杂模型的方法,以避免过拟合的风险。正规化有多种类型,但最受欢迎的有三种:

  • 套索
  • 山脉
  • 弹性网

我们通过向我们优化的损失函数添加某些项来进行正则化。在 Lasso 回归的情况下,传统的 MSE 变为:

通用套索公式;作者图片

我们在新的损失函数中加入绝对系数值的和。系数的绝对和越大,损耗越高。因此,在优化时,算法因系数大而受到惩罚。

通用岭公式;作者图片

岭回归带来了更大的系数损失,因为幅度是平方的。岭回归的一个缺点是,这种类型的回归不会将任何系数设置为 0,而 lasso 可以用于特征约简,因为它可以将一些系数设置为零。

通用弹性网公式;作者照片

弹性网结合了脊和套索回归。λ值通常介于 1 和 0 之间。

既然我们已经有了一个简单的理论概述,我们可以继续讨论实际部分了。我们将使用的数据来自 Kaggle 关于 2014 年至 2015 年美国房屋销售的数据。

原始数据;按作者分类的表格

我们将尝试使用 6 个可用特征来解释房子的价格。

我们将标准化这些功能。在本文中,我想展示 TensorFlow 和 Sklearn 之间的可比性,因此我不会花太多时间对数据集进行特征工程。

标准化数据集;按作者分类的表格

让我们试试弹性网的 Sklearn 实现

https://sci kit-learn . org/stable/modules/generated/sk learn . linear _ model。ElasticNet.html

Sklearn 中使用的损失函数为:

Scikit 学习弹性净损失函数;作者图片

让我们设置 alpha = 1,lambda(在 Sklearn 中称为 l1 比)为 0.02。

# Fitting the model to data using sklearn
el = ElasticNet(alpha=1.0, l1_ratio=0.02)
el.fit(d[features], d[y_var])# Extracting the coefs
coefs = el.coef_# Creating a dataframe with the coefs
coefs_df = pd.DataFrame({‘feature’: features, ‘coef_sk’: coefs})# Appending the intercept
coefs_df = coefs_df.append({‘feature’: ‘intercept’, ‘coef_sk’: el.intercept_[0]}, ignore_index=True)

得到的系数数据帧是:

弹性净回归结果;按作者分类的表格

Tensorflow 是一个非常流行的深度学习网络。该框架允许我们使用弹性网络正则化,以及使用 L1L2 类https://keras.io/api/layers/regularizers/#l1l2-class。

让我们比较两个公式 sklearn one 和 TensorFlow。
Scikit 学:

Scikit 学习弹性网

张量流:

正如我们所见,TensorFlow 没有将等式的 MSE 部分除以 2。为了获得可比较的结果,我们需要为 TensorFlow 创建自己的自定义 MSE 函数:

模仿 sklearn 的自定义 MSE 作者代码

写完这个自定义损失函数后,我们现在有以下等式:

张量流的自定义损失;作者方程式

现在,我们可以均衡这两个方程,并尝试根据 sklearn 的 alpha 和 lambda,在 TensorFlow 中创建 lambda 1 和 lambda 2 的公式。

左手边:sklearn,右手边:TensorFlow 作者方程式

因此,我们只剩下:

将 sklearn 正则化转换为张量流正则化参数的函数:

从 sklearn 到 TensorFlow 作者代码

现在,让我们将所有内容放在一起,通过正则化训练一个张量流模型:

# Defining the original constants
alpha = 1.0
l1_ratio = 0.02# Infering the l1 and l2 params
**l1, l2 = elastic_net_to_keras(alpha, l1_ratio)**# Defining a simple regression neural net
numeric_input = Input(shape=(len(features), ))
output = Dense(1, activation=’linear’, kernel_regularizer=L1L2(l1, l2))(numeric_input)model = Model(inputs=numeric_input, outputs=output)
optimizer = tf.keras.optimizers.SGD(learning_rate=0.0001)# Compiling the model
model.compile(optimizer=optimizer, loss=**NMSE()**, metrics=[‘mse’])# Fitting the model to data using keras
history = model.fit(
  d[features].values, 
  d[y_var].values, 
  epochs=100, 
  batch_size=64
)

α= 1.0,l1 比值为 0.02 时,张量流正则化的常数为 0.02 和 0.49。

训练看起来很顺利:

模特培训;作者照片

张量流和 sklearn 回归系数:

# Creating the coef frame for TF
coefs_df_tf = pd.DataFrame({
  ‘feature’: features + [‘intercept’],
  ‘coef_tf’: np.append(model.get_weights()[0], model.get_weights()[1])
})## Merging the two dataframes
coefs_df_merged = coefs_df.merge(coefs_df_tf, on='feature')coefs_df_merged['percent_diff'] = (coefs_df_merged['coef_sk'] - coefs_df_merged['coef_tf']) / coefs_df_merged['coef_sk'] * 100

生成的数据帧为:

系数比较;按作者分类的表格

系数相差很小。这是因为在引擎盖下,sklearn 和 TensorFlow 用不同的函数初始化系数,涉及到一些随机性,我们总是可以调整时期和批量大小以获得越来越接近的结果。

在本文中,我们:

  • 简单介绍了一下正规化。
  • 创建了自定义张量流损失函数。
  • 在 TensorFlow 中创建了一个模仿 sklearn 正则化的函数。
  • 创建并比较了两个模型。

快乐学习编码!

完整代码:

https://gist . github . com/eligijus 112/5309 d9dd 037236 B1 a 95 a7b 906 f 2406 cf

[1]
美国金县房屋销售;
网址:https://www . ka ggle . com/datasets/harlfoxem/housesales prediction?资源=下载

执照:https://creativecommons.org/publicdomain/zero/1.0/

Elasticsearch Beats 研讨会#1

原文:https://towardsdatascience.com/elasticsearch-beats-workshop-1-c73189069793

安全 Metricbeat

托姆·米尔科维奇在 Unsplash 上拍摄的照片

欢迎来到 Beats 工作坊的第一部分。像往常一样,为了使每篇文章尽可能紧凑,我将把查询简化为片段。如果你想看到完整的代码,配置,或查询,请咨询我的 GitHub 页面。如果谷歌把你带到这里,你可能想检查一下系列的其他部分。

今天,我们将为 Metricbeat 配置安全通信。使用 Elasticsearch Stack 8,默认情况下启用 SSL 通信。官方的文档可能会让人不知所措,你可能很难找到具体的参数。除了 SSL 之外,我们还将了解需要为 Metricbeat 授予的特定权限。最后但同样重要的是,应该如何安全地调用这个用户的凭证。一如既往:让我们直接开始吧!

本次研讨会的系统拓扑

Elasticsearch 和 Kibana 的 YAML 文件全文在我的 GitHub 页面上。设置非常简单:Elasticsearch 节点作为 srvelk8 暴露给网络。本次研讨会的 Elasticsearch 版本为 8.0.1。Elasticsearch、Kibana 和 Metricbeat 都运行在同一个 VM 上。下面是我的/etc/hosts 的样子:

192.168.1.68   srvelk8      srvelk8.local.ch

根 CA 指纹

为了安全通信,您需要根证书或根 CA 十六进制编码指纹。我将向您展示这两个选项,现在,我们来看看如何获取指纹。你的 kibana.yml 里可能有指纹:

grep fingerprint /etc/kibana/kibana.ymlca_trusted_fingerprint: a2929842b8920e5c0ebd91ea157c159f16b62df7e3b6998de93ad56ff2693b59}]

如果您可以访问 http_ca.crt,也可以使用 OpenSSL 提取指纹:

openssl x509 -fingerprint -sha256 \ 
  -in /etc/elasticsearch/certs/http_ca.crt| \
  grep Fingerprint|cut -d  '=' -f2| tr -d ':'|tr A-Z a-z

a2929842b8920e5c0ebd91ea157c159f16b62df7e3b6998de93ad56ff2693b59

装置

安装 Metricbeat 与:

curl -L -O [https://artifacts.elastic.co/downloads/beats/metricbeat/metricbeat-8.0.1-amd64.deb](https://artifacts.elastic.co/downloads/beats/metricbeat/metricbeat-8.0.1-amd64.deb)
sudo dpkg -i metricbeat-8.0.1-amd64.deb
apt-mark hold metricbeat

如果想在 Ubuntu 使用 APT,请看一下官方文档。

创建必要的角色和用户

首先,我们需要一个角色在 Kibana/Elasticsearch 中设置 Metricbeat。初始设置后,您将删除该角色,因为它不再是必需的。现在创建角色“metricbeat_setup_role ”,并授予这些权限:

作者图片

现在为 Metricbeat 创建用户。我现在使用 metricbeat_internal:

作者图片

创建密钥库

因为您不想将用户名/密码存储在 yml 文件中,所以我们需要一个密钥库来加密凭证并将它们存储在一个安全的地方:

metricbeat keystore create
metricbeat keystore add MB_USER
metricbeat keystore add MB_PW

我们现在可以在 YAML 文件中将用户名和密码定义为“\({MB_USER}”和“\)”。keystone 本身存储在与“path.data”中定义的文件夹相同的文件夹中,在 Ubuntu 中默认为/var/lib/metricbeat。使用运行 metricbeat 的同一用户运行 keystone 命令。

重要事项:定义至少包含一个字母的密码。否则,密码将被存储为一个 int,而不是一个字符串,这将导致以后的问题。

配置

您现在可以启用您需要的所有模块。因为我使用 Metricbeat 进行堆栈监控,所以我启用了 Elasticsearch、Kibana 和 beat 模块:

metricbeat modules enable elasticsearch-xpack
metricbeat modules enable kibana-xpack
metricbeat modules enable beat-xpack

metricbeat.yml

例如,Kibana 设置的部分:

setup.kibana:
  host: "[http://srvelk8.local.ch:5601](http://srvelk8.local.ch:5601)"
  username: "${MB_USER}"
  password: "${MB_PW}"
  ssl:
    #certificate_authorities: /etc/elasticsearch/certs/http_ca.crt
    enabled: true
    ca_trusted_fingerprint: "a2929842b8920e5c0ebd91ea157c159f16b62df7e3b6998de93ad56ff2693b59"

如您所见,我禁用了 certificate_authorities。因为我使用指纹,所以不需要 certificate _ authorities。我们还避免将用户名和密码定义为明文。

模块配置

模块也是如此。以下是 elasticsearch-xpack.yml 的一个例子:

- module: elasticsearch
  xpack.enabled: true
  period: 10s
  hosts: ["[https://192.168.1.68:9200](https://192.168.1.68:9200)"]
  protocol: "https"
  username: "${MB_USER}"
  password: "${MB_PW}"
  #api_key: "TxDLW38BJmYfkUzINFEF:0foLANnlS-qMNgx_jEXhGw"
  ssl:
    #certificate_authorities: /etc/elasticsearch/certs/http_ca.crt
    enabled: true
    ca_trusted_fingerprint: "a2929842b8920e5c0ebd91ea157c159f16b62df7e3b6998de93ad56ff2693b59"

由于每个模块与其他模块略有不同,请查看 GitHub 页面上的示例。

设置 Metricbeat

现在运行“metricbeat setup -e”。过一会儿,您应该会看到这些消息:

metricbeat setup -eIndex setup finished.
Loading dashboards (Kibana must be running and reachable)
Loaded dashboards

创建监控角色

现在为 Metricbeat 创建监视角色。添加角色“metricbeat_monitoring”后,您可以删除角色“metricbeat_setup_role”:

作者图片

用此角色更新用户。

启用并运行 metricbeat

好了,就这样。您现在可以运行 Metricbeat:

systemctl enable metricbeat
systemctl start metricbeat

结论

如果你成功了:祝贺你!现在,您应该能够通过安全通信运行 Metricbeat 了。如果您遗漏了某个特定的配置,那么 metricbeat reference 有更多的示例,请查看。

如果您有任何问题,请在 LinkedIn 上留言、联系或关注我

原发布于https://cdax . ch

Elasticsearch Beats 研讨会#2

原文:https://towardsdatascience.com/elasticsearch-beats-workshop-2-ea07d7bb4b00

创建您的 Metricbeat 发货人

在 Unsplash 上 Launde Morel 拍摄的照片

欢迎来到 Beats 工作坊的第二部分。这里可以找到第一家作坊。像往常一样,为了使每篇文章尽可能简洁,我将代码简化为片段。如果你想看完整的代码,请查阅我的 GitHub 页面。如果谷歌把你带到这里,你可能还会检查系列的其他部分。

今天,我们创建了第一个 Metricbeat 模块和 metricset。虽然官方文档很好地解释了如何设置您的开发环境,但是弄清楚如何编写 Metricbeat 模块可能是相当具有挑战性的。虽然本研讨会不要求更深入的 Go 语言知识,但我推荐 Stephen Grider 的 Udemy 课程“Go:完整的开发人员指南(Golang)”来获得一些该语言的基础知识。老实说:在我写这篇文章的两周前,我对 Go 一无所知——但是这个课程帮助我理解了幕后发生的事情,并理解了默认安装中提供的 Metricbeat 模块的源代码(因此也理解了其机制)。

我们的第一个 Metricbeat 模块将使用一个非常简单的配置作为数据收集的输入—进行预热。然而:在本系列的第三部分中,我们将深入研究并开发一个基于更实际用例的度量集。今天,我们将讨论以下主题:

  • 设置 Go 和开发环境
  • 定义用例
  • 定义数据结构
  • 定义模块和度量集的配置
  • 编码矩阵集
  • 编译和配置 metricbeat
  • 测试矩阵集

如你所见,有很多工作要做——请给自己拿杯茶,系好安全带准备上路。说够了:让我们直接开始吧!

设置 Go 和开发环境

安装 Go

请记住,我们将克隆几个 Git Repos,因此需要千兆字节的磁盘空间。有了 10GB 的自由空间,你就好了。

在您设置 Go 之前,请通过以下方式检查您的 Go 版本:

go version

如果你的版本低于 1.17.8,你需要从官方回购安装 Go。官方文档会引导你完成这个过程,不过,我会为你简化它。我们需要安装 python 3.7 和 Go 1.17.8:

sudo apt install python3.7
sudo apt-get install python3-venv
sudo mkdir -p /usr/local/go
wget [https://go.dev/dl/go1.17.8.linux-amd64.tar.gz](https://go.dev/dl/go1.17.8.linux-amd64.tar.gz)
sudo tar -C /usr/local/ -xzf go1.17.8.linux-amd64.tar.gz
export PATH=/usr/local/go/bin:$PATH

再次查看 go 版本,应该会看到类似“go 版本 go1.17.8 linux/amd64”的内容。

克隆官方 Beats 回购

通过设置$GOPATH 环境变量并克隆官方的 beats Git Repo,现在安装 dev env:

mkdir ~/go
export GOPATH=~/go
mkdir -p ${GOPATH}/src/github.com/elastic
git clone [https://github.com/elastic/beats](https://github.com/elastic/beats) ${GOPATH}/src/github.com/elastic/beats

安装 Mage

安装 mage,它是 Go 构建所需要的,并将设置开发环境的其余部分:

cd ~
git clone [https://github.com/magefile/mage](https://github.com/magefile/mage)
cd mage
go run bootstrap.go
sudo cp $GOPATH/bin/mage /usr/local/bin
cd ${GOPATH}/src/github.com/elastic/beats
make update

模和度规集的区别

首先:模和度规集之间有什么区别?该模块包含一个或多个公制集合。虽然模块是顶层文件夹,但它为每个 metricset 保存一个文件夹和一个“_meta”文件夹。下图显示了该结构:

作者图片

我们不会修改顶层文件夹“my_module”中的文件。生成“fields.go”和“doc.go”。我们将只使用文件“fields.yml”、“docs.asciidoc”、“config.yml”和“file_mon.go”。或者换句话说:图中蓝色标记的方框。

创建模块和度量集框架文件

设置开发环境后,我们为新的 Metricbeat 模块和 metricset 创建一个框架:

cd ${GOPATH}/src/github.com/elastic/beats/metricbeat
make create-metricset

我们将输入以下值:

Module name: my_module 
Metricset name: file_mon

make 应该以下列结尾:

Module my_module created. 
Metricset file_mon created.

为了测试一切是否正常,我们现在将编译 Metricbeat:

mage update
mage build
chmod go-w ~/go/src/github.com/elastic/beats/metricbeat/metricbeat.yml
/metricbeat -e -d "*"

定义用例

我们将做一些相当简单的事情:我们将检查一个文件是否经常被修改,因此是否有实际的数据。

我们通过每 10 秒检查一次修改时间戳来监控这些文件,并将修改时间和实际时间之间的差异发送给 Elasticsearch —我们将该差异称为“delta”。我们不为警报设置阈值,这是下一个研讨会的使用案例。我们只想在 my_module.yml 的配置中添加一个文件列表,并将文件名和增量发送给 Elasticsearch。

在 my_module/_meta/config.yml 中定义数据结构

第一:路径

~/go/src/github.com/elastic/beats/metricbeat/module/my_module

将从这一点缩短为 just my_module。

在这种情况下,数据结构非常简单:它只是一个文件名列表。由于“make metric-set”已经创建了我们将需要的所有文件,我们可以在 my_module 文件夹中的一个文件中实现所需的结构,该文件将用作我们未来模块 my_module 的默认配置文件。请打开文件“my_module/_meta/config.yml”。您应该会看到类似这样的内容:

- module: my_module
  metricsets: ["file_mon"]
  enabled: false
  period: 10s
  hosts: ["localhost"]

替换为:

- module: my_module
  metricsets: ["file_mon"]
  enabled: true
  period: 10s
  hosts: ["localhost"]
  files:
  - "/var/log/syslog"

现在,正如您可能猜到的,定义了“var/log/syslog ”,只是为了让未来的用户了解文件名必须如何放置在我们未来的配置文件 my_module.yml 中。该配置文件将是生成的文件 my_module.yml 的蓝图,该文件将在我们在过程结束时编译和构建 Metricbeat 后创建。

配置文件 config.yml 的重要之处在于,它包含了所有指标集的配置。如果添加多个指标集,请确保将它们都添加到 config.yml 中。

定义模块和指标集的配置

my_module/_meta/docs.asciidoc

我们一步一步地首先定义我们的配置文件。作为第一步,我们向 my_module 文档添加一个描述。您可以随意向文件 my_module/_meta/docs.asciidoc 添加这样的注释:

This is the my_module module.
You can find the sourcecode in [https://github.com/PascalThalmann/ElasticBeatWorkshop/tree/master/2_create_a_module_1](https://github.com/PascalThalmann/ElasticBeatWorkshop/tree/master/2_create_a_module_1)

my_module/_meta/fields.yml

my_module/_meta/fields.yml 文件包含关于模块的顶级信息。我们只改变描述,因为其余的都很好:

- key: my_module
  title: "my_module"
  release: beta
  description: >
    my_module module is part of the metricbeat workshop 2
  fields:
    - name: my_module
      type: group
      description: >
      fields:

my _ module/file _ mon/_ meta/docs . asciidoc

正如您可能猜到的,文件 my _ module/file _ mon/_ meta/docs . asciidoc 包含了描述。随意添加类似这样的内容:

This is the file_mon metricset of the module my_module.
The metricset reads the last modicfication time and subtracts it from the current time. The result will be a field delta wich will be send to the Elasticsearch cluster

my _ module/file _ mon/_ meta/fields . yml

my _ module/file _ mon/_ meta/fields . yml 文件包含我们的 metricset 的字段定义。它将用于在 metricbeat 的弹性搜索索引中创建正确的映射。在这里设置正确的结构和核心数据类型至关重要。如果您不确定您需要哪种核心数据类型,请查看官方文档中的数据类型。我们将添加一个字段“文件名”键入“关键字”:

- name: file_mon
  type: group
  release: beta
  description: >
    file_mon
  fields:
    - name: files
      type: object
      description: >
        the filenames with full path of the files that will monitored

编码矩阵集

好了,我们定义了所有的配置文件。现在让我们对 metricset 进行编码,代码位于文件 my_module/file_mon/file_mon.go 中

为指标集定义所需的数据结构

我们现在定义对象矩阵集的结构。虽然 Go 不是面向对象的语言,但结构可以被看作是对象的属性集合。每个属性必须由一个数据类型定义,如果数据被添加到该结构,字段的数据类型必须与您添加到该字段的数据相匹配。因此,当我们处理一个结构时,我们处理的数据必须被分配给正确的字段并具有正确的数据类型。因为我们只读取文件列表,所以使用 string 类型的值列表就可以了:

type MetricSet struct {
        mb.BaseMetricSet
        files           []string
}

你可能已经看到在这个结构中定义了另一个东西:mb.BaseMetricSet。这就是神奇之处:这是一个接口,实现了读取 my_module.yml 中的配置选项所需的所有方法。长话短说:接口 mb。MetricSet 让我们以一种非常方便的、近乎懒惰的方式读取配置文件。

创建度量集实例

我们接下来要看的是“新”函数。此函数将读取配置,并将使用 struct MetricSet 作为从配置文件 my_module.yml 中读取的值的存储:

func New(base mb.BaseMetricSet) (mb.MetricSet, error) {
  cfgwarn.Beta("The my_module file_mon metricset is beta.")type Config struct {
 Files      []string `config:"files"`
  }

  config := Config{}if err := base.Module().UnpackConfig(&config); err != nil {
    return nil, err
  }return &MetricSet{
    BaseMetricSet:  base,
    files:          config.Files,
    }, nil
}

你可能会问自己,阅读部分在哪里?它在这里:

Files      []string `config:"files"`

我们在这里定义命名文件列表,并分配在“文件”字段下定义的配置中的所有内容。我们的配置文件如下所示:

- module: my_module
...
  files:
  - "/var/log/syslog"

我们可以看一下&MetricSet 对象:

return &MetricSet{
    BaseMetricSet:  base,
    files:          config.Files,
    }, nil

我们在这里返回的是对 struct MetricSet 的引用。与号代表引用 MetricSet 的内存地址。稍后,您将了解更多关于结构以及如何将它们传递给函数的知识。

获取数据并发送给 Elasticsearch

我们现在遍历我们的文件列表,读取修改时间并从实际时间中减去它。为此,我们需要我们的 MetricSet、库“os”以及“time”和“math”。这个函数很简单,但是要理解细节,您需要更深入地了解语言 Go:

func (m *MetricSet) Fetch(report mb.ReporterV2) error {
 files := m.filesfor _, file_name := range files{act_time := time.Now()
  f, _ := os.Open(file_name)
  out, _ := f.Stat()
  mod_time := out.ModTime()
  difference := act_time.Sub(mod_time).Seconds()
  delta := int(math.Round(difference))

让我们来看看第一行:

func (m *MetricSet) Fetch(report mb.ReporterV2) error {

调用“Fetch”方法时使用了一个带 mb 的参数。ReporterV2 方法。mb。ReporterV2 方法向 Elasticsearch 发送数据。Fetch 方法最终返回一个错误对象。所以不管发生什么,Fetch 方法总是会返回一些东西。

“m *MetricSet”是一个“接收器”:这意味着,我们可以用点的概念访问和操作结构 MetricSet。星号告诉我们,我们通过引用访问 struct MetricSet,这非常重要,因为传递给函数的结构是复制的。因此,如果要操作原始结构,应该始终向函数传递结构的引用,否则,只能操作该结构的副本。

files := m.files

为了方便起见,我复制了存储在 struct MetricSet 中的文件列表。“:=”概念意味着变量“文件”被初始化。

for _, file_name := range files{

这里唯一要提到的是循环调用的“”部分。在 Go 中用“range”循环数组会返回两个值:键和值——因此需要定义两个变量。但是如果不需要元素键呢?如果没有使用变量,Go 将报告一个错误。但是如果你不需要这个变量,你可以通过使用一个“”来超越它。

act_time := time.Now()

我正在访问时间包。请查看官方围棋文档了解更多用例。

让我们来看看循环中进行一些系统调用的部分:

f, _ := os.Open(file_name)
out, _ := f.Stat()
mod_time := out.ModTime()

我正在访问 Go os 软件包并使用“操作系统。打开方法来访问文件。然后,我使用该文件对象上的“Stat”接口来收集统计信息,比如修改时间。尽管 Go 不是面向对象的,但接口是 Go 使用方法的一种非常强大的方式。简而言之:接口为同类对象提供方法,比如这个文件对象。

difference := act_time.Sub(mod_time).Seconds()
delta := int(math.Round(difference))

好,我们再次调用时间库,从实际时间中减去修改时间。由于对象的类型是 float,所以我使用数学库和 round 方法来获得正确的值,最终将 float 类型转换为 int。

最后,我们发送带有文件名和增量的报告:

report.Event(mb.Event{
 MetricSetFields: common.MapStr{
   "delta": delta,
   "file": file_name,
 },
})

我们从 ReporterV2 方法调用事件函数,并将我们要发送的值放入要返回的结构中。

就是这样!如需完整代码,请查看本次研讨会的 GitHub Repo。

编译和配置 metricbeat

如果您正确设置了您的开发环境,您应该能够切换到 metricbeat 的根文件夹,并使用 mage 编译新的模块和 metricset:

cd ~/go/src/github.com/elastic/beats/metricbeat
mage update 
mage build

在我们用新编译的 Metricbeat 二进制文件测试我们的模块之前,您需要设置 metricbeat.yml 配置文件以连接到 Elasticsearch 集群。因为您可能从 GitHub 克隆了最新的 metricbeat 版本,所以您需要向我们的 metricbeat.yml 添加以下选项:

output.elasticsearch.allow_older_versions: true

如果您只想查看新模块中的条目,您还需要禁用系统模块—默认情况下它是启用的:

./metricbeat modules disable system 
./metricbeat modules enable my_module

测试矩阵集

您可以使用详细日志记录来启动 Mericbeat:

./metricbeat -e -d "*"

这些文档应该出现在您的 metricbeat 索引中:

作者图片

结论

如果你成功了:祝贺你!现在,您应该能够创建 Metricbeat 模块和 metricset 了。这是一个相当简单的配置示例,需要在 Elasticsearch/Kibana 端做一些不必要的调整。下一个研讨会将向您展示如何创建和读取更复杂的配置,这将为 metricset 增加一些智能。

如果您有任何问题,请发表评论,联系或关注我在 LinkedIn 上的

原载于https://cdax . ch

Elasticsearch Beats 研讨会#3

原文:https://towardsdatascience.com/elasticsearch-beats-workshop-3-c47054367a80

适用于您的 Metricset 的更复杂的配置

约书亚·索蒂诺在 Unsplash 上拍摄的照片

欢迎来到 Beats 工作坊的第三部分。这里可以找到第一家作坊。像往常一样,为了使每篇文章尽可能简洁,我将代码简化为片段。如果你想看完整的代码,请查阅我的 GitHub 页面。如果谷歌把你带到这里,你可能还会检查系列的其他部分。

这个工作坊是在上一个工作坊的基础上建立的,你可以在这里找到。所有的准备工作、开发环境的创建以及定制 metricbeat 框架的创建都在这里。如果您想加快进程并跳过阅读那篇文章,按照文章中描述的那样设置开发环境,克隆存储 workshop 2 的文件的 GitHub repo,您就拥有了这个 workshop 所需的一切。

今天,我们创建了一个更加复杂的 metricset,其配置为您提供了更多选项,并为您的托运人增加了更多智能。在本模块结束时,您将能够创建各种指标,只需了解一点 Go 知识。你会惊讶于创建一个专业的 Metricbeat 模块是多么容易。

但是:研讨会的一部分还包括部署您的 Metricbeat 模块。在第二次研讨会中,我们完全忽略了一件事,那就是你新创作的节拍的包装。剧透警告:Docker 会参与!

这是游戏计划:

  • 定义用例
  • 定义数据结构
  • 定义模块和度量集的配置
  • 编码矩阵集
  • 编译和配置 Metricbeat
  • 测试矩阵集
  • 创建 Dockerfile 文件
  • 建立形象
  • 运行容器并检查输出

如你所见,有很多工作要做——请给自己拿杯茶,系好安全带准备上路。说够了:让我们直接开始吧!

定义用例

在最后一部分中,我们只对监控文件列表感兴趣。我们没有为警报定义任何阈值——我们只将文件名和上次修改时间之间的差异发送到 Elasticsearch 集群。

我们需要的输入

这一次,我们为每个文件添加了四个选项。我们甚至为默认值定义了选项。这使用户能够保持 YAML 配置文件尽可能的精简。让我们确定所需的选项:

  • 文件名(必填)
  • 以秒为单位的最大增量(可选)
  • 警报的开始时间(可选)
  • 警报的结束时间(可选)
  • 一周中应发出警报的日期(可选)
  • 除文件名外,以上所有选项的默认值

配置文件的结构如下:

作者图片—图表 1:输入字段

我们所做的处理

使用来自 YML 配置文件的输入(我们设置的选项),我们的处理将如下所示:

  1. 读取每个文件名(字段文件名)
  2. 读取每个定义的选项(最大增量、开始时间、周天数)
  3. 我们做了一些检查:
  • 我们检查文件名是否存在。如果没有,我们将向群集发送一条警告消息,其中包含文件名和特定消息。
  • 如果设置了可选字段,我们会检查每个可选字段。如果不是:我们使用特定字段的默认值
  • 我们检查实际工作日和实际时间。我们将它与工作日以及定义实际一天的监控时间窗口的开始和结束时间进行比较。如果我们在时间窗口中,并且实际工作日是要监控的一天:我们的字段“active”被设置为 true。否则,我们的字段“活动”将被设置为假。
  • 我们读取文件统计信息,并用文件最后一次修改的时间戳计算实际时间的增量。我们将它存储在字段“delta”中。
  • 最后,我们将 delta 与 max_delta 进行比较,如果 delta 超过 max_delta 中定义的值,则将 alter 设置为 true

我们发送的输出

如果文件名存在,我建议将所有输入值和处理步骤中计算出的值一起发送给 Elasticsearch。这使得调试更加容易。如果没有,我们只需要一个特定的错误消息,我们可以在 ELassticsearch 中监控它,以查找不再存在的文件(因此要么不再需要监控,要么存在更深层次的问题)。我们将发回的数据结构如下所示:

作者提供的图片—图表 2:输出字段

可能与输出有关的事情

监控框架可以是:在 Elasticsearch 集群中有一个观察者,它向您最喜欢的工具(电子邮件、Slack、Nagios 等)发出警报。)在警报为真且监视器激活的情况下。

定义模块和度量集的配置

因为我们已经在上一个研讨会中创建了数据结构,所以我们只需要更改配置文件的一个子集。在这里,您可以看到文件夹结构的概述,我们将更改的文件标记为蓝色:

作者图片—图表 3:文件夹结构

与第二次研讨会一样,路径

~/go/src/github.com/elastic/beats/metricbeat/module/my_module

将从这一点简称为“我的 _ 模块”。

my_module/_meta/config.yml

首先,我们定义模板,该模板将用于生成文件 my_module.yml,该文件将在 metricbeat 安装期间在/etc/metricbeat/modules.d 中创建。my_module/_meta 中 config.yml 的缩写版本需要这样放置:

- module: my_module
  metricsets: ["file_mon"]
...
  default_max_delta: 600
  default_start_time: [8,0]
  default_end_time: [22, 0]
  default_week_days: [0, 1, 2, 3, 4, 5, 6]
  files:
  - file_name: "/var/log/syslog"
    max_delta: 1200
    start_time: [7, 0]
    end_time: [22, 0]
    week_days: [1, 2, 3, 4, 5]

my _ module/file _ mon/_ meta/fields . yml

我们现在设置 config.yml 中定义的结构的字段定义。这需要正确的数据类型,因为 metricbeat 需要它来在 Elasticsearch 的索引中创建正确的映射:

- name: file_mon
  type: group
  release: beta
  fields:
    - name: default_max_delta
      type: object
      object_type: long
    - name: default_start_time
      type: object
    - name: default_end_time
      type: object
    - name: default_monitoring_week_days
      type: object
    - name: files
      type: object
      fields:
        - name: file_name 
          type: keyword
        - name: max_delta
          type: object
          object_type: long
        - name: monitorin_start_time
          type: object
        - name: monitoring_end_time
          type: object
        - name: monitoring_week_days
          type: object

在这里设置正确的结构和核心数据类型至关重要。如果您不确定您需要哪种核心数据类型,请查看官方文档中的数据类型。

编码矩阵集

这就是配置文件。我们现在可以在我们的度量集中实现规范。

为指标集定义所需的数据结构

我们现在定义对象矩阵集的结构。虽然 Go 不是面向对象的语言,但结构可以被看作是对象的属性集合。每个属性必须由一个数据类型定义,如果数据被添加到该结构,字段的数据类型必须与您添加到该字段的数据相匹配。因此,当我们处理一个结构时,我们处理的数据必须被分配给正确的字段并具有正确的数据类型。因为我们的缺省值都是整数列表,所以我们在 MetricSet 结构中定义它们,如下所示:

type MetricSet struct {
 mb.BaseMetricSet
 DefaultMaxDelta  int          `config:"default_max_delta"`
 DefaultStartTime []int        `config:"default_start_time"`
 DefaultEndTime   []int        `config:"default_end_time"`
 DefaultWeekDays  []int        `config:"default_week_days"`
 FileConfig       []FileConfig `config:"files"`
}

标签 config:“XXX”将用于匹配我们在配置中定义的字段。功能“New”将读取配置,并在标签的帮助下进行匹配。

如您所见,在该结构的最底部,有一个数据类型为 FileConfig 的 list FileConfig。这只不过是我们需要定义的另一个具有数据类型的结构。结构 FileConfig 将保存我们为每个文件名定义的特定值:

type FileConfig struct {
 FileName  string `config:"file_name"`
 MaxDelta  int    `config:"max_delta"`
 StartTime []int  `config:"start_time"`
 EndTime   []int  `config:"end_time"`
 WeekDays  []int  `config:"week_days"`
}

在我们深入研究“新”方法之前,我们先用一个函数来返回 MetricSet 和 FileConfig 结构:

func returnConfig() MetricSet {
 return MetricSet{}
}

创建度量集实例

New-method 将调用函数 returnConfig()并接收 my_module.yml 中的值:

func New(base mb.BaseMetricSet) (mb.MetricSet, error) {
  ...
  config := returnConfig()
  ...
  return &MetricSet{
    BaseMetricSet:    base,
    FileConfig:       config.FileConfig,
    DefaultMaxDelta:  config.DefaultMaxDelta,
    DefaultStartTime: config.DefaultStartTime,
    DefaultEndTime:   config.DefaultEndTime,
    DefaultWeekDays:  config.DefaultWeekDays,
  }, nil
}

我们现在正在填充我们定义的结构矩阵集。如果在配置中发现了什么,New()将解包数据并用它填充我们的 MetricSet 结构。

获取数据并发送给 Elasticsearch

我们的 fetch 方法读取存储在 MetricSet 中的数据,并将其保存在变量 FileConfig 中。它保存了我们之前定义为 struct MetricSet 的特定文件配置。我们用引用 m.FileConfig 来调用它。

func (m *MetricSet) Fetch(report mb.ReporterV2) error {
      FileConfig := m.FileConfig

现在,让我们来读一下实际的时间、年份和月份。这是以后需要的:

act_time := time.Now()
year := act_time.Year()
month := act_time.Month()

现在让我们遍历文件 config,看看循环中的前几行:

for _, file_config := range FileConfig {
   f, err := os.Open(file_config.FileName)

调用标准 Go 库的一个好处是,它们中的许多会返回一个错误对象。在我们的例子中,确保我们打开的文件是存在的是非常重要的。否则,您将得到一个非常糟糕的异常,如下所示:

log.origin":{
     "file.name":"runtime/panic.go",
     "file.line":221 },
"message":
     "recovered from panic while fetching 
     'my_module/file_mon' for host 'localhost'. 
     Recovering, but please report this.",
"error":{
     "message":"runtime error: invalid memory 
     address or nil pointer dereference" }

因此,我们评估 err 对象,如果它不为零,让 metricbeat 向 Elasticsearch 发送一个报告——正如我们在图 2 中定义的那样:

if err != nil {
   report.Event(mb.Event{
       MetricSetFields: common.MapStr{
           "error":     "file not existing",
           "file_name": file_config.FileName,
           "warning":   true,
           },
       })
       continue
 }

我们现在读取下一个块中的统计数据,并计算增量:

out, _ := f.Stat()
mod_time := out.ModTime()
difference := act_time.Sub(mod_time).Seconds()
delta := int(math.Round(difference))

从那时起。Sub()。Seconds()方法以 float 形式返回秒数,我们对其进行舍入并将其转换为 int。

我们现在为变量 alert 和 active 设置默认值——没什么特别的或值得解释的:

alert := false
active := false

接下来的几行得到实际的工作日。我们首先测试 file_config。工作日切片有实际数据。如果没有,我们采用默认配置。此外,我们测试实际的工作日是否在 file_config 中。工作日切片:

if len(file_config.WeekDays) == 0 {
    file_config.WeekDays = m.DefaultWeekDays
}
for _, x := range file_config.WeekDays {
    if act_weekday == x {
        active = true
    }
}

我们现在测试所有其他的 file_config 值。如果它们是空的,我们设置默认值。默认值必须由引用“m”调用,因为我们没有将它们赋给变量:

if file_config.MaxDelta == 0 {
   file_config.MaxDelta = m.DefaultMaxDelta
}
if len(file_config.StartTime) == 0 {
   file_config.StartTime = m.DefaultStartTime
}
if len(file_config.EndTime) == 0 {
   file_config.EndTime = m.DefaultEndTime
}

我们现在检查我们现在是否在监视器应该被激活的时间窗口中。如果是,我们检查增量是否超过阈值,如果是,则发出警报:

window_start := time.Date(year, month, file_config.StartTime[0],           
                file_config.StartTime[1], 0, 0, 0, time.UTC)window_end := time.Date(year, month, file_config.EndTime[0],
              file_config.EndTime[1], 0, 0, 0, time.UTC)if window_start.Before(act_time) && window_end.After(act_time) && active {
   if file_config.MaxDelta < delta {
      alert = true
      }
   } else {
      active = false
}

最后但同样重要的是,我们正在发送数据,如图 2 所示:

report.Event(mb.Event{
   MetricSetFields: common.MapStr{
      "delta":      delta,
      "max_delta":  file_config.MaxDelta,
      "file_name":  file_config.FileName,
      "alert":      alert,
      "active":     active,
      "start_time": file_config.StartTime,
      "end_time":   file_config.EndTime,
      "week_days":  file_config.WeekDays,"default_max_delta":  m.DefaultMaxDelta,
      "default_start_time": m.DefaultStartTime,
      "default_end_time":   m.DefaultEndTime,
      "default_week_days":  m.DefaultWeekDays,
   },
})

就是这样。是时候测试我们的矩阵集了。

编译和配置 Metricbeat

如果您正确设置了您的开发环境,您应该能够切换到 metricbeat 的根文件夹,并使用 mage 编译新的模块和 metricset:

cd ~/go/src/github.com/elastic/beats/metricbeat
mage update
mage build

在我们用新编译的 Metricbeat 二进制文件测试我们的模块之前,您需要设置 metricbeat.yml 配置文件以连接到 Elasticsearch 集群。因为您可能从 GitHub 克隆了最新的 metricbeat 版本,所以您需要向我们的 metricbeat.yml 添加以下选项:

output . elastic search . allow _ older _ versions:true

如果您只想查看新模块中的条目,您还需要禁用系统模块—默认情况下它是启用的:

./metricbeat modules disable system
./metricbeat modules enable my_module

测试矩阵集

您可以使用详细日志记录来启动 Mericbeat:

./metricbeat -e -d "*"

如果您在 metricbeat 索引中看到数据,请检查您的群集。现在,默认的 my_module.yml 文件应该是这样的:

作者图片

警报和活动可以是真或假。如果运行 Metricbeat,您应该会看到一个具有上述结构并包含上述数据的文档。当我们稍后在 Docker 容器中运行相同的配置时,这看起来会有所不同。

构建和部署

如果您还没有找到,请转到 metricbeat 根文件夹,创建一个归档文件,将我们需要的所有内容打包到 my_module.tar.gz 中,并将所有内容复制到新创建的文件夹~/workspace 中:

cd ~/go/src/github.com/elastic/beats/metricbeat/
./metricbeat modules enable my_module
tar zcvf my_module.tar.gz \
   module/my_module \
   fields.yml \
   metricbeat.reference.yml \
   metricbeat.yml \
   modules.d/my_module.yml \
   metricbeat
mkdir ~/workspace
cp my_module.tar.gz ~/workspace
cd ~/workspace

有了那个包裹,你现在就没事了。你可以用 sftp 或者 Ansible 之类的工具把它复制到你想要的每一台机器上。或者你可以用它创建一个 rpm。或者创建一个 Docker 映像并将其上传到您选择的 Docker 注册表。我们采用后者,让我们解压缩 tar.gz-archive:

tar zxvf my_module.tar.gz

创建 Dockerfile 文件

我们创建的映像将包含我们编译的二进制 metricbeat、metricbeat.yml 配置文件,以自动连接到我们的 Elasticsearch 集群,并且该过程使用用户 metricbeat 运行:

FROM ubuntu:18.04RUN useradd -rm -d /metricbeat -s /bin/bash -g root -G sudo -u 1000 metricbeat \
    && mkdir /metricbeat/modules.d \
    && chown metricbeat:root /metricbeat/modules.d \
    && apt update \
    && apt -y upgradeUSER metricbeat
WORKDIR /metricbeatCOPY metricbeat /metricbeatEXPOSE 9200CMD cd /metricbeat && ./metricbeat -e -d "*"

建立形象

我们现在使用 Dockerfile 文件构建映像,并将其标记为 my _ module 版:

docker build -f Dockerfile . -t my_module:1.0

将图像上传到您的注册表

这里是一个新版本 1.1 的整个过程。不要混淆,我使用 Nexus 3 作为 Docker 图像的本地注册表,但它与 Harbor 的过程相同:

docker login -u xxx -p yyy srvnexus:8082
docker build -f Dockerfile . -t my_module:1.1
docker image tag my_module:1.1 srvnexus:8082/repository/dh/my_module:1.1
docker image push srvnexus:8082/repository/dh/my_module:1.1

现在,您可以在每台运行 docker 的服务器上获取您定制的 Metricbeat:

docker pull srvnexus:8082/repository/dh/my_module:1.1

创建 Docker 图像的 tar.gz 档案

可以使用“docker 图像保存”将 docker 图像保存为 tar.gz-archive:

docker image save -o my_module.tar.gz [image id]

运行并测试 Docker 映像

运行容器的时间到了。因为我们不想构建新的映像,所以每次我们更改 my_module.yml 或 metricbeat.yml 文件时,我们都直接从本地文件系统挂载它。您可以通过 Puppet、Ansible 或任何其他部署工具分发这些配置文件:

METRICPATH=$HOME/workspace/metricbeat.yml
MODULEPATH=$HOME/workspace/modules.ddocker run \
--mount type=bind,source=$MODULEPATH,target=/metricbeat/modules.d \
--mount type=bind,source=$METRICPATH,target=/metricbeat/metricbeat.yml \
-it [image id]

检查在 Kibana 中创建的文档,您会感到惊讶:

作者图片

是的,文件/var/log/syslog 不存在。就像大多数码头集装箱一样。好了,让我们更改我们的文件~/modules.d/my_module.yml 并添加/var/log/lastlog 作为第二个要监视的文件:

- file_name: "/var/log/lastlog"
    max_delta: 10
    start_time: [2, 0]
    end_time: [22, 0]
    week_days: [0, 1, 2, 3, 4, 5]

再次启动容器:

docker container start $(docker container ls -lq)

您应该会看到 lastlog 的统计数据:

作者图片

从 docker.com 下载图片

最后一个命令:如果你想下载 Docker 镜像并随便玩玩,可以在docker.com上找到。

docker pull cdax75/workshop:my_module

按照我们在“运行并测试 Docker 映像”中所做的那样运行容器。

结论

如果你成功了:祝贺你!现在,您应该能够创建 Metricbeat 模块和 metricset,并将其部署为 docker 映像。这是一个比第一个例子更聪明的例子。如果您使用 file_mon.go 中的结构作为蓝本,您应该能够创建更复杂的 metricsets。

如果您有任何问题,请在 LinkedIn 上留言、联系或关注我。

玩得开心!

最初发布于https://cdax . ch