TowardsDataScience-博客中文翻译-2021-二十五-
TowardsDataScience 博客中文翻译 2021(二十五)
原文:TowardsDataScience Blog
协议:CC BY-NC-SA 4.0
Python 中的并发和并行
原文:https://towardsdatascience.com/concurrency-and-parallelism-in-python-bbd7af8c6625?source=collection_archive---------3-----------------------
理解大数据
Python 中可用方法的简明概述
照片由在 Unsplash 上拍摄
如果你即将开始一个大数据项目,你将要么检索大量信息,要么在你的机器上处理大量数据,或者两者兼而有之。然而,如果代码是顺序的或同步的,你的应用程序可能会开始挣扎。
让我们看看在每种情况下,哪些概念和 Python 库可以提高应用程序的性能。
什么是并发和并行,它们解决什么问题
有两个方面可以提高程序的速度——I/O 和 CPU 消耗。例如,如果您的代码需要通过网络进行大量的文件访问或通信,那么它就是 I/O 受限的。CPU 绑定的代码涉及大量计算。例如,训练统计模型绝对是一项计算密集型工作。
这两种类型的工作在所需资源方面有什么不同?
当 I/O 绑定的代码发送多个请求时,它并没有真正利用机器的 CPU 内核,因为本质上,它是在空闲地等待响应。因此,这样的应用程序不能通过增加更多的计算能力来提高性能。它更多的是关于请求和响应之间的等待时间。
对于 CPU 绑定的代码片段来说,情况正好相反。
缓解任何一种瓶颈的两种机制分别是并发和并行。
通常,并发被认为是比并行更大的概念。简单来说就是同时做多件事。在实践中,有一个特殊的角度来区分这两种思想,尤其是在 Python 中。并发通常被理解为同时“管理”多个作业。实际上,这些作业并不会同时执行。它们巧妙地交替出现。
然而,并行执行意味着同时执行多个任务,或者并行执行。并行性允许在一台机器上利用多个内核。
三个用于并发和并行的 Python 库
在 Python 中,并发由[threading](https://docs.python.org/3/library/threading.html)
和[asyncio](https://docs.python.org/3/library/asyncio.html)
表示,而并行是通过 [multiprocessing](https://docs.python.org/3/library/multiprocessing.html)
实现的。
穿线
使用threading
,您可以创建多个线程,您可以在这些线程之间分配一些 I/O 相关的工作负载。例如,如果您有一个简单的函数来下载一些文件download_file(f)
,您可以使用[ThreadPoolExecutor](https://docs.python.org/3/library/concurrent.futures.html#concurrent.futures.ThreadPoolExecutor)
来启动线程,然后使用map
从文件列表中调用每个参数文件:
*with ThreadPoolExecutor() as executor:
executor.map(download_file, files)*
这里值得一提的是,Python 中的线程工作方式与 Java 等其他语言不太一样——CPython 的全局解释器锁(GIL)实际上确保了内存使用是线程安全的,因此一次只能处理一个线程(更多信息请参见[threading](https://docs.python.org/3/library/threading.html)
文档)。因此,它实际上是一种如上定义的并发机制。
阿辛西奥
使用asyncio
,您可以为类似的目的创建任务:
*tasks = [asyncio.create_task(download_file(f)) for f in files]*
但是任务背后的想法不同于线程。事实上,任务运行在单线程上。然而,如果第一个任务正在等待它的响应而不是阻塞它,每个任务都允许操作系统运行另一个任务。这就是异步 IO* 的本质。(在后面的文章中对异步程序进行了更全面的介绍)。*
大多数情况下,您还会想要创建一个特殊的事件循环对象来管理主函数中的任务。
线程与异步
对于 I/O 绑定的程序来说,asyncio
模块可以显著提高性能,因为创建和管理任务的开销比线程少。
线程化方法可以被认为更危险,因为线程之间的切换可以在任何时候发生,甚至在语句执行的中途,这是由于抢先多任务,而asyncio
任务在准备切换时会发出信号——这种机制被称为协作多任务。如果此时出现问题,那么使用线程方法来跟踪它会更加困难。
然而,使用asyncio
模块需要编写大量代码来适应它。
多重处理
以上两种方法对于加速 I/O 相关的程序都很有效。至于 CPU 受限的程序,多重处理将真正有所帮助。
multiprocessing
模块为每个进程创建一个 Python 解释器。它实际上利用了您机器上的 CPU 内核数量。一个典型的 CPU 相关代码的例子是压缩文件。因此,如果您有一个函数compress_file(f)
,启动新进程并在它们之间分配工作负载的语法将类似于线程示例:
*with ProcessPoolExecutor() as executor:
executor.map(compress_file, files)*
如果多处理这么神奇,为什么不一直用呢?
用multiprocessing
写代码有几件棘手的事情。首先,您需要能够确定某些数据实际上是否需要被所有进程访问——因为进程之间的内存不是共享的。此外,有时很难确定程序的哪些部分可以清晰地划分为独立的进程。
最后,您应该仔细评估multiprocessing
带来的性能提升和成本之间的权衡。如果计算实际上不是那么密集的话,multiprocessing
可能不会加速那么多,因为为每个进程增加解释器会带来很大的开销。
你对这些模块的实验结果如何?对他们在不同环境中的行为有什么有趣的观察吗?
如果你对关于 Python 的文章感兴趣,可以随意查看我关于 Python 3.9 中的新特性和 Python 代码优化的帖子!
Python 中的并发性:如何用线程加速代码
原文:https://towardsdatascience.com/concurrency-in-python-how-to-speed-up-your-code-with-threads-bb89d67c1bc9?source=collection_archive---------28-----------------------
用 Python 实现并发执行的理论+实践指南
照片由雷纳·辛普森在 Unsplash 拍摄
顺序执行并不总是有意义的。例如,如果输出不相互依赖,让程序闲置是没有意义的。这就是并发背后的基本思想——今天你会学到很多关于这个话题的知识。
本文将教您如何通过并发运行任务来加速 Python 代码。请记住,并发执行并不意味着同时。有关同时(并行)执行的更多信息,请查看本文。
这篇文章的结构如下:
- 线程简介
- 实现线程—发送 1000 个请求
- 结果呢
- 结论
你可以在这里下载这篇文章的源代码。
线程简介
那么,什么是线程化呢?简而言之,这是一个允许并发运行代码的编程概念。并发意味着应用程序运行多个任务,第一个任务不必在第二个任务开始之前完成。
假设您正在向某个 web API 发出一堆请求。发送一个请求,等待响应,一遍又一遍地重复同样的过程是没有意义的。
并发使您能够在第一个请求等待响应时发送第二个请求。下图应该比文字更好地解释了顺序和并发执行背后的思想:
图 1 —顺序执行与并发执行(作者提供的图片)
请注意,单个点代表任务的一小部分。如果任务闲置一段时间,并发可以帮助加快运行时间(想想请求-响应类型的通信)。
现在,您已经从理论上了解了线程的基础知识。下一节将向您展示如何用 Python 实现它。
实现线程—发送 1000 个请求
用 Python 实现线程非常简单。但首先,让我们描述一下任务。
我们希望声明一个向端点发出 GET 请求并获取一些 JSON 数据的函数。JSONPlaceholder 网站非常适合这个任务,因为它是一个虚拟 API。我们将重复这个过程 1000 次,并检查我们的程序在多长时间内基本上什么都不做—等待响应。
先不穿线程做测试吧。剧本是这样的:
我认为在上面的脚本中应该没有什么是不熟悉的。我们重复请求 1000 次,并记录开始和结束时间。fetch_single()
函数中的打印语句在这里只有一个原因——查看程序在执行时的行为。
以下是运行该脚本后您将看到的输出:
图 2 —顺序执行的输出(作者提供的图片)
如您所见,一个任务必须完成,另一个任务才能开始。对我们这种类型的问题来说不是最佳行为。
接下来让我们实现线程化。该脚本看起来或多或少是相同的,但有几处不同:
- 我们需要额外的进口—
concurrent.futures
- 我们不打印最后一条语句,而是返回它
ThreadPoolExecutor()
用于并发提交和运行任务
以下是完整的片段:
一旦执行,您将看到类似于下面的输出:
图 3 —并发执行的输出(作者提供的图片)
这些都很好,但是速度真的有提高吗?接下来让我们检查一下。
结果呢
到目前为止,您已经了解了顺序执行和并发执行之间的区别,以及如何将代码转换为并发执行函数调用。
现在让我们比较一下运行时性能。下图以秒为单位总结了上述任务的运行时间,即进行 1000 次 API 调用:
图 4 —使用和不使用线程的运行时比较(图片由作者提供)
如您所见,执行时间减少了约 13 倍——至少可以说相当不错。
结论
今天,您已经学到了很多——从线程和并发执行背后的基本理论,到如何将非并发代码“转换”为并发代码。
请记住,并发并不是提高 Python 速度的万能答案。在您的应用中实现线程之前,请考虑应用是如何设计的。一个功能的输出是否直接作为另一个功能的输入?如果是这样的话,并发性可能不是您想要的。
另一方面,如果您的应用程序大部分时间处于空闲状态,“并发执行”可能就是您一直在等待的术语。
感谢阅读。
喜欢这篇文章吗?成为 中等会员 继续无限制学习。如果你使用下面的链接,我会收到你的一部分会员费,不需要你额外付费。
https://medium.com/@radecicdario/membership
了解更多信息
- Python 并行性:几分钟内加速 Python 代码的基本指南
- 新的 M1 macbook 对数据科学有好处吗?让我们来看看
- 如何使用 Python 创建 PDF 报告—基本指南
- 如何用 FastAPI 构建和部署机器学习模型
- PyTorch + SHAP =可解释的卷积神经网络
保持联系
- 关注我的 Medium 了解更多类似的故事
- 注册我的简讯
- 在 LinkedIn 上连接
- 查看我的网站
原载于 2021 年 2 月 8 日 https://betterdatascience.com**。
Conda:基本概念和技巧
原文:https://towardsdatascience.com/conda-essential-concepts-and-tricks-e478ed53b5b?source=collection_archive---------15-----------------------
对于初学者和有经验的用户
在这篇博文中,我将描述 conda 是什么,以及如何有效地使用它,无论你是第一次看它还是经验丰富的用户。虽然在后一种情况下,你会知道很多事情,但你仍然会发现一些技巧,可以用来改善你的体验。
在 Unsplash 上由 Patrick 拍摄的照片
目录
为什么康达
入门级举例
什么是康达
∘ 康达和 pip
∘ 康达 vs anaconda vs miniconda
如何安装康达
∘ 获取 Miniconda
安装包、 和环境
∘ 基地环境
∘ 其他环境
∘ 使用 Jupyter 和 conda 的最佳方式
∘ 移除环境
∘ 共享一个环境
通道
∘conda-forge 通道
Conda 和 pip
为什么是康达
如果符合以下一项或多项条件,Conda 适合您:
- 你花了太多的时间安装和配置软件,而不是专注于你需要工作的项目
- 你总是以一个巨大的混乱结束,你必须清理,然后从头开始
- 您希望能够在机器之间移动您的环境
- 您需要在同一台机器上为不同的项目安装冲突的需求
- 您希望有一个可重复、可跟踪的安装过程,可以跨平台和发行版共享,其中也可以包括非 python 包
- 您刚刚得到一台新机器(可能配有 GPU ),并且希望快速上手
- 你总是想尝试所有东西的最新版本,但不想处理不兼容的问题,也不想弄清楚哪个版本适合哪个版本
- 您有多台机器安装了不同的 Linux 发行版,甚至混合了 Linux/macOS/Windows,并且您希望在它们之间使用相同的环境
如果这些都是真的,康达将会对你非常有用。
入门级示例
比方说,你刚刚得到一个新的闪亮的 GPU 机器,你想安装 NVIDIA CUDA 工具包。你是想做这个然后花接下来的 5-10 个小时来完成这个任务,还是宁愿做了这个然后走自己的路?
> conda install -c conda-forge cudatoolkit=10.2
你想安装pytorch
并加入深度学习的行列吗?
> conda install pytorch cudatoolkit=10.2 -c pytorch
是否要在同一环境下安装 Tensorflow 和 Pytorch?这不是疯狂,只是:
> conda install -c conda-forge -c pytorch python=3.8 cudatoolkit=10.2 pytorch pytorch tensorflow tensorboard
还有更多。一般来说,大多数事情都是一个conda install
之遥。最重要的是,如果您搞砸了,您只需删除环境并重试,不会在您的系统中留下任何痕迹。
我希望这能给你一点提示,为什么 conda 是一个如此神奇的工具。让我们投入其中,了解更多相关信息。
什么是康达
Conda 是跨平台的,开源包管理器。
您可能已经在系统上使用了软件包管理器。在 Linux 中,你可能有一个或多个apt
、yum
或snap
。在 macOS 中你有homebrew
或其他。Conda 类似,但它是平台无关的。它确实适用于 Linux、Mac 和 Windows,并且在所有 3 个平台上都以相同的方式工作。
康达和皮普
一个常见的错误是将conda
与pip
相比较。它们相似,但在某种程度上也有很大不同:pip
是一个以 Python 为中心的包管理器(毕竟pip
包的存储库被称为 Python 包索引),而conda
是语言不可知的。虽然pip
包确实包含有时编译的库(例如,numpy
、scipy
、pandas
……),但一般来说,这些只是支持 Python 接口。相反,使用conda
你可以安装 C/C++库、编译器、图形库、与 Python 无关的成熟应用程序。你甚至可以使用conda
来安装 GPU 软件,比如 NVIDIA CUDA toolkit,或者go
语言,或者npm
、julia
等等。换句话说,conda
生态系统远远超越了 Python。因此conda
与yum
或homebrew
比pip
更相似,正如我们所说的。事实上,一个典型的conda
安装包含 pip
作为另一个包,你可以使用 pip 在你的 conda 环境中安装包(但是在你这样做之前要看下面的警告)。
康达 Vs 水蟒 Vs 迷你康达
如上所述,conda
是包经理。
Anaconda 是一个conda
包的集合,包含了您在日常工作中将要用到的大部分东西(当然也包括conda
包管理器)。有些人更喜欢它,因为它提供了一个很好的图形用户界面来处理环境和包,而不是命令行工具(CLI)。我个人从不使用 Anaconda,因为我觉得它很臃肿,而且我不介意 CLI。我用 Miniconda 代替。
Miniconda 是一个准系统的包集合:它包含 python、conda
包管理器以及一些其他的包(包括pip
)。它没有任何图形用户界面,只有 CLI。这是您构建环境的起点,该环境包含您需要的内容,仅此而已。它对于构建 Docker 容器也非常有用(见下文)。我个人只用 Miniconda。
如何安装康达
在这篇博文中,我们将重点放在 Miniconda 和 CLI 上。这是迄今为止最常见的用例,但是如果您想使用 Anaconda 及其 GUI,这里讨论的大部分内容也适用。
获取 Miniconda
转到这里并下载适合您的系统(Linux、Windows 或 Mac)的自安装包。把它保存在某个地方。
或者,运行以下命令:
注意:这里所有的命令行示例都假设使用 Linux 和
bash
shell。如果你在 Mac 和 bash 上,事情将是相同的。如果您使用的是另一个 shell,那么改动可能很小。例如,在下面的命令中,如果您在 Mac 上,请用 MacOSX 替换 Linux。我不会介绍 Windows,但是在 Windows 中将命令翻译成 shell 应该很容易(或者您可以使用 WSL
# Download Miniconda. You can also use wget or any other command
# line download tool for this purpose> curl [https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh](https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh) > Miniconda3-installer.sh
现在转到下载文件的地方,通过运行以下命令安装 Miniconda:
# Add run permissions for current user
> chmod u+x Miniconda3-installer.sh
> ./Miniconda3-installer.sh -b -p ~/miniconda3
您可以用任何其他前缀替换-p ~/miniconda3
,但是,通常最好保留那个前缀。为了简单起见,这篇博文的其余部分将假设 Miniconda 的路径。
恭喜你,你已经安装了迷你康达!现在让我们将它添加到 PATH 环境变量中,然后激活它:
如果您发现
conda
很有用,您可能希望将这些行添加到您的.bashrc
文件(或者您的 shell 用作 init 脚本的任何文件)中,这样您就不必为每个新的终端都这样做了。
> export PATH=${PATH}:~/miniconda3/bin# While you could use `conda activate` instead,
# this way of activating is more portable
> source ~/miniconda3/bin/activate
注意,我们将 miniconda3 路径放在 PATH env 变量的末尾。这是我使用的一个技巧,以便 Miniconda 的存在是微创的。例如,如果现在我在没有激活 conda 的情况下运行 python,我仍然会进入安装在我的系统中的 python 解释器,而不是 Miniconda 自带的解释器。如果我把 path 放在 PATH env 变量的开头,我会进入 Miniconda python,不管我是否激活 conda。
我们现在已经准备好了,您应该会看到这样的内容:
(base) giacomo@fd4af0669a8:/#
(base)
部分告诉你,你处于“基础”环境,conda 已经可以使用了。
等等!不要在基础环境中安装任何东西。首先阅读下一部分
安装软件包和环境
软件包有两种安装方式。一种是显而易见的,即使用命令:
> conda install [name of the package]
在某些情况下,您需要添加一个通道规范(参见关于通道的部分)。
另一种方法是创建环境并在创建过程中指定包。让我们看看那个。
环境是conda
中最有用的概念之一。它们是独立的装置:一个环境中的一切都依赖于该环境中的事物。
嗯,不是 100%,而是 99.9%。你仍然依赖于你的系统的一些核心库,比如 Linux 上的
*libc*
,但是这些都是高级细节(在底部描述)。对于所有意图和目的以及 99.9%的用户来说,我刚才说的近似值是考虑环境的一个好方法。
是的,它们在概念上类似于 python 的虚拟环境,但是它们可以包含比 python 包更多的东西。
如果你对这是如何实现的感兴趣,看看这篇文章的底部。
关于环境的文档包含了所有的细节。在这里,我总结了要点,并提供了一些提示和经验教训。
基础环境
基本环境是在安装 Miniconda 或 Anaconda 时创建的。它包含基本操作所需的conda
和包。
一个典型的初学者错误是将软件包安装到基础环境中。不要那样做。这样做会与您将要创建的其他环境产生冲突。
基础环境应该只包含conda
,它的依赖项,以及与 conda 相关的东西,比如conda-build
或mamba
(参见下面的mamba
是什么)。相反,对于任何其他软件,您应该总是依赖于其他环境。
其他环境
因为我们不想在基础环境中安装任何东西,所以首先要为日常操作创建您的首选环境。例如,标准的数据科学家环境可能是这样的:
> conda create --name ds -c conda-forge python=3.8 matplotlib numpy scipy pandas jupyter jupyterlab seaborn
康达将打印一份长长的包清单,这些包是让一切正常运转所必需的。您可以查看列表,然后输入y
进行确认。如果您想避免该提示,只需在命令行中添加-y
。
这将创建一个ds
环境,同时安装软件包。
提示:如果你已经知道你将需要更多的包,那么用这种方式安装它们,而不是以后依赖于
conda install
,这样 conda 将会找出满足你的需求的最佳依赖组合
正如你可能已经猜到的,你可以在那里添加任何你需要的软件包,而且很有可能你会在conda-forge
频道找到它。我们一会儿会谈到这意味着什么。
您现在需要激活此环境:
> conda activate ds
由于这是我们的首选环境,您可能希望将上面的行添加到您的.bashrc
或您的 shell 运行的任何 init 脚本中,这样每次您打开 shell 时,您都会发现自己处于ds
环境中。
从现在开始,如果您运行conda install [package]
,新的包将被安装在活动环境中。
你不需要在这里停下来。假设您今天想尝试一下最前沿的 python 3.9,但是您不想中断您的日常操作。很简单,只要创造一个不同的环境:
> conda deactivate
> conda create --name py39 python=3.9 numpy scipy matplotlib
> conda activate py39
在创建和激活下一个环境之前,conda deactivate
部分会停用当前环境,并使您返回到base
环境。这里我们也看到了如何指定包的显式版本,就像在python=3.9
中一样。
提示:在激活一个新的环境之前,一定要运行
conda deactivate
。这避免了奇怪的问题,例如环境变量没有被设置
现在,您在py39
环境中安装的任何东西都完全独立于ds
环境中的东西。
注意:激活一个环境后,如果您查看$PATH 环境变量(
echo ${PATH}
),您会看到conda activate
将路径添加到环境的bin
目录中。这意味着您在那里安装的任何东西都优先于您系统中其他地方安装的东西。
类似地,您可以使用安装环境,比如说一个较旧的 PyTorch 版本,您需要复制一篇旧论文或者从您的 python 环境中单独安装go
语言,这里仅举几个例子。
在任何时候,您都可以看到具有以下特征的环境列表:
> conda env list
使用 Jupyter 和 conda 的最佳方式
如果你在日常工作中使用 Jupyter(谁没有呢?)有一个你不能错过的扩展: nb_conda_kernel s .这个简单的扩展允许你从 Jupyter(笔记本或实验室)界面控制哪个环境用于哪个笔记本。你只需要把它安装在你的默认环境中(我们上面称之为ds
),然后从你的默认环境中启动 Jupyter
> conda activate ds
> conda install -c conda-forge jupyterlab nb_conda_kernels
> jupyter lab
这是你将得到的:
使用 nb_conda_kernels,您无需离开 Jupyter 就可以为每台笔记本电脑选择使用的环境
注意:您不需要在每个环境中安装 Jupyter,但是您必须在每个环境中安装至少一个内核(例如,Python 的 ipykernel)。没有内核的环境不会出现在 Jupyter 的可用环境列表中。
移除环境
如果您想删除一个环境以释放一些磁盘空间,或者因为您想从头开始,您只需执行以下操作:
> conda deactivate
> conda uninstall --name py39 --all
这将完全删除py39
环境及其所有包。
共享一个环境
环境可以通过多种方式复制。了解它们之间的差异是很重要的。
首先,你需要激活你的环境。
然后,如果您要导出到相同的平台(比如 Linux 到 Linux),只需:
> conda env export > environment.yml
environment.yml
文件类似于pip
的requirements.txt
文件,如果你知道我在说什么的话。它包含您的环境中包含的每一个包,当然包括 C/C++库之类的。它可用于在同一平台上重建环境,如下所示:
> conda env create -f environment.yml
一个典型的用例是在 Linux 上“开发”一个环境,然后以这种方式导出它,以便在 Linux Docker 容器中重新创建。这为您提供了一个精确副本的保证,不仅包括您手动安装的东西,还包括它们所有的依赖项。其中一些是依赖于平台的,这使得在不同的平台上(比如从 Linux 到 macOS)复制这个环境变得困难或者不可能。
相反,如果您希望您的环境可以跨平台复制,请以这种方式导出:
> conda env export --from-history > environment.yml
这个版本的environment.yml
文件将只包含你在conda create
或conda install
中明确安装的包。当在一个不同的平台上重新创建环境时(比如从 Linux 到 Mac),conda 将使用目标平台上可用的东西来解决环境文件中列出的包的依赖关系。当然,您可以像以前一样在目标平台上使用这个环境文件:
> conda env create -f environment.yml
第三个选项是核心选项:有一种方法可以将您的整个环境打包到一个二进制文件中,并在目的地解包(这当然只能在相同的平台上工作)。这在某些情况下非常有用,尤其是在使用 conda 和 PySpark 时。这是通过 conda-pack 实现的,详情见此处。
频道
Conda 包被远程托管在通道中,例如,通道相当于yum
或apt
的存储库。如果在conda install
或conda create
期间未指定任何-c
参数,则使用默认通道。否则,将使用您指定的通道。这意味着 conda 不仅会在默认频道中查找某个包,还会在您指定的频道中查找。例如,像这样的命令:
> conda install -c pytorch torch
将在pytorch
通道和默认通道中寻找torch
包。然后,可用版本将与此处说明的规则进行比较。
提示:始终打开
strict
频道策略。它使 conda 更快,并有助于避免冲突。你可以用conda config --set channel_priority strict
来做
conda-forge
频道
conda-forge 组织在conda-forge
渠道中维护着一个庞大的包列表。你可以在他们的网站上找到构建这些包的方法,上面有 GitHub 的链接。您也可以轻松地将自己的软件包贡献给康达锻造。
如果你看看周围的网络,有康达锻造的爱好者和憎恨者。我属于前一类。然而,你需要知道一些重要的事情来使用它。
conda-forge
包和默认 conda 通道中包含的包之间存在兼容性问题。因此,在安装东西或创建环境时,你应该总是按照上一节所解释的那样设置channel_priority: strict
,并且优先使用conda-forge
通道而不是默认通道。有两种方法可以做到这一点。您可以始终使用 conda-forge 指定conda install -c conda-forge
或conda create -c conda-forge
作为第一个列出的频道,或者在您的家中创建一个包含以下内容的.condarc
文件:
channels:
- conda-forge
- defaults
channel_priority: strict
一个环境,从创造到毁灭,要么用康达-福吉,要么不用。不要混搭。如果你没有使用 conda-forge 频道就创建了它,那么就不要中途把它添加到组合中。在实践中,我总是用 conda-forge 创建一个环境,除非在非常特殊的情况下,我发现不兼容。
第三种选择是在您的.bashrc
中定义一个 bash 函数,如下所示:
condaforge() {
# $1 is the command, ${@:2} is every other parameter # Print the command before executing it
echo "==>" conda "$1" -c conda-forge "${@:2}" conda "$1" -c conda-forge "${@:2}"
}
然后用它来创建环境和安装包:
> condaforge create --name test python=3.8
或者
condaforge install numpy
该功能会将-c conda-forge
通道添加到您的 conda 安装命令中。
提示:有时很难记住一个给定的环境是否是用 conda-forge 创建的。一个简单的技巧是总是在环境名前面加上
cf
,比如conda create --name cf_py39 -c conda-forge python=3.9
。或者,使用conda list | grep python
查看 python 是否是从 conda-forge 通道安装的。在前一种情况下,您会看到类似以下内容:
python 3.8.5 h1103e12_7_cpython conda-forge
康达和皮普
康达和皮普在历史上很难结合。现在情况好多了,在很多情况下,事情都很顺利。
但是,一般来说,您应该优先考虑这两者之一。例如,通常你会优先考虑 conda,也就是说,你会先尝试用 conda 安装包。如果这不可用,那么使用画中画。
在某些情况下,您可能想做相反的事情,优先考虑 pip。在这种情况下,创建一个只有 python+pip 的环境,然后从那时起使用 pip。
一个折中的办法是使用 conda 来安装基本组件(numpy、scipy、matplotlib、jupyter……)以及对 PyTorch、TensorFlow、Cuda toolkit、OpenCV 等重编译库的依赖,或者安装 GDAL 和 rasterio 等复杂而晦涩的包。用 pip 安装所有 python 专用的包。这不太可能给你带来问题。
注意,如果你用 pip 安装一个依赖于比如 numpy 的包,并且你已经用 conda 安装了 numpy,pip 会识别它,它不会再安装它(除非有版本冲突)。这就是为什么大部分时间事情都是正常的。
最后,请注意,当您如上所述导出环境时,环境文件确实包含所有安装了 pip 的包以及安装了 conda 的包,因此在 conda 环境中使用 pip 不会妨碍它的共享。
康达很慢
对 conda 最常见的抱怨之一是包求解器很慢。不幸的是,这是真的,尽管随着时间的推移,情况会越来越好。一个很酷的替代品刚出来,它叫mamba
(见此处)。
Mamba 是 conda 安装程序的直接替代,所以你可以用mamba install
代替conda install
,用mamba create
代替conda create
。你会以快得多的方式得到同样的结果。相当酷!
您需要在您的基础环境中安装mamba
:
> conda deactivate
# Make sure your prompt says (base)
> conda install mamba
释放一些磁盘空间
过一会儿,你会发现你的 miniconda 目录开始变得很大。主要原因是 conda 保存了你曾经下载过的所有软件包的档案。您可以使用以下工具轻松安全地清理这些垃圾:
conda clean --all
释放一些空间。
康达和多克
在构建 Docker 容器时(即在 Docker 文件中),可以使用 Miniconda 来安装环境。有几个很好的理由说明为什么大腿在某些情况下可能是个好主意:
- 您可以使用一个环境文件并完全复制您的开发环境。这是一种快速而简单的方法,可以确保您开发的内容能够找到您在开发过程中使用的相同依赖项
- 例如,你可以安装康达-福吉的产品。这允许您安装东西,即使您在容器中使用的发行版(基本映像)没有您需要的包
- Docker Hub 上有现成的图片,包含已经预装的 conda:https://hub.docker.com/r/continuumio/miniconda3,所以使用 conda 非常方便,不会增加太多复杂性
- 您可以安装和运行软件包,而不必成为
root
,从安全的角度来看,这有时更好,特别是当这些软件包启动 web 服务时,例如
请注意,在 docker 文件中,您应该在安装命令的末尾运行conda clean --all -y
,删除那些会浪费图像空间的无用归档文件。
深入:RPATH 和 conda
你完全不需要知道这些,但是如果你想知道即使在编译库的情况下,conda 是如何实现独立环境的,这里就有。
当你编译一个 C/C++或 FORTRAN 包或一些其他编译的库/可执行文件时,你可以静态地或动态地链接你所依赖的库。大多数现代应用程序都是用动态链接编译的。这意味着在运行时,系统需要查看你的可执行文件或库,了解它所依赖的其他库,并在你的系统中找到它们(动态链接)。
系统有一些预定义的地方来寻找这些库,并维护这些路径的缓存。例如,在 Linux 上,这些地方类似于/lib
或/usr/lib
等等。您可以使用以下命令查看 Linux 系统已知的所有库的列表:
> ldconfig --verbose
macOS 也有类似的系统。现在,如果我们拿一个可执行文件或一个库,我们可以看到它依赖于其他哪些库。例如,它打印了我的系统vim
所依赖的库:
> ldd /usr/bin/vim
linux-vdso.so.1
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6
libtinfo.so.6 => /lib/x86_64-linux-gnu/libtinfo.so.6
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2
libpython3.8.so.1.0 => /lib/x86_64-linux-gnu/libpython3.8.so.1.0
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6
/lib64/ld-linux-x86-64.so.2
libutil.so.1 => /lib/x86_64-linux-gnu/libutil.so.1
正如所料,这些都是系统库。如果我在conda
vim 上做同样的事情:
> conda install -c conda-forge -y vim
> ldd ${CONDA_PREFIX}/bin/vim
linux-vdso.so.1
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6
libtinfo.so.6 => /root/miniconda3/envs/py39/bin/../lib/libtinfo.so.6
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2
libpython3.9.so.1.0 => /root/miniconda3/envs/py39/bin/../lib/libpython3.9.so.1.0
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6
/lib64/ld-linux-x86-64.so.2
libutil.so.1 => /lib/x86_64-linux-gnu/libutil.so.1
我们可以看到,现在链接器在 conda 环境中找到了libtinfo
和libpython
,尽管它们在系统/lib
中是可用的。为什么?因为 conda 中的vim
是使用 RPATH 编译的,也就是说,路径是硬编码在可执行文件中的,它指向 conda 环境。
这意味着我安装在这个特定环境中的vim
只链接到同一个环境中的库,所以我可以在不同的环境中或者在我的系统中有不同的vim
,有不兼容的版本,一切都很好,没有任何冲突。
但是你也可以注意到我们仍然依赖于一些基本的系统库,比如linux-vdso
(一些内核功能的接口)、libc
等等。这些不能与 conda 一起运输。这也是为什么 conda 环境不像 Docker 容器那样独立于系统。然而,这些系统库保证是向后兼容的,并且它们在任何 Linux 发行版上都提供相同的接口,所以它们不太可能导致任何问题。
macOS 也是如此,尽管系统库不同。
您甚至可以看到 conda 在您的环境中使用的 RPATH 设置。每次执行conda activate
并激活环境时,conda 都会设置一些环境变量:
- CONDA_PREFIX:活动 CONDA 环境的根路径
- LDFLAGS:这是一个标准的 env 变量,由链接器在编译时读取。如果仔细查看,您会看到 RPATH 设置。例如,在我的笔记本电脑上,我看到:
(ds) giacomov@gr723gad9:~$ echo $LDFLAGS
-Wl,-O2 -Wl,--sort-common -Wl,--as-needed -Wl,-z,relro -Wl,-z,now -Wl,--disable-new-dtags -Wl,--gc-sections -Wl,-rpath,/home/user/miniconda3/envs/ds/lib -Wl,-rpath-link,/home/user/miniconda3/envs/ds/lib -L/home/user/miniconda3/envs/ds/lib
-rpath
标志指示链接器将该路径硬编码为任何可执行文件中的 RPATH。这意味着当环境处于活动状态时编译可执行文件或库,它将包含 RPATH 设置。这是conda-build
运作的基础,但那是以后的事了。
3.CXXFLAGS,CFLAGS:C 编译器的特定标志,包括 conda 环境中头文件的路径
结论
当然还有更多要说的,这篇文章已经够长了。我希望你能从中获得有用的信息,不管你是不是初学者。请随意发表评论和提出问题。
条件概率和三强争霸赛
原文:https://towardsdatascience.com/conditional-probability-and-the-triwizard-tournament-9c2ab6fe0af0?source=collection_archive---------56-----------------------
概率可以帮你避开匈牙利犀鸟!
李中清在 Unsplash 上拍照
概率通常用骰子和硬币来教授。在这篇文章中,我们将做一些不同的事情。我们将用《哈利·波特》中的例子来代替。今天我们将关注发生在《哈利·波特与火焰杯》三强争霸赛中的相关随机事件。
从属事件依赖于之前发生的事件。例如,纸牌游戏中的许多动作可以被认为是相关事件,因为从这副牌中抽取牌的概率取决于已经打出的牌。如果我要在 21 点游戏中算牌,我需要记住所有在洗牌前打出的牌,以便分析我赢一手牌的概率。
把条件概率看作是分析相关事件的一种方式。我们将条件概率表示为ℙ(A|B,这意味着在事件 b 已经发生的情况下,事件 a 发生的概率。
先决条件和符号
- ω:样本空间;被认为是一个集。
- ω:样本结果。
- A :事件;ω的子集。
- | A |:集合 A. 中元素的个数
- a ∈ S :值 a 是集合 S 的“一个成员”或简单的“在”集合S中。
回想一下,上一篇帖子中的三强争霸赛示例,其中我们的样本空间是ω= { SSS,CWG,CF,HH}。为了说明相关事件的影响,让我们将样本空间改为如下:
ω= { SSS,SSS,CWG,CWG,CWG,CF,HH}其中
- 瑞典短吻
- CWG =普通威尔士绿色
- CF =中国火球
- HH =匈牙利犀鸟
选择瑞典短吻猪的几率是七分之二。如果芙蓉·德拉库尔选择了瑞典短吻鳄,那么选择瑞典短吻鳄的可能性有多大?自从我们从袋子里拿走了一条龙,机会就变了,因为现在少了一条。
这里的想法是,如果我们在巫师每次选择龙的时候都替换龙,那么概率不会改变,事件被认为是独立的。然而,在这个例子中,龙是而不是被替换,因此事件被认为是相关的。
定义:如果ℙ(A) > 0 那么 b 给定 a 的条件概率为
让我们再多讨论一下这个符号。
在我们的例子中,假设事件 A 是“首先选择一只瑞典短吻鳄”,概率为 2/7,事件 B 是“其次选择一只瑞典短吻鳄”。
现在是棘手的部分,对于事件 B,我们有四个选择:
- 如果我们首先选择瑞典短吻龙,现在的概率是 1/6。
- 如果我们选择一个普通的威尔士绿色,现在的概率是 3/6。
- 如果我们选择一个中国火球,现在的概率是 1/6。
- 如果我们选择匈牙利犀鸟,现在的概率是 1/6。
我们必须规定哪个事件先发生。为了做到这一点,我们使用数学符号“|”来表示“给定”。因此,ℙ(A|B)的意思是“给定事件 b 的事件 a ”,也被称为给定事件 b 的条件概率。让我们使用我们的新符号来做一个例子。先选一条普通威尔士绿龙(事件 A),再选一条普通威尔士绿龙第二(事件 B)的几率有多大?所以我们可以从条件概率公式开始,稍微重新排列一下:
我们知道选择普通威尔士绿的概率是 3/7 (ℙ(A),但是在我们从袋子里取出那条龙之后,从袋子里选出的第二条龙不太可能是普通威尔士绿:ℙ(B|A) = 2/6。
所以我们输入数字:
这看起来很简单,但有时却很棘手。例如,ℙ(a|b = ℙ(b|a).通常不是这种情况事实上,它们可以是极其不同的!让我们在回答这个问题时想一想:假设我们首先选择了一个中国火球,选择瑞典短吻的概率是多少,ℙ(A|B?
第二,这种可能性是否等同于选择中国火球,而首先选择瑞典短吻海豚(ℙ(B|A)?
好吧,第一个问题的答案是 2/6,因为一旦我们去掉了中国的火球,袋子里就有两个瑞典的短吻海豚了。现在,如果我们先选择瑞典短吻猪,然后选择中国火球,这一事件的概率将是 3/6。看吧!不一样!ℙ(A|B)不等于ℙ(B|A)!
在下一场三强争霸赛中,你将会确切地知道你选择每条龙的概率。希望这个新技能能帮助你通过任务一。
通过微调 GPT-2 的条件文本生成
原文:https://towardsdatascience.com/conditional-text-generation-by-fine-tuning-gpt-2-11c1a9fc639d?source=collection_archive---------3-----------------------
给定一个标题和一系列关键词,GPT-2 能产生令人信服的假新闻吗?
照片由在 Unsplash 上反推
虽然基于 transformer 的模型近年来在一系列自然语言处理任务上取得了良好的效果,但是文本生成仍然是一个令人好奇的案例。早在 2020 年 9 月,《卫报》发表了一篇令人印象深刻的文章,据称是由 OpenAI 的 GPT-3 从无到有撰写的,在主流媒体上广受好评,但许多人工智能专家仍然持怀疑态度。
文本生成的一个问题是缺乏对其方向的控制。使用 GPT-3,你可以给模型一个介绍和说明,但即使这样,也需要一个人类编辑从多个输出中挑选和安排文本,使之具有凝聚力。还有其他方法,例如 Salesforce 的 CTRL 和 UberAI 的 PPLM 。
在本文中,我们将微调 Huggingface 预训练的 GPT-2,并提出我们自己的解决方案:通过选择数据集,我们可能会更好地控制文本样式和生成的内容。
数据
我们将使用来自新闻聚合数据集的样本。它包含来自著名新闻出版商的 40 多万篇新闻文章的标题和超链接。为了减少训练时间,我从 4 个新闻类别中随机抽取了大约 10k 篇文章:商业、科学、娱乐和健康。文章是预先下载的,以减少运行时间。
关键词提取
我们需要在训练过程中从每篇文章的关键字列表。有一系列可用的方法,从 Rake 到使用 BERT 的等等,但是我们在这里将坚持一个简单的 TFIDF ,因为这不是我们的主要关注点。在我们的关键字选择中,我们还将允许 2 个字母的短语组成一个专有名词短语,例如,“内容创建者”。此过程也是离线执行的,因为只需执行一次。
数据下载和关键词提取的代码可以在我的 GitHub 库中找到。
管道
管道设置包括定义记号化器、模型和数据集,然后使用训练器类进行微调,最后是文本生成。我假设您熟悉这个一般设置— 本文详细介绍了管道,如果您需要提醒的话。我将重点介绍为了实现条件文本生成,我做了哪些不同的工作。
您可以访问我的 Colab 笔记本中的完整代码了解更多详细信息,也欢迎您进行复制和实验。
模型
在这个实验中,我们将使用 12 层解码器的小型版 GPT-2。该模型在 800 万个网页上进行了训练,在语言任务方面已经相当强大。为了在采用我们的数据集时保持其在语言建模中的一般能力,我们将通过设置其参数来冻结底部 6 层。requires_grad 为 False,并且仅训练顶部 6 层。这也将加速训练,因为向后传球的次数减少了。
模型层的名称可以简单地通过打印(模型)找到。
培训设置
在标准的文本生成微调中,由于我们是在给定我们到目前为止看到的文本的情况下预测下一个标记,所以标签只是移位编码的标记化输入(注意,如果我们设置 labels=input_ids,则标签会在模型内自动移位—参见下面的参考文献 1)。
但是在这里,我们希望有更多的控制——除了文章文本,我们还会给模型一个标题和一个微调的关键字列表。我们在定制的数据集类中实现了这一点。
在标准设置中,我们在文本前面加上 bos_token,在后面加上 eos_token:
我们还将在文本前插入标题和关键字列表,用特殊的分隔符号分隔:
为了帮助模型泛化,我们通过使用函数 join_keywords()在训练期间对关键字列表进行采样和洗牌来引入数据扩充。但是在验证期间没有应用任何增加来保持跨时期的一致性。然后,按照标准实践,使用训练器类为少量时期(在我们的例子中是 4 个时期)训练模型。
结果
为了测试我们新的假新闻生成器的威力,我从 BBC 新闻中挑选了一条最近热门的轻松新闻:“当我们的照片成为一种模因时,我们感到非常悲伤”。通过使用相同的标题并(相当主观地)从文章中挑选几个关键词,让我们看看我们的模型能给它带来什么样的变化。要用的关键词是:‘火车’,‘小伙子’,‘喝酒’,‘图片’,‘搞笑’和‘insta gram’。
我们为语料库设置的关键字的大小相当大,但是如果我们想要使用的关键字不在这个集合中,我们总是可以使用集合中的同义词,或者在一些单词相似性度量方面最接近的一个。
有几种方法可以从模型中生成文本。如果我们使用波束搜索和采样,我们得到样本如下:
Unfortunately, all we have right now is an image that has gone viral.
The picture was taken by one of the boys on Instagram and quickly went viral after it appeared to show a group of friends getting drunk at a New York City bar.
As soon as the picture came out online, many people took to Twitter to express their disgust with the picture.
"What's wrong with this f**king train??," one user wrote.
Another said: "I can't believe my eyes didn't even open."
A third added: "Just saw some pictures of men being mugged in NYC... I'm so sick of these dumbasses."
This content is created and maintained by a third party, and imported onto this page to help users provide their email addresses. You may be able to find more information about this and similar content at piano.io
每一句都是语义连贯的,前三句也确实与标题有关,但随后文章发生了意想不到的转折。“这混账火车怎么了?”…我也在想这件事。随着“思想”列车慢慢偏离轨道,我们似乎有了一些控制,但可能还不够。
一些关键词(‘火车’、‘喝酒’、‘图片’和‘insta gram’,或者它们的同义词或内涵)按照指示被用在生成的文本中。但是,‘滑稽’没有用;相反,我们用了“厌恶”这个词,它有效地概括了作品的情绪,这很可能是因为我们选择的标题。
这与原始的 GPT-2 相比如何?使用标题作为第一句话,下面是一个来自原始模型的输出示例以供比较:
We got a lot of grief when our photo became a meme.
"I'm not going to lie, I don't know how many times we've been in that kind of situation," he said. "It's hard for me to put it into words."
He added: "There was no way this could have happened without the help of my family and friends who were there with us on Saturday night. We're all so proud of what they did as well."
这一段开头不错,但最后一句无意的转折泄露了秘密。不出所料,这些关键字根本不重要。
在某种程度上,我们试图做的是与文本摘要相反的事情——我们试图将标题扩展成一篇以关键词为特色的文章,希望标题的效果会渗透到整篇文章中。相比之下,原始的 GPT-2 只是从第一句话开始,标题的记忆效果可能更短暂。
回到我们的模型,我们也可以使用像 top-p (nucleus)采样这样的方法生成文本,这往往会产生更多的变体。这里有一些有趣的,听起来部分真实,部分有趣和令人不安。它们可能没有说服力,但至少很有趣:
It was like we were being mugged and all over again.
“I think it's really sad that this happened to us because people are so used by the pictures on their Instagram feeds... they just want attention," said Dr Emily Loughner-Bullock from Kings College London in England who works as an epidemiologist at King Mungol University School Of Public Health (KMU). ‘When you look back through history there have been many examples where celebrities can make headlines for quite controversial things - such is how social media has affected public health research into mental illness or addiction."
The story spread online after one famous photograph emerged which showed two young men with guns talking about drug use while drinking together before another took off his shirt revealing something he had hidden under her skirt: "Nice impression but I wonder if girls don't understand what 'hooking up' looks exactly?" wrote Shilpa Khetrapal Singh Khalsa Mukherjee following Twitter users sharing similar images showing them laughing happily out loud without any justification whatsoever behind some sort action picture taken during dinner parties held between friends...
There will be no further comment here due today afternoon..
When I was 12 years old my friends and family started seeing pictures from the train accident. It just made them cry so much that they took to Instagram after it happened:
As far as their reactions are concerned this is all very funny but if you take out your cell phone or tablet then these people will be talking about what went down in Boston today - there's no way we could have imagined how bad things would look with photos like those...
“It's hard to remember the day you started your life in this world and it was just too much for one kid. It is really sad that we can no longer celebrate those days with these photos because they were meant only as fun pictures."
Join us for the world’s leading event about accelerating enterprise transformation with AI and Data by signing up today
The internet was flooded in on Saturday morning after one man posted an extremely disturbing photograph to his Twitter account. In it he is seen sitting at home surrounded only wearing headphones – just as we have done before: The picture has gone viral! Here are some highlights from that hilarious moment…
1) It's been nearly six months since I saw this image
It was all very funny. It’s not like I'm going to stop posting photos because people will be more than happy with it and the memes are still growing every day on Twitter
A new poster for an American Idol-themed picture that appeared in The New York Post is showing up at this week's event where fans can get drunk together (and drink too) before their favorite shows!
仔细看看人工智能写作的现状,似乎记者不会很快被技术取代。
毕竟,这是我首先发表这篇文章的原因——否则我怎么能在道德上有理由在互联网上这么容易地制造一个有效的假新闻生成器呢?
参考和鸣谢
- 拥抱脸 GPT-2 文件
- 拥抱脸变形金刚示例
- 如何生成文本:用变形金刚使用不同的解码方法进行语言生成
- 杰伊·阿拉玛的插图版 GPT-2
- 为万智牌风味文本生成微调 GPT-2
- 伊恩·波特的 GPT-2 教程
用 FedJAX 进行联合学习研究
原文:https://towardsdatascience.com/conducting-federated-learning-research-with-fedjax-7be86d349a94?source=collection_archive---------15-----------------------
思想和理论; ToF
关于使用 FedJAX 进行联合学习研究的十个或更少的要点
(图片由作者提供)ToF 中“o”顶部的️symbol 表示该 t of 的内容本质上更具技术性,因此可能更适合对机器学习以及编码概念更有经验的读者。
十个或更少的 (ToF 的简称,可以读作“tuff”)博客背后的想法是高效地分享围绕特定主题的主要概念、要点、观点等。具体来说,我会尽量简短,只说十件或更少的相关事情。
隶属关系披露:
我在integrate . ai领导机器学习科学团队,在这里我们专注于让联合学习(FL)更容易实现。我不隶属于 FedJAX,也没有参与过这个开源项目。
**附送代码:https://github . com/integrate ai/openlab/tree/main/fed jax _ tutorial
(0) (一本 FL 入门书,你可以随意跳过,只要需要就可以回头查阅。) FL 允许建立机器学习模型,而无需首先将数据带到中央位置。在典型的 FL 设置中,有个客户端* ,它们各自将自己的数据集存放在自己的单独节点中,还有一个中央服务器,它“利用”这些非集中式数据集,以便构建一个全局 ML 模型(即,通常称为服务器模型),然后由所有客户端共享。重要的是,数据集从不聚集在一起形成大规模的训练数据集,而是保存在各自的客户端节点上,并且仅通过在每个客户端节点和中央服务器之间传递模型参数(或它们的更新)来促进训练。FL 框架的基本步骤如下(改编自 Ro,Suresh,Wu (2021) )。*
*Note that that FL training is done in multiple rounds, where in each round the following steps are taken:1\. Server selects a set of clients to participate in the current round;2\. Server communicates the current model parameters of the global, server model to the participating clients;3\. Each client creates a local version of the server model using the snapshot provided in 2\. and updates this by training it on its local data.4\. After performing it's individual client update, each client then communicates back the model parameters updates to the server.5\. The server takes the collection of client model parameter updates and performs an aggregation on them (e.g., via averaging).6\. The server updates the server model via the aggregated model parameter update computed in the previous step.*
(1) FedJAX 是一个进行 FL 研究的库。FedJAX 旨在缩短开展 FL 研究的周期时间(例如,为 FL 进行实验)并使其更加标准化。它通过两种方式做到这一点。首先,由于在进行 FL 模型的算法研究时,执行服务器和客户机之间的通信是完全不必要的,因此 FedJAX 模拟基本上跳过了步骤 2。第四。上面列出的。这是因为使用 FedJAX,多客户端 FL 设置只是在单台机器上虚拟创建的,因此,FedJAX 不应该用于构建和部署实际的 FL 解决方案。其次,FedJAX 为 FL 框架中的核心元素提供了方便的接口,例如:FederatedData
、ClientDataset
、Models
、ClientSampler
和FederatedAlgorithm
,它们调用函数来处理客户端模型更新和服务器模型更新。
在 FedJAX 中执行 FL 培训的代码片段。
(2) 上 FedJAX 一点都不差。我发现在 FedJAX 上提升到可以在数据集上执行普通水平 FL 的水平相对简单。尽管在写这篇博客的时候还处于早期阶段,文档和官方代码还是很有帮助的。此外,正如学习任何新库的典型情况一样,有一点相关的学习曲线,所以我花了大约 1 周的时间才能够学习足够的库来完成两个示例:I)使用被分成 3400 个客户端的 EMNIST 数据集的示例;以及 ii)一个使用 CIFAR-10 数据集的示例,该数据集被分成 100 个客户端。对于 EMNIST 示例,我使用的数据集和 CNN 模型都是由 FedJAX 库提供的。相比之下,对于 CIFAR-10 示例,我使用 FedJAX 提供的帮助函数创建了一个定制数据集和一个定制 CNN 模型。下面分享了运行时和最终服务器模型的准确性,但是您也可以找到这两个示例的代码,以便自己执行它们这里!
打印输出报告两个 FL 示例的性能指标和运行时间:EMNIST 和 CIFAR-10。
(3) 事先熟悉 JAX 并不是入门的必要条件,但对于使用 FedJAX 进行更严肃的研究来说,了解这一点是很重要的。在深入研究 FedJAX 之前,我没有和 JAX 一起工作过,但是我没有发现这是学习 FedJAX 接口和在前面提到的两个例子上运行 vanilla FL 的主要障碍。然而,当更深入地查看源代码时,我肯定开始意识到,我可以从更熟悉 JAX 中受益。所以,我觉得如果有人想使用 FedJAX 在外语方面做更严肃的研究,那么花时间熟悉 JAX,或许还有其他基于 JAX 的深度学习库,比如俳句,肯定是值得的。
接下来要说的三件事涵盖了 FedJAX ( *v=0.0.7*
)库中提供的许多核心类中的三个,这些核心类支持标准化的外语模拟。
(4) FederatedData
是包含关于客户端数据集的元信息和用于在模拟外语训练下执行任务的便利方法的数据结构。此外,由于FederatedData
可以被认为是提供了client_id
和ClientDataset
之间的映射,因此访问表示实际观察的类似数组的数据结构需要更多的工作——这在一定程度上反映了实际的 FL 设置,其中从客户端节点访问数据是具有挑战性的,或者出于隐私考虑,在没有干预的情况下甚至是不可能的。最后,FedJAX 方便地提供了从一个numpy.array
创建一个小的定制FederatedData
的功能,这是我在第二个例子中用来创建 CIFAR-10 数据集的功能。
从 numpy.array 创建 FederatedData 并访问客户端数据观察的示例代码片段。(改编自 FedJAX 文档中教程的代码)
(5) Model
是用于指定服务器 ML 模型结构和损失函数的 FedJAX 类。重要的是要注意到Model
类是无状态的,这意味着在每个历元/回合之后的训练期间没有params
属性被更新。相反,Model
将其信息提供给jax.grad()
,后者自动计算相关目标函数的梯度,并将这些信息传递给选定的Optimizer
,后者最终返回一组完全符合Model
结构的params
。通过调用apply_for_eval()
(或者apply_for_train()
,如果需要一个随机键来为像 dropout 这样的东西注入随机性的话)可以生成对例子的预测。FedJAX 还提供了助手函数,用于从其他基于 JAX 的深度学习库(如 Haiku 或jax.example_libraries.stax
)创建Model
。
对一批示例进行训练后获取一组新参数的代码片段。然后,新的参数可以被传递给另一轮训练或评估函数,该函数将参数和模型都作为输入。
(6) FederatedAlgorithm
是促进 FL 训练的类(即,客户端和服务器更新,或步骤 3。& 5。本博客顶部列出了一个 Model
上一个 FederatedData
。构建一个定制的FederatedAlgorithm
将需要定义执行客户端模型更新以及聚合和服务器模型更新的函数,这些函数应该封装在它的apply()
方法中。只有另外一个方法属于这个类,即init()
,它初始化服务器模型的状态。FedJAX 还旨在通过利用可用的加速器来提高客户端更新的效率,因此,您需要以特定的方式定义客户端更新函数(即,通过三个函数client_init
、client_step
和client_final
)。
(7) 总的来说,FedJAX 得到了很多承诺。加速和规范外语研究的前提是好的。在撰写本文时,FedJAX 提供的接口既有用又方便,为更深入地研究 FL 打下了良好的基础。在不久的将来,我希望看到更多的数据集和基准有助于这个项目,以提高可重复性和整个领域的水平设置。此外,超越普通 FL 的更多模块和示例将使该项目更加相关,例如考虑不同隐私、跨客户端数据集的非 iid 案例、垂直 FL,甚至可能是非 SGD 类型的客户端/服务器模型的方法。
DevOps 工程师的自白:冲刺
原文:https://towardsdatascience.com/confessions-of-a-devops-engineer-sprints-1b74631509a1?source=collection_archive---------55-----------------------
如何提高你的冲刺和避免常见的菜鸟错误
威廉·艾文在 Unsplash 上的照片
一个故事
在冲刺日,我们反思前两周的成就(或不足)。大约 20 分钟后,我们会跳到 zoom 上,分享我们的想法和反思。我看着我们的黑板。我过滤我的名字,我看到我两周前开始的任务都在进行中。
我可以很容易地解释为什么我不能完成冲刺任务。理由总是包括一些关于需求变化或一些不可预见的障碍或缺乏数据或一些其他“合理”的借口。我的任务和其他人做的完全不同,对吗?
事实是,我的任务和其他人的任务没什么不同。唯一不同的是我缺乏经验。有经验的工程师可以更准确地测量给定任务需要多长时间,然后相应地完成任务。
在这里,我将试着描述一些我犯的新手错误,以及一些在冲刺阶段创建任务的建议。
给出合理的时间估计
我犯的最大错误之一是估计完成一项任务需要多长时间。现在,我的估计如此不准确的原因之一是因为我缺乏经验,不知道完成一项任务需要多长时间。如果你从未攀登过珠穆朗玛峰,就很难确切知道要爬多长时间。
为了解决这个时间估计问题,我试着更细致地思考,并依靠我更有经验的队友来帮助我估计任务。当我说“考虑得更细”时,我并不是指考虑所需的每一行代码和测试,而是考虑完成任务所需的更大的步骤。一个很好的例子可能是部署一个新特性。这里,较大的步骤包括编写、审查、测试,然后部署代码。根据特性的性质,编写代码可能需要几个小时,审查和测试可能需要一天,部署代码可能需要一两天。因此,在这里,我们可以估计大约 4-5 天来开发这一新功能。比你最初想象的要长,对吗?
有时,当我们定义 sprint 任务时,队友和经理可能会质疑这些估计。他们可能会说“嘿,我不认为这需要 X 天;应该只需要一半的时间”。现在,如果你对完成任务需要做什么还没有一个坚实的理解,你可能很容易被说服同意。重要的是在下一个 sprint 计划之前花一些时间,定义必要的任务,并估计完成它们需要多长时间。
清除任务输入和输出
在创建新任务之前,清楚地定义什么是输入和输出是很重要的。输入包括您的时间、精力和其他材料,如设计文档。输出等于所需的东西,例如新产品功能。
这些输入和输出定义得越清楚,你的团队和管理层就越清楚你已经完成了什么或者你正在努力完成什么。
下面是一个错误任务定义的示例:
输入:3 天
输出:新功能
所以我们来解剖一下。输入是 3 天的工作,相当于大约 27 小时的专用时间(假设每天工作 9 小时)。输出是一个“新特征”。这个新功能到底是什么?完成这个模糊的目标不需要其他先决条件?您是否有访问代码库的权限?这个任务的完成意味着特性被部署到客户那里,还是仅仅意味着代码在本地工作?
好吧,让我们稍微改进一下我们的例子:
输入:3 天,bob 的设计文档
输出:改进控制台横幅
这是一个改进,因为我们现在引用的设计文档可能提供了方向。我们的输出包括一些关于开始构建的清晰性,但是定义的任务仍然非常模糊。3 天也是相当多的时间。通常,当分配给某个特定任务的时间超过 2 天时,这是一个危险信号,表明该任务可以被分解成更小的部分。
我将提供一个相当不错的任务定义的例子,而不是描述更多糟糕的例子:
输入:1 天
输出:设计文档,详细说明控制台横幅搜索索引到数据库的实施
输入:. 5 天,设计文档
输出:与团队一起评审设计文档
输入:0.5 天,Jim Henderson(开发)支持和实施
输出:为控制台横幅搜索添加索引
输入:. 5 天,马克·约翰逊(DevOps)支持与监测结果
输出:本地测试为控制台横幅搜索添加的索引
输入:. 5 天,测试结果,技术主管支持批准拉动式请求
输出:审查本地测试的代码和结果,提交并合并到开发环境中
输入:1 天,Jenn Smith (DevOps)支持部署
输出:向客户部署改进的控制台横幅搜索
希望你能明白。任务需要很长时间才能完成,并且不完全依赖于你的技能和专业知识。通常需要一个村庄来完成一项任务。任何失败都会产生重大后果。
反思和迭代
这听起来可能很明显,但重要的是反思你定义的目标,以及你是否能够及时完成这些目标。在本文的开头,我设置了一个场景,反思我和我的团队最近的冲刺。在那些场合的积极反思帮助我思考如何提高我的短跑。
我问自己“为什么我不能完成这个任务”,“我的任务定义太模糊了”或者“我给自己足够的时间了吗”?
我鼓励每个人花时间问自己这些难题,并跟踪进展。也许有过创建带有底层子任务的任务的经历。也许允许自己在编写初始代码后调整评估。测量初始时间估计和实际时间估计怎么样。也许早先我们的初始估计和实际估计相差很大,但正在慢慢地趋于一致。
置信区间与预测区间
原文:https://towardsdatascience.com/confidence-intervals-vs-prediction-intervals-7b296ae58745?source=collection_archive---------3-----------------------
混淆这两者可能代价高昂。了解它们的不同之处以及何时使用它们!
置信区间和预测区间都表示统计估计的不确定性。然而,每一个都与来自不同来源的不确定性有关。有时,人们可以用相同的数量来计算这两者,这导致了在解释统计模型时的混乱和潜在的严重错误。让我们看看它们有什么不同,它们表达了什么样的不确定性,以及何时使用它们。
回归模型中的不确定区间
让我们从实际出发,用一个简单的线性回归模型来拟合加州住房数据。我们将只使用前 200 条记录,并跳过第一条作为测试用例。该模型基于一个单一的预测值,即邻居的中值收入来预测房价。我们只使用了一个预测值,以便能够很容易地看到 2D 的回归线。
在模型总结中,我们看到了下表。
===========================================================
coef std err t P>|t [0.025 0.975]
-----------------------------------------------------------
const 0.7548 0.078 9.633 0.000 0.600 0.909
MedInc 0.3813 0.021 18.160 0.000 0.340 0.423
邻里收入中位数的系数 MedInc 为 0.3813,其 95%的区间为 0.340 — 0.423。这是一个置信区间。置信区间与从多个值估计的统计量有关,在这种情况下是回归系数。它表达了采样不确定性,这是因为我们的数据只是我们试图建模的人口的随机样本。它可以解释如下:如果我们收集了许多其他关于加州房屋的数据集,并为每个数据集拟合了这样一个模型,在 95%的情况下,真实人口系数(如果我们有加州所有房屋的数据,我们就会知道这个系数)将落在置信区间内。
置信区间属于从多个值估计的统计量。它表示抽样不确定性。
现在,让我们使用该模型对我们在培训中忽略的第一个观察结果进行预测。代替predict()
方法,我们将使用get_predict()
结合summary_frame()
来提取更多关于预测的信息。
我们得到以下数据帧:
mean mean_se mean_ci_lower mean_ci_upper obs_ci_lower obs_ci_upper
3.9295 0.1174 3.697902 4.161218 2.711407 5.147713
这个房子的预测值是 3.9295。现在,mean_ci
列包含本次预测的置信区间的下限和上限,而obs_ci
列包含本次预测的预测区间的下限和上限。
您可以立即看到预测区间比置信区间宽得多。我们可以通过使用该模型来预测一系列不同邻里收入的房价,从而很好地可视化它,这样我们就可以看到回归线和预测值周围的区间。
现在,pred
就像以前一样,只有 500 行,包含 0 到 15 之间 500 个不同收入值的预测和区间界限。我们现在可以用它来绘制回归线及其周围的区间。
周围有间隔的回归线。图片由作者提供。
这里有两个主要的东西要看。首先,收入中值在 2 到 5 之间时,置信区间较窄,在更极端的值时,置信区间较宽。这是因为,对于数据中的大多数记录,收入在 2 到 5 之间。在这种情况下,模型有更多的数据,因此抽样不确定性较小。
第二,预测区间比置信区间宽得多。这是因为表达了更多的不确定性。除了采样不确定性之外,预测区间还表示特定数据点的固有不确定性。
预测区间表达了采样不确定性之上的特定数据点的固有不确定性。因此它比置信区间更宽。
这种数据点级别的不确定性来自于这样一个事实,即在同一个邻域中可能有多个价值不同的房屋,因此在模型中具有相同的预测值。这在这个例子中很明显,但在其他情况下也是如此。非常相似或者甚至完全相同的多个特征向量与不同的目标值相关联。
让我们回顾一下:
- 置信区间表示从许多数据点估计的数量的抽样不确定性。数据越多,采样不确定性越小,因此间隔越小。
- 除了采样不确定性之外,预测区间也表示单个值周围的不确定性,这使得它们比置信区间更宽。
但是这些区间从何而来,它们又是如何包含这些不同的不确定性来源的呢?接下来我们就来看看吧!
音程从何而来
在传统的统计学中,人们会将预测 y-hat 周围的区间计算为
其中 t-crit 是 t 分布的临界值,SE 是预测的标准误差。对于置信区间和预测区间,右侧的两个数字将是不同的,并且是基于各种假设计算的。
然而,统计学中参数假设的时代幸运地即将结束。最近计算能力的提高允许使用简单的、一刀切的重采样方法来进行统计。因此,与其用推导和公式来烦你,不如让我向你展示如何通过重采样来构造这两种类型的区间。这种方法不仅适用于线性回归,而且基本上适用于你能想到的任何机器学习模型。此外,它将使人们瞬间清楚哪种不确定性被哪个区间所覆盖。
拔靴带
我们将使用的重采样技术是自举。归结起来就是从原始数据中抽取许多样本,比如说 10 000 个样本,然后替换掉。这些被称为引导样本,因为我们是用替换来绘制的,相同的观察结果可能在一个引导样本中出现多次。这样做的目的是从一个假设的总体中获得许多样本,以便我们可以观察抽样的不确定性。接下来,我们对每个 bootstrap 样本分别执行我们想要的任何分析或建模,并计算感兴趣的量,例如模型参数或单个预测。一旦我们有了这个量的 10 000 个自举值,我们就可以查看百分位数来得到区间。整个过程如下图所示。
改编自作者在 DataCamp 教授的 R 课程中的用插补处理缺失数据。
自举置信区间
让我们用 bootstrap 置信区间来预测一所房子的价值,该房子位于中值收入为 3 英镑的社区。我们采用 10 000 个 bootstrap 样本,对每个样本拟合一个回归模型,并预测 MedInc 等于 3。这样,我们得到了 10 000 个预测。我们可以打印它们的平均值,以及表示置信区间下限和上限的百分位数。
Mean pred: 1.9019164610645232
95% CI: [1.83355697 1.97350956]
这个 bootstrap 样本考虑了抽样的不确定性,所以我们得到的区间是一个置信区间。现在让我们看看如何引导一个预测区间。
引导预测区间
除了采样不确定性之外,预测间隔还应该考虑特定预测数据点的不确定性。为此,我们需要对代码做一个小小的改动。一旦我们从模型中获得预测,我们也从模型中提取随机残差,并将其添加到该预测中。通过这种方式,我们可以将个体预测的不确定性包含在 bootstrap 输出中。
Mean pred: 1.9014631013163406
95% PI: [1.07444778 2.72920388]
正如所料,预测区间明显比置信区间宽,即使平均预测是相同的。
感谢阅读!
如果你喜欢这篇文章,为什么不在我的新文章上 订阅电子邮件更新 ?通过 成为媒介会员 ,你可以支持我的写作,并无限制地访问其他作者和我自己的所有故事。
需要咨询?你可以问我任何事情,也可以在这里 预定我 1:1 。
你也可以试试我的其他文章。不能选择?从这些中选择一个:
</8-tips-for-object-oriented-programming-in-python-3e98b767ae79> </6-useful-probability-distributions-with-applications-to-data-science-problems-2c0bee7cef28>
Python 中的置信区间
原文:https://towardsdatascience.com/confidence-intervals-with-python-bfa28ebb81c?source=collection_archive---------6-----------------------
用 Python 实现大学统计
介绍
在一系列的每周文章中,我将会涉及一些重要的统计学主题。
目标是使用 Python 来帮助我们获得对复杂概念的直觉,从经验上测试理论证明,或者从零开始构建算法。在本系列中,您将会看到涵盖随机变量、抽样分布、置信区间、显著性检验等主题的文章。
在每篇文章的最后,你可以找到练习来测试你的知识。解决方案将在下周的文章中分享。
迄今发表的文章:
- 伯努利和二项随机变量与 Python
- 用 Python 从二项式到几何和泊松随机变量
- 用 Python 实现样本比例的抽样分布
- Python 的置信区间
- 使用 Python 进行显著性测试
- 用 Python 进行组间差异的双样本推断
- 分类数据的推断
- 高级回归
- 方差分析— ANOVA
像往常一样,代码可以在我的 GitHub 上找到。
置信区间和误差幅度
一群学生试图理解《老友记》中哪个角色最有趣,结果是钱德勒·宾和罗斯·盖勒。
图 1: 《老友记》是一部美国电视情景喜剧,围绕住在纽约曼哈顿的六个二三十岁的朋友展开。
他们对罗斯实际获胜的可能性感兴趣,因为与钱德勒讽刺和诙谐的幽默感相比,他有一种非常笨拙的幽默感。他们决定在学校里发起一次投票。理想情况下,他们会询问全体学生,但很快他们就明白询问 5000 名学生的偏好是不可行的。相反,他们决定随机抽取 40 名学生,计算支持罗斯的样本比例。他们得出的第一个值是 p̂=0.61.
请注意,为了继续他们的研究,这组学生需要确保满足计算某个比例的有效置信区间的条件。有三种情况:
- 样本必须是随机的。
- 正态分布可以近似样本比例的抽样分布。经验法则是,你至少需要有 10 次成功和 10 次失败。
- 要求样本是独立的。经验法则是,如果你是在没有替换的情况下抽样,你的样本量应该少于总体量的 10%。
import numpy as np
import seaborn as sns
import math
from scipy.stats import bernoulli, norm, t, skewnorm
import matplotlib.pyplot as pltp_hat = 0.61
n = 40print('Normal conditions:')
print('successes >= 10: ' + str(n*p_hat >= 10))
print('failures >= 10 : ' + str(n*(1-p_hat) >= 10))
print('--')
print('Independence condition:')
print(40/5000 < 0.1)Normal conditions:
successes >= 10: True
failures >= 10 : True
--
Independence condition:
True
所有条件都满足后,这组学生现在可以专注于构建样本比例的抽样分布;根据这一分布,他们计算了可能得到的样本比例及其可能性。
我们已经看到,抽样分布的平均值是实际总体比例 p 和样本比例的标准偏差:
让我们开始把这些概念和置信区间的概念联系起来。p̂ = 0.61 在范围内的概率是多少
对于正态分布,这大约是 95%。这相当于说有 95%的概率 p 在内
这是置信区间的基本概念。
现在,我们有一个问题。我们不知道 p ,所以我们需要使用一个估计值。我们最好的估计自然是 p̂.因此,不使用
我们使用标准误差:
计算我们的置信区间。
SE_hat_p = np.sqrt(p_hat*(1-p_hat)/n)
print(f'With 95% confidence between {np.round(p_hat - 2*SE_hat_p, 2)} and {np.round(p_hat + 2*SE_hat_p, 2)} of students prefer the awkward humor of Ross.')With 95% confidence between 0.46 and 0.76 of students prefer the awkward humor of Ross.
请注意,我们上面计算的置信区间可以根据我们实际选择的样本比例而变化。如果该组学生再次抽样 40 名新学生,则新的样本比例现在可以是 0.55。
p_hat = 0.55
n = 40
SE_hat_p = np.sqrt(p_hat*(1-p_hat)/n)
print(f'With 95% confidence between {np.round(p_hat - 2*SE_hat_p, 2)} and {np.round(p_hat + 2*SE_hat_p, 2)} of students prefer the awkward humor of Ross.')With 95% confidence between 0.39 and 0.71 of students prefer the awkward humor of Ross.
我们可以把这个概念和误差范围联系起来。我们第一次试验的误差幅度(知道我们有兴趣获得 95%的置信度)是我们 SE 的 2 倍。
一个经常出现的有趣问题是“你能做些什么来减少误差幅度”?请注意,误差幅度取决于 SE,SE 与样本大小成反比。因此,减少误差的一个可能方法是增加样本量。
print(f'Margin of error = {2*SE_hat_p}')Margin of error = 0.15732132722552272
同样的推理也适用。根据我们的样本比例,我们的误差幅度可能会有不同的值。
其思想是,如果我们重复使用这种计算置信区间的方法,每次都会产生不同的区间(取决于样本比例),其中 95%的时间包含真实比例。
confidence_interval=0.95
p = 0.61
n = 50
number_trials = 25
p_hat_list = []
SE_hat_p_list = []
for i in range(number_trials):
s_ = bernoulli.rvs(p=p, size=n)
p_hat = s_[s_==1].shape[0] / s_.shape[0]
p_hat_list.append(p_hat)
SE_hat_p_list.append(2*np.sqrt(p_hat*(1-p_hat)/n))j=0
_, ax = plt.subplots(1, 1, figsize=(6, 8))
for i in range(len(p_hat_list)):
if (p>p_hat_list[i]-SE_hat_p_list[i]) & (p<p_hat_list[i]+SE_hat_p_list[i]):
# interval contains p
ax.errorbar(p_hat_list[i], np.arange(len(p_hat_list))[i],lolims=True, xerr=SE_hat_p_list[i], yerr=0.0, linestyle='', c='black')
j +=1
else:
# interval does not contain p
ax.errorbar(p_hat_list[i], np.arange(len(p_hat_list))[i],lolims=True, xerr=SE_hat_p_list[i], yerr=0.0, linestyle='', c='red')
ax.axvline(0.61, color='darkorange')
plt.xlim(0,1)
plt.show()
print(f'{j}/{number_trials}={np.round(j/number_trials,2)}')
图 2:样本比例的置信区间。
24/25=0.96
我们正在绘制样本比例 p̂和区间:
注意,大约 96%的样本区间包含真实比例 p 。随着样本数量的增加,这个数字将收敛到 95%。
number_trials = 2000
j=0
for i in range(number_trials):
p_hat = bernoulli.rvs(p=p, size=n)
p_hat = p_hat[p_hat==1].shape[0] / p_hat.shape[0]
SE_hat_p = 2*np.sqrt(p_hat*(1-p_hat)/n)
if (p>p_hat-SE_hat_p) & (p<p_hat+SE_hat_p):
# interval contains p
j +=1
print(f'{j}/{number_trials}={np.round(j/number_trials,2)}')1877/2000=0.94
如果我们对 99%的置信区间感兴趣呢?我们需要计算特定置信水平的临界值,也称为 z*。临界值只不过是低于和高于平均值的标准偏差的数量,我们需要得到这个值来获得期望的置信水平(99%)。请注意,使用 z 表或使用来自scipy
的norm.ppf
时,请记住您获得的值是针对单尾置信区间的。这不是我们想要的,所以我们需要得到 99.5%的值(在分布的每个尾部留下 0.5%给出 99%的置信度)。
CI = 0.99
critical_value = norm.ppf(CI+(1-CI)/2) # we want the critical value for a two-tail distribution
critical_value2.5758293035489004
有 99%的可能性 p 在:
number_trials = 1000
j=0
for i in range(number_trials):
p_hat = bernoulli.rvs(p=p, size=n)
p_hat = p_hat[p_hat==1].shape[0] / p_hat.shape[0]
SE_hat_p = critical_value*np.sqrt(p_hat*(1-p_hat)/n)
if (p>p_hat-SE_hat_p) & (p<p_hat+SE_hat_p):
# interval contains p
j +=1
print(f'{j}/{number_trials}={np.round(j/number_trials,2)}')994/1000=0.99
比例的有效置信区间的条件
让我们首先回忆一下比例有效区间的条件:
- 样本必须是随机的。
- 正态分布可以近似样本比例的抽样分布。经验法则是,你至少需要有 10 次成功和 10 次失败。
- 要求样本是独立的。经验法则是,如果你是在没有替换的情况下抽样,你的样本量应该少于总体量的 10%。
为了帮助我们理解其中的含义,我们将举例说明当其中一个条件不满足时会发生什么。首先,让我们创建一个函数来计算置信区间,并绘制最后 50 个样本。
def confidence_interval(p, n, number_trials, N, ci=0.95, sample='random'):
p_ = bernoulli.rvs(p=p, size=N)
p_hat_list = []
SE_hat_p_list = []
if sample!='random':
# Inducing bias on the sampling
p_.sort()
p_ = p_[:-int(0.2*N)]
np.random.shuffle(p_)
for i in range(number_trials):
s_ = np.random.choice(p_, n, replace=False)
p_hat = s_[s_==1].shape[0] / s_.shape[0]
p_hat_list.append(p_hat)
SE_hat_p_list.append(2*np.sqrt(p_hat*(1-p_hat)/n))
j=0
_, ax = plt.subplots(1, 1, figsize=(6, 8))
for i in range(len(p_hat_list)):
if (p>p_hat_list[i]-SE_hat_p_list[i]) & (p<p_hat_list[i]+SE_hat_p_list[i]):
# interval contains p
if i > len(p_hat_list)-50:
ax.errorbar(p_hat_list[i], np.arange(len(p_hat_list))[i],lolims=True, xerr=SE_hat_p_list[i], yerr=0.0, linestyle='', c='black')
j +=1
else:
# interval does not contain p
if i > len(p_hat_list)-50:
ax.errorbar(p_hat_list[i], np.arange(len(p_hat_list))[i],lolims=True, xerr=SE_hat_p_list[i], yerr=0.0, linestyle='', c='red')
ax.axvline(0.61, color='darkorange')
plt.xlim(0,1)
plt.show()
print(f'{j}/{number_trials}={np.round(j/number_trials,2)}')
第一个例子是我们的样本不是随机的,也就是说,我们从总体中取样的方式会引入一些偏差。参考我们的上下文,这可能意味着我们的学生小组正在调查学校喜剧俱乐部之外的人,钱德勒的笑话更有效地与他们联系在一起。我们的信心突然下降到 90%以下。
confidence_interval(p=0.61, n=35, number_trials=1000, N=500, sample='not_random')
图 3:非随机抽样的样本比例的置信区间。
884/1000=0.88
第二种情况是,我们不能假设我们的抽样分布是正态的。请注意,我们的抽样规模是 10,这并不保证成功和失败超过 10 次。同样,即使我们计算出 95%的置信区间,真实比例 p 在计算区间内的次数百分比大约是 90%。
n = 10
print('Normal conditions:')
print('successes >= 10: ' + str(n*p_hat >= 10))
print('failures >= 10 : ' + str(n*(1-p_hat) >= 10))Normal conditions:
successes >= 10: False
failures >= 10 : Falseconfidence_interval(p=0.61, n=10, number_trials=1000, N=500)
图 4:非正态分布样本比例的置信区间。
897/1000=0.9
最后,最后一个条件是样本之间的独立性。如果不满足 10%的经验法则,我们就不能假设独立。我们的信心再次下降到接近 90%。
n = 150
N=600
print('Independence condition:')
print(n/N < 0.1)Independence condition:
Falseconfidence_interval(p=0.61, n=n, number_trials=1000, N=N)
图 5:不满足独立性标准的样本比例的置信区间。
904/1000=0.9
现在我们已经看到了所有不满足条件的情况,让我们创建一个通过所有 3 个测试的情况。
confidence_interval(p=0.61, n=35, number_trials=1000, N=500)
图 6:满足所有 3 个标准的样本比例的置信区间。
947/1000=0.95
我们的信心有效地收敛到 95%。我们可以对自己的自信充满信心。
估计总体均值
我们一直在解决估计人口比例的问题,人口中有百分之几的人更喜欢罗斯的幽默而不是钱德勒的幽默。一个不同的问题是估计人口的平均数。让我们来看看主要的区别。当我们估计人口比例的置信区间时,我们定义:
根据同样的原则,我们将总体平均值定义为:
请注意,我们不知道我们的总体标准差,所以我们使用我们的最佳估计,样本标准差。不幸的是,如果我们使用这种方法来计算我们的置信区间,我们将会低估实际的区间。为了达到 95%的置信度,我们需要使用基于 t 分布的不同临界值。
让我们做几个实验来证明我们的观点。首先,我们基于样本标准偏差定义均值的置信区间,但从正态分布计算临界值。
def confidence_interval_mean(μ, σ, n, number_trials, N, ci=0.95, sample='random'):
x_ = norm.rvs(loc=μ, scale=σ, size=N)
x_hat_list = []
SE_hat_x_list = []
if sample!='random':
# Inducing bias on the sampling
x_.sort()
x_ = x_[:-int(0.2*N)]
np.random.shuffle(x_)
for i in range(number_trials):
s_ = np.random.choice(x_, n, replace=False)
x_hat = np.mean(s_)
x_hat_list.append(x_hat)
SE_hat_x_list.append(norm.ppf(ci+(1-ci)/2)*np.std(s_)/np.sqrt(n))
j=0
_, ax = plt.subplots(1, 1, figsize=(6, 8))
for i in range(len(x_hat_list)):
if (μ>x_hat_list[i]-SE_hat_x_list[i]) & (μ<x_hat_list[i]+SE_hat_x_list[i]):
# interval contains p
if i > len(x_hat_list)-50:
ax.errorbar(x_hat_list[i], np.arange(len(x_hat_list))[i],lolims=True, xerr=SE_hat_x_list[i], yerr=0.0, linestyle='', c='black')
j +=1
else:
# interval does not contain p
if i > len(x_hat_list)-50:
ax.errorbar(x_hat_list[i], np.arange(len(x_hat_list))[i],lolims=True, xerr=SE_hat_x_list[i], yerr=0.0, linestyle='', c='red')
ax.axvline(μ, color='darkorange')
#plt.xlim(0,1)
plt.show()
print(f'{j}/{number_trials}={np.round(j/number_trials,2)}')confidence_interval_mean(2, 0.5, 12, 2000, 1000)
图 7:使用 z*计算的样本均值的置信区间。
1837/2000=0.92
我们期待的事情发生了,因为真正的平均值只有 92%的时间包含在我们的置信区间内。这不是有意的,因为我们正在计算平均值的 95%置信区间。
在第二个实验中,现在使用的临界值是从 t 分布计算出来的。
def confidence_interval_mean_t(μ, σ, n, number_trials, N, ci=0.95, sample='random'):
x_ = norm.rvs(loc=μ, scale=σ, size=N)
x_hat_list = []
SE_hat_x_list = []
if sample!='random':
# Inducing bias on the sampling
x_.sort()
x_ = x_[:-int(0.2*N)]
np.random.shuffle(x_)
for i in range(number_trials):
s_ = np.random.choice(x_, n, replace=False)
x_hat = np.mean(s_)
x_hat_list.append(x_hat)
SE_hat_x_list.append(t.ppf(ci+(1-ci)/2, df=n-1)*np.std(s_)/np.sqrt(n))
j=0
_, ax = plt.subplots(1, 1, figsize=(6, 8))
for i in range(len(x_hat_list)):
if (μ>x_hat_list[i]-SE_hat_x_list[i]) & (μ<x_hat_list[i]+SE_hat_x_list[i]):
# interval contains p
if i > len(x_hat_list)-50:
ax.errorbar(x_hat_list[i], np.arange(len(x_hat_list))[i],lolims=True, xerr=SE_hat_x_list[i], yerr=0.0, linestyle='', c='black')
j +=1
else:
# interval does not contain p
if i > len(x_hat_list)-50:
ax.errorbar(x_hat_list[i], np.arange(len(x_hat_list))[i],lolims=True, xerr=SE_hat_x_list[i], yerr=0.0, linestyle='', c='red')
ax.axvline(μ, color='darkorange')
#plt.xlim(0,1)
plt.show()
print(f'{j}/{number_trials}={np.round(j/number_trials,2)}')confidence_interval_mean_t(2, 0.5, 12, 2000, 1000)
图 8:使用 t*的样本均值的置信区间。
1892/2000=0.95
我们的信心有效地收敛到 95%。再一次,我们可以对自己的自信充满信心。
有效 t 间隔的条件
我们已经看到了比例有效区间的条件。在 t 间隔的情况下,同样的规则适用。区别在于如何验证我们的分布是否可以被认为是正态分布。:
- 样本必须是随机的。
- 样本均值的抽样分布可以近似为正态分布。有三种方法可以实现:样本量大于 30(中心极限定理适用),原始分布是正态的,或者原始分布是对称的。
- 要求样本是独立的。经验法则是,如果你是在没有替换的情况下抽样,你的样本量应该少于总体量的 10%。
我们把证明上述要点的实验作为本周的练习。
结论
在本文中,我们讨论了置信区间和误差幅度等概念。我们从定义和计算样本比例的置信区间开始。要计算这样的置信区间,必须满足 3 个条件。我们模拟了 3 种不满足条件的场景。通过分析这些影响,我们观察到在每个场景中引入的偏差影响了我们的信心水平。
我们还解决了计算样本均值置信区间的问题。在这种情况下,用于计算的临界值不能基于正态分布,而是基于 t 分布。通过模拟大量样本,我们展示了基于正态分布的临界值是如何低估实际置信区间的。最后,与我们对样本比例所做的一样,我们建立了有效 t 区间的条件。
保持联系: LinkedIn
练习
你将在下周的文章中找到答案。
- 更改函数
confidence_interval_mean_t
并构建 5 个不同的实验来计算样本均值的 95%区间,其中 3 个不满足 t 区间的条件,2 个满足。对于不满足条件的 3,定义以下情况:抽样不随机,原始分布不近似正态,不满足独立性。对于满足条件的两种情况,定义一种情况下原始分布是正态分布,另一种情况下原始分布是偏斜的,但采样均值是正态分布。对于后两种情况,真正的总体均值应该包含在 95%的计算置信区间内。
提示:您可能会发现使用 *scipy*
中的 *skewnorm*
函数很有用。下面,您有一个正态分布的修改版本,由偏斜度参数、平均值和标准偏差来偏斜。
# code adapted from https://stackoverflow.com/questions/49367436/scipy-skewnorm-mean-not-matching-theory
skew = 4.0
mean = 2
stdev = 0.5
delta = skew / math.sqrt(1\. + math.pow(skew, 2.))
adjStdev = math.sqrt(math.pow(stdev, 2.) / (1\. - 2\. * math.pow(delta, 2.) / math.pi))
adjMean = mean - adjStdev * math.sqrt(2\. / math.pi) * delta
print('target mean={:.4f} actual mean={:.4f}'.format(mean, float(skewnorm.stats(skew, loc=adjMean, scale=adjStdev, moments='mvsk')[0])))
print('target stdev={:.4f} actual stdev={:.4f}'.format(stdev, math.sqrt(float(skewnorm.stats(skew, loc=adjMean, scale=adjStdev, moments='mvsk')[1]))))target mean=2.0000 actual mean=2.0000
target stdev=0.5000 actual stdev=0.5000# Original skewed distribution
plt.hist(skewnorm.rvs(a = skew, loc=adjMean, scale=adjStdev, size=2000), bins=50);
# Approximately normal distribution of the sample mean because sample
# size is bigger than 30 (CTL applies)
plt.hist(np.mean([skewnorm.rvs(a = skew, loc=adjMean, scale=adjStdev, size=35) for _ in range(2000)], axis=1), bins=50);
上周的答案
- 里克在一个遥远的星球上对 75 名公民进行了 SRS 调查,以了解抽样调查的公民中有多少人对自己的生活水平感到满意。假设生活在这个星球上的 10 亿公民中有 60%对自己的生活水平感到满意。对生活水平满意的公民比例抽样分布的均值和标准差是多少?
mu_hat_p = 0.6
print(mu_hat_p)
sigma_p_hat = np.sqrt(0.6*(1-0.6)/75)
print(sigma_p_hat)0.6
0.0565685424949238
2.某个拥有超过 1,000,000 个家庭的星球的平均家庭收入为 1,000,000 美元,标准差为 150,000 美元。Rick 计划随机抽取 700 个家庭样本,计算样本平均收入。计算 x̄.抽样分布的平均值和标准差
μ = 1000000
σ = 150000
n = 700
print(f'μ_x_bar = {μ}')
print(f'σ_x_bar = {σ/n**(1/2)}')μ_x_bar = 1000000
σ_x_bar = 5669.467095138409
3.Rick 正在对不同的入口枪进行质量控制测试,因为在制造过程中存在一些可变性。某枪靶厚 5mm。厚度分布向右倾斜,平均值为 5 毫米,标准偏差为 1 毫米。该零件的质量控制检查包括随机抽取 35 个点,并计算这些点的平均厚度。样本平均厚度的抽样分布是什么形状?样品中的平均厚度在目标值 0.2 毫米以内的概率是多少?
# Since n = 35 >= 30, the central limit theorem applies.
# Even though the population is skewed to the right, the sample means
# are normally distributed due to the sample size.μ = 5
σ = 1
n = 100norm.cdf(5.2, μ, σ/n**(1/2)) - norm.cdf(4.8, μ, σ/n**(1/2))0.9544997361036418
使用数据类的 Python 配置文件
原文:https://towardsdatascience.com/configuration-files-in-python-using-dataclasses-ec8528e72e01?source=collection_archive---------12-----------------------
使用 dataclasses 对 Python 中的配置文件进行类型安全解析
作者图片
TL;速度三角形定位法(dead reckoning)
有了 Python dataclasses
和新的dataconf
库,我们现在可以安全地将配置文件解析成数据类。对于来自 Scala 的用户来说,这是从 case 类和 PureConfig 类型安全解析的简单过渡。要查看 Python 和 PySpark 用例中的示例用法,请跳到用法。
介绍
啊,配置文件。一个人必须爱他们,对不对?也许吧?看情况。对于那些使用 Scala 和其他 JVM 语言的人,我们可以使用 HOCON 、json 的人类可读格式、typesafe config
和 pureconfig 轻松地将复杂的配置或属性文件直接加载到 case 类中。有了这些,生活是美好的。我们的 Python 用户呢?
数据类的介绍
在 Python 3.7 中,数据类通过简单的 pip 安装向后兼容 Python 3.6。通过这个介绍,Python 本质上引入了可变格式的 Scala case 类。但是,dataclasses
可以被冻结以实现不可变的变体。有了这个介绍,我们的 Python 用户能实现同样的简化的配置文件解析吗?还没有。的确,PyHocon 已经存在了很多年,但是仍然缺少了一些东西。2020 年 5 月,Github 用户 @zifeo 将他的库 dataconf 发布到 PyPI,这是链中的最后一环。
数据会议库
dataconf
所做的是允许用户读入带有定义参数的配置文件,并直接输入到 Python dataclass
中。大约在 2021 年 8 月,我在寻找一种将配置文件轻松传递到 Python 的方法时偶然发现了这个库。根据我使用 Scala 的经验和对 Python 的dataclasses
的了解,我很高兴看到这个功能。在过去的几个月里,我添加了一些已经在版本0.1.5
、0.1.6
和0.2.0
中发布的附加特性,以进一步复制pureconfig
。目前,dataconf
已经快速成熟,目前是版本0.3.0
。由于缺少 Python 3.7.x
中没有的更新,dataconf
将只能在 Python >= 3.8.x
上工作。
在 True Digital Group 这里,我们正在开发一个定制的 MLOps 管道,用 Python 以自动化的方式为我们的用户和客户服务。然而,为了编排这些管道,我们将使用类似于我们在 Scala 中构建的数据管道的配置文件。答案是。我添加了解析嵌套配置的能力,并使用 Python 中的抽象基类dataclasses
模拟 Scala 密封特征的行为。这个库可能并不完美,但是我们现在可以依赖它来满足我们的 Python 管道需求。
为了使用dataconf
,用户入口点主要是load
和loads
。然而,如果传递ConfigTree
对象,它们将需要使用__parse
。当前的计划是在未来的版本中,用from_config
、from_file
和from_string
重构用法,使之类似于pureconfig
或另一种类似的模式。带代码的演示报告可在这里找到。最后注意,版本0.2.0
和更低版本不能解析-
,所以使用版本0.2.1
或更高版本。
用法示例
假设我们需要运行一个管道,接收数据或数据源,进行一些处理,然后将数据写出来。然而,数据可能来自 Python 中许多不同的文件格式,或者来自表、sql 查询或 HDFS 路径。在这种情况下,使用配置文件、数据类和dataconf
可以简化我们的工作并避免分支。在示例中,我使用抽象元类来处理不同的输入类型。有了这个,我可以让PipeParams
或Params
手柄决定dataclass
匹配。所有的类都带有load_df
,所以我们可以使用相同的方法名调用来加载数据帧,而不管哪个被解析。下面的例子仅仅是关于如何使用 dataclasses 和dataconf
来简化你的产品编码的皮毛。
原载于 2021 年 10 月 25 日https://tech . true analytics . ai。
使用传统的机器学习算法配置 CNN 模型
原文:https://towardsdatascience.com/configure-a-cnn-model-using-traditional-machine-learning-algorithms-ac31a11e1c12?source=collection_archive---------21-----------------------
将集成学习算法应用于影像数据集,影像数据集是通过 python 实现由卷积图层提取的要素
***Table of Contents* 1\. Introduction
2\.** [**Layers**](#096c) **2.1\. Convolutional Layer
2.2\. Pooling Layer
2.3\. Dropout Layer
2.4\. Flatten Layer
3\.** [**Tutorial**](#5928) **3.1\. Dense Layer Approach
3.2\. Ensemble Learning Approach
4\. Results
5\.** [**Discussion**](#bab4)
1.介绍
在传统的机器学习应用中,在对数据集应用必要的数据预处理过程之后,它主要被转换成 (n_samples,n_features) 并应用该算法。为了避免过拟合和欠拟合等情况,样本的数量应该很大。为了防止这种情况,或者通过各种方法来扩展图像数据集的图像扩充,或者应用诸如特征提取、特征选择或维数减少的方法。
卷积神经网络(CNN)是一种深度学习方法,主要用于图像数据集。它通过用人工神经网络训练模型来用于分类。当我们处理该模型时,给定图像数据集的特征与其结构中的层一起被提取,并且这些获得的特征由诸如密集层的各种层训练。
本文包括如何使用集成学习算法对使用卷积层提取特征的图像数据集进行分类。python 实现丰富了这项工作。
照片由尤里·赛洛斯在 Unsplash 上拍摄
2.层
首先,让我们简要了解一下在构建本教程中使用的模型时使用的图层:
2.1.卷积层
卷积层是卷积神经网络(CNN)的主要构件。它们将像素值作为输入,并执行特征提取。它由过滤器和内核组成。学习是通过从数据集中提取一个子集,然后对其进行过滤和处理来进行的。利用线性乘法来执行这些处理,并且提取关于图像的诸如边缘检测之类的特征。图 1 显示了由具有不同内核的 cv2 库提供的梯度滤波器的应用。
图一。内核在渐变滤镜中的效果,图片作者
如果我们再深入一步,这个过程是如何发生的?如上所述,它是一个简单的数学运算,名为卷积。用数学来说明:
输入= [ 5 10 15 20 25 30]
过滤器= [0 1 0]
输出计算如下:
[5 10 15] . [0 1 0] = 10
[10 15 20] . [0 1 0] = 15
[15 20 25] . [0 1 0] = 20
[20 25 30] . [0 1 0] = 25
过滤后的矩阵,即输出为【10 15 20 25】。这个过程也可以作为 2D 卷积层多样化。
2.2.汇集层
汇集层对卷积层之后获得的矩阵值执行各种操作。平均池取确定的矩阵大小中像素值的平均值,而顾名思义,最大池取最大值。如图 2 所示,通过使用 2x2 池,4x4 矩阵已经缩小到 2x2 大小。它概括了特定区域的特征,降低了特征的维数。这样,在模型变得更加通用的同时,避免了过拟合。
图二。最大池(左)和平均池(右)是做什么的?,来源
2.3.脱落层
用最简单的话来说,它删除了图 3 中获得的一些特征,也就是说,它导致了信息丢失。如果我们处理 128×128×3 的 RGB 图像,并考虑像素是图像数据集的特征,我们将有大约 50000 个特征。通过申请退学,可以放弃其中的一些功能。这样,也防止了过拟合。
图 3。辍学层是做什么的?,来源
2.4.展平图层
扁平化层用于 CNN 模型第一部分的最后一层,该模型将矩阵形状从 3x3 转换为 9x1,如图 4 所示,以便为通过完全连接的层进行分类准备数据集。
图 4。展平图层是做什么的?,来源
3.辅导的
在图像的特征之后,使用卷积层提取数据集,这些特征分别由密集层和集成学习算法训练。讨论了实现和结果。
可以通过链接访问数据集。
3.1.密集层方法
该数据集由 233 个样本组成,包含杯子、盘子、碟子,被训练用于分类。首先,使用图像增强过程来扩展数据集。在应用数据预处理过程之后,它被分成训练集和测试集。训练数据集使用如下构建的模型进行训练:
- [1] -图像放大、调整大小和缩放
预定义的图像增强过程重复 15 次,并且样本数量增加大约 3500。数据集中的所有图像都调整为 128 x 128 像素,每个像素除以 255 进行缩放。
- 【2】-型号
CNN 模型由两个主要部分组成。使用‘model’
提取特征,它作为第一个组件按顺序构建。由于像素是图像数据集的特征,并且图像的形状是 128×128×3,所以特征的总数是 49152。输入形状在第一卷积层中定义。在接下来的卷积层中, L1 & L2 regularizations
被用于防止过拟合。L1&L2 正则化的作用是调整权重的重要性,因此可以假设卷积层的正则化参数是层的学习速率。此外,以不同的速率应用Dropout
以防止过拟合,最后,使用Flatten layer
将模型的形状转换为(n_samples,n_features)。该模型的概要如图 5 所示。
图 5。模型摘要,图片由作者提供
查看展平层的输出形状,可以看到,开始时的特征数为 49152,使用层后为 1728。
在模型的第二部分中,在提取特征之后,应用密集层来执行分类过程。最后,通过组合输入(是提取特征的部分)和输出(是进行分类的部分)来创建“T4”。
- 【3】-模型评估
准备混淆矩阵和测试数据集的分类报告来评估模型。
- 【4】——模型泛化性能
使用 google images 随机下载了 15 张杯子和盘子的图像,并用训练好的模型进行预测,以测试模型的泛化性能。
3.2.集成学习方法
在引言句中已经提到,机器学习中的数据集是以 (n_samples,n_features) 的格式进行训练的。在这一部分中,应用了集成学习算法,但是可以使用任何分类算法来代替。查看图 5 中的展平图层,可以看到它被提取为 1728 个要素。在这一部分中,分类过程使用集成学习算法而不是密集层来完成,如下所示:
- [1]-通过 CNN 模型的第一部分
‘model’
预测训练集、测试集和外部测试集,并创建派生数据集。 - [2]-创建包含混淆矩阵结果的函数,以便应用所有算法。
- [3]- XGBoost、LGBM、基于直方图的 GB、ExtraTree、AdaBoost、Bagging 算法在其基础版本中用于分类。
4.结果
密集层方法的混淆矩阵如图 6 所示。
图 6。测试集的混淆矩阵(左),外部测试集的混淆矩阵(右),图片作者
可以看出,在测试数据集中实现了 91%的成功,而在外部测试数据集中获得了 13/15 的准确性,该外部测试数据集是从不同的源随机生成的,用于模型泛化性能。
集成学习方法的结果如图 7 所示。
图 7。集成学习算法的结果,图片由作者提供
可以看出,尽管测试数据集精度高,但是在外部测试数据集中获得了低精度结果。这表示过拟合。
5.讨论
由于这项研究主要是关于开发一个 CNN 模型,它不是集中在集成学习方法。然而,可以看出,尽管没有调整超参数,但是这些方法中的一些,例如 XGBoost,具有令人满意的结果。
有必要了解它是如何工作的,以促进卷积神经网络的应用。本文旨在提供不同的选择和灵活性。有可能提高在集成学习算法中获得的准确性结果,例如使用 GridSearch 检测超参数的最佳组合或扩展数据集。深度学习中的 CNN 模型在图像数据集上的效果无可争议地好,但当作为替代方案进行研究时,这种方法甚至可以被评估用于不同的目的。
回到指引点击这里。
https://ibrahimkovan.medium.com/machine-learning-guideline-959da5c6f73d
在 1 分钟内创建一个你的同事能够理解的代码库
原文:https://towardsdatascience.com/configure-a-codebase-your-colleagues-will-understand-in-1-minute-faa02483cbf?source=collection_archive---------14-----------------------
晚上创作的背景照片 _ 陶—
实践教程
使用 PyScaffold 和预提交挂钩配置结构化数据科学报告
在组织中,数据科学代码库(又名存储库或包)有一个通用文件结构。
结构是指代码库中文件的布局,例如:
基本代码回购结构。(图片由作者创作)。
在大学、Kaggle 或宠物项目中,你可以在代码库结构上有点无赖——毕竟,最重要的是输出。
但是在组织中,代码库的结构也很重要,而且非常重要。
我们在这里讨论的是构建代码库的通用最佳实践——组织希望你作为数据科学家使用的那种。
为什么通用代码库结构很重要?
这很重要,因为在组织中,其他人会与你的代码进行交互。当其他人与你的代码交互时,你希望他们在尽可能短的时间内理解你的代码库这样他们就可以开始为之做出贡献。
如果文件结构是一种通用格式,您的数据科学家和开发人员同事只需花几分钟就能理解它,然后就能进入有趣的部分——钻研代码本身。
或者,如果代码库结构不是的通用格式,那么每次有人查看新的代码库时,他们将不得不花费额外的时间(比如 2 小时)来熟悉它的结构。无聊吧?我们宁愿直接找到代码并开始编程!
然后是整个团队的时间损失。如果你考虑一个有 100 名开发人员的企业,每个人平均一年开发 10 个现有的代码库,他们花 2 个小时熟悉每个代码库的结构—2000 个小时仅仅是理解回购结构。那就是每年有 83 天或 3 个月不必要的工作损失。
令人难以置信的是,如果开发者花 1 分钟,为回购建立一个共同的结构,这是可以避免的。对于 10 次回购,这是10 分钟的 成本,以节省 3 个月的损失时间。
多划算啊!
如何在 1 分钟内创建结构化 Git 回购
好消息是,实际上就这么简单:
your_directory$ **pip install pyscaffold**
your_directory$ **putup your_repo_name**
就是这样!在您想要存储 repo 的目录中执行这两行代码后,它将在大多数数据科学家常用的文件结构中创建—不到 1 分钟!它将看起来像这样,并立即准备好开始编码:
你的结构性回购。(图片由作者创作)。
让您的代码库更加可用
在你的新代码库中有 3 部分标准文件对此有帮助——src文件夹、 setup.cfg 文件(和预提交钩子)和 README 文件:
(图片由作者创作)。
src 文件夹
这个 repo 最重要的部分是 src (source)文件夹,因为这是您的数据科学代码将要存放的地方。您可以从 src 构建一个完整的数据科学项目,而无需接触任何其他文件。
src 文件夹最初看起来像这样:
使用 pyscaffold putup 函数后的 src 文件夹(图片由作者创建)。
可以忽略 init。py 和 skeleton.py 文件。重要的是您添加到该文件夹的内容,即用于数据清理、标记、建模等的功能。
构造 src 文件夹的常用方法如下:
- 包含函数的文件
- 一个连续调用这些函数并提供输出的 runner 文件
以下是一个 src 结构示例:
一个非常基本的 src 文件夹结构的例子(图片由作者创建)。
如您所见,有三个文件夹和,每个文件夹都包含 python 文件和函数:
- 预处理:用于清理你的数据(处理缺失值,标准化数据等)
- 模型:任何需要建立的模型(如贝叶斯神经网络)以及根据需要训练它的功能
- 结果:用于输出您的预测结果(以图表或 CSV 等形式)
然后我们有了非常重要的 runner.py 文件,它导入数据,按顺序调用这些函数,并提供输出(可能会将结果保存到 csv 或绘图到文件夹等)。
自述文件
自述文件是你回购的另一个重要部分。这告诉你的数据科学家同事如何使用你的代码库。它非常有用,可以解释如下内容:
- 你的回购做什么
- 需要哪些依赖项以及任何安装说明
- 任何其他使用说明
- 如何与作者取得联系
您的同事在开始处理您的代码库时,可能会首先查看这个文件,所以有必要弄清楚这一点
setup . CFG 文件&预提交钩子
在这最后一步,我们会告诉您的同事他们需要哪些安装来运行您的代码库,并配置规则(挂钩),以帮助确保只有格式良好的代码才能提交到您的代码库。
首先让我们看看 setup.cfg 文件。这里值得编辑的主要部分是“ install_requires”。这个是一个超级有用的部分,因为它告诉新用户需要哪些包和版本来运行你的代码库。如果没有这一点,您的同事可能会安装没有所需功能的旧版本(因此在运行时会导致错误)。
库以 库 == 版本 的形式添加到本节中,例如:
(图片由作者创作)。
在 install_requires 部分,我们还可以添加三个高质量的包,这有助于使您的实际代码对您的同事来说更具可读性:
(图片由作者创作)
预提交和预提交钩子是很棒的包!它们本质上拥有一组格式化“钩子”和格式化规则,在你提交任何东西之前,你的代码必须遵守这些规则。这些规则是标准的最佳实践,在数据科学中被广泛使用(并被期待)。例如:
- 代码 行长度不能大于 100 个字符
- 导入语句必须在文件的顶部
- 每个函数之间必须留有两个空行
当您尝试提交时,预提交包将让您知道哪些规则没有被满足,以便您可以修复它们。
设置预提交挂钩的两个简单步骤:
- 通过在 repo 的终端(或其他 shell)中执行以下命令来安装预提交:
your_directory$ **pip install pre-commit**
your_directory$ **pre-commit install -t pre-commit**
2.创建一个. pre-commit-config.yaml 文件来存储你的钩子
这个文件是 pre-commit 在你提交某个东西的时候读取的— 所以 你应该在这里列出你想要哪个钩子。添加。将 pre-commit-config.yaml 文件提交到您的根文件夹(即 src 上面的文件夹)。
下面是一个基本配置,你可以复制到你的中。pre-commit-config . YAML文件开始—它指示上面要点中的三个钩子:尾随空格,重新排序 python 导入, flake8 (代码风格指南实施—使用非常广泛)。
用于复制和粘贴的代码:
default_language_version: python: python3repos: - repo: local hooks: - id: reorder-python-imports name: reorder-python-imports entry: reorder-python-imports language: python types: ["python"] - id: flake8 name: flake8 entry: flake8 language: python types: ["python"] - id: trailing-whitespace name: trailing-whitespace entry: trailing-whitespace-fixer language: python types: ["python"]
它应该是这样的:
(图片由作者创作)。
现在,当您提交时,钩子应该开始工作:)为了进行测试,尝试提交一个包含错误代码的. py 文件——它应该被拒绝,并且应该在终端中返回一个需要修复的代码行列表。
您可以在中添加任意数量的挂钩。预提交 config.yaml 文件。预提交的文档可以在这里看到,更完整的钩子列表可以在这里看到。
就这样!您可以像往常一样将这个代码库推送到 GitHub,因为您已经掌握了专业代码库设置的基础知识:)
最后一个音符
结构化回购有用的关键在于,每个人都使用相同的结构——一种大家熟悉的已知结构。你的组织可能会有一个固定的结构,它可能与上面的不同。然而,上述方法是数据科学中一个众所周知的结构,在没有其他指导原则的情况下,这是一个很好的选择。
希望那有用!如果您有任何问题,请随时在 LinkedIn 上给我发消息。你也可以订阅我的帖子 这里。
最后,如果你想进一步支持 Medium 上的作者,你可以在这里注册成为会员。
配置没有 DevOps 学位的 DVC 远程
原文:https://towardsdatascience.com/configure-a-dvc-remote-without-a-devops-degree-3b2b06961e8f?source=collection_archive---------37-----------------------
照片由 Honey Yanibel Minaya Cruz 在 Unsplash 上拍摄
有了 DAGsHub 储物件,一切都变得简单了
DVC 是一个伟大的工具;它可以让你追踪和分享你的数据、模型和实验。它还支持管道对典型 ML 工作流中的步骤进行版本控制。要共享您的数据和模型,您需要配置一个 DVC 遥控器(如 S3、GCloud Storage、GDrive 等。),但这样做可能会很麻烦,而且会花费大量时间。
要订购的东西太多了…照片由汉斯-彼得·高斯特 / Unsplash 拍摄
在这篇文章中,我将向你展示这种配置不应该如此困难;应该是流畅轻松的。为了解决这个问题,我们创建了 DAGsHub Storage,这是一个超级容易配置的 DVC 遥控器,无需信用卡,无需授予复杂的权限,也无需云设置。只需五个命令,您就可以开始了!
首先,您需要在 DAGsHub 上有一个项目。有两种方法可以做到这一点,要么从头创建一个要么从任何其他平台连接一个现有项目(我们支持 GitHub、GitLab、BitBucket 和任何其他可访问的 Git remote)。
如果你需要,我们有一个关于如何在我们的平台上开始一个新项目的教程https://dagshub.com/docs/experiment-tutorial/overview/。
要继续这个教程,你需要先安装 DVC。
在 Git 项目中安装 DVC 后,通过运行以下命令初始化它
*dvc init*
该命令将创建.dvc/.gitignore
、.dvc/config
、.dvc/plots
和.dvcignore
。这些条目可以用
*git commit -m "Initialize DVC"*
对于本教程,我已经创建了一个具有以下结构的新项目
*data
├── processed
│ ├── test_text.txt
│ └── train_text.txt
└── raw
└── test_full.txt*
为了开始跟踪我们的数据,无论是文件还是目录,我们使用dvc add
*dvc add data*
**这里是 DVC 施展魔法的地方。存储关于添加到.dvc
文件中的条目的元数据;这是一个小文本文件,包含关于如何访问原始条目的信息,但不是原始条目本身。这个命令将添加的条目添加到.gitignore
文件中,这样我们就不会不小心提交了。
在我们的例子中,DVC 创建了一个名为data.dvc
的文件,如下所示
*outs:
- md5: 61b3e1a6439d6770be4d210b758f6cbd.dir
size: 0
nfiles: 3
path: data*
这是将由 Git 进行版本控制的文件。
在这一步之后,我们准备提交.dvc
文件,就像我们处理任何源代码一样。
*git add data.dvc .gitignore
git commit -m "Add data"*
远程存储数据
配置一个桶不应该这么难!杰西卡·约翰斯顿 / Unsplash 拍摄的照片
太棒了。我们现在正在跟踪数据的版本,现在我们必须弄清楚在哪里存储数据本身。
正如我之前提到的,我将向你展示如何毫不费力地配置 DVC 遥控器。遵循五个简单的命令,您将把您的数据和模型与代码放在一起。为了便于比较,我还将向您展示设置遥控器的传统方式,这样您就可以很容易地理解使用 DAGsHub 存储节省的时间。
没有 DevOps 学位怎么做
在 DAGsHub,我们会自动为平台上的每个项目创建一个 DVC 遥控器来推送您的数据和模型,就像您收到 Git 遥控器来推送您的代码一样。这就是简单性开始显现的地方!要从该 URL 推送或提取数据,我们将使用现有的 DAGsHub 凭据(通过 HTTPS 基本身份验证)。这意味着我们不需要配置任何 IAM,不需要提供访问令牌来访问您的存储桶或任何与云提供商相关的东西。
公共存储库将拥有公开可读的数据,就像代码一样。如果您想要共享或接收来自协作者的数据,请将他们添加为项目协作者。如果你的库是私有的,那么只有维护者能够将数据拉进或推进其中。
基本上能克隆代码就能拉数据!在 DAGsHub 上添加合作者
让我们把手弄脏吧!
- 我们需要添加 DAGsHub 作为我们的 DVC 遥控器
*dvc remote add origin --local <https://dagshub.com/><username>/<repo_name>.dvc*
2.接下来,我们需要告诉 DVC 如何要求我们的凭证
*dvc remote modify origin --local auth basic
dvc remote modify origin --local user <username>
dvc remote modify origin --local ask_password true*
3.最后,将数据推送到新的遥控器
*# Make sure you are using DVC 1.10 or greater for the next command
dvc push -r origin*
就是这样!只需 5 个命令,您就可以毫不费力地配置您的 DVC 遥控器;我们从未打开云提供商网页,处理复杂的 IAM,或提供信用卡信息。
简易柠檬榨汁机。由 Unsplash 上的 Louis Hansel @shotsoflouis 拍摄的照片
如果你需要更多关于 DAGsHub 存储的信息,你可以阅读我们的 功能参考
如何用 DevOps 学位做这件事——一个比较
在我们深入本节之前,除了 DAGsHub 存储之外,DAGsHub 目前还支持 AWS S3 和 GCS 。如果你的目标是用最简单的方式安装 DVC 遥控器,那么你已经完成了。
为了便于比较,我们来看看亚马逊 S3 是如何做的。
- 聘请 AWS 作为您的云提供商。这包括拿出你的信用卡(如果你已经有一个账户,你可以跳过这一步)
- 设置一个存储桶来存储您的数据
- 安装 AWS CLI 工具
- 使用 CLI 工具登录 AWS
- 如果将要使用存储桶的用户不是管理员,创建一个 IAM 用户
- 分配正确的权限来使用铲斗
*{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "<IAM-user-ARN>" (e.g: "arn:aws:iam::7777777:user/dags-lover")
},
"Action": [
"s3:GetObject",
"s3:PutObject",
"s3:ListBucket",
],
"Resource": [
"arn:aws:s3:::/*"
"arn:aws:s3:::"
]
}
]
}*
很多事情,对吧?即使对于最有经验的用户来说,所有这些步骤都容易出错,所以如果你是第一次这样做,预计会错过一些东西。
这还没有结束。如果你想集成 DAGsHub,你需要在你的项目设置中添加一个存储键,这样我们就可以在我们的文件查看器中列出、显示和区分你的文件。
你会在https://dagshub.com/用户名> / <回购名称>/设置/存储/密钥中找到这个设置页面
DAGsHub 上的存储键菜单
一旦您输入您的 bucket URL,您将收到添加存储密钥的所有说明。
跟上!我们还没完成呢!现在你需要为 DVC 安装 S3 软件包
*pip install "dvc[s3]"
#Or if you are using poetry
poetry add dvc --extras "s3"*
接下来,我们需要添加 bucket 作为我们的遥控器
*dvc remote add s3-remote s3://your-bucket/storage*
最后,我们把我们的数据
*dvc push -r origin*
了解更多信息
我希望这能帮助你理解如何设置 DVC 遥控器(一个简单的方法和一个困难的方法)。更多关于 DAGsHub 的信息,请查看我们的网站、文档,或者加入我们的 Discord 社区。
在 Django 中配置读取副本数据库
原文:https://towardsdatascience.com/configure-a-read-replica-database-in-django-b0d54ec897f1?source=collection_archive---------29-----------------------
软件开发
何时以及如何在 Django 中配置读取副本数据库
图片由海燕在 Unsplash 上拍摄
何时以及如何在 Django 中配置读取副本数据库
在软件工程中,最关键的步骤之一是架构的选择,以至于选择中的任何错误都可能导致网站出现故障,从而对业务绩效产生不利影响。
通常,与系统性能相关的问题,尤其是对于大型复杂的系统,对于维护和诊断是至关重要的,因为它们可能与不同的软件环境相关。这些问题可能由多种因素引起,包括硬件、软件或网络相关问题。
下一篇文章将讨论与数据库性能相关的问题,以及使用读取副本减轻这些问题的方法。我目前的体验是基于部署在谷歌云平台上的 App Engine 应用和 PostgreSQL 复制。
数据库中的性能问题
在大多数情况下,由于与数据库性能相关的问题,系统会变得混乱。造成这种情况的因素有很多,最常见的是选择了错误的模式设计。因此,如果在牢记预期操作的同时没有正确设计,数据库将最终表现不佳。相反,一个设计良好的模式不一定能达到标准,因为许多其他因素会影响它的性能,例如连接数、压力或负载处理能力,或者数据库要处理的数据量。例如,当单个数据库处理大量用户(考虑几千个)时,它将遇到大量连接命中,并且它不一定有资源来实时满足这些命中。因此,为了缓解这种情况,引入了副本的概念。
数据库副本
关于软件和硬件的术语“复制”是指利用特定资源的多个副本(或复制品)来改善/增强性能、服务可用性和容错的过程。关于数据库系统中的复制,通常认为多台服务器在处理相同的数据。有多种配置和过程可用于将复制合并到数据库中:
- 在所有情况下都允许读或写命令。
- 多个只读实例和一个主实例(允许读/写命令)。注意,在这种模式中,数据复制和同步可以以同步和异步方式执行。
在 Django 中处理读取副本配置
在 Django 应用中配置和使用读取副本之前,应考虑以下两点:
- 读取副本实例应该在 Django 应用程序中声明为数据库。
- 需要配置路由器来选择相应的读取副本。
在 Django 中声明读取副本实例为数据库的程序
在 Django 中将读取副本配置和声明为数据库的方法包括设置 Django 设置文件。如上所述,我们将设置一个默认的单个主实例(允许读/写的服务器)数据库,而读副本将被声明为附加数据库。例如,考虑到已经配置了两个复制副本,settings.py 文件应该如下所示:
DATABASES = {
"default": {
"ENGINE": "django.db.backends.postgresql",
"HOST": "/cloudsql/project-id:region:master-instance-id",
"NAME": "pg_master",
"USER": "pg_user",
"PASSWORD": "master_password",
},
"replica_1": {
"ENGINE": "django.db.backends.postgresql",
"HOST": "/cloudsql/project-id:region:replica1-instance-id",
"NAME": "pg_replica1",
"USER": "pg_user",
"PASSWORD": "replica1_password",
},
"replica_2": {
"ENGINE": "django.db.backends.postgresql",
"HOST": "/cloudsql/project-id:region:replica2-instance-id",
"NAME": "pg_replica2",
"USER": "pg_user",
"PASSWORD": "replica2_password",
}
}
一旦配置完成,这两个副本就可以通过 Django 应用程序使用了。我们可以通过使用 QuerySet API 的方法来再次确认这一点。例如,可以使用以下命令从主数据库和副本数据库检查 Lead 模型的可访问性:
# Here the leads are retrieved from the master instance:
Lead.objects.all()# Here the leads are retrieved from the replica instance 1:
Lead.objects.using('replica_1').all()# Here the leads are retrieved from the replica instance 2:
Lead.objects.using('replica_2').all()
也可以在通过传递“using”参数的“ save 方法保存对象时,将给定的数据库设置为可用。请注意,在一个读取副本中保存对象时,将会遇到错误,因为实例只允许读取操作,不允许写入。
路由器配置有助于在需要时访问特定的读取副本
一旦在 Django 应用程序中配置了副本实例,并且确保了可访问性,软件开发人员就以这样的方式设计程序,即在适当的相应副本上执行只读操作。因此,默认情况下,这种方法会妨碍可扩展性,因为它更像是配置复制副本实例选择的手动过程。这意味着将来添加更多的副本将需要修改代码并手动配置路由过程。
然而,手动配置的另一个聪明的方法是使用 Django 的数据库路由器。在这种配置中,可以创建定制的路由器,它自动选择默认实例来执行写操作,或者选择随机选择的副本来执行读操作。下面是自定义路由器配置,显示了该过程的工作原理:
class DatabaseRouter:
def db_for_read(self, model, **hints):
return random.choice(['replica_1', 'replica_2']) def db_for_write(self, model, **hints):
return 'default' def allow_relation(self, obj1, obj2, **hints):
return True def allow_migrate(self, db, label, model=None, **hints):
return True
按照上面的过程,现在我们需要通过设置默认的数据库路由来更新“setting.py”文件:
DATABASE_ROUTERS = ['app.router.DatabaseRouter']
一旦更改生效,应用程序中的所有读取操作将被路由到副本,写入操作将被定向到主实例。
结论
总结一下我们的讨论,在 Django 中打开读取副本实例的过程非常简单。此外,它有助于增强应用程序的性能以及整个系统的功能。在我们原始代码的基础上,对配置文件和设置进行微小的修改,就可以让事情朝着对系统有利的方向发展。
感谢阅读这篇文章!如果你有任何问题,请在下面留言。另外,看看我以前的文章,你可能会喜欢:
https://vpodk.medium.com/principles-of-software-engineering-6b702faf74a6
验证性因素分析基础
原文:https://towardsdatascience.com/confirmatory-factor-analysis-theory-aac11af008a6?source=collection_archive---------0-----------------------
思想和理论
它是如何工作的,可以在你的研究中使用
由 Charles Deluvio 在 Unsplash 上拍摄的照片
如果你已经做到这一步,你可能已经读过我的探索性因素分析(EFA) 文本。如果你还没有读过,在直接进入验证性因素分析(CFA)之前先检查一下,因为这两种分析有一些重要的相似之处!在本文中,我们将介绍 CFA 的基本原理,它是如何工作的,并且我们将比较 CFA 和 EFA。
我如何表示我的构造?
与 EFA 一样,CFA 使用公共因子模型,即它将观察变量之间的协方差视为一个或多个因素影响的反映,也是一个未解释的方差。这与网络分析不同,网络分析允许项目之间的协方差在它们之间有一个原因。换句话说,因素分析的心理测量模型一般认为项目的协方差只是因为有一个潜在的因素来解释它。这是一个要记住的非常重要的假设,因为也许你的结构不符合公共因子模型,而是一个网络模型。我将用 Borsboom 和 Cramer (2013)给出的一个例子来解释。
下面,我们看到一个测量重度抑郁症的工具的因子模型。在这份报告中,这些项目衡量的方面包括:情绪低落、体重增加、睡眠问题、运动问题、疲劳、注意力不集中等。我们从图中看到,项目得分的变化有一个共同的原因,即抑郁(即,一个人的抑郁水平越高,他们越多地报告有这些症状)。
主要抑郁因素模型。图片来自 Borsboom 和 Cramer (2013 年)
然而,我们可以认为一些项目之间的关系不仅仅是由于抑郁。这方面的一个例子是注意力集中问题的原因及其与其他症状的关系。睡眠有问题的人会变得疲劳,因此会有注意力问题(睡眠问题→疲劳→注意力问题)。换句话说,可以推断一个可观察变量和另一个变量之间的因果关系,这与公因子模型“决裂”。下图是这种模型的一种可能的表示形式,其中各个项目之间存在因果关系。
焦虑与抑郁症的关系。图片来自 Borsboom 和 Cramer (2013)。
那么,我如何知道我的结构是遵循公因子模型还是更像网络模型呢?嗯,基于理论!我知道研究人员在很长一段时间里只关心统计数据来指导一切,但对我们来说,重要的是从理论上重新思考我们的构建,然后从经验上测试理论。
好了,你决定最适合你的结构的模型是因子模型,现在呢?
什么是 CFA?我们何时申请 CFA?
CFA 是一种多变量统计,用于估计工具的结构,验证测量变量在多大程度上代表结构的数量。也就是说,它验证一个乐器的结构是否可以是真实的,但不一定是真实的。为此,我们需要陈述我们想要测试的结构。一般来说,当有先前的研究告诉我们该工具的维度时,就使用 CFA。例如,我们将有一项北美研究,它使用 EFA 来验证工具的维度,而您使用 CFA 来验证这种结构在巴西数据中的表现如何。然而,这不是你使用 CFA 的唯一方法!例如,你可以在同一个研究中使用 EFA(探索维度),但仍然可以使用 CFA 测试不同的理论模型。
因此,当您想要估计工具的维度时,EFA 和 CFA 都适用(注意,我说的是估计,而不是探索/发现维度)。例如,我们可以在自我报告工具中应用 CFA,其中项目代表行为、想法或感觉。另一个例子,我们可以将它应用于一系列其他的测量,比如焦虑的心理物理学测量。因此,CFA 适用于测量幸福、焦虑、偏见等属性的工具。
饱和/无限制模型和限制模型之间的差异
全民教育模式可以称为饱和/无限制模式。这是因为所有潜在维度解释了所有项目的差异,如下图所示。
饱和/无限制模型。作者制作的图像。
至于 CFA,我们可以称之为限制模型,即我们对模型施加一些限制,例如,一个因素不能与另一个因素的项目交叉加载。下图举例说明了受限模型。
受限模型。作者制作的图像。
当然,一种模式和另一种模式之间存在一些实际差异。第一个是,一般来说,CFA 的因子加载输出不同于 EFA。在 EFA 中,所有因素都有交叉负荷,而在 CFA 中,一些负荷被设置为 0,如下图所示。
CFA 中因子加载的例子。作者制作的图像。
我做了一个表格,展示了非限制模式(EFA)和限制模式(CFA)的区别。
EFA 和 CFA 的区别。作者制作的图像。
我们在上表中看到,对于验证性因素分析,我们需要有一个明确的假设,即背后必须有一个理论来直接指导我们的分析,我们不能只是在没有适当理由的情况下继续探索。这和 EFA 有一点不同,EFA 的结构背后有一个理论,但是你测试这个结构是否会在数据中得到佐证(通过平行分析之类的)。当然,在全民教育中,我们可以根据理论提取因素,这在某种程度上类似于直接指导分析的假设。
同样重要的是再次强调,在 CFA 中,我们可以测试不同的模型,能够进行修改并允许残差相关性。见下图。
同一结构的不同 CFA 模型。作者制作的图像。
我们甚至可以测试更复杂的模型,比如层次模型或者双因素模型。
分层模型(左)和双因素模型(右)。作者制作的图像。
简而言之,因为 CFA 对模型进行了限制,所以我们有可能测试大量的东西!CFA 的一个用途是通过多组 CFA,我在之前的文本中写过。
模型识别
当我们谈论一个受限模型时,我们必须处理一个称为模型识别的“问题”(Bollen,1989)。换句话说,我们需要我们的数据有足够的“信息”来进行必要的统计。
有 4 个项目的因素模型。作者制作的图像。
在上图中,我们使用 CFA 来估计单维度。我们看到我们估计了 4 个因子负载(λ;每个项目一个)和 4 个残差(ε;每项一个),也就是我们有 8 个信息需要估计。我们拥有的信息片段是 V1、V2、V3 和 V4 的分数(即这个人对每个观察到的变量的分数)以及它们之间的相关性。
V1、V2、V3 和 V4 之间的关联矩阵。作者制作的图像。
因此,我们有 4 个分数+ 6 个相关性= 10 条信息。换句话说,由于我们手中有 10 条信息,用 4 个项目我们可以估计 8 条因子载荷和残差。按照这个逻辑,很容易看出,为了能够识别模型,每个潜在因素的最小项目数是 3 个项目。看,在有 3 个项目的单因素模型中,我们将估计 3 个因素负荷+ 3 个剩余= 6 个必要信息。我们有 3 个项目的信息+ 3 个相关性= 6 个信息。所以我们将有 0 个自由度(DF)。
- 如果 DF < 0, the unidentified model (nothing will be estimated);
- If DF = 0, the model is under-identified (only factor loadings will be arbitrarily estimated; no fit indexes will be generated);
- If DF> 1,过度识别的模型(一切都可以估计)。
只有当 DF> 1 时,才应解释模型,因为这是解决项目和潜在变量的协方差方程的唯一方法,允许拟合指数的输出。
拟合指数
拟合指数代表你所估计的模型的似是而非程度。拟合良好的模型会减少适马矩阵(人口协方差矩阵,即您放入模型的模式)和 S 矩阵(样本协方差矩阵,即您的经验矩阵)之间的差异。
有几个适合指数,每一个都有其分界点(布朗,2015;Mair,2018)。我制作了另一个表格,显示了 fit 指数的描述及其建议。
不同的拟合指数及其推荐临界值。作者制作的图像。
拟合指数中的高级主题
一个模型可以有很好的拟合指数,但不能推广到总体。换句话说,我们必须小心适应指数!更复杂的模型通常具有更好的拟合指数。我们可以调整我们的模型来解释来自线性方程、二次方程甚至六次方程的数据。有时候,6 次方程完美地解释了数据!然而,考虑到方程的复杂性,这种模型不太通用。因此,我们在模型复杂性和拟合指数之间有一个成本效益关系,我们必须小心不要过度拟合(或夸大拟合)。
Bonifay 和蔡(2017)的一篇论文验证了以下每个模型的总体拟合程度。也就是说,模型是否总是呈现良好的拟合指数。为此,测试了一个半无限制模型(只有 2 个负载受到限制;黑色的模型);双因素模型(绿色模型);分级模型(蓝色和黄色);和一维模型(红色)。为此,对 1000 个模拟数据集的拟合指数进行了分析。
在 Bonifay 和 Cai (2017)中测试的模型。图像由 Bonifay 和蔡制作(2017)。
下图总结了他们的发现。我们看到,在样本空间所有可能的拟合指数中,半无限制模型和双因素模型几乎总是表现出良好的拟合指数。这意味着在这些情况下,我们不能以与其他模型相同的方式解释拟合指数。例如,如果您要比较双因素模型和一维模型,您很可能会在双因素模型中找到更好的拟合指数,但这不一定是解释数据的最佳模型。当然,我们必须比较嵌套模型的拟合指数,但是这个例子只是一个说明。
完整的数据空间。图像由 Bonifay 和蔡制作(2017)。
考虑到这一点,有一个闪亮的应用程序可以为你的数据模拟最合适的分界点(McNeish 和 Wolf,2020)。我不会详细解释它是如何工作的,因为网站本身有一个解释。这样,我们就有机会检查一维模型和多维模型的最合适的拟合指数,并测试它们的等价性。该站点如下所示。
闪亮的应用程序网站的图像。
非常感谢您阅读本文到目前为止!我希望你喜欢并学到了很多!如果你喜欢,不要忘记与同事和朋友分享你的知识!很快,我们将制作一个关于如何在数据集中做 CFA 的教程。跟着我!
这篇文章最初是在巴西葡萄牙语的 PsicoData 上发表的,我也是作者。
接触
LinkedInResearchGate谷歌学术 如需论文合作或统计咨询,可通过邮件联系(rafavsbastos@gmail.com)
参考
K.验证性因素分析。在 K. A. Bollen(编辑。),含潜变量的结构方程, 1989,Willey。
W.Bonifay 和 L. Cai,论项目反应理论模型的复杂性,2017,多元行为研究, 52 (4),465–484。
D.Borsboom 和 A. O. Cramer,网络分析:精神病理学结构的整合方法,2013 年,临床心理学年度回顾, 9 ,91–121。
T.A. Brown,应用研究验证性因素分析第二版, 2015,吉尔福德出版社。
页(page 的缩写)Mair,现代心理测量学带 R, 2018,施普林格。
D.麦克内什和 M. G .沃尔夫。验证性因子分析模型的动态拟合指数截止值,2020 年 7 月 7 日https://doi.org/10.31234/osf.io/v8yru
共形预测导论
原文:https://towardsdatascience.com/conformal-prediction-4775e78b47b6?source=collection_archive---------8-----------------------
量化人工智能不确定性时,你应该始终考虑的一种方法
在决策中,人工智能(AI)系统不仅需要做出预测,还需要量化其预测的确定性(不确定性)。例如,考虑一个股票自动交易系统,其中人工智能系统预测股票价格。由于股票市场的高度随机性,人工智能系统的点位预测可能与真实值有很大差异。但是,另一方面,如果人工智能系统可以估计保证以高概率覆盖真实价值的范围,交易系统可以计算最好和最差的回报,并做出更明智的决定。
共形预测是一种量化人工智能系统不确定性的技术。特别地,给定输入,保形预测估计回归问题中的预测区间和分类问题中的一组类。预测区间和集合都保证以高概率覆盖真实值。
在关于保形预测的教程中,Glenn Shafer 和 Vladimir Vovk 给出了如下定义:
"保形预测利用过去的经验来确定新预测的精确置信水平."
在本文中,我们利用同独立分布(i.i.d)数据集上的保形预测,即,
其中 X 是输入要素,Y 是标注,n 是数据点的数量。我们还假设已经训练了一个机器学习模型 f: X->Y。该模型可以是经典的机器学习模型,如线性回归、支持向量机(SVM)或深度学习技术,如全连接或卷积网络。目标是估计模型输出的预测集。为了说明这个想法,我们将描述保形预测的步骤、保证和例子。
作者图片
一、步骤
a .确定分数函数以量化不一致性
确定一个合适的得分函数 s(X,Y) ∈ R,以测量模型输出ŷ's 和标签 y 之间的差异。这个得分函数非常关键,因为它实际上决定了我们可以得到什么样的预测集。例如,在回归问题中,我们可以将|ŷ-y|作为得分函数。这样,得到的预测集的值在预测ŷ周围的 L1 范数球内;在分类问题中,我们可以把 1-ŷ_i 作为得分函数,其中ŷ_i 是真正经典的预测逻辑。通过这种方式,我们将获得一个预测逻辑大于某个阈值的类的预测集。
b .计算分数的(1- ɑ)分位数
计算分数{s_1,…,s_n}的分位数,其中
在全共形预测方法中,我们需要训练 m 个模型来计算分数并构建预测集,其中 m 是 Y { n+1 }可能取值的数量。这无疑在计算上是昂贵的。为了降低计算复杂度,可以使用归纳(分裂)保形预测。简而言之,该方法将整个训练集分成适当的训练集和校准集。然后,只在适当的训练集上训练模型;并且分数仅在校准集上计算。这样,我们只需要对模型进行一次训练。
c .使用模型预测和(1- ɑ)分位数构建预测集
使用分位数形成新示例的预测集,
对于(1-分位数),我们可以通过包含值 y 来构建输入 X_{n+1}的预测集,这些值的得分小于或等于。
二世。担保
保形预测可以提供数学上的严格保证。设 Y_{n+1}为真值。y 可以是分类问题中的类别标签,也可以是回归问题中的真实值。设τ(X_{n+1})为预测集(或区间)。我们定义τ(X_{n+1})覆盖 Y_{n+1}如果 Y_{n+1}在τ(X_{n+1})中,即,
然后,给定一组相同独立分布(i.i.d)的样本{(X_1,Y_1),(X_2,Y_2),,…,(X_n,Y_n)},共形预测集满足以下覆盖保证,即,
基于可交换性(i.i.d)假设的覆盖保证的证明可以在的附录《保形预测和无分布不确定性量化的简明介绍》中找到。注意,在这个证明中,( 1- ɑ)水平变为(n+1)(1- ɑ)/n,以考虑有限样本的情况。
三。示例
在这一节中,我们的目标是给出一些关于共形预测集的直觉。
a .分类预测集
我们在图 1 中显示了三个分类预测集。在这项任务中,训练一个神经网络来对输入图像进行分类。保形预测用于构建类别集(在花括号中),这些类别集保证以高概率包括输入图像的真实标签。
图 1 分类预测集(来自 Sangdon Park 等。:通过校准预测的深度神经网络的 PAC 置信集
b .回归预测区间
在图 2 中,我们展示了一个回归预测区间。该系统的目标是在给定输入 x 的情况下预测ŷ。保形预测构建回归预测集(蓝线之间的间隔),保证以高概率覆盖真实值 y。
图 2 回归预测集(来自 Anastasios N. Angelopoulos 和 Stephen Bates: 保形预测和无分布不确定性量化的温和介绍)
四世。结论
本文简要介绍了保形预测,包括它的步骤、保证和例子。我们可以将保形预测应用于分类和回归问题。在这两种情况下,保形预测旨在量化机器学习模型的不确定性。保形预测易于实现,并且可以提供严格的保证。我们相信保形预测是走向安全人工智能的一个很好的垫脚石,其中不确定性量化是必须的!
熊猫的多指标困惑?需要了解的 9 项基本操作
原文:https://towardsdatascience.com/confused-by-multi-index-in-pandas-9-essential-operations-to-know-e6aec29ee6d8?source=collection_archive---------11-----------------------
了解要领,不再有困惑
Erik Mclean 在 Unsplash 上拍摄的照片
介绍
在许多用例中,我们处理的是单级索引。在类似电子表格的表格中,最简单的情况是行号作为索引,列号作为列。你可能有一种误解,认为我永远不会处理多级索引。让我们考虑泰坦尼克号数据集。出于本教程的考虑,我们将只包括两个数字列:age
和fare
以及三个分类列:sex
、class
和embark_town
。
泰坦尼克号数据集
我们数据处理中的一个常见操作是查看相关组的平均数据,如下所示。为了简化显示,我将age
和fare
的浮点数转换为整数。
分组平均数据
如您所见,这个数据集的索引看起来不像典型的单个级别。的确,这个DataFrame
使用了分级索引,也就是俗称的多级索引。
你对多级索引了解多少?或者说,你有没有被多重索引迷惑过?让我们在本文中了解多级索引的基本方面。
1.什么是 MultiIndex?
我们提到过,单级索引使用一系列标签来唯一地标识每一行或每一列。与单级索引不同,多级索引使用一系列元组,每个元组唯一标识一行或一列。为了简化术语,我们只关注行的索引,但是同样的规则也适用于列。
多级索引
如上所示,我们可以访问一个DataFrame
对象的 index 属性。您可能会注意到,我们将索引作为一个MultiIndex
对象来获取,这是 pandas DataFrame
或Series
的多级或分层索引对象。这个对象有三个关键属性:**names**
、**levels**
和**codes**
。我们来复习一下。
>>> df_mean.index.names
FrozenList(['embark_town', 'class', 'sex'])
>>> df_mean.index.levels
FrozenList([['Cherbourg', 'Queenstown', 'Southampton'], ['First', 'Second', 'Third'], ['female', 'male']])
>>> df_mean.index.codes
FrozenList([[0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2], [0, 0, 1, 1, 2, 2, 0, 0, 1, 1, 2, 2, 0, 0, 1, 1, 2, 2], [0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1]])
- 名称:我们的指数对每一个指数级别都有三个名称:
embark_town
、class
和sex
。 - 级别:每个级别的标签。
embark_town
有三个标签,class
有三个标签,sex
有两个标签。 - 代码:表示每一级指标的整数。例如,
FrozenList
中的第一个列表指示所有行的'embark_town
级别(0 - >'瑟堡',1 - >'昆斯敦,2 - >'南安普顿)。
2.将多索引转换为常规索引
在示例DataFrame
(即df_mean
)中,作为使用groupby
功能的结果,自动创建多索引。如果我们从一个没有多索引的数据帧开始,但是一些列可以创建为多索引,那会怎么样呢?考虑下面的DataFrame
。
>>> df = df_mean.reset_index()
>>> df.head()
embark_town class sex age fare
0 Cherbourg First female 36 115
1 Cherbourg First male 40 93
2 Cherbourg Second female 19 25
3 Cherbourg Second male 25 25
4 Cherbourg Third female 14 14
我们简单地重置了索引,创建了一个使用单级索引的DataFrame
,这种DataFrame
您可能更熟悉,对吧。需要注意的一点是,reset_index
方法带有一个参数drop
,该参数决定索引是被删除还是作为列保留。在我们的例子中,我们对drop
使用默认的False
,它会将多级索引转换为三列,这是我们想要的操作。
3.重新创建多重索引
为了为这个DataFrame
创建多级索引,我们可以使用set_index
方法将适用的列指定为索引,如下所示。
>>> df_mi = df.set_index(['embark_town', 'class', 'sex'])
>>> df_mi.head()
age fare
embark_town class sex
Cherbourg First female 36 115
male 40 93
Second female 19 25
male 25 25
Third female 14 14
如您所见,df_mi
与df_mean
DataFrame
具有相同的多级索引。
除了用现有的列设置索引之外,我们还可以手动创建MultiIndex
对象,如果愿意的话,将它分配给一个DataFrame
。如下所示,我们能够重新创建一个与我们在df_mean
中使用的对象相匹配的MultiIndex
对象。from_product
方法使用提供的列表顺序创建所有可能组合的产品。
手动创建多索引
除了 from_product 方法之外,还有几种方法经常用来创建MultiIndex
对象,比如[from_tuples](https://pandas.pydata.org/docs/reference/api/pandas.MultiIndex.from_tuples.html#pandas.MultiIndex.from_tuples)
、[from_arrays](https://pandas.pydata.org/docs/reference/api/pandas.MultiIndex.from_arrays.html#pandas.MultiIndex.from_arrays)
和[from_frame](https://pandas.pydata.org/docs/reference/api/pandas.MultiIndex.from_frame.html#pandas.MultiIndex.from_frame)
。用法应该很简单,感兴趣的读者可以参考各自的参考资料,了解如何使用它们(点击这些方法上的链接)。
4。选择特定级别
选择数据最直接的方法是使用带有loc
属性的基于元组的索引。如前所述,多级索引本质上是一个元组列表。因此,我们可以为想要检索的行指定所需的元组。下面是一些例子。
>>> df_mean.loc[('Queenstown',)]
age fare
class sex
First female 33 90
male 44 90
Second female 30 12
male 57 12
Third female 22 10
male 28 11
>>> df_mean.loc[('Southampton', 'Second')]
age fare
sex
female 29 21
male 30 19
- 您可以跳过元组中的前 n 个级别,这将检索更低级别的所有元素。例如,
(‘Queenstown’,)
将选择该级别的所有行,而(‘Southampton’, ‘Second’)
将为embark_town
选择级别为‘Southampton’
的行,为class
选择级别为‘Second’
的行。 - 检索到的数据没有指定的级别,因为所有数据都满足指定的级别。
- 示例中没有显示的是,您可以省略 tuple 外延,这可以作为这些操作的快捷方式。例如,代替
df_mean.loc[(‘Queenstown’,)]
和df_mean.loc[(‘Southampton’, ‘Second’)]
,你可以分别做df_mean.loc[‘Queenstown’]
和df_mean.loc[‘Southampton’, ‘Second’]
。但是,通常不建议这样做,因为这会导致混乱。因此,我通常会列出所有适用的信息,这样就不会有歧义。 - 另一件要注意的事情是,我省略了列的
:
选择器,因为我确实想选择年龄和费用列。如果您只选择列的子集,请指定。
5.使用 xs 选择横截面
除了使用loc
方法,您还可以使用DataFrame
的xs
方法,该方法检索横截面数据行。要检索特定级别,只需指定索引。下面是一些例子。
>>> df_mean.xs('Queenstown')
age fare
class sex
First female 33 90
male 44 90
Second female 30 12
male 57 12
Third female 22 10
male 28 11
>>> df_mean.xs(('Southampton', 'First', 'female'))
age 32
fare 99
Name: (Southampton, First, female), dtype: int64
您可以为xs
设置的另一个有用的参数是level
,它指的是在多索引中使用的级别。例如,要检索DataFrame
中的所有第一类,我们可以执行以下操作,选择横截面数据。
>>> df_mean.xs('First', level='class')
age fare
embark_town sex
Cherbourg female 36 115
male 40 93
Queenstown female 33 90
male 44 90
Southampton female 32 99
male 41 52
6.同时选择多个级别
当您想要选择具有不同级别的行时,可以在 list 对象中指定所需数据的索引。例如,假设我们要在第三名皇后镇(女性)和第一名南安普敦(男性)之间选择数据。下面是如何通过指定范围。请注意,该范围包括边界,就像您对单级索引使用loc
一样。
>>> df_mean.loc[('Queenstown', 'Third', 'female'):('Southampton', 'First', 'male')]
age fare
embark_town class sex
Queenstown Third female 22 10
male 28 11
Southampton First female 32 99
male 41 52
如果希望选择不连续的行,可以传递元组列表,这些元组是行的索引。考虑下面的例子,它只选择了两行数据。
>>> df_mean.loc[[('Queenstown', 'Third', 'female'), ('Southampton', 'First', 'male')]]
age fare
embark_town class sex
Queenstown Third female 22 10
Southampton First male 41 52
与上面的例子密切相关的是,我们也可以通过传递一组列表来选择数据,但是它们做事情的方式不同。如下所示,列表元组将产生多级索引,每个列表引用每个级别的多个标签。
>>> df_mean.loc[(['Queenstown', 'Southampton'], ['First', 'Second'], ['female', 'male'])]
age fare
embark_town class sex
Queenstown First female 33 90
male 44 90
Second female 30 12
male 57 12
Southampton First female 32 99
male 41 52
Second female 29 21
male 30 19
7.使用切片的高级选择
当我们使用列表元组时,多级索引是从这些列表中创建的。但是,当某个级别有多个标签时,您可能希望使用 slice 对象来表示一系列标签,而不是逐一列出它们。考虑下面的例子。
>>> # Instead of df_mean.loc[(['Cherbourg', 'Queenstown', 'Southampton'], 'Second', ['female', 'male'])]
>>> df_mean.loc[(slice('Cherbourg', 'Southampton'), 'Second', slice(None))]
age fare
embark_town class sex
Cherbourg Second female 19 25
male 25 25
Queenstown Second female 30 12
male 57 12
Southampton Second female 29 21
male 30 19
slice(start, end)
定义范围内的所有指数。- 因为我们只有三个标签用于
embark_town
级别,而不是使用slice(‘Cherbourg’, ‘Southampton’)
,我们可以使用slice(None)
,这被自动解释为引用所有标签。 - 除了使用
slice
函数,pandas 还提供了一种更好的方法来引用多索引——IndexSlice
,这有点像 NumPy 中使用的引用。下面是一个例子。在本例中,:
表示该级别的所有标签。
>>> df_mean.loc[pd.IndexSlice[:, 'First', :]]
age fare
embark_town class sex
Cherbourg First female 36 115
male 40 93
Queenstown First female 33 90
male 44 90
Southampton First female 32 99
male 41 52
8.重组级别
到目前为止,数据帧已经有了原始顺序的多级索引。然而,我们可能希望索引以不同的顺序排列。为此,我们可以使用reorder_levels
方法。例如,期望的顺序是class-sex-embark_town
,而不是embark_town-class-sex
。这种操作如下所示。
>>> df_mean.reorder_levels(['class', 'sex', 'embark_town']).head()
age fare
class sex embark_town
First female Cherbourg 36 115
male Cherbourg 40 93
Second female Cherbourg 19 25
male Cherbourg 25 25
Third female Cherbourg 14 14
除了指定级别的名称,还可以通过指定级别的数值来支持。因此,上述操作相当于df_mean.reorder_levels([1, 2, 0])
。
如果你想切换两个级别的顺序,另一种方法是使用swaplevel
方法。顾名思义,该方法直接在两个级别之间翻转顺序。
>>> df_mean.swaplevel(0, 1).head()
age fare
class embark_town sex
First Cherbourg female 36 115
male 40 93
Second Cherbourg female 19 25
male 25 25
Third Cherbourg female 14 14
9.排序多索引
多级索引重组后,DataFrame
看起来不再有组织,因为顺序还是用原来的那个,是根据embark_town-class-sex
的索引排序的。为了根据所需的级别聚合数据,我们可以对索引进行排序,以便更好地组织数据。
>>> df_mean.swaplevel(0, 1).sort_index().head()
age fare
class embark_town sex
First Cherbourg female 36 115
male 40 93
Queenstown female 33 90
male 44 90
Southampton female 32 99
在示例中,我们简单地使用了sort_index
方法,默认情况下,该方法使用第一级对数据进行排序。
但是,如果您喜欢使用不同的级别对数据进行排序,我们可以指定级别的数值或名称,如下所示。
>>> df_mean.swaplevel(0, 1).sort_index(level='sex').head()
age fare
class embark_town sex
First Cherbourg female 36 115
Queenstown female 33 90
Southampton female 32 99
Second Cherbourg female 19 25
Queenstown female 30 12
结论
在本文中,我们回顾了您可能需要用来处理多级索引的基本操作。我知道对于许多初学者来说这是一个令人困惑的话题,但是如果你掌握了要点,当多级索引相关时,你应该能够处理大多数日常工作。
感谢阅读这篇文章。通过注册我的简讯保持联系。还不是中等会员?使用我的会员链接,通过支持我的写作。
锥形与平面毛刺:初始数据
原文:https://towardsdatascience.com/conical-vs-flat-burrs-initial-data-57762063f915?source=collection_archive---------28-----------------------
咖啡数据科学
泰坦磨床项目综述
在咖啡社区,关于咖啡研磨机的讨论已经持续了很多年,特别是平磨锥与圆锥磨锥的对比。还没有一个决定性的答案,但是很多个月前( 2007 ),在家庭咖啡师论坛上,有一个关于多台研磨机的评论。
所有图片由作者提供
然而,该评论被分散在他们论坛的多个帖子上,最终结果并不明显。我对关于磨床相互比较的数据特别感兴趣。甚至他们对 grinders 的比较分析也是以文本形式(没有图表)在单条线程的多个页面上进行的。
我一直在为研磨机做一些咖啡颗粒分析,有人建议看看这项研究。所以我看了这个研究,我认为它在当时是一个伟大的研究,但是有一些小事情我会做得不同:
- 分析了每台研磨机的多种研磨设置(我见过一些,但不在本文中)。
- 测量更多变量,如输出重量(即 TDS)
- 采集更多样本
- 将所有数据绘制成图表
- 在数据收集的同一天收集所有数据,因为烘烤在数据收集期间老化了几天。
撇开这些批评不谈,这些数据非常有趣。我想把其中的一些绘制成图表,以便更仔细地观察。也许会出现一个更清晰的画面。
原始数据
我将把重点放在使用不同研磨机比较浓缩咖啡的数据上。他们每天使用相同的烘焙方法,将研磨机与他们的质量标准进行比较,如下图所示的 Mazzer Robur 。这台研磨机很贵,应该放在咖啡店里。
有两个剂量设置,13.5g 和 16.5g,并且在每个剂量设置下为每个研磨机拍摄两个镜头。更多详情,请参见数据。
作者们还做了一个盲品测试,并相互比较了几组照片。
分析
让我们首先来看提取率,它是被提取的可溶物的量。他们有多页文字形式的数据,我在这里编译了一下。
他们在计算味道指标的最终分数时只有一个错误,所以这很好!
让我们通过将每台研磨机与基线进行比较来绘制一些数据。
数据显示,所有这些研磨机都无法达到与 Robur 相同的 EY。在 EY 也有一些很大的波动,这很可能是因为拍摄量而不是重量是停止的标准。由于无法获得注射重量信息,所以我无法使用总溶解可溶物(TDS)作为另一个比较指标。
然后我拿出了两剂:
对于 13.5 克的剂量,Robur 肯定更好。对于 16.5 克的剂量,就不太清楚了。肯定有一个较低的平均值,但它没有 13.5 克剂量的变化大。
我还看了研磨机和它们的磨锥装置:
我对锥形然后是平的毛刺感到惊讶,因为我本以为这些是最好的,但也许在颗粒分布和提取上有一种有趣的相互作用,这还不清楚。
另一个不清楚的变量是研磨机是如何调整的,因为研磨设置的变化很可能会产生更大的影响。另一个被控制的输出变量是时间,我也不认为时间是一个很大的变量,或者至少是总拍摄时间。
尝
对于他们的口味测试,所有的测试都是相互关联的,我认为他们没有尽可能客观地在所有的研磨机上给每一个镜头打分。
我把他们赢-平-输的数字放在一起,我加入了一个决定性胜利的指标,这意味着任何平局都被认为是有问题的磨床赢了,而不是罗布。
罗布人赢了,但实际上,大多数研磨者的口味没有太大差异。
圆锥形与扁平形
我拿走了所有磨床的数据,忽略了照片是在不同的日子拍摄的。然后,我绘制了 13.5 克和 16.5 克拍摄的平均 EY,以查看不同类型的研磨机(即,圆锥形、扁平形和圆锥形然后扁平形)。
从该图来看,似乎有证据表明平毛刺具有更高的提取率。
因此,让我们将每种毛刺类型的最佳提取方法配对,不包括 Robur 刀片:
我们可以在 13.5 克剂量和 16.5 克剂量之间进行划分,但我们得到的是相同的模式:
这提供了一些强有力的证据,表明基于提取率,平毛刺比圆锥毛刺好,但成对的拍摄经过一周,这可能会引入一些误差。
相反,让我们根据时间上最接近的镜头来配对镜头。这些收集之间最多有 2 天的时间。结论还是和之前一样。
所有这些数据总体上意味着什么?从这些数据中可以得出两个结论,但要说这两个结论中的任何一个是确定的,还需要更多的数据和更多的控制。
- 罗布在性能上是无可匹敌的,但它几乎可以与之匹敌。
- 平毛刺比锥形毛刺提取率高。
如果你愿意,可以在 Twitter 和 YouTube 上关注我,我会在那里发布不同机器上的浓缩咖啡视频和浓缩咖啡相关的东西。你也可以在 LinkedIn 上找到我。也可以关注我中。
我的进一步阅读:
浓缩咖啡系列文章
工作和学校故事集
个人故事和关注点
乐高故事启动页面
摄影启动页面
使用图像处理测量咖啡研磨颗粒分布
改善浓缩咖啡
断奏生活方式概述
测量咖啡磨粒分布
咖啡萃取
咖啡烘焙
咖啡豆
浓缩咖啡用纸质过滤器
浓缩咖啡篮及相关主题
意式咖啡观点
透明 Portafilter 实验
杠杆机维护
咖啡评论和想法
咖啡实验
使用 Python 连接到 Azure SQL Server
原文:https://towardsdatascience.com/connect-to-azure-sql-server-using-python-76eba1fb458b?source=collection_archive---------9-----------------------
本文提供了在 Linux 操作系统上使用 Python 连接到 Azure SQL Server 的分步教程。
马库斯·温克勒在 Unsplash 上拍摄的照片
本文提供了在 Linux 操作系统上使用 Python 连接到 Azure SQL Server 的分步教程。
创建 Azure SQL 数据库/服务器后,您可以在概述页面上找到服务器名称。
Azure SQL Server 使用 ODBC(开放式数据库连接)作为驱动程序。
数据库驱动程序是实现数据库连接协议(ODBC 或 JDBC)的计算机程序。
让我用通俗易懂的语言解释一下。您还记得我们购买硬件或软件时,会附带一张驱动程序磁盘,您必须在使用应用程序之前安装该驱动程序吗?嗯,你可以把数据库想象成应用程序,数据库驱动程序本质上是使我们能够访问数据库的驱动程序,或者 DBMS(数据库管理系统)。不同的数据库系统(Postgresql、Mysql、SQL Server、Oracle 等)有不同的驱动程序,大多数不是 ODBC 就是 JDBC。
Pyodbc
是一个开源的 python 包,使访问 ODBC 数据库变得容易。有些人使用pymssql
,但pyodbc
是最受欢迎的一个。
让我们把手弄脏吧!首先,导入所需的包。我们使用sqlalchemy
,这是一个流行的 python SQL 工具包,在这里创建连接,使用urllib
创建连接字符串。
import os
import pyodbc
import sqlalchemy assa
from sqlalchemy import create_engineimport urllib (Python 2.7)
from urllib.parse import quote_plus (Python 3)
注意,我们将用来生成连接字符串的 quote_plus 在 Python 2.7 和 Python 3 中是不同的。建立连接的第一步是声明环境变量。我们使用os.getenv
来指定变量和凭证,以便它们处于安全的状态。
server = os.getenv('SERVER_NAME')
database = os.getenv('DB_NAME')
username = os.getenv('USERNAME')
password = os.getenv('PASSWORD')
port = os.getenv('PORT')
Azure SQL Server 的默认端口是 1433。我们还需要一个变量,司机。为了找到正确的驱动程序,在您的终端中运行以下命令行(确保您安装了**pyodbc**
):
$ odbcinst -j
unixODBC 2.3.4
DRIVERS............: /etc/odbcinst.ini
SYSTEM DATA SOURCES: /etc/odbc.ini
FILE DATA SOURCES..: /etc/ODBCDataSources
USER DATA SOURCES..: /home/jamesho/.odbc.ini
SQLULEN Size.......: 8
SQLLEN Size........: 8$ cat /etc/odbcinst.ini
[ODBC Driver 13 for SQL Server]
Description=Microsoft ODBC Driver 13 for SQL Server
Driver=/opt/microsoft/msodbcsql/lib64/libmsodbcsql-13.1.so.9.0
UsageCount=1
驱动程序的信息存储在odbcinst.ini
文件中。将驱动程序设置为您的驱动程序的名称。
driver = '{ODBC Driver 13 for SQL Server}'
接下来,我们将设置连接字符串。定义连接字符串有两种方法,一种是使用urllib
包下的 quote_plus 解析字符串,另一种是使用 sqlalchemy 的 URL 格式。
# Using urllib
odbc_str =
'DRIVER='+driver+';SERVER='+server+';PORT='+port+';DATABASE='+database+';UID='+username+';PWD='+passwordconnect_str = 'mssql+pyodbc:///?odbc_connect='+quote_plus(odbc_str)#Using sa URL format
sa_url = f"mssql+pyodbc://{username}:{password}@{server}:{port}/{database}?driver={driver}"
不同数据库的连接字符串的完整列表可以在这里找到。
最后,创建一个引擎,并将字符串传递给引擎。使用引擎的 execute 函数运行您的查询,该查询也应该作为字符串传递。
engine = create_engine(connect_str / sa_url)print(engine.execute(‘’’
YOUR SQL QUERY
‘’’).fetchall())
完整脚本:
import os
import pyodbc
import sqlalchemy assa
from sqlalchemy import create_engine
import urllib (Python 2.7)
from urllib.parse import quote_plus (Python 3)server = os.getenv('SERVER_NAME')
database = os.getenv('DB_NAME')
username = os.getenv('USERNAME')
password = os.getenv('PASSWORD')
port = os.getenv('PORT',default=1433)driver = '{ODBC Driver 13 for SQL Server}'#connect using parsed URL
odbc_str = 'DRIVER='+driver+';SERVER='+server+';PORT='+port+';DATABASE='+database+';UID='+username+';PWD='+ password
connect_str = 'mssql+pyodbc:///?odbc_connect=' + quote_plus(odbc_str)#connect with sa url format
sa_url = f"mssql+pyodbc://{username}:{password}@{server}:{port}/{database}?driver={driver}"engine = create_engine(connect_str/sa_url)print(engine.execute('''
YOUR SQL QUERY
''').fetchall())
转到您的终端,像这样导出环境变量,并运行这个 python 脚本。
$export SERVER_NAME =
$export DB_NAME =
$export USERNAME =
$export PASSWORD =
$export PORT =$python {your script name}.py
您已经成功连接到您的 Azure SQL 数据库,并且可以使用 sqlalchemy 与其进行交互。
连接生物学和人工智能:生长神经细胞自动机
原文:https://towardsdatascience.com/connecting-biology-and-ai-growing-neural-cellular-automata-fd53f2834ee2?source=collection_archive---------24-----------------------
卡罗琳娜·格拉博斯卡在的照片
1966 年,被认为是 20 世纪顶级数学家之一的约翰·冯·诺依曼引入了术语细胞自动机,并将其定义为以离散步骤进化的动态系统。四年后,约翰·康威(John Conway)创造了众所周知的生命游戏(Game of Life),其主要特点是进化是由其初始状态决定的,不需要进一步的输入。
维基百科,康威的人生游戏
此后,基于这些细胞自动机(CA)的研究不计其数。像扬森斯(2009 年)或者梅勒妮·米切尔(1998 年)这样的评论描述了这个领域中一些最相关的作品。
然而,一篇引起机器学习社区注意的文章是由 Mordvintsev 等人(2020) 发表的,他描述并实现了一个开发细胞自动机更新规则的神经网络。此外,当我阅读这篇文章时,我的一个相关贡献是作者将这项工作与形态发生联系起来,形态发生是一个生物学术语,指的是单细胞如何自我组装成高度复杂的有机体的过程。
我在这篇文章中的目标是向您介绍几个概念,以便这篇文章之后变得易于阅读。其结构如下:
- CA 简介
- 与生物学的联系
- 生长神经细胞自动机
- 未来的工作
1.CA 简介
如前所述,细胞自动机(CA)被约翰·冯·诺依曼定义为一个以离散步骤进化的动态系统。换句话说,元胞自动机由一个网格单元组成,该网格单元根据一组预定义的规则在每个时间步进行更新。单元的新状态将取决于它的当前状态和它的紧邻单元的状态。
这里有一个基本的例子,以便你简单地理解它的方法。
- 1D CA 有两个可能的状态和一个 3 单元的邻域
- 选择的规则是 规则 110 元胞自动机 (通常简称为规则 110 ),这是一个初等元胞自动机,在稳定和混沌的边界上具有有趣的行为。此 CA 的规则显示如下。
- 在第一个时间步长之后,输出如下所示。
- 在第二个时间步骤之后,这里是输出。
- 经过 n 个时间步后,我们得到下图。
下面是它如何更新的动画:
维基百科,动画为规则 110。
更改算法会显著改变输出。例如,使用规则 18:
有趣吧?在我看来,非常令人惊讶的是,我们可以用如此简单的规则创建这些数字。
如果你感兴趣,这里有一个规则的编号系统。这在以下链接的章节编号系统中有很好的解释。
2.与生物学的联系
与 CAs 类似,大多数多细胞生物从单细胞开始其生命,并生长直至成为高度复杂的解剖结构。这个过程被称为形态发生,它包括细胞如何与它们的邻居沟通,以决定器官的形状和位置。或者,更令人印象深刻的是,何时停止。
有趣的是,一些贝壳的图案如芋螺和 Cymbiola 是由自然细胞自动机生成的。对于这些贝壳来说,色素细胞位于贝壳边缘的一个狭窄区域。每个细胞根据其相邻色素细胞的激活和抑制活性分泌色素,遵循数学规则的自然版本。细胞带在缓慢生长时在外壳上留下彩色图案。
尽管对于从单细胞和规则中出现复杂生物体的相互作用仍有许多问题,但似乎很清楚的是,进化已经将这些信息编码在它们的基因组编码细胞硬件中。
3.生长神经细胞自动机
由于理解细胞形态发生过程的重要性,我们在计算机科学界的目标是制定新的模型来帮助阐明这些过程。
如上所述, Mordvintsev 等人(2020) 做出了相关贡献,因为他们实现了一个自动机,你可以给它一个图像,并可以创建一个算法,不仅可以增长细胞,直到获得图像,而且还可以在被破坏时再生。
如果你想看他们的结果,我鼓励你去这个网页,玩动画。
https://distill.pub/2020/growing-ca/
在这篇文章中,我不打算解释这个模型的架构,因为其他优秀的文章已经描述过了。特别是,除了原文,我强烈推荐阅读以下文章,并尝试他的代码。
https://medium.com/the-scinder/playing-pokemon-grow-with-differentiable-cellular-automata-a233eb345439
我做了一些修改就实现了它,下面是我的输出。
- 培训的第 100 个时代
- 训练纪元 500 年
- 训练纪元 1000 年
4.未来的工作
一旦你到了这一步,我想你会对这个话题感兴趣。因此,我首先会建议阅读原文,然后观看以下视频(点击视频下方的链接)。它展示了一些现在正在进行的关于这个话题的研究。这个视频属于 Cross Labs ,这是一个跨学科的研究机构,致力于通过计算研究来理解智能和生命的数学基础。具体来说,如果你有 10 分钟的时间,从 12 点 20 分到 22 点 20 分。
https://www.youtube.com/watch?v=XVmzGW293bI&t = 797s
如果你喜欢这篇文章,请考虑 订阅 。你将获得我所有的内容+所有其他来自牛逼创作者的文章!
将 Google Colab 连接到 Amazon EC2 实例
原文:https://towardsdatascience.com/connecting-google-colab-to-an-amazon-ec2-instance-b61be9f9cf30?source=collection_archive---------15-----------------------
提升您的 Colab 笔记本电脑的 GPU 性能
照片由西格蒙德在 Unsplash 上拍摄
在深入学习教程之前。让我们来谈谈 Jupyter 笔记本。
朱庇特
Jupyter 是一个免费的、开源的、可共享的、交互式的 web 应用程序,它允许用户组合代码、计算输出、可视化、文本和媒体。
Jupyter 笔记本已经成为数据科学家的首选计算工具。名字是由 Jupyter 目前支持的 40+编程语言中的三种语言 Ju lia、 py thon、 R 组成的。
笔记本的问题
笔记本并不都很棒。与使用笔记本相关的一些问题包括—
笔记本在运行长时间异步任务时会遇到问题。像深度学习中典型的那样训练一个模型几个小时或几天可能会变得乏味,特别是当显示超时时。对此的解决方法是定期检查模型权重并将日志文件写入磁盘。
笔记本电脑出现故障时返回的错误(应该注意,这更多是用户问题)
它鼓励糟糕的软件工程实践。例如,缺乏单元测试,将代码编写成可重用的块。
然而,许多人会认为这些都不应该被认为是问题,因为笔记本电脑从来就不是为解决这些问题而设计的。它非常适合快速实验和原型制作。很有可能将代码移动到脚本中,并且仍然从笔记本中调用它们。
Jupyter 笔记本是一种探索工具,而不是生产工具
科拉布
google Colaboratory 是一个基于 Jupyter 的免费笔记本环境,运行在 Google 的云服务器上,允许用户利用 Google 提供的硬件(CPU、GPU 和 TPU)。其中后两个对于数据科学家和机器学习工程师来说相当有用。使用 Colab 的另一个优点是它允许访问 google drive,可以通过文件浏览器安装和访问它。Colab 还预装了一套像 TensorFlow 和 Keras 这样的深度学习库。
谷歌 Colab 提供了 12GB 的 NVIDIA Tesla K80 GPU,NVIDIA 计算能力为 3.7,可连续使用长达 12 小时。虽然这对于实验和原型制作来说非常好,但是在处理大型数据集和/或大型网络时,很快就会遇到限制。
在我们进入教程之前,重要的是要注意,这不仅适用于亚马逊的 EC2 实例,还可以用于谷歌云的计算引擎、微软 Azure 的虚拟机,甚至是本地设置。
将外部运行时连接到 Colab 只是允许用户在使用 GPU 加速而不是 Colab 默认提供的加速时保留 Colab 接口。
使用 AWS,许多人更喜欢使用 SageMaker,因为它负责在后台创建 EC2 实例和设置 Jupyter 笔记本连接的细节,这使得 Sagemaker 比 EC2 更贵。因此,创建一个 EC2 实例并将其连接到一个 Colab 笔记本上,比使用 SageMaker 更便宜,同时还能保留(许多人)首选的 Colab 接口。
比较成本,俄亥俄州地区 EC2 上的一个 p3.2xlarge 实例每小时的成本为 3.06 美元,而同一地区 SageMaker 上的相同实例每小时的成本为 3.825 美元。
让我们开始吧。
亚马逊 EC2
登录 AWS 管理控制台。
点击左上角的服务并选择 EC2。
EC2 仪表板
在左窗格中选择实例,然后启动实例。
EC2 左侧窗格
选择图像类型。这决定了预装的操作系统和软件版本。这里我们选择了一个 Ubuntu 18.04 安装和 TensorFlow 2.4.1 以及 CUDA 安装。
AMI 图像
接下来,我们选择实例类型。这将决定我们得到的硬件类型。出于本教程的考虑,我将选择一个 p 3.2x 大型实例。这包括一个 Nvidia V100 GPU、8 个 vCPUs 和 61GB RAM。
如果这是您第一次启动 GPU 实例,请注意默认情况下 GPU 实例不可用。查看包含的链接了解如何使用 AWS 增加 GPU 实例限制。此外,GPU 实例不是免费的,请参见此链接了解点播价格。请注意,不同地区的价格不同。
如果您希望设置存储和网络选项等其他详细信息,可以选择“配置实例详细信息”。要保留默认设置,请选择“查看并启动”。
实例类型
选择现有的密钥对或创建新的密钥对。这将作为登录服务器的身份验证。如果一个新的被创建,一个
查看详细信息,然后单击启动
密钥对
通过单击左侧窗格中的实例,返回到实例仪表板。这将列出所有实例,包括刚刚创建的实例。等待创建的实例如下所示,实例状态显示为“正在运行”,状态检查为“2/2 检查通过”。这意味着实例现在正在运行。
单击实例 ID。您应该会看到如下所示的屏幕。然后点击连接。
通过 SSH 连接
单击 ssh 客户端的https://console.aws.amazon.com/ec2/v2/home?region=us-east-1#选项卡,查看该实例的 SSH 登录详细信息。
SSH 详细信息
然而,对于本教程,我们将使用 putty SSH 客户端登录到实例。Putty 可以从这里下载。我们使用 Putty 的主要原因是为了设置 SSH 隧道。这是让 Colab 连接到 EC2 运行时所需要的。
PuttyGen
在我们安装油灰之前。如果我们回想一下,从 AWS 下载的密钥文件是. pem 文件格式。我们需要将它转换成 putty 可以识别的格式。putty 的安装中包括另一个名为 PuttyGen 的程序。此工具可以将. pem 文件转换为. ppk 文件。打开 PuttyGen,选择文件→加载私钥
PuttyGen
选择。要加载的 pem 文件。选择文件→保存私钥以存储加载的内容。pem 文件在。ppk 格式。
PuttyGen 另存为 ppk
既然密钥文件的格式正确,我们就可以在 putty 上设置 SSH 连接了。
油灰
在前面的步骤中,在 SSH Client 选项卡中,我们查看了 EC2 实例的 SSH 登录信息。我们现在需要它。(需要注意的一点是,每次重启实例时,SSH 登录信息都会改变,请务必再次复制该信息)。
确保通过在“保存会话”文本框中指定名称并单击“保存”将详细信息保存到配置文件中。在下面的例子中,我选择“aws”作为要另存为的概要文件名。
油灰应如下图所示设置—
油灰型材
保存后,单击配置文件名,然后单击 Load。
SSH 隧道
在左侧导航树中,选择连接→ SSH →隧道。
在源端口中,填写 8888(我们将在后面指定,这是 Jupyter 将通过的端口)。在目的端口中,填写 127.0.0.1:8888,然后单击添加。最终结果应该如下所示—
SSH 隧道
也可以将它保存到个人资料中,这样就不需要每次都输入了。转到会话,选择配置文件,然后单击保存。
现在我们已经准备好用 putty 登录 EC2 实例了。在左侧导航树中,转到连接→ SSH → Auth,单击浏览并选择。ppk 文件,然后单击打开。
油灰认证
成功登录后,putty 应该看起来像这样。我们现在有一个命令行来控制 EC2 实例。只要 SSH 终端窗口打开,来自源端口的所有流量都会被转发到目的端口。
EC2 端子
如果 Jupyter 还没有安装,应该通过命令行安装。跟着这个链接。
接下来需要安装由 Google Colabotory 创作的 jupyter_http_over_w 扩展,以允许连接到 Colab。在命令行中运行下面的命令—
*****pip install jupyter_http_over_ws******jupyter serverextension enable — py jupyter_http_over_ws*****
使用下面的命令在 EC2 实例上启动 Jupyter Notebook 服务—
****jupyter notebook \
— NotebookApp.allow_origin=’**[**https://colab.research.google.com**](https://colab.research.google.com/)**' \
— port=8888 \
— NotebookApp.port_retries=0
— NotebookApp.disable_check_xsrf=true”****
我们将端口 8888 指定为 SSH 隧道配置期间指定的相同端口。
如果一切顺利,终端屏幕上应该会显示一个 IP 地址。应该复制该地址,因为下一步将需要它。
笔记本终端
打开 Google Colab,在右上角选择 Connect to local runtime。
Colab 本地运行时
从终端复制 IP 地址并点击连接。
Colab 后端 URL
最终结果应该是这样的。请注意“已连接”旁边的“本地”。这意味着 Colab 连接到一个运行时,而不是默认的 Colab。我们还运行一些测试来确认 GPU 被检测到。
Colab 笔记本
Colab 列出设备
我们在下面注意到,检测到的 GPU 是 Tesla V100,这是典型的 P3.2xlarge 实例类型。
Colab T100
快速笔记。连接到本地运行时意味着 Colab 将不再能够访问 Google Drive。为了解决这个问题,一个可能的工具是 P yDrive 。
完成后,不要忘记关闭 EC2 实例。
参考文献
Stern J (2012)如何用 PuTTY 建立 SSH 隧道https://www . sky verge . com/blog/How-to-Set-Up-an-SSH-Tunnel-With-PuTTY/
Perkel J (2018)为什么 Jupyter 是数据科学家的首选计算笔记本https://www.nature.com/articles/d41586-018-07196-1
穆勒 A (2018)木星笔记本吸的 5 个理由https://towards data science . com/5-reasons-why-jupyter-notebooks-suck-4d c201 e 27086
连接朴素贝叶斯和逻辑回归:二元分类
原文:https://towardsdatascience.com/connecting-naive-bayes-and-logistic-regression-binary-classification-ce69e527157f?source=collection_archive---------4-----------------------
概率、似然和张量流概率库
给企鹅分类【照片由马丁·韦特斯坦在 Unsplash 上拍摄】
朴素贝叶斯和逻辑回归都是非常常用的分类器,在这篇文章中,我们将试图找到并理解这些分类器之间的联系。我们还将使用帕尔默企鹅数据集来看一个例子,该数据集在 CC-0 许可下可用。你希望从这篇文章中学到什么?
- 概率和可能性基础。
- 朴素贝叶斯分类器是如何工作的?
- 区分和生成分类器。
- 朴素贝叶斯和逻辑回归之间的联系。
这里使用的所有公式都来自我的笔记本,链接和其他有用的参考资料都在参考资料部分。我们开始吧!
概率和可能性:
每个概率分布都有一个连续分布的概率密度函数(PDF ),如高斯分布(或离散分布的概率质量函数或 PMF,如二项式分布),表示样本(某点)取特定值的概率。该函数通常由 P ( y | θ 表示,其中 y 是样本值, θ 是描述 PDF/PMF 的参数。当一个以上的样本彼此独立抽取时,我们可以写成—
情商。1:独立绘制样本的 PDF。
当我们知道分布(和相应的参数 θ )并想要推导出ys 时,我们在计算中考虑 PDF。这里我们认为 θ 对于不同的样本是固定的(已知的),并且我们想要推导出不同的 y 。似然函数是相同的,但是有所改变。这里 y 是已知的,而 θ 是我们想要确定的变量。至此,我们可以简单介绍一下最大似然估计(MLE)的思想。
极大似然估计: MLE 与数据的建模密切相关;如果我们观察数据点 y 1, y 2,…, yn 并假设它们来自一个由 θ 参数化的分布,那么似然性由 L ( y 1, y 2,…、yn|θ);对于 MLE,我们的任务是估计最大似然的θ。对于独立观察,我们可以将最佳θ的表达式写成如下所示—
情商。2:最大化可能性
优化的惯例是最小化一个函数;因此,最大化似然归结为最小化负对数似然。这些是我们稍后将会用到的概念,现在让我们转到朴素贝叶斯分类器。
朴素贝叶斯分类器:
朴素贝叶斯分类器是生成分类器的一个例子,而逻辑回归是鉴别分类器的一个例子。但是我们所说的生成性和辨别力是什么意思呢?
判别分类器:一般来说,分类问题可以简单地认为是预测给定输入向量的类别标签p(C _ k|x)。在判别模型中,我们假设p(C _ k|x)的某种函数形式,并直接从训练数据中估计参数。
生成分类器:在生成模型中,我们估计p(x|C _ k)的参数,即每个类的输入的概率分布以及类先验 p ( C_k )。两者都用在贝叶斯定理中计算p(C _ k|x)。
我们已经将类别标签定义为 C_k ,让我们在此基础上定义贝叶斯定理——
情商。3:贝叶斯定理,x 是训练数据 C_k 代表类别标签。
p ( x )可以认为是一个归一化常数;p(x)=∑p(x|C _ k)p(C _ k),∑超过类标签 k 。
让我们考虑一个一般化的场景,其中我们的数据有 d 个特征和 K 个类,那么上面的等式可以写成—
情商。4:同 Eq。3 但是对于具有 d 特征的数据。
给定类 Y ,通过“天真地”假设每个数据特征 X_i 是相互条件独立的,可以极大地简化类条件概率项。现在我们重写等式(2.2),如下所示
情商。5:同 eq。但是对于给定的类 y,数据特征有条件地相互独立。
这是朴素贝叶斯分类器的基本方程。一旦估计了类别先验分布和类别条件密度,朴素贝叶斯分类器模型就可以为新的数据输入 X 做出类别预测 Y ^ (y hat)
情商。6:对新数据点的类别预测。
由于我们这里的分母 p ( X_ 1, X_ 2,…, X_d )对于给定的输入是常数。我们可以用最大后验概率(MAP)估计来估计p(Y=c _ k)和p(X _ I|Y=c _ k)。前者则是训练集中类别的相对频率。这些在我们后面做编码部分的时候会更加清晰。
不同的朴素贝叶斯分类器的区别主要在于它们对p(X _ I|Y=c _ k)的分布所做的假设。这对于 MAP 估计非常重要,例如,如果我们假设类别条件是单变量高斯分布,则需要确定的参数是均值和标准差。要估计的参数数量取决于特征和类别。
连接朴素贝叶斯和逻辑回归:
代替上述具有 K 类的朴素贝叶斯分类器的一般化情况,我们简单地考虑 2 个类,即 Y 现在是布尔型(0/1,真/假)。由于逻辑回归(LogReg)是一种判别算法,它从假设P(Y|X)的函数形式开始。
情商。7:用于逻辑回归任务的 Sigmoid 函数。
正如所料,逻辑回归的条件类分布的函数形式基本上是 sigmoid 函数。在另一篇文章中,我详细讨论了如何从线性回归开始实现逻辑回归。可以使用训练数据导出参数(权重 w )。我们可以拓展情商。7,对于 Y(类标签)为布尔型—
情商。8:同 Eq。7,但明确是为二进制分类编写的。
对于给定的 X,要指定 Y=0,我们施加一个简单的条件如下—
在 Eq 上加一个条件。8,并在第二步中对两边应用自然对数。
我们将使用高斯朴素贝叶斯(GNB)分类器,恢复 P(Y|X)的形式,并将其与逻辑回归结果进行比较。
高斯朴素贝叶斯作为二元分类器;
在高斯朴素贝叶斯(GNB)分类器中,我们将假设类条件分布p(X _ I|Y=c _ k)是单变量高斯分布。让我们明确地写出假设—
- Y 有一个布尔形式(即 0/1,真/假),它由伯努利分布控制。
- 既然是 GNB,对于类条件句P(X _ I|Y=c _ k)我们假设一元高斯。
- 对于所有 i 和j≦I, X_i , X_j 都是有条件独立给定 Y 。
让我们用贝叶斯法则写出P(Y= 1 |X)
情商。9:类似于 Eq。4,但只为 Y=1 而写。
我们可以通过引入指数和自然对数来进一步简化这个方程,如下所示—
情商。10:由等式简化而来。用一种更适合与逻辑回归比较的形式来写它。
让我们假设p(y= 1 |x)=π,⟹p(y= 0 |x)= 1-π并且还使用给定类别标签的数据点的条件独立性来将上面的等式重写如下——
情商。11:来自 Eq。10 我们假设P(Y= 1 |X)=π的先验分布,并使用条件独立性。
对于类别条件P(X _ I|Y=c _ k)我们假设单变量高斯函数带参数N(μ_ { ik】, σ_i ),即标准偏差为我们将用它来简化上面等式的分母。
情商。12:简化等式中的分母。11 假设类条件句由单变量高斯函数描述。
我们可以将该表达式用于之前的等式(等式)。11)以更简洁的形式写出 Y=1 的后验分布,如下所示
情商。13:使用等式中的表达式。12 回到 Eq。11
把P(Y= 1 |X)写成这种形式,让我们有了直接和 Eq 比较的可能。8,即逻辑回归的条件类分布的函数形式,我们根据高斯均值和标准差获得参数(权重和偏差),如下所示—
情商。14:以高斯平均值和标准偏差表示的逻辑回归参数。
这里,我们从高斯朴素贝叶斯分布出发,得出了逻辑回归的生成公式,并且,对于给定的二元分类问题,我们还可以找到这两种分布的参数之间的关系。
实现高斯朴素贝叶斯;循序渐进:
理解上述步骤的最佳方式是实现它们,为此,我将使用 Palmer Penguin 数据集,它与 Iris 数据集非常相似。让我们从导入必要的库和加载数据集开始。
这是一个数据集,包括 3 种不同的企鹅‘阿德利’、‘巴布亚’和‘下颚带’,以及一些特征,如喙长、鳍长等。都是给定的。我们可以看到企鹅类基于两个参数“喙长度”和“喙深度”的分布,使用简单的一行代码如下—
penguin_nonan_df = penguin.dropna(how=’any’, axis=0, inplace=False)
sns_fgrid=sns.FacetGrid(penguin_nonan_df, hue=”species”, height=6).map(plt.scatter, “bill_length_mm”, “bill_depth_mm”).add_legend()plt.xlabel(‘Bill Length (mm)’, fontsize=12)plt.ylabel(‘Bill Depth (mm)’, fontsize=12)
图 1:基于 2 个不同参数的不同企鹅种类的分布。(来源:作者笔记本)
为了简单起见,我们将只选择这两个特性,而不是使用所有可用的特性。
penguin_nonan_selected_df = penguin_nonan_df[['species', 'bill_length_mm', 'bill_depth_mm']]X=penguin_nonan_selected_df.drop(['species'], axis=1)Y=penguin_nonan_selected_df['species']from sklearn.model_selection import train_test_splitX_train, X_test, y_train, y_test = train_test_split(X, Y, test_size=0.2, random_state=30, stratify=Y)print (X_train.shape, y_train.shape, X_test.shape)>>> (266, 2) (266,) (67, 2)X_train = X_train.to_numpy()
X_test = X_test.to_numpy()y_train = y_train.to_numpy()
y_test = y_test.to_numpy()
要从头开始构建朴素贝叶斯分类器,首先,我们需要定义类的先验分布,在这种情况下,我们将计算唯一类的数量,然后除以样本总数,以获得类的先验分布。我们可以定义如下—
让我们打印基于训练样本的先验分布—
prior = get_prior(y_train)print (prior)print (‘check prior probs: ‘, prior.probs,)>>> [0.43984962 0.20300752 0.35714286]
tfp.distributions.Categorical("Categorical", batch_shape=[], event_shape=[], dtype=int32)
>>> check prior probs: tf.Tensor([0.43984962 0.20300752 0.35714286], shape=(3,), dtype=float64)
定义先验分布后,我们将定义类别条件分布,正如我之前所述,对于高斯 NB,我们将假设单变量高斯分布,如下式所示。记住,对于我们的问题,我们有 2 个特性和 3 个类。
情商。15:高斯分布作为类条件
为了定义类别条件,我们需要知道均值和方差,对于正态分布,它们可以很容易地计算出来,查看这里的。
情商。16:等式中类别条件分布的均值和方差。15:
让我们把它们放在一起,定义类条件函数。
再次检查代码块,理解并领会它确实给了我们 Eq。15 使用等式的平均值和方差。16.我们还可以打印来检查训练数据的均值和方差—
class_conditionals, mu, sigma2 = class_conditionals_MLE(X_train, y_train)print (class_conditionals)print (‘check mu and variance: ‘, ‘\n’)print (‘mu: ‘, mu, )print (‘sigma2: ‘, sigma2, )# batch shape : 3 classes, event shape : 2 features>>> tfp.distributions.MultivariateNormalDiag("MultivariateNormalDiag", batch_shape=[3], event_shape=[2], dtype=float64)>>> check mu and variance:
>>> mu: [ListWrapper([39.017094017093996, 18.389743589743592]), ListWrapper([49.12592592592592, 18.479629629629624]), ListWrapper([48.063157894736854, 15.058947368421052])]
>>> sigma2: [[7.205861640733441, 1.5171597633136102], [10.038216735253773, 1.1042146776406032], [9.476642659279785, 0.9687357340720222]]
最后,我们在测试集上进行预测。因此,我们逐个样本地选择,并使用来自先验概率和类别条件的信息。这里我们构建一个函数来表示 Eq。5 和情商。这是我们在文章开头写的。
def predict_class(prior_dist, class_cond_dist, x):“””We will use prior distribution (P(Y|C)), class-conditional distribution(P(X|Y)),and test data-set with shape (batch_shape, 2).“”” y = np.zeros((x.shape[0]), dtype=int) for i, train_point in enumerate(x): likelihood = tf.cast(class_cond_dist.prob(train_point), dtype=tf.float32) #class_cond_dist.prob has dtype float64 prior_prob = tf.cast(prior_dist.probs, dtype=tf.float32) numerator = likelihood * prior_prob denominator = tf.reduce_sum(numerator) P = tf.math.divide(numerator, denominator) # till eq. 5 #print (‘check posterior shape: ‘, P.shape) Y = tf.argmax(P) # exact similar to np.argmax [get the class]
# back to eq. 6 y[i] = int(Y) return y
我们可以预测测试数据点的类别,并将它们与原始标签进行比较
predictions = predict_class(prior, class_conditionals, X_test)
为测试数据点绘制决策边界(使用等高线图)将产生下图
图 2:使用 GNB 分类器的测试数据集的决策区域。(来源:作者笔记本)
以上所有任务都可以用 Sklearn 完成,只需要几行代码—
from sklearn.naive_bayes import GaussianNBsklearn_GNB = GaussianNB()
sklearn_GNB.fit(X_train, y_train)predictions_sklearn = sklearn_GNB.predict(X_test)
了解这些基本算法的幕后工作总是好的,我们可以比较与我们之前获得的参数非常接近的拟合参数—
print ('variance:', sklearn_GNB.var_)print ('mean: ', sklearn_GNB.theta_)>>> variance: [[ 7.20586167 1.51715979]
[10.03821677 1.10421471]
[ 9.47664269 0.96873576]]
mean: [[39.01709402 18.38974359]
[49.12592593 18.47962963]
[48.06315789 15.05894737]]
让我们绘制决策区域,以便与我们的硬编码 GNB 分类器进行比较—
图 3:与图 2 相同,但结果来自使用 Sklearn 库。(来源:作者笔记本)
他们看起来和预期的非常相似。让我们移动到明确连接 GNB 和逻辑回归分类器的二元分类问题。
来自 GNB 的逻辑回归参数:
如前所述,为了将朴素贝叶斯和逻辑回归联系起来,我们会想到二元分类。由于企鹅数据集中有 3 个类,首先,我们将问题转化为一个 vs rest 分类器,然后确定逻辑回归参数。同样关于 GNB 作为二元分类器的推导,我们将使用相同的σ_i 用于两个不同的类(没有 k 依赖性)。这里我们会找到 6 个参数。4 为 μ_{ik} & 2 为 σ_i 。这排除了使用我们之前使用的类条件函数的可能性,因为在标准差公式中使用了 μ_{ik} ,并且均值取决于类和特征。所以我们要写一个函数,用梯度下降型优化来学习类独立标准差。这是主要的编码任务。
在所有这些之前,我们需要对标签进行二值化,为此,我们将对标签为 2 的样本使用标签 1。
class_types_dict = {'Adelie':0, 'Chinstrap':1, 'Gentoo':2}y_train_cat = np.vectorize(class_types_dict.get)(y_train)y_train_cat_binary = y_train_caty_train_cat_binary[np.where(y_train_cat_binary == 2)] = 1
# gentoo == chinstrapy_test_cat = np.vectorize(class_types_dict.get)(y_test)y_test_cat_binary = np.array(y_test_cat)y_test_cat_binary[np.where(y_test_cat_binary == 2)] = 1print (‘check shapes: ‘, y_train_cat_binary.shape, y_test_cat_binary.shape, y_train_cat_binary.dtype, ‘\n’, y_train_cat.shape)>>> check shapes: (266,) (67,) int64
>>> (266,)
我们可以绘制数据分布图,如下图所示—
图 4:对巴布亚企鹅和下颚带企鹅使用相同的分类标签,将问题转化为二元分类。(来源:作者笔记本)。
我们可以使用先验分布函数来获得这两个类别的类别标签先验
prior_binary = get_prior(y_train_cat_binary)print (prior_binary.probs, print (type(prior_binary)))>>> [0.43984962 0.56015038]
<class 'tensorflow_probability.python.distributions.categorical.Categorical'>
tf.Tensor([0.43984962 0.56015038], shape=(2,), dtype=float64) None
与之前的先验分布相比,我们会看到 Adelie penguin 类具有相同的先验(0.43),并预期增加 Gentoo 和 Chinstrap 先验分布(≈ 0.20 + 0.35)。
为了学习标准差,我们将在给定数据和标签的情况下,使用梯度下降来最小化负对数似然。
一旦训练结束,我们就可以检索参数—
print(class_conditionals_binary.loc.numpy())print (class_conditionals_binary.covariance().numpy())
使用类条件句,我们可以绘制如下等高线——
图 5:2 类[0,1]的类条件轮廓。(来源:作者笔记本)。
我们也可以画出二元 GNB 分类器的判定边界——
图 6:使用 GNB 分类器的二元分类的判定边界。
一旦我们有了均值和对角协方差矩阵,我们就可以为逻辑回归寻找参数了。权重和偏差参数是使用等式中的均值和协方差导出的。14,让我们再重写一遍—
情商。17:用均值和协方差矩阵表示的逻辑回归参数。
就这样,我们到了帖子的末尾!涵盖了许多重要的基本概念,希望这对您有所帮助。
参考资料:
[1] 企鹅数据集,CC-0 许可,可自由改编。
[2]机器学习的书;卡内基梅隆大学的汤姆·米切尔;新章节。
[3]本帖使用的完整笔记本。 GitHub 链接。
保持坚强!!
连接人工智能、物联网、云和网络开发
原文:https://towardsdatascience.com/connecting-the-dots-ai-iot-cloud-and-web-dev-848447e1ca66?source=collection_archive---------34-----------------------
使用趋势技术进行端到端解决方案开发的小旅程
最终目标和步骤:
这个项目背后的想法是确定我在家工作的性能,并了解如何使用物联网设备、AWS 云以及简单的 Web 应用程序在 edge 上使用计算机视觉来改善我的工作站设置。
此外,我想分享在开发过程中发现的挫折,以及我为解决这些挫折而采取的措施。
所以,根据需求,我的第一个想法是这样的:
我工作站上方的摄像机,为了确定脸部位置,我拍摄作者
一旦定义了初始设置,我就开始确定获取数据所需的最少工具,在本例中是相机;由于在 LPR 识别文章 中我使用了 SV3C 低成本摄像头,我决定使用相同的摄像头,因为集成已经使用 HTTP 完成。
这些是最初的图像:
右中我作者法师
空,左,我作者法师
我使用了两个脚本来获取这些图像,一个用 Python,一个用 Bash(注意:关于这个项目的所有信息都可以在下面的 Github repo 中获得)。第一个用于创建名为create-folder-structure . sh的文件夹结构,第二个用于收集名为 collect_images.py 的数据。
获取输入数据:
此时,我有了每个位置的设置和 200 张图像,我开始考虑如何使用这些图像,所以我最终使用带有 EfficientNetB0 的迁移学习作为特征提取器,只训练最后一层。这里是 Colab 链接
仅仅过了几个纪元,我就能达到 80%以上的准确率。然而,我在实时测试中发现了一些挫折,因为我的想法是基于我的头部位置进行训练。然而,网络实际上学习了我的肩膀和手臂的位置,所以我有了更多的选择,如获得更多的数据,获得不同的图像,数据增强和更复杂的网络。不过,我想保持简单,所以我做了更多的研究,找到了一种新的方法。
基于我最初的想法,我想跟踪我的脸,经过一些研究,我发现了一个名为 MoveNet 的神经网络,它由谷歌在 2021 年发布,能够检测身体中的 17 个关键点(鼻子,左眼,右眼,左耳,右耳,左肩,右肩,左肘,右肘,左手腕,右手腕,左臀部,右臀部,左膝盖,右膝盖,左脚踝,右脚踝),通过前五个关键点,我有了一些关于我的脸的信息,或者任何信息
另外,我改变了摄像机的位置。这就是做一个真正的项目而不是用数据集测试和学习的区别。对于真实的项目,您可以更改输入数据,并验证新数据是否比以前的数据提供了更多信息,我可以这样做,因为这是一个端到端的项目。
我是作者的法师
有了这个信息,现在的方法是检测这 5 个关键点,并选择 ML 分类器来确定头部的位置。
选择分类器:
作为面向 ML 初学者的趋势技术的一部分,有几个 AutoML 解决方案( FLAML 和 MLJAR ),所以我决定测试 FLAML 并获得使用哪个分类器的初始方向
只用几行代码:
from flaml import AutoML
automl = AutoML()
automl.fit(X_train, y_train, task=”classification”, time_budget=120)
我在验证集里得了 84 分
最佳 ML 解决方案,作者本人作者*
但是在测试集中有 93%。
我作者法师
这里是用于 MoveNet 未来提取和 AutoML 分类器的 Colab 。
与 AWS 物联网的集成:
一旦我设置好获取图像,使用 MoveNet 获取关键点,并使用 FLAML 对图像进行分类,我想将信息发送给 AWS。一个有趣的服务是 AWS 的物联网核心,所以这是我最后要介绍的基本架构:
建筑,我作者法师
基本架构描述:
SV3C 摄像头符合 OVNIF 标准。OVNIF 有一些使用 HTTP 协议获取图像快照的标准方法,允许您随时获取图像,而不必处理视频流。你可以在 Github 中看到这个请求。
对于终端设备和 AWS 物联网核心之间的通信,我使用了 MQTT,这是一种帮助我轻松通过远程设备进行通信和操作的通信协议,允许我在未来添加任何智能开关,以便在我离开办公室时关灯。
这部分是基于下面的 AWS 博客来使用 Python awsiotsdk
关于我正在使用的 AWS 服务,两者都是无服务器的,可以扩展到数十亿台设备,我只为我使用的服务付费(按需付费)。对于 DynamoDB,集成基于以下文档。我还将图片上传到一个 S3 桶中,并存储在一个名为 predictions 的文件夹中,这将帮助我验证模型的行为。
然后我们有 Streamlit,我现在在本地使用它只是为了得到一个概述。
在 JetsonNano 中运行它:
当我准备好模型并在我的电脑上工作后,我决定将它转移到 Jetson Nano 上时,真正的挑战就开始了。主要原因是 Jetson 耗尽了内存,AutoML 库(Flaml)有一些问题需要安装。
经过进一步的研究,我发现使用 Tflite 的 MoveNet 模型解决了内存问题,但我仍然有 Flaml 库的问题。然而,这个博客中提到了解决方案;我建议 AutoML 获得一个初始方向,并且基于从 Flaml 库获得的输出,我找到了 AutoML 建议的模型的特定库,在这种情况下, LGBM 如(最佳 ML 解决方案*)图所示。
参见realtimepredictionmovenetflaml.py
中的 Tflite 实现和本 Colab 中的初始测试
参见本 Colab 中的 LGBM 培训
我作者法师
杰特森留言,我法师作者
AWS 物联网控制台记录消息
运行项目的脚本:
- 要进行实时推断并将数据发送给 AWS:
python realtimepredictionmovenetflaml.py
- 要在本地运行 Streamlit 服务器:
streamlit run app.py
- 要从相机收集图像:
python collect_images.py
- 要训练 NN,去实验室
网页原型,作者本人图片
从原型到产品的改进和评论:
本项目有许多需要改进的地方,例如:
- 从 Streamlit 到 SPA 的变化可能类似于 React.js
- 使用更多图像进行训练,以提高准确性
- 添加数据扩充
- 添加基础设施作为配置所有 AWS 服务的代码
- 获取更多指标
- 添加可见性(日志)
为数据科学家、分析师和工程师连接到 SQL 数据库
原文:https://towardsdatascience.com/connecting-to-sql-databases-for-data-scientists-analysts-and-engineers-58dc77a9165e?source=collection_archive---------8-----------------------
了解如何利用企业中最常见的数据存储来源之一。
本杰明·雷曼在 Unsplash 上的照片
无论你是在构建分析还是在寻求训练一个机器学习模型,数据工程、分析和科学的基础都是对数据的访问。数据本身可以从许多不同的来源收集:web 抓取、API 调用、平面文件;但是跨企业的数据存储的最常见来源之一是结构化数据库,它通常被称为 SQL 数据库。
SQL 数据库是一个包罗万象的术语,指的是使用结构化查询语言(SQL 查询)进行交互的关系数据库管理系统(RDBMS)。SQL 数据库能够快速处理和存储大量数据,使其成为企业中非常常用的数据存储和管理应用程序。
虽然 SQL 语言能够对数据库执行标准分析(GROUP BY/FILTER/etc……),但在实践中,许多企业不鼓励直接在数据库本身上大量使用 SQL,因为它们要么是热数据库(根据它们所服务的软件应用程序的需要而活动),要么是报告数据库(从热数据库同步,专门用于数据提取)。此外,由于 SQL 语言的限制,许多统计和机器学习工具不可用,因此在企业环境中,在处理数据之前摄取数据是常见的做法。
数据接收是从一个存储介质(源)获取数据并将其转储到另一个更适合数据操作的存储介质(接收器)的过程。谈到大数据,企业环境中最常见的大规模数据吸收汇是数据湖(通常通过 Hadoop 生态系统)。一旦数据进入湖中,就可以由任何 Hadoop 生态系统工具(Spark、Pig 等)自由转换或操纵。)或转换成开发者喜欢的不同形式。为了将数据从 SQL 数据库接收到您选择的介质中,必须使用连接器作为开发的软件应用程序的一部分。
ODBC / JDBC 驱动程序
开放式数据库连接(ODBC)是数据库采用的 API 标准,它允许软件应用程序与数据库管理系统(DBMS)接口。在这方面,ODBC 驱动程序或 Java 数据库连接器(JDBC)驱动程序都是这些标准的实际应用,它们可以被软件应用程序用来连接到如图 1 所示的数据库。
图 1 软件应用程序通过 ODBC/JDBC 驱动程序连接到 SQL 数据库的描述(图片由作者提供)
由于每个数据库引擎(MySQL、Microsoft SQL、PostGreSQL、Oracle 等)的内部操作不同,每个数据库引擎都有自己特定的 ODBC/JDBC 驱动程序用于交互。然而,这些 ODBC/JDBC 驱动程序的功能都是相似的,因此许多编程语言都有一种标准的方式来调用用于连接这些数据库的各种 ODBC/JDBC 驱动程序。一旦软件应用程序加载了 ODBC/JDBC 驱动程序,该驱动程序就被配置为指向 SQL 数据库并与之交互,这需要设置:主机/URL、数据库名称以及可以访问数据集的凭证。
为了演示从 SQL DB 获取或加载数据的不同连接方式,本教程将介绍使用 Python (pyodbc 包)、Spark(Scala Spark 和 PySpark)和 Sqoop(Hadoop 生态系统的数据获取工具)获取数据。此外,Docker 将用于容器化环境,以更接近地模拟企业环境,并允许读者轻松复制演示。
码头工人
Docker 是一个允许您轻松构建和部署轻量级虚拟机(也称为容器)的工具,这些虚拟机可以连接起来形成一个网络。在大多数实际的企业环境中,需要来自 SQL 服务器的数据的软件应用程序不会在与 SQL 服务器相同的机器上运行,因此我们可以使用图 2 所示的 Docker 体系结构来模拟这样的企业环境。
图 2 使用 Docker 容器和网络的模拟企业环境(图片来自作者)
为了便于跟随教程,上面的 Docker 环境和所有用于连接 MySQL 数据库的脚本都可以在 GitHub [1]上找到。
使用 MySQL 设置 SQL 数据库
MySQL 是一个用于存储和管理企业架构中常见的结构化数据的通用数据库引擎,它代表了一个用于本地部署的开源(并且容易获得)SQL DB,以构建我们的沙盒企业环境。
mysql 提供了一个基本的 Docker 映像,mysql/mysql-server [2],它在一个容器中启动一个预安装的 MySQL 实例,该实例将在我们的模拟企业环境中充当 SQL Server。
此 Docker 图像接受。sql 脚本作为容器初始化时运行的命令,我们可以使用它(与。下面的 sql 脚本)来配置数据库,并为我们的连接测试创建假数据。
*-- Create database**CREATE DATABASE test_db;**USE test_db;**-- Create table**CREATE TABLE test_table(**row_id INT AUTO_INCREMENT PRIMARY KEY,**test_value VARCHAR(255) NOT NULL**);**-- Fill table with values**INSERT INTO test_table(test_value) VALUES ("A");**INSERT INTO test_table(test_value) VALUES ("b");**INSERT INTO test_table(test_value) VALUES ("C");**INSERT INTO test_table(test_value) VALUES ("4");**-- Add user with remote access priveleges**CREATE USER "remote_connect_user"@"%" IDENTIFIED BY "remote_connect_password";**GRANT ALL PRIVILEGES ON * . * TO "remote_connect_user"@"%" WITH GRANT OPTION;**FLUSH PRIVILEGES;*
上面的代码执行两个主要功能:
- MySQL 服务器创建一个数据库(名为 test_db ),在数据库中创建一个表(名为 test_table ),并用少量记录填充 test_table(见下面的表 I ),当我们尝试提取数据时,可以在接收端验证这些记录
- MySQL 服务器创建一个用户帐户(名称:remote_connect_user,密码:remote_connect_password ),该帐户具有远程访问数据库的权限
表 I: test_db.test_table 值
设置好 MySQL 数据库后,我们可以专注于如何通过各种软件应用程序提取数据,在本教程中从 Python(和 pyodbc 包)开始。
使用 Python 的 MySQL 数据库连接(通过 pyodbc)
通过使用 pip install 调用许多可用的 ODBC 包之一,可以很容易地使用 Python 连接到 SQL DB。在本教程中,我们将重点关注使用 pyodbc [3]包使用 Python 连接到 MySQL DB,该包作为 Docker 映像 laudio/pyodbc [4]提供,并包含 MySQL ODBC 8.0 驱动程序。
为了连接到容器以建立 python 连接,我们可以运行命令:
*docker exec -it sql-ingestion-tutorial-python-client-1 python*
它远程连接到容器,并在容器中启动 python 的交互式会话。
加载 python 后,我们可以使用下面的代码来加载 pyodbc 包,配置驱动程序的设置以连接到我们的 MySQL 实例,并运行测试查询来选择*并在控制台中输出结果。
*# Imports**import pyodbc**# Set configuration for DB**MYSQL_HOST="mysql-server"**MYSQL_USER="remote_connect_user"**MYSQL_PASS="remote_connect_password"**MYSQL_DB="test_db"**MYSQL_TABLE="test_table"**# Establish connection to MySQL DB**cnxn = pyodbc.connect(f"DRIVER={{MySQL ODBC 8.0 Driver}};SERVER={MYSQL_HOST};DATABASE={MYSQL_DB};UID={MYSQL_USER};PWD={MYSQL_PASS}")**cursor = cnxn.cursor()**# Run query to select * and output results**cursor.execute(f"SELECT * FROM {MYSQL_TABLE}")**row = cursor.fetchone()**while row:* *print (row)* *row = cursor.fetchone()*
在这种情况下,pyodbc.connect 函数引用 MySQL DB 的预安装 odbc 驱动程序,并且该驱动程序被配置为包括服务器 URL、数据库名称和运行查询所调用的凭证。然后,test 命令通过对 DB 中的表运行 SELECT *语句来引用这个连接,并迭代地打印输出,如下所示。
(1, 'A')
(2, 'b')
(3, 'C')
(4, '4')
使用 Apache Sqoop 的 MySQL 数据库连接
Apache Sqoop [5]是 Hadoop 生态系统中的一个工具,用于结构化数据库中的数据与 Hadoop 文件存储之间的批量传输。虽然 Apache Sqoop 已于 2021 年 6 月退役[6],但该工具通常被企业用来将数据吸收到数据湖中,实际上需要一段时间才能从企业生产系统中完全退役。
与其他容器类似,Apache Sqoop 可以使用 dvoros/sqoop 映像[7]立即获得,该映像预装了 Apache Sqoop 和所有用于支持 Sqoop 的 Hadoop 生态系统工具。
Sqoop 映像不包含 JDBC 驱动程序,Sqoop 将使用该驱动程序连接到 MySQL 数据库,因此正在启动的 Docker 容器包括将 JDBC 驱动程序装载到容器中,当该容器放置在/usr/local/sqoop/lib 文件夹中时,Sqoop 将自动识别该容器。考虑到要连接到一个 MySQL 数据库,我们可以通过下载 MySQL 网站[8]上提供的连接器的平台无关版本来获得这个连接器。
Sqoop 本身有许多参数来帮助实现常见的数据摄取功能[9],但是出于本教程的目的,演示将是使用下面给出的代码以文本形式从 MySQL 数据库到 HDFS 的基本摄取:
*# Create the data ingestion location**hdfs dfs -mkdir /user/sqoop* *# Sqoop import example**MYSQL_HOST=mysql-server**MYSQL_USER=remote_connect_user**MYSQL_PASS=remote_connect_password**MYSQL_DB=test_db**MYSQL_TABLE=test_table**sqoop import --connect jdbc:mysql://$MYSQL_HOST/$MYSQL_DB --table $MYSQL_TABLE --username $MYSQL_USER --password $MYSQL_PASS --as-textfile --target-dir /user/sqoop/text -m 1**# Test the output**hdfs dfs -ls /user/sqoop/text**# Inspect the parquet file**hdfs dfs -cat /user/sqoop/text/part-m-00000*
如代码所示,首先在 HDFS 创建一个目标文件夹来存储接收到的数据。Sqoop 摄取过程直接从命令行执行,与建立连接的其他应用程序类似,MySQL 连接器被引用并配置为指向正确的表位置和凭证。
1,A
2,b
3,C
4,4
代码的最终结果如上所示,它验证了 MySQL 数据库的快照已经被 HDFS 接收。此时,可以通过 Spark 或其他方式在 Hadoop 中原生拾取。
使用 Spark 的 MySQL 数据库连接
与上面的例子类似,我们可以利用 Spark 自带的 Docker 容器,在这种情况下,我们将使用 jupyter/pyspark-notebook 映像[10]。然而,与其他连接不同,当我们提交应用程序时,我们必须将 JDBC 驱动程序作为一个添加的 jar 文件包含在 Spark 中。下面是 Scala Spark 和 PySpark 连接 MySQL 数据库的示例代码。
使用 Scala Spark 连接 MySQL 数据库
与之前的容器一样,我们首先运行以下命令来连接 Spark 容器并调用 Scala 提示符:
*docker exec -it sql-ingestion-tutorial-pyspark-client-1 spark-shell --jars /jdbc/**
连接到 Scala 提示符后,以下命令调用 JDBC 驱动程序连接到 DB 并打印结果数据以验证连接成功。
*// Set configuration for DB**val MYSQL_HOST="mysql-server";**val MYSQL_USER="remote_connect_user";**val MYSQL_PASS="remote_connect_password";**val MYSQL_DB="test_db";**val MYSQL_TABLE="test_table";**// Establish connection for MySQL DB using credentials provided**val df = (spark.read**.format("jdbc")**.option("url", s"jdbc:mysql://$MYSQL_HOST/$MYSQL_DB")**.option("driver", "com.mysql.cj.jdbc.Driver")**.option("dbtable", MYSQL_TABLE)**.option("user", MYSQL_USER)**.option("password", MYSQL_PASS)**.load())**// Display results for validating successful connection**df.show()*
成功建立连接后,将生成以下输出。
+------+----------+
|row_id|test_value|
| 1| A|
| 2| b|
| 3| C|
| 4| 4|
+------+----------+
使用 PySpark 连接到 MySQL 数据库
为了连接到 PySpark 提示符,将调用之前使用的同一个容器,但是下面的命令将启动一个 PySpark 会话来连接到 DB。
*docker exec -it sql-ingestion-tutorial-pyspark-client-1 pyspark --jars /jdbc/**
调用 JDBC 驱动程序并提取数据的 PySpark 版本代码如下:
*# Set configuration for DB**MYSQL_HOST="mysql-server"**MYSQL_USER="remote_connect_user"**MYSQL_PASS="remote_connect_password"**MYSQL_DB="test_db"**MYSQL_TABLE="test_table"**# Establish connection for MySQL DB using credentials provided**df = spark.read.format('jdbc').options(**url = f"jdbc:mysql://{MYSQL_HOST}/{MYSQL_DB}",**driver = "com.mysql.cj.jdbc.Driver",**dbtable = MYSQL_TABLE,**user = MYSQL_USER,**password = MYSQL_PASS**).load()**# Display results for validating successful connection**df.show()*
成功建立连接后,将会看到以下输出。
+------+----------+
|row_id|test_value|
| 1| A|
| 2| b|
| 3| C|
| 4| 4|
+------+----------+
结论
没有数据,分析或数据科学就没有机会让业务受益。大多数企业系统严重依赖 SQL 数据库来存储大量数据,并不是每个团队都有专门的数据工程师或数据仓库来提供对开发数据的轻松访问。在这种情况下,值得你自己学习这些技能,让你的生活变得更轻松。本文简要介绍了如何使用 ODBC 和 JDBC 连接器在软件应用程序中建立与数据库的连接,并使用 Python (pyodbc 包)、Sqoop 和 Spark (PySpark 和 Scala Spark)进行了演示。
参考
[1] SQL 摄取教程 Github 页面,https://github.com/mkgray/sql-ingestion-tutorial
[2] MySQL 服务器 Dockerfile,【https://hub.docker.com/r/mysql/mysql-server/
[3] PyODBC 包,【https://pypi.org/project/pyodbc/
[4]pyodbc dock file,https://hub . docker . com/r/laudo/pyodbc
[5] Apache Sqoop,https://sqoop . Apache . org/
[6] Apache Sqoop Attic,https://attic . Apache . org/projects/sqoop . html
[7]Apache sqoop docerfile,https://hub . docker . com/r/dvosos/sqoop
[8] MySQL JDBC 连接器,https://dev . MySQL . com/downloads/connector/j/
[9] Apache Sqoop User Guide,https://sqoop . Apache . org/docs/1 . 4 . 6/sqoop user guide . html
[10]spark dock file,https://hub . docker . com/r/jupyter/pyspark 笔记本电脑
使用虚拟网络对等和 ARM 模板连接两个分立虚拟网络
原文:https://towardsdatascience.com/connecting-two-discrete-vnets-using-vnet-peering-and-arm-templates-c33a96812d9c?source=collection_archive---------33-----------------------
利用 VNet 对等和 Azure ARM 模板从我们的代码构建基础设施
照片由 Unsplash 上的 israel palacio 拍摄
动机:
如果操作不当,连接虚拟网络有时可能会很麻烦。一次又一次地创建它,会更容易出错。因此,我们将利用来自 Azure 的名为 Azure ARM Templates 的服务,以幂等的方式部署我们的基础设施。我们也将只为一些任务使用门户网站,但它的大部分将从模板完成。
建筑:
苏拉布什雷斯塔。使用 VNet 对等和 ARM 模板连接两个分立的 VNet 1。2021.JPEG 文件。
先决条件:
- Azure 帐户
- Azure 虚拟机
- Azure VNet
- ARM 模板
Azure 虚拟网络:
Azure 虚拟网络是 Azure 在云中的网络。这个虚拟网络可以细分成不同的子网。在本练习中,我们将创建两个虚拟网络:东和西,每个虚拟机有两个子网,其中东 VNET 仅限于私有 IP,西可以访问公共 IP,如上图所示。稍后,我们将使用 VNet 对等来连接不同地区的这两个不同的 VNet。
ARM 模板:
ARM 模板是以 JSON 形式编写基础设施以获得最大可用性的幂等方法。创建虚拟机、虚拟网络和子网是一个非常漫长的过程,我们在创建过程中可能会出现错误,因此,ARM 模板是首选。我已经创建了 ARM 模板,并且在我的 GitHub 上。但是不要担心,我会教你如何编写 ARM 模板,更重要的是生成它们,因为从头开始编写非常困难。
假设我已经创建了一些基础设施,我想为它创建一个 ARM 模板。进入资源组,选择资源,和导出模板。
苏拉布什雷斯塔。使用 VNet 对等和 ARM 模板连接两个分立的 VNet 2。2021.JPEG 文件。
然后点击下载按钮。
苏拉布什雷斯塔。使用 VNet 对等和 ARM 模板连接两个分立的 VNet 3。2021.JPEG 文件。
您将获得 template.json 和 parameter.json。template . JSON 包含您想要使用其详细信息创建的基础结构,parameter . JSON 包含您想要为资源指定的唯一名称。在这篇文章中,我将添加我自己的默认值。您可以通过 parameter.json 添加唯一的名称,并输入下面给出的命令。
在您使用 CLI 执行命令后,它可能无法运行,因为您必须对 JSON 文件进行一些整理,比如删除订阅 id 以实现动态可用性,还需要删除不必要的键值对。对于这篇文章,你不必担心,因为我提供的 JSON 已经发挥到了极致。打开代码后,这里是您需要线性输入的命令。
az group create --name oss-east-rg --location eastusaz group create --name oss-west-rg --location westusaz deployment group create --resource-group oss-east-rg --template-file template.jsonaz deployment group create --resource-group oss-west-rg --template-file template.json
虚拟网络对等:
我们将使用一个门户来对等这两个虚拟网络。进入东方虚拟网络,设置,peering和 +Add
苏拉布什雷斯塔。使用 VNet 对等和 ARM 模板连接两个分立的 VNet 4。2021.JPEG 文件。
我们应该记住,我们连接的是东到西,但也是西到东,所以有两个空白的对等链接名称。填写基本信息,点击添加。
苏拉布什雷斯塔。使用 VNet 对等和 ARM 模板连接两个分立的 VNet 5。2021.JPEG 文件。
演示:
现在,让我们连接到具有公共 IP 地址(west)的虚拟机,然后使用不同 VNet 上的私有 IP 地址连接到 east。我已经在存储库中提供了 PEM 文件。先从西 VM 说起。
sudo ssh -i vm.pem azureuser@104.40.10.98
已经建立了连接。
苏拉布什雷斯塔。使用 VNet 对等和 ARM 模板连接两个分立的 VNet 6。2021.JPEG 文件。
现在,让我们使用私有 IP 连接到东部虚拟机。记得将 PEM 文件复制到虚拟机本身。
sudo ssh -i vm.pem azureuser@10.0.0.4
再次建立了连接。
苏拉布什雷斯塔。使用 VNet 对等和 ARM 模板连接两个分立的 VNet 7。2021.JPEG 文件。
结论:
我们展示了如何利用 Azure ARM 模板轻松创建复杂的基础设施。这只是最低限度,因为我们可以向 ARM 模板添加越来越多的内容。还有其他工具,如 Terraform 和 Pulumi,我们可以利用它们以声明和命令的方式编写 IaC 代码。可能性是无限的,选择是无限的,你想做什么取决于你自己。如果你遇到任何问题或难以遵循这些步骤,请在下面评论这篇文章或在 tsulabh4@gmail.com 给我发消息。也可以在 Linkedin 和 GitHub 上和我联系。
资源:
[1] Azure 虚拟网络:https://docs . Microsoft . com/en-us/Azure/Virtual-Network/Virtual-networks-overview
[2] ARM 模板:https://docs . Microsoft . com/en-us/azure/azure-resource-manager/templates/overview
将微件连接到可视化
原文:https://towardsdatascience.com/connecting-widgets-to-visualizations-dc668bbeaeb?source=collection_archive---------43-----------------------
使用 IPyWidgets 创建小部件来控制可视化
来源:作者
数据可视化有助于分析数据中肉眼不可见的隐藏模式。它有助于理解数据行为和数据关联。有各种各样的可视化工具可用于分析数据,如条形图、散点图等。
当我们试图分析不同的数据点时,控制可视化会很有帮助。它不仅有助于控制数据,还可以用来显示一个数据点相对于其他数据点的表现。
IPyWidget 是一个开源 Python 库,用于创建有助于控制图形或数据并使其具有交互性的小部件。
在本文中,我们将探讨如何使用通过 IPyWidgets 创建的小部件来控制数据可视化。
让我们开始吧…
安装所需的库
在本文中,我们将使用 Bokeh 创建一个可视化,并使用 IPyWidgets 创建小部件。所以我们需要使用 pip 安装来安装这些库。下面给出的命令将安装这两个库。
!pip install bokeh
!pip install ipywidgets
导入所需的库
在这一步中,我们将导入创建可视化和小部件所需的所有库。
import numpy as np
import bokeh
from bokeh.models import ColumnDataSource
from bokeh.plotting import figure, show, output_notebook
from ipywidgets import interact
创建可视化
现在我们将创建想要使用小部件控制的可视化。在创建可视化之前,我们需要运行散景命令来显示笔记本中的可视化。
output_notebook(bokeh.resources.INLINE)x = np.linspace(0, 2*np.pi, 2000)
y = np.sin(x)
source = ColumnDataSource(data=dict(x=x, y=y))
p = figure(title="Bokeh example", plot_height=300, plot_width=600)
p.line('x', 'y', source=source, color="#2222aa", line_width=3)
show(p, notebook_handle=True)
可视化(来源:作者)
创建小部件
现在我们将开始创建小部件,我们将使用它来控制我们上面创建的可视化。
def update(f, w=2, A=1, phi=0):
if f == "sin": func = np.sin
elif f == "cos": func = np.cos
elif f == "tan": func = np.tan
source.data['y'] = A * func(w * x + phi)
bokeh.io.push_notebook()_ = interact(update, f=["sin", "cos", "tan"], w=(0,100), A=(1,10), phi=(0, 10, 0.1))
来源:作者
现在我们将使用这个小部件来控制我们上面创建的可视化。
来源:作者
在这里,您可以清楚地看到我们如何控制我们创建的可视化的不同方式。继续尝试不同的可视化效果,并使用小部件控制它们,让我知道你在回复部分的评论。
本文是与 Piyush Ingale 合作完成的。
在你走之前
感谢 的阅读!如果你想与我取得联系,请随时通过 hmix13@gmail.com 联系我或我的 LinkedIn 个人资料 。可以查看我的Github*简介针对不同的数据科学项目和包教程。还有,随意探索* 我的简介 ,阅读我写过的与数据科学相关的不同文章。
ConnectorX:加载 Python 数据框最快的库
原文:https://towardsdatascience.com/connectorx-the-fastest-way-to-load-data-from-databases-a65d4d4062d5?source=collection_archive---------4-----------------------
理解大数据
用一行代码将 Pandas read_sql 加速 10 倍
由 NASA 在 Unsplash 上拍摄的照片
ConnectorX 旨在通过向开发人员提供高效、轻量级且易于使用的工具来加快从数据库加载数据的过程。在本文中,我们将通过回答以下问题为您简要介绍 ConnectorX:
- 什么是 ConnectorX?
- 如何使用 ConnectorX?
- 为什么 ConnectorX 是更好的选择?
- 接下来会发生什么?
什么是 ConnectorX?
ConnectorX 是一个开源库,可以加速将数据从数据库加载到像 pandas 这样的数据结构中。数据框用于进一步处理和分析。
ConnectorX 的高级工作流程示例
ConnectorX 由两个主要概念组成:源(例如 PostgreSQL )和目的地(例如熊猫。数据帧。ConnectorX 会将用户给出的 SQL 查询转发给源,然后高效地将查询结果从源传输到目的地。上图显示了当前支持的源和目的地的示例。
为了同时提供高效的性能和强大的功能,ConnectorX 中繁重的提升工作量被写成了 Rust。它还有一个带有简单 API 的 Python 绑定,可以轻松地与 Python 中的其他数据科学库进行互操作。
接下来,让我们看看如何通过一行代码以不同的方式使用 ConnectorX。
如何使用 ConnectorX?
步骤 1:安装连接器 x:
pip install connectorx
第二步:用 read_sql 从数据库加载数据。使用连接字符串定义源,默认情况下目的地是 pandas。数据帧可以通过设置 return_type 来改变:
import connectorx as cx
# source: PostgreSQL, destination: pandas.DataFrame
df = cx.read_sql("postgres://postgres:postgres@localhost:5432/tpch", "SELECT * FROM lineitem")
查询结果将返回一只熊猫。数据帧如下所示:
为了进一步提高速度,ConnectorX 支持通过对查询进行分区并并行执行分区查询来提高 CPU 和带宽资源的利用率。用户可以指定分区列,也可以手动定义分区查询:
# specify the partition column and number of partitions
df = cx.read_sql("postgres://postgres:postgres@localhost:5432/tpch", "SELECT * FROM lineitem", partition_on="l_orderkey", partition_num=4)
# manually partition the query
# the partition bellow is equivalent with the one above
df = cx.read_sql("postgres://postgres:postgres@localhost:5432/tpch", [
"SELECT * FROM lineitem WHERE l_orderkey > 0 AND l_orderkey <= 15000000",
"SELECT * FROM lineitem WHERE l_orderkey > 15000000 AND l_orderkey <= 30000000",
"SELECT * FROM lineitem WHERE l_orderkey > 30000000 AND l_orderkey <= 45000000",
"SELECT * FROM lineitem WHERE l_orderkey > 45000000 AND l_orderkey <= 60000000"
])
ConnectorX 将并行运行所有分区查询,并将所有查询结果连接成一个单独的 pandas。数据帧。至于分区,目前,对于 SPJA 查询,ConnectorX 支持对整数列进行自动分区。下面是一个更复杂的查询示例:
query = f”””
SELECT l_orderkey,
SUM(l_extendedprice * ( 1 — l_discount )) AS revenue,
o_orderdate,
o_shippriority
FROM customer,
orders,
lineitem
WHERE c_mktsegment = ‘BUILDING’
AND c_custkey = o_custkey
AND l_orderkey = o_orderkey
AND o_orderdate < DATE ‘1995–03–15’
AND l_shipdate > DATE ‘1995–03–15’
GROUP BY l_orderkey,
o_orderdate,
o_shippriority
“””df = read_sql(“postgresql://postgres:postgres@localhost:5432/tpch”, query, partition_on=”l_orderkey”, partition_num=4)
请查看我们的 Github repo 获取更多用法和示例!
为什么 ConnectorX 是更好的选择?
其他常用的 Python 库如 Pandas 已经提供了类似的 read_sql 函数,那么为什么还要使用 ConnectorX 呢?为了回答这个问题,让我们来看一个简单的基准测试,我们将 ConnectorX 与其他三个现有的解决方案( Pandas 、 Modin 和 Dask )进行了比较,这三个解决方案也能够将数据从数据库加载到数据框。
我们使用来自 TPC-H 的 LINEITEM 表,并将比例因子设置为 10。该表包含 60M 记录 x 16 列,如果转储到 CSV 文件中,其大小为 8 GB,在 PostgreSQL 中为 11 GB。我们测量每个解决方案从数据库加载整个表并写入到 pandas 所需的时间。不同并行度(1 到 10 核)和带宽条件下的 DataFrame 。我们还测量了该过程中每种方法的峰值内存使用量。我们在这里展示的测试结果是在一个 AWS r5.4xlarge 实例上进行的,我们在该实例上运行 ConnectorX,并从运行在 AWS RDS 上的 db.m6g.4xlarge 实例上的 PostgreSQL 加载数据。(有关其他数据库的更多基准测试结果,请点击查看。)结果显示,在所有场景中,ConnectorX 都是速度最快、内存效率最高的解决方案!
- 更快的数据加载
下图显示了使用 4 个 CPU 内核测试不同方法速度的结果。我们可以看到,ConnectorX 是所有解决方案中速度最快的,在 PostgreSQL 上比 Modin 、 Pandas 、 Dask 分别加快了 3x 、 10x、和 20x 的数据加载速度!
read_sql (4 核)的时间比较
我们还改变了用于 read_sql 的内核(分区)数量,从 1 到 10 不等,并在不同的网络条件和机器下进行了测试。( Dask 由于内存不足(OOM)无法使用完一个内核。Pandas 不支持并行,所以我们只使用一个内核。)我们发现 ConnectorX 在所有设置中始终优于其他方法。
2。更小的内存占用
接下来,我们来看看每种方法的内存使用情况。这里我们绘制了 4 核设置的比较结果。我们可以看到 ConnectorX 使用的内存比其他方法少 3 倍。在不同的并行度下,结果是相同的。
read_sql 的内存比较(4 核)
【ConnectorX 是如何做到这一点的?
ConnectorX 实现这一性能的三个主要原因是:
- 用原生语言编写:与其他库不同,ConnectorX 是用 Rust 编写的,避免了用 Python 实现数据密集型应用的额外成本。
- 精确复制一次:当从数据库下载数据时,现有的解决方案或多或少会进行多次数据复制,而 ConnectorX 的实现遵循“零复制”原则。我们设法精确地复制数据一次,直接从源到目的地,即使是在并行的情况下。
- CPU 缓存高效:我们应用了多项优化,使 ConnectorX CPU 缓存友好。与“零拷贝”实现不同,ConnectorX 中的数据处理是以流的方式进行的,以减少缓存缺失。另一个例子是,当我们在 Python 中构造字符串时,我们将一批字符串写入一个预先分配的缓冲区,而不是为每个字符串分配单独的位置。
接下来会发生什么?
到目前为止,ConnectorX 支持广泛使用的源,包括 PostgreSQL、MySQL、SQLite 以及其他采用相同有线协议的数据库(例如,通过 PostgreSQL 的 Redshift、通过 MySQL 的 Clickhouse)。我们现在正致力于增加更多的流行数据库和数据仓库。我们还计划在未来支持以不同的文件格式(如 CSV、JSON、Parquet)从数据存储(如亚马逊 S3 )传输数据。
至于目的地,ConnectorX 支持 Python 和 Rust 中所有流行的数据帧,包括熊猫、阿帕奇箭头、摩丁、 Dask 和 Polars 。已完成和正在进行的源和目的地的完整列表可在这里找到。让我们知道你是否有其他的建议!
除了支持更多的源和目的地,该团队还在开发新功能,以帮助最大限度地减少数据加载的时间成本,例如维护一个客户端数据缓存。我们还对优化查询分区感兴趣,例如支持从数据库收集元数据的自动分区。您可以在 Github 上关注我们,了解我们的最新实施情况和下一步计划!
征服数据科学面试中的 Python 编码回合
原文:https://towardsdatascience.com/conquer-the-python-coding-round-in-data-science-interviews-5e27c4513be3?source=collection_archive---------2-----------------------
我 2021 年在印度班加罗尔作为数据科学家面试的经历。
编码环节已经成为数据科学面试不可或缺的一部分。尽管它可能无处不在,但对许多人来说,它也是一个可怕的回合。在这篇文章中,我的目标是通过分享我最近遇到的不同类型的编码采访和问题,用信息战胜恐惧。
让我们看看执行和提问的不同格式,并了解问题所测试的是什么概念。
格式 1 —现场编码
照片由在 Unsplash 上绘制
你被要求打开一个编辑器(Jupyter 笔记本),与面试官分享你的屏幕。当一个候选人在整个过程中与面试官保持一致时,这是值得赞赏的。通常,面试官会将应聘者推向预期的方向。大多数面试官都很体贴,允许稍微搜索一下语法等。
一些例子:
Q1。探索新冠肺炎数据集。绘制各州的月环比 Covid 正数。显示六月份的前 3 个州。
https://www.kaggle.com/sudalairajkumar/covid19-in-india?select=covid_19_india.csv
概念测试
- 探索性数据分析
2。数据清理
3。处理缺失值
4。数据帧操作
5。执行聚合操作
6。日期时间操作
7。数据可视化
Q2。创建一个包含传感器值的虚拟数据集
传感器数据,虚拟数据集(图片由作者提供)
找出这个时间范围内压力与温度的最高比值。
概念测试—
- 探索性数据分析
2。数据清理
3。数据帧操作
4。执行聚合操作
5。日期时间操作
6。数据可视化
Q3。编写一个代码,从用户那里获取一个数字,并输出小于用户输入的所有斐波纳契数。
概念测试—
1。基本 Python 编程
2。基本逻辑思维
3。了解数据结构和算法(使用动态编程可以更快地解决这个问题)
照片由 LinkedIn 销售解决方案在 Unsplash 上拍摄
格式 2 —基于平台的测试
在 Hackerrank/Hackerearth(或其他)平台上作为定时测试执行。
公司使用这种测试来检查数据科学的各个领域。因此,常见的是混合了概率和统计、机器学习、深度学习的客观类型问题(比如 10 个问题,每个 2 分)和一些关于 SQL、机器学习和数据结构和算法的编码问题(很少但很明显)(2-5 个问题,其权重基于复杂性和概念)
几个例子:
Q1。给定一个分布的 CDF,求其均值。
概念测试— 基础概率论
Q2。人 A 决定进行一次跳伞旅行。根据他的研究,小故障导致死亡的概率是 0.001。如果 A 进行 500 次高空跳伞,死亡概率是多少?
解决方案选项:
答:50
b) .29
c) .39
d) .01
概念测试— 分布知识
Q3。给定 1 年期间欧洲 4 家商店出售的软饮料的数据集。执行数据争论和可视化。你能预测未来的需求并确定不同的特征如何影响它吗?如果合适,请使用评论和可视化方式向技术和非技术受众有效地解释您的发现。
概念测试 — 数据科学项目直到建模的全部活动。
Q4。关于在样本数据集上编写 SQL 查询的问题。
概念测试— 联接、分区和排序、排序依据、分组依据
Q5。给定两个数字 a,b;a<b .的打印输出
f(a,b)= g(a)+g(a+1)+g(a+2)+…+g(b-2)+g(b-1)+g(b)
其中 g(x)定义为所有小于 x 的斐波那契数。
概念测试—
1。Python 编程
2。逻辑思维
3。数据结构和算法
Q6。给定一个数 X,求 X 的两个因子(a,b)的最小和
概念测试—
1。Python 编程
2。逻辑思维
Q7。使用 get 请求读取这个 链接 中的数据。它包含了莎士比亚的全部作品。删除 链接 中出现的数字和停止字。现在数数课文中出现的独特单词的数量。
概念测试—
- 使用 Get 和 Pull 请求读取数据
2.基本的自然语言处理,如停用词移除
3.将字符串拆分成标记
照片由 BRUNO EMMANUELLE 在 Unsplash 拍摄
格式 3 —现场案例研究/带回家作业
这可以是现场(现在是在线)短期(1-3 小时)案例研究,也可以是为期 3-7 天的带回家作业,其中给候选人一个样本数据集(在大小和复杂性上与真实数据集非常相似),并要求其在 90 分钟内解决一个业务目标。指出他们需要向面试小组介绍他们的解决方案和思考过程。
在带回家的版本中,大多数公司理解人们也有他们的日常工作,并且足够体贴地在合理的范围内延长时间表。
亲提示:
这种形式是展示你知识广度和深度的好地方。超越所陈述的问题会得到高分。比如找与手头问题相似的文献(论文)。展示你的解决方案是如何受到论文启发的。如果小组特别要求基于深度学习的解决方案,那么就这样做,但也要创建一个机器学习解决方案,并比较和对比他们的结果。也许一个模型在数据的某些部分优于另一个。调查这些细分市场。尝试建立两者的整体模型。
这向面试小组展示了你超越了最低要求,并展现了你所有的技能。
举例: 零售交易案例分析
这家公司给了我一个礼品店两年的交易数据集。
商业问题:预测一个客户下个月是否要买一个产品。
他们坚持要我用深度学习技术解决这个问题。
这是一个完美的地方来展示我在模型制作方面的技能,我充分利用了上面提到的技巧来将面试转化为工作机会。
结论
我希望通过这篇文章,我减轻了对编码的恐惧,并在一定程度上平衡了比赛场地。它展示了公司测试应聘者编码和解决问题能力的各种方法。实践上面提到的概念肯定会有很大的帮助。
如有问题,您可以在 LinkedIn 上留言或给我发信息。
你可能也喜欢:
</4-types-of-data-science-interview-questions-part1-d17db4253c69> </4-types-of-data-science-interview-questions-part2-106f5bf7218d>
意识和人工智能
原文:https://towardsdatascience.com/consciousness-and-ai-8be0f8860247?source=collection_archive---------35-----------------------
播客
格奥尔格·诺瑟夫解释了一个好的意识理论如何能带来更好的人工智能
苹果 | 谷歌 | SPOTIFY | 其他
在过去的十年里,人工智能的进步主要是由深度学习推动的——这是一个直接从人脑的结构和功能中汲取灵感的研究领域。通过在大脑和计算机之间进行类比,我们已经能够建立计算机视觉、自然语言和其他预测系统,这在十年前是不可思议的。
但是类比有两种方式。既然我们已经有了自动驾驶汽车和人工智能系统,它们在日益复杂的任务中经常胜过人类,一些人想知道逆转通常的方法——并从人工智能中汲取灵感以告知神经科学的方法——是否可能是一种有前途的策略。这种更加数学化的神经科学方法正是今天的嘉宾格奥尔格·诺尔托夫正在研究的。Georg 是渥太华大学的神经科学、精神病学和哲学教授,作为他为神经科学发展更多数学基础的工作的一部分,他探索了一种独特而有趣的意识理论,他认为这种理论可能会成为开发更先进的人工智能系统的有用框架,从而造福人类。
以下是我最喜欢的对话内容:
- 格奥尔格的意识理论强调感知的时间维度的重要性。他认为,如果某种东西的内部状态能够在很大范围的不同时间尺度上跟踪其环境的状态,那么它就是有意识的。作为一个例子,他引用了人类大脑及其欣赏音乐的能力,这要求我们对非常短时间范围内的事件(如单个音符或一小组音符)以及更长时间范围内的事件(如叠句和合唱)做出反应。这些不同的时间尺度被一起处理,导致对“旋律”的感知。他讨论了一些有趣的实验数据,这些数据支持大脑从根本上感知和处理不同时间尺度的观点,我们讨论了致幻剂和心理障碍对这种感知的影响。
- 由于格奥尔格的理论从一个实体能够做出反应的时间和空间范围来确定它的意识水平,这表明人工智能没有理由不能变得有意识,而且它还表明人类可以变得比现在更有意识,只要增加我们能够感知的时间窗口。例如,人类无法从视觉上察觉时间尺度小于 30Hz(30 分之一秒)的事件。我们也往往不会注意到当时足够缓慢的视觉变化——例如,我们不认为植物是移动的生物,但它们在一天中确实移动了相当一部分,因为它们试图将自己朝向太阳。通过让自己对更多的时间尺度敏感,我们将能够欣赏更多的世界,甚至可能意识到更多的东西比我们想象的更有意识,包括像植物(移动太慢)和变形虫(移动太慢,而且太小)这样的东西。Georg 认为人工智能的一个重要用例将是人类直接感知在新的时间尺度上的延伸。
- Georg 在一定程度上深入考虑了大脑/计算机类比,我们讨论了 OpenAI 的 GPT-3 等高级语言模型使用的处理策略与 Georg 主张的基于时间的处理相比如何。特别是,我们回顾了婴儿学习新单词和抽象概念的学习过程,以及今天深度学习系统使用的学习过程。Georg 认为这种比较提供了洞察力,可以导致更具表演性的人工智能系统。
你可以点击这里查看乔治的网站,或者点击这里在 Twitter 上关注我
播客中引用的链接:
- 乔治出版了关于神经科学的书籍。
章节:
- 0:00 介绍
- 1:33 乔治的背景
- 8:09 时标问题
- 14:32 音乐示例
- 18:00 与神经科学的联系
- 26:44 衬底独立性和 AI
- 人类文明和意识
- 33:19 共同货币
- 40:46 透视隐形实体
- 43:42 气候变化示例
- 51:51 生活经历
- 55:12 大脑
- 57:57 总结
请查看以下文字记录:
杰瑞米·哈里斯(00:00):
大家好,我是杰瑞米。欢迎回到“走向数据科学”播客,顺便说一下,该播客现在配备了一个全新的专业麦克风。对此我真的很兴奋。显然是如此兴奋,以至于我甚至没有等到摊位的到来。它仍由亚马逊运送,但我们会为您设置一整套专业设置,并很快准备就绪。我甚至不能在这一集使用它,但我想在这个介绍中使用它。
Jeremie Harris (00:19):
无论如何,尽管我对麦克风感到兴奋,但我对今天的嘉宾感到超级兴奋。我们采访了乔治·诺瑟夫,他是渥太华大学的神经科学、精神病学和哲学教授。他有一个令人着迷的意识理论,实际上是非常独特的,它与我们在前几集关于人工智能甚至人工智能安全的很多对话有着惊人的联系。我们会讨论意识理论。
Jeremie Harris (00:44):
如果我们要在未来设计更好的人工智能系统,我们还将研究 Georg 的想法,为什么意识对于理解意识非常重要,以及意识和大脑之间可能有什么联系。在这一集里,一大堆真正有趣的哲学、神经科学和人工智能的话题交织在一起。我希望你喜欢它。录制音乐非常有趣。我二话没说,就要让开了,让你们尽情聊天。乔治,非常感谢你能来参加这个节目。
格奥尔格·诺瑟夫(01:10):
不客气。
Jeremie Harris (01:11):
我听过很多你的演讲。我看过你很多关于意识主题的作品,也看过很多关于人工智能的第一次。我认为这是一个非常有趣的领域,因为现在很少有人探索这种协同作用。在我们深入讨论之前,我不想在这里超越自己。你能不能先给我们定位一下,你最初是怎么进入这个领域的,你的背景是什么?
Georg Northoff (01:33):
我最初的背景,我是一名神经科学家、精神病学家和哲学家,但我一直对大脑思维感兴趣。就大脑而言,我们并不真正知道大脑是如何工作的。我们只是不知道。我们喜欢模型和设计。我们现在有了一个特定的想法,并在整个演讲中展现出来。我现在可以用人工智能来探索我的一些想法,真正地探索它是否可行,因为你们大多数人都是工程师,这个东西必须可行。这证明了你的模型是正确的。
Georg Northoff (02:10):
另一件事是,我也是一名精神病医生,我看到这些病人,我们仍然在通过反复试验来治疗他们。我希望从大脑中学习一些东西,但超越大脑,我们可以通过使用一些人工智能设备更好地治疗这些患者。你会看到,在我的关注点,用户关注点…当然,对于临床医生,你需要一些分类,你有大规模数据集,10,000 名受试者,然后你会得到一些更好的。这不是我在《人工智能在精神病学中的案例》中预见的过去。
Jeremie Harris (02:44):
那么,可以公平地说,你正在使用人工智能作为一种更多地从基本原则出发解决大脑问题的方法,从我们可以更直接地理解和操纵的数学基础上建立它吗?
乔治·诺瑟夫(02:57):
是的。非常好的问题。我们缺少大脑的数学运算。我们不知道。我们也不知道神经元活动如何转化为精神活动。实际上,我的一个非常聪明的博士后学生,Kolozaki 元帅说,“你真的缺乏关于大脑内在特征的知识。”独立于认知的大脑的内在是什么?我们不知道。这基本上是你的基本设计原则,你需要知道,设计你的人工智能设备,设计你的深度学习网络,这可能是有帮助的。
杰里米·哈里斯(03:36):
对不起。在这种情况下,什么是内在特征?什么-
格奥尔格·诺瑟夫(03:39):
例如,对于大脑来说,你有不同的时间尺度。你操作,你很慢的时间尺度,很快的时间尺度。我给你举个例子。当你去海边的时候,你会去大西洋或太平洋,这里是加拿大。你有一个非常暴风雨的一天,你会看到很多缓慢的海浪。缓慢是极其强大的。
格奥尔格·诺瑟夫(04:01):
然后你会看到许多其他的波浪,慢一些,快一些,你会看到各种不同的波浪。不同持续时间的波浪,很强的,很强的,不太强的等等。大脑有丰富的时间尺度。我们称之为内在神经时间尺度。基本上不同的大脑区域,不同的时间尺度。例如,我认为这是大脑典型的内在特征。你和我不同。你和我的时间表略有不同,因为你和我是在不同的环境中形成的。
Jeremie Harris (04:44):
不,不。这真的很有趣,因为开幕式上有一个人,我叫他 Nick Camerata。他是他们安全小组的成员,他自己也做过很多探索性的药物实验。他贴了很多关于这个话题的非常有趣的链接。我看到的其中一项研究谈到了这一点……有一种特征性的频闪效应,当你服用 LSD 或某些种类的药物时,人们称之为频闪效应,每个人似乎都会经历遵循特定频率或特征模式的感官知觉扭曲。那和这个有关系吗?或者我说的太离谱了?
格奥尔格·诺瑟夫(05:23):
不,不,不。你说得很对,因为这个例子表明,你的感知和认知强烈依赖于你的时间尺度。这些人中的许多人随后体验到时间变快或扭曲或变慢。这决定了你能感知什么,以及你如何感知它。这就像你有一栋有很多不同窗户大小的房子,透过每扇窗户你都能看到不同的东西。你可以看到树枝,也可以看到树干,但是如果不把所有的时间尺度放在一起,你就不能把它们放在一起。
杰瑞米·哈里斯(06:03):
是的。
格奥尔格·诺瑟夫(06:06):
我现在可以向你展示我的观点。三个窗口,每个窗口的大小,较小的和较大的一个,我感知完全不同的东西。但是我需要把它们放在一起。当前人工智能的一个问题是,尽管取得了进步和强化学习,但它们的时间范围非常有限。大脑是巧妙的。大脑显然并不聪明,它有很多局限性,但结合不同的时间尺度真的很好。当你听音乐时,你有各种各样的时间尺度,不同的层次。你可以把它们分开,但是你把它们放在一起。这时你会听到旋律。
Jeremie Harris (06:50):
所以,核心,我不想称之为大脑的神秘功能,但是大脑做的核心事情与大多数人工智能策略做的事情有很大不同,你会说这是它结合这些不同时间尺度的方式……顺便说一下,我不知道这句话对不对。其他感知模式,比如长度,是不是太简单了,如果我放大得太近,就像只见树木不见森林。差不多吧?
格奥尔格·诺瑟夫(07:18):
是的,没错。然后你看到了绝对的细节,但你没有看到整个森林。正是如此。你的大脑有人把它放在一起,这可能也是人类和非人类大脑的区别,他们有稍微不同的时标。正如我的博士后所说,卡拉佐基元帅指出了这一点。我们刚刚提交了一篇论文。它说不同物种之间的时间尺度有些重叠。这就是为什么我们可以和我们的狗交流。是啊。我每天早上跑步的时候都会看到,为了狗的主人,是吗?
杰里米·哈里斯(07:54):
是的。
格奥尔格·诺瑟夫(07:55):
但在另一端,这是一个微小的差异。也许我们有更精细、更慢的窗口、更大的时间窗口,这样我们就可以感知更多、整合更多,以不同的方式把事情放在一起。
杰里米·哈里斯(08:09):
是的。这真的让我产生了共鸣。在过去的几个月里,我围绕这个话题进行了很多奇怪的对话。举个例子…事实上,我很乐意让你来做这件事。当你看到一个长时间快进的植物视频时。当你看着一株植物时,它看起来是静止的,但一天下来,它实际上是在移动,它在世界上表达自己。如果你快进的话,它几乎看起来栩栩如生。然而我们似乎不认为植物是有生命的东西。你会说因为我们的时间尺度不相容,因为我们在更短的时间尺度上运作?
格奥尔格·诺瑟夫(08:44):
我们缺少时间表。我们缺少看到这一点的时间尺度。你看,我们认为它是静态的,并说,“好吧,这很好。”但也许只是因为我们的时间表。是一个很好的例子。另一个例子是在哲学中大量讨论的。你们中的一些人可能知道,托马斯·内格尔,做一个坏的什么是什么感觉[听不清 00:09:06]。他说,“好吧,坏罐工序。我不相信波,因为它的生物物理设备,最终它的时间尺度。我们不能。”好吧。那部分现实对我们来说仍然是一个黑洞。
耶雷米·哈里斯(09:22):
有意思。它真的为一些基本问题打开了大门,这些问题是关于有多少事情是我们有意识的,但我们可能没有意识到,或者无法接受。在我们深入讨论这个问题之前,我确实想先缩小一下,因为我让我的兴奋情绪占了上风。但是你会说,有更多的事情,比如,你的客人,有更多的事情是有意义的意识的,比我们想象的要多吗?
格奥尔格·诺瑟夫(09:50):
我当然认为其他物种也有意识,但范围略有不同/比如说可能只是感知小窗户,但在那里面他们有独立的意识。当然,我可能会说,你的时间尺度对你意识的延伸有很大的影响。如果你有一个更大的曲目,你有更大的可能性拥有更广泛的意识。我这里说的扩展指的是时间空间,然后你可以考虑不同种类的内容。如果我有更小的时间尺度,我可以考虑花在移动。但我不是。也许某个聪明的工程师明天会打电话给我说,“是的,诺瑟夫,我在你的大脑中以较慢的时间尺度打败了你,这样你就能感知花的运动。”这就是我想要人工智能的原因。文档。
杰里米·哈里斯(10:57):
嗯,这真的是……这让我想到了有意识的东西之间的区别,换句话说,就是有意识,能够对它做出反应。让你的大脑知道,“哦,看植物在动。”或者意识到 20 年时间跨度内的市场变动,否则我们不会注意到。但它似乎也潜在地不同于意识的概念,在某种意义上,我有这种体验,我不觉得我是一个非玩家角色,一个哲学僵尸,有时被称为。但是我觉得…在我眼睛后面这里,有东西在我眼睛后面。你认为这两件事有联系吗?你如何从一个地方到另一个地方?
格奥尔格·诺瑟夫(11:44):
我想是后一种情况,对我来说意识是非常基本的东西。你在世界上导航。
杰里米·哈里斯(11:52):
好的。
格奥尔格·诺瑟夫(11:53):
是的。你表现得很好。即使有变焦,我们也不在同一个房间,但至少在同一个城市。我导航,我们共享某个空间,当然在这种情况下是虚拟空间。这意味着我可以连接我内心的时间和空间坐标,将它们延伸到我之外的你身上。然后把照片放大作为一种奇妙的工具,因为你总是把自己看作更广阔场景的一部分,这就是我的意识。你在世界中航行。为了在这个世界中导航,你现在需要把自己定位为一个更广阔的背景的一部分。否则,你可以导航。如果你失去了那种能力,你只是站在那里,不知道该怎么办。在精神疾病中你可以看到这一点。
哈利斯(12:47):
什么样的失调?
格奥尔格·诺瑟夫(12:49):
例如,精神分裂症患者。他们经常会失去空间感。他们无法将自己定位为更广阔空间的一部分。然后他们不知道去哪里。他们只是站在那里。从认知上来说,他们知道那个地址到处都是,但是他们就是不能把这个和他们联系起来。
哈利斯(13:11):
好的。所以你是说某人的意识在一定程度上取决于他的精神状态与环境的相关性?这样说公平吗?就像精神分裂症患者一样,因为他们有这种关联是一种习惯?
格奥尔格·诺瑟夫(13:25):
对我来说,我不喜欢这种相关性的东西,因为这样看起来好像你有两个不同的东西。我是世界的一部分,我和你一起在这里导航,你现在可以阅读我的手的动作,你知道它是什么,所以我们现在真正共享一个特定的虚拟空间。你就住在里面。有了这个,你就可以和他们交流了。所以你多少意识到你是你的事物中的一部分。这和导航一样,没有覆盖现实。
Jeremie Harris (14:00):
本质上,有这样一个连续统一体。不清楚我在哪里结束,环境在哪里开始,反之亦然。
格奥尔格·诺瑟夫(14:05):
是的。
杰瑞米·哈里斯(14:06):
好的。如果我非常粗略地放置一个分隔符…假设我们真的可以放置一个分隔符,在这种情况下,说它是某种相关性是否公平?就像是我头脑中发生的事情反映了世界上正在发生的事情,以至于我意识到了这一点?
格奥尔格·诺瑟夫(14:26):
让我给你举个例子。如你所见,我试图回避这个问题。
哈里斯(14:31):
很公平。
格奥尔格·诺瑟夫(14:32):
让我给你举个例子。当你随着音乐跳舞时,你会做什么?很明显你和音乐的节奏同步。你可以在大脑中看到这一点,大脑的节奏与音乐的节奏同步。你可以测量一下。你可以测量一下。
杰里米·哈里斯(14:55):
通过脑电波还是?
格奥尔格·诺瑟夫(14:58):
脑电波。脑电波的开始总是与曲调的开始同步。
哈利斯(15:04):
好的。
格奥尔格·诺瑟夫(15:05):
是啊。是两个同步的波。你可以测量一下。你与音乐节奏同步得越好,你就越能感受到音乐的最佳状态。你越有感觉,“哇。这真的很好。我要死了。我真的感觉到了。”所有精神动力药物都能改善这种情况。大脑就是这么做的。我认为这是一个关键的区别,这种与环境节奏波动的同步。不仅仅是音乐,还有语言。
格奥尔格·诺瑟夫(15:43):
或者实际上,当我看到我的一些精神病患者时,他们马上会做和你一样的事情。他们与你同步。当我像这样移动我的手臂时,在几毫秒内,他们也这样做,反之亦然。当他们这样做的时候,我经常观察自己,我也在这样做。完全无意识。我导航,所以我同步。这就像[听不清 00:16:07]。然后你会觉得你和音乐同步得越好,给你的感觉就越好。
耶雷米·哈里斯(16:13):
你认为也有反例吗?比如说,我不知道……某人被丢进一个不熟悉的环境,然后顽固地拒绝加入新环境的仪式。新环境和他们自己的倾向之间的不和谐。那怎么会映射到这里?
格奥尔格·诺瑟夫(16:35):
好的。当然是非常不同的水平,但我真的同意。实际上,昨天我和一个学生进行了一次长时间的采访和讨论,他是在美国的第一代中国人。你可以清楚地看到他是如何在两种不同的价值体系之间挣扎的。在中国,你需要一些附庸风雅,你需要 100 岁,你非常正式。在美国,你必须说,“在这里,我是最伟大的,等等,等等。”它更加以自我为中心等等。你真的可以看到他是如何在这两者之间被撕裂。
格奥尔格·诺瑟夫(17:11):
这是一个非常无意识的层面。我们的大脑替我们做这项工作。我们不知道。我们无法接触到它。我认为这是人工智能可以从脑科学中学习的地方。不是这个认知水平高。AI 在这方面很棒。在强化学习,深度学习模型中,这是一个博弈,目标。比任何人类都好。但这里的问题是,他们只能在非常有限的任务中做到这一点,也就是你所说的[听不清 00:17:45]概括问题。大脑非常慷慨,可以做各种各样的任务,甚至可以学习新的任务。我认为这是我与,例如,时间尺度的东西相交的地方。
杰里米·哈里斯(18:00):
好的。好吧。那是有帮助的。也许在我们深入到人工智能方面的事情之前,只是因为我知道很多人在听,坦率地说也喜欢我,我真的不熟悉神经科学。我真的不熟悉意识理论。你能不能把这些东西放在一个角度看?还有其他的意识理论吗?你的理论符合什么情况?这样我们就能对这里的风景有所了解。
格奥尔格·诺瑟夫(18:24):
好的。神经科学,这是我的小背景,它专注于特定的内容。你感知这个,然后你观察大脑。当你感知到这些内容时,大脑在做什么?它以许多刺激输入为导向,这就是我们所说的认知神经科学。你从认知开始,你用内容感知,然后你看我看到这个内容的时候大脑发生了什么。然后我转移到这个内容。我现在向你们展示另一个关于大脑活动的例子。然后你寻找-
Jeremie Harris (19:01):
如果你看不到视频,Georg 拿着两支不同的笔。他说,当你看着这支笔时,发生的是你看着那支笔…对不起,我只是为人们做这些-
乔治·诺瑟夫(19:12):
我知道。在我做的那一刻,我变得-
哈利斯(19:12):
不,这很好。太好了。是啊。
格奥尔格·诺瑟夫(19:14):
那就是你要做的。这也适用于,好吧,你有某些想法,现在你寻找这些想法的神经关联。
耶雷米·哈理斯(19:26):
对。
格奥尔格·诺瑟夫(19:27):
然而,那只是大脑上部的 10%。许多关于意识的理论都集中在这个上面的表格上,例如,全球工作空间理论这是一个很好的理论,它将大脑视为一个全球神经元空间。传入的内容需要在整个大脑中处理和分配,然后你就有了意识。还有一个非常流行的理论,综合信息理论。该理论认为,你需要将这些内容与背景融为一体,然后你就很有可能产生后果。
格奥尔格·诺瑟夫(20:10):
但对我来说,那只是蛋糕上面的 10%。这只是它上面的樱桃,因为你有一整个更深的层,这不是关于意识的处理。是你的无意识。你有你的梦想。当你走进雪中时,你会想知道。你有一些梦或者其他什么,与你环境中的内容完全无关。这怎么可能呢?这就是精神分析所说的无意识。
格奥尔格·诺瑟夫(20:40):
还有更深的一层。在这个时间空间里,基本上你的时间尺度的数量,对你的大脑能够处理什么内容,然后感知什么内容有很大的影响。就像我最初画的那样。当你有一个非常…这个更深的层不允许我感知植物的缓慢运动。我永远无法意识到植物的运动和植物的运动。事实上,我不能感知,我不能同源,我不存在,但那不是真的。你说只有…你需要在设计中考虑这个更深的层次。大脑设计的不同时间尺度。
哈里斯(21:36):
有意思。每当我遇到意识理论时,我总会有一个恼人的问题,这是主观经验的概念吗?举例来说,当你谈论意识的神经关联时,基本上那意味着什么,据我所知,你有一个输入。有人把一支笔放在你面前,然后我们说,“好吧,神经元放电模式是什么?”所以我们实际上可以使用观测仪器或设备进行客观测量。然后我们研究移动笔和这些东西做什么之间的映射。基本上就像 neural link 在做的一样。
杰里米·哈里斯(22:10):
虽然这显然是描述性的,但你可以很好地描述客观世界。我仍然很难理解……这几乎让人觉得是一个奇怪的问题,不管你能对世界的方式做出多少真实的陈述,你永远也不会对世界应该如何做出陈述。有一个障碍,似乎这些世界不能融合。你如何看待主观世界和客观世界之间的联系,主观世界就像我们似乎经历了什么,而客观世界只是数学描述?我不知道。你对此有什么看法?
格奥尔格·诺瑟夫(22:46):
显然,这几乎是一个哲学问题,但也是一个工程问题。问题是,我认为用神经科学。它的视野非常有限。它只是从这种主观的东西接近。当然,当你说,“好吧。”你从一些主观的东西开始,然后测量默认情况下留下差距的相关性。弥合这一差距。我决定也许我应该反过来。没有错,只是太局限了。
格奥尔格·诺瑟夫(23:16):
所以我说,也许我可以反过来,我从下往上看,独立于所有这些认知,大脑自己在做什么。那是大脑的内在特征。这是我团队中一位聪明的博士后 Marhal Kolozaki 说的。这些都是大脑的内在品质。忘掉所有的感知,认知。我们只是想看看在此之前大脑本身做了什么。这让我想到了时间和空间。
格奥尔格·诺瑟夫(23:42):
令人惊讶的是,这一方面让我想到大脑的时间和空间是如何与环境中的时间和空间同步的,比如音乐。另一方面,至少也许我们的一些心理特征有一个时空结构。这就是为什么我们主张意识的时空理论。基本上你可以变得有意识,如果你有一定的体温持续时间。如果温度持续时间太短你的内容,你不能成为有意识的。
耶雷米·哈理斯(24:16):
哦,有意思。这就像是意识的连续体。你认为它是一个连续体还是像你说的有一个明显的分界线?
格奥尔格·诺瑟夫(24:23):
这就是链接。这是客观和主观之间的联系。如果你有一个更长的持续时间,比方说,如果你真的…再次,我再次呈现取决于,一段时间。你看到的越多,它到达你意识的可能性就越大。如果我只提出很短,你有一个非常缓慢的船。意思是内容是一样的,但是脾气背景是不同的,这对你的大脑很重要。你的大脑部分根据时间特征对内容进行编码。
杰里米·哈里斯(25:01):
这非常直观。这很有道理。我们可以看到,作为生物有机体,当然有一个最大的时间窗口。没有人处理信息的时间跨度超过 100 年左右。更短的时间跨度,我们会遇到像神经回路这样的工程限制。这两者之间的空间充满了人类意识。比方说你拿一只蚂蚁或者别的什么东西,甚至不是蚂蚁,一只寿命很短的阿米巴原虫,在这一生中,可能阿米巴原虫对发生在比我们更短的时间范围内的事情更敏感。你会说它的意识体验向光谱的那一端转移吗?也许意识不那么强烈,因为它没有那么宽广。
格奥尔格·诺瑟夫(25:51):
真的。
耶雷米·哈里斯(25:52):
好的。
格奥尔格·诺瑟夫(25:53):
我完全可以说,你有一系列不同程度的可能意识。这显然是一个时空谱。音阶,不同的音阶。尺度很重要。变形虫的时间尺度非常小。很明显,由于生物因素,蚂蚁的时间尺度非常小,但在这个小时间尺度内,它可能比我们更精细。你可以看到他们在社会组织中表现出色。所以他们必须有一个更精细的临时窗口,在他们的小窗口中有许多细分,因为他们在他们的上下文中非常敏感。我希望通过人工智能,我们可以扩大一些我们到达的时间范围。
耶雷米·哈里斯(26:44):
好的。太好了。这就把我们带到了人工智能的起点。我想通过问你一个问题来让我们到达那里,我希望这个问题能引发很多关于人工智能的对话。这就是底物依赖性的问题。人们经常认为有一场关于机器是否会有意识的辩论,因为它们是由硅树脂或其他材料制成的。我认为意识的底物独立性或底物依赖性,当你达到人类群体或 ed 群体的水平时,这已经是一个问题了。你可能会说,当你拉远观察很长一段时间。就像如果你看一个城市,一个快速前进的人类城市,它看起来像一个该死的动物,一些模式反映了一些怪异的生物。你会如何描述人类城市和人类文明的意识?那你对 AI 的底物独立性有什么看法?我认为这可能是一个值得探索的有趣领域。
格奥尔格·诺瑟夫(27:39):
是的。我先说最后一件事。在上世纪 80、90 年代,有很多关于功能主义与非功能主义的讨论,以及在没有基础的情况下,是否需要某些输入输出关系。作为一名神经科学家,这听起来很奇怪。我不应该说这个。我不认为这是基质的问题。重要的是你的时间表。时标显然是时标的放大,它依赖于时标的上下文。
格奥尔格·诺瑟夫(28:12):
显然,大脑提供了一个完美的[听不清 00:28:15]神经服务和我自己的亚麻布,等等,等等。是啊。但那只是一个模型。这并不意味着我们的模型是什么,对于安装所有这些时间尺度和意识也是必要的。我认为我们经常混淆我们的模型,我们的方法论与现实和真理。从我的观点来看,我对意识的时空理论的观点是完全独立的,因为重要的是时间尺度。
格奥尔格·诺瑟夫(28:49):
如果你给我生产一些具有相似时标数量的代理,现在不仅是时标的数量,还有时标的灵活性,因为这些时标是变化的。当您提供外部输入时,它们会以[听不清 00:29:05]的方式发生变化。我有另一个非常聪明的博士后工程师,他实际上已经造了一个机器人北欧野蛮人,他称这个机器人为技术对话。他是个搭桥的人。他直接将所有的认知操作转化为行为。你真的可以在机器人的行为中看到认知,这太棒了。
格奥尔格·诺瑟夫(29:36):
我讨论了很多,说:“是的。”但最终它并不灵活,这是事实。为了具有灵活性和动态性,适应环境,根据环境的持续需求改变其工作记忆输出,这是机器人做不到的。这就是为什么他来到我的小组,说,“也许我们可以转换。”我认为这就是我们可以从大脑中学到东西的地方。并不是说我们可以从大脑学习底物,我不这么认为。但是我们可以从大脑难以置信的适应性和灵活性机制中学习,同时保持它的连续性和独特性。
哈里斯(30:22):
有意思。好吧。这确实让我想到了关于城市、国家和文明的问题,因为我想这些图表显示了什么是最受欢迎的…抱歉。谷歌搜索次数最多的术语是在一个特定的州,例如,在美国。在不同的时间,你会对两周后或总统选举产生兴趣。这些尖峰很有趣。它们持续很长一段时间,在某些情况下,持续很短一段时间,其他情况视情况而定,或者随着环境的变化而定。在我看来,根据这个定义,我们可以认为,人类文明或者任何人类的集合,只要足够连贯,能够交流,有叙述和话语,就有资格成为有意识的。你同意这种描述吗,或者说这有点过了?
格奥尔格·诺瑟夫(31:14):
你看我是如何拼命地回避意识这个话题的。我希望在某个时候我们不需要它。这是一个常识术语。意识,是的,现在我们试图找到哲学家所说的意识的自然种类。一个叫做意识的实体。我认为我们在某些时候不需要它。记得我们说过遗传密码…当然,我们知道基因是什么,但最终我们现在知道它是 DNA,是以不同方式结合的四种不同的蛋白质。沃森和克里克就是这么做的。好吧。还有很多其他的例子。20 世纪初,存在生命能源的可能性。我们不再需要那个了。
格奥尔格·诺瑟夫(31:56):
就大脑而言,20、30 年前,我们应该听说过很多关于边缘系统的事情。现在是什么限制了它的拼接?它是一个海马体,杏仁核是这个和那个的整体。我也是。我认为意识只是我们缺乏知识,以为我们拼命在世界上或大脑中寻找一个叫做意识的实体。对我来说,这只是,好吧,我们在世界上航行,这可能是不同形式的连接世界,你描述了其中的一些是城市。你可以再次看到,这种波动和不同形式的同步。那我们就不再需要那个了。我们没有明智的研究。
杰瑞米·哈里斯(32:37):
好的。研究方面。有意思。好吧。你会说我们不需要它来对世界做出任意好的预测,这是我直觉上同意的吗?我们真的不需要一个意识的概念来拿起一堆亚当斯说,“它要做这个,或者它要做那个。”当我想到意识时,我最终会想到主观体验。这似乎是我可以用盒子围起来的东西,但也许我错了。是主观体验,你在这个语境下把它看做和意识一样吗?
格奥尔格·诺瑟夫(33:11):
意识是多种不同的含义。
耶雷米·哈里斯(33:14):
是的。
格奥尔格·诺瑟夫(33:15):
你不会想进入那种状态的。
耶雷米·哈里斯(33:16):
是的。
格奥尔格·诺瑟夫(33:19):
传统上它有很高的等级。认知。我不一样。我开始意识到自己,这是从哲学中传达出来的。大部分仍然在意识中是非常特殊的。非常特别,主要区别于任何无意识的事物。然而,神经科学在某种程度上超越了这一点,因为它仍然在寻找特殊的神经元特征,这些特征只是专用于意识,与我们的实验室不同。特殊的意识。我称之为专家的观点。然而,我会说,算了吧。那是一种错觉。你最好寻找什么是相似的,什么是大脑和意识共有的。那是我的时空物品。我称之为共同货币。
格奥尔格·诺瑟夫(34:07):
现在我们来看一下持续时间,或者说我感觉这个采访,这个问题持续了一分钟,但是只有 20 秒钟,因为它是……然后我会假设在我的大脑中,你有相应的一分钟的持续时间间隔,这是那个方向的频率。一旦你明白了这一点,好吧,就很清楚了。我可以预测。这是读数。就像内科一样。从我的血糖水平来看。我的天啊。糖分真的很高。你一定有很多症状。
杰里米·哈里斯(34:50):
是啊。
格奥尔格·诺瑟夫(34:51):
我也是。嗯,你一定很清楚这一点。
杰瑞米·哈里斯(34:55):
意识,无论是主观体验的还是其他的,都只是一种输出。这是一种你可以预测的症状,因此科学已经做到了这一点。这是公平的吗?
格奥尔格·诺瑟夫(35:06):
是也不是,但是科学,现在你可以说它不是【听不清 00:35:12】。它只是消除,它不相信。不,因为我说大脑构建自身神经元活动的方式本质上是主观的。那是时间和空间的东西。你给我一个 20 秒的间隔,我把它想象成一分钟。我的大脑增加了一些东西。我的大脑加上剩下的 40 秒。当然,这不太可能,但我还是要问一件事,那就是意识。
杰瑞米·哈里斯(35:44):
嗯,肯定有【相声 00:35:45】
格奥尔格·诺瑟夫(35:46):
加入任何东西,我都不会有意识。
杰里米·哈里斯(35:48):
好的。是啊。是啊。这和你之前说的非相关性是有道理的。我想称之为相关性,但是是的。完美。好吧。我认为这是一个开始我们关于人工智能的对话的好地方,因为我认为你正在探索的那些时间窗口和真正的深度学习系统的架构之间的映射有很多东西可以说,只是它们设置的方式。你介意从你的角度来探讨一下你如何看待意识和人工智能之间的交集吗?
格奥尔格·诺瑟夫(36:20):
最好让我们说说大脑和人工智能。我看着…我的照片调查了很多有趣的特征,大脑中不同的时间尺度以及它们之间的联系。它们被展开到大脑的空间。训练组织中的大脑有一定的地形组织。它有一定的组织,有一定的等级制度。这是一个时间层次。时间在空间中展开。现在你可以想象,比方说,如果我有一个代理人,我是一个精神病人,我想对我不正常的想法进行某种治疗,我总是听到声音。
Georg Northoff (37:06):
采访前一切就绪,我听到了你的声音。我们能做什么?也许代理人能帮我。也许我现在可以不断地记录我的脑电波,比方说,用脑电图仪或脑电图仪或扫描设备,FMI。那是在特定的时间范围内。也许现在我可以把它转给一个代理,这个代理可能有自己的时间表,并且比现在的代理有更多的曲目。
Jeremie Harris (37:44):
喜欢更长或更短的时标。
格奥尔格·诺瑟夫(37:45):
更长,更短,更多的可变性,更细的颗粒,更粗的颗粒,不仅仅是两三个时间尺度或有限的数量,而是展开的。然后也许那个代理人可以说,我们在幻觉期间把我的时间尺度输入代理人。然后,也许理想的代理,这是类似的行为,当我听到你的声音,而你不在时,我感到困惑。然后也许那个代理人也能告诉我,我需要如何改变我大脑中的时间尺度来使这些声音消失?因为我不能消除时间尺度。
格奥尔格·诺瑟夫(38:26):
我不能只是抑制,因为那意味着我改变了整个大脑。我需要和大脑本身一起工作。也许我稍微改变了这些时间表。我认为代理可以帮助我很多,因为代理还可以提供可能不同的阴影,不同程度的时间尺度,这是我的大脑不可用的,或者当我听到声音时,我的时间尺度曲目非常有限。也许我的代理人可以在我的曲目中提供一些反馈机制,这样我就不再需要听到声音了,因为我还有其他的时间表。相同的输入可以在另一个时间刻度上工作。
耶雷米哈里斯(39:11):
有趣。我们的希望是,你基本上可以让一个智能体成为一个模仿健康人类大脑行为的人工智能,这样你就可以用它来建立一个可比性,“好吧,这就是我们所缺少的。这是我们需要弥补和修补的。”
格奥尔格·诺瑟夫(39:27):
是的。我一直反对模拟人类。在日本和英国,有托尼·普雷斯科特、朱尼·唐尼的自我模型。这是一个非常好的模型。但它是否真实的问题是一样的。它经历过它们吗?总会有你提出的问题。我的代理人有意识吗?我认为这是徒劳的。对我来说,申请人更感兴趣的是什么,从这个意义上来说,我真的很满足,我说,“也许我们不能意味着……我不能代表曲目的某个时间表。也许我可以增强这个或者改变那个。”代理可以帮助你。这可能会改变我们的行为。
哈利斯(40:15):
对。实际上,我也发现了这个问题的有趣之处,有这么多轴线,人类是沿着这些轴线看不见的。有时间尺度的部分,有空间的部分,所有你谈论过的东西。此外,我想作为一名前物理学家,我想到了现在所有无形地流经我们身体的中微子,我们周围的红外线和紫外线,我们没有意识到,因为…嗯,我想这是一个有趣的问题。我们意识到我们意识到的事物,因为进化大概优化了我们,使我们能够意识到它们。
Jeremie Harris (40:46):
很明显,比如紫外线,虽然它可以长期导致癌症,皮肤癌,但它不是一种超级致命的疾病,也不是我们生活中的一个问题,所以我们对它视而不见。我们能够同样好地狩猎,同样好地制造而不浪费能量追踪紫外线。除了你已经讨论过的时间尺度和空间的东西,你认为获得那些看不见的实体的观点有价值吗,或者你认为时间尺度和空间更有前途?
格奥尔格·诺瑟夫(41:20):
这对我来说很难讲。我和物理学家李斯·斯莫林进行了很多讨论。我在那里给了一个谈话时间和大脑。这是一种乐趣,因为我基本上可以说出我所有关于时间和大脑的想法,因为物理学家是聪明的人,他们理解时间的东西。神经科学家对这段时间有真正的问题,因为他们不认为这是一个动态。对我来说很难讲出来。你深入到量子层次…我是所谓的无标度的忠实粉丝,这意味着你有不同的时间标度或嵌套在其他时间标度中。是啊。
格奥尔格·诺瑟夫(41:58):
这就像一扇俄罗斯的门。你有更小的,更大的,更大的时间尺度,它们都嵌套在一起。这个嵌套模型在特殊条件下可能是真的。那么当然,量子级应该会有影响。但这可能是由于我缺乏我要提到的知识。是啊。这就像我们对植物的了解。很难说。我认为我现在工作中最关注的事情是大脑的时间尺度和环境的时间尺度之间的趋同程度有多大?因为那个界面。
Georg Northoff (42:42):
我的时间刻度可以与你的时间刻度同步多少?你想知道。在我们的 Zoom 访谈中,你会无意识地将自己与我的时间表对齐,因为特别是在 Zoom 中,这并不总是很容易,因为你非常清楚。例如,我们在人工智能方面获得了英国和加拿大的一大笔拨款[听不清 00:43:11],我们正在研究时间尺度的联系,以及他所说的环境和大脑之间的三种能量交换,我们将其与时空动态联系起来。我认为这是关键。这是理解大脑和意识的关键,也是产生更好的人工智能的关键,人工智能更具适应性,并具有这些增强的能力。
Jeremie Harris (43:36):
你能详细说明一下吗?我个人并不熟悉那些意识理论。
格奥尔格·诺瑟夫(43:42):
让我给你举个气候变化的例子。气候变化当然是一个大话题。气候变化发生的时间极其缓慢,除了我们的生活方式之外,我们无法了解。但是当然时间尺度是非常重要的,因为许多气候现象是非线性的。我们需要过渡,这又是一个时间表。一个很长很长很长很长的时间尺度会突然变成很短的时间尺度。这就像冰涂抹地震,你有更长的一些构造系统起飞,突然你有大爆炸。
格奥尔格·诺瑟夫(44:22):
你需要了解正在发生的事情。你需要了解动力学,而我们没有模型。为什么?因为我们自己的大脑不涵盖这些时间尺度。我会说,也许我们可以创造一个与我们自己的时间表有些重叠的代理。如果我们知道不同时间尺度如何相互作用的原理,例如,它们如何放大。野蛮人,我组里做人工的那个学生……特工干的正是那个。这些时标是如何放大的?然后,也许我们可以创建一个代理,它有更大的时标,但仍然与我们连接,这样我们就可以…然后,如果我们知道时标如何相互转换,我们仍然可以读取代理的输出。这可能是一个很好的代理建模客户。
耶雷米哈里斯(45:14):
有趣。这里的要求是,至少我们能够与代理交互,在你的模型中,在时间尺度上必须有重叠,因为否则我们就不能交流。就像植物什么的,因为我们只是-
格奥尔格·诺瑟夫(45:27):
是的。
杰里米·哈里斯(45:27):
好的。
格奥尔格·诺瑟夫(45:28):
你与可怜的植物不同步。如果植物在想,我不知道它是否会想,“这些人类真是傲慢。”是啊。
杰里米·哈里斯(45:38):
是的。如果是看人好。是啊。是啊。我也发现这个很有趣,因为它确实在玩弄可预测性的概念。就像大卫·休谟有这个…我希望我没看错是大卫·休谟。但是你不能 100%确定,无论你如何研究过去,未来会发生什么。物理定律可能会改变。数学法则明天可能会改变。这将永远是一个艰难的上限,但有一些连续体,在那里我们接近那个极限,在那里我们只能访问在这个短时间内发生的事情,如你所说。这使得气候之类的事情看起来不可预测,而在现实中,如果我们缩小范围,我们可以看到整个事情,突然之间,这是一个可预测的过程。
格奥尔格·诺瑟夫(46:26):
是的。因为这样我们就能更好地了解一些现象的统计或随机分布。如果我们有最多的时间刻度,我们就有更多的时间点,所以我们可以做一个更好的模型。如果因为我们有限的时间窗口,你有非常有限的时间点,那么当然你有不确定性。这是默认的。这种纯粹统计层面上的不确定性…
格奥尔格·诺瑟夫(46:52):
实际上,我以前的一位博士后,现在在日本,日本人中尾孝(Takashi Nakao)向我展示了这也体现在心理层面上。你对某件事的心理不确定性和你大脑的不确定性有关系。这是怎么回事,你怎么能预测。这是一回事。如果我们的时间尺度与环境不匹配,你说的股票市场波动,地震地震波,气候变化,我们就有很多不确定性。你所说的不确定性并不是一个有趣的特征。只是我们缺乏时间尺度和知识。我们太蠢了,就这样。
杰里米·哈里斯(47:31):
是的。我对这个假设持开放态度。是啊。我确实有一个关于深度学习系统的问题,我猜它们是否可能是有意识的。当我们谈论时间尺度时,我想到的一件事是,是时间尺度真正重要,还是空间技能重要,或者是抽象层。我的意思是看自然语言模型。如果我给你一个句子,我们的大脑一次专注于一个单词,然后最终像孩子一样,我们学会把单词串在一起。然后我们学会了在句子层面,然后在段落层面理解事情。这实际上正是 GPT 三和其他语言模型所做的。
杰里米·哈里斯(48:16):
一开始他们完全不知道,然后他们开始看到一大堆单词。最终他们会明白,“哦,这就是香蕉这个词。”然后他们可以理解为,“哦,在香蕉上滑倒是这个意思。”然后他们可以把整个句子放在一起,你实际上可以看到这在自然语言人工智能的进化历史中发挥作用。起初,它们只适用于文本自动完成,下一个单词,猜测,这个单词可能是什么?现在我们让他们把连贯的多段文章放在一起。让我想到这两者可能有联系的一点是当你看时标的时候。
杰里米·哈里斯(48:49):
当我们看到生命中的一瞬间时,我们可以讲述这些故事。这几乎就像我们最终专注于与文字相似的细枝末节,但当你把事情拉长,最终我可以告诉你在过去五分钟或最后一天发生在我身上的故事。现在这个故事开始变得更加有力,看起来也更加抽象了。涉及到更多的抽象实体。最终我到达了 GPD 三,我在讲述一个很长时间的故事。你认为这两者之间有对应关系吗?或者你不同意其中的一部分?
格奥尔格·诺瑟夫(49:22):
不,我觉得这很有趣。对我来说,抽象并不重要。这个单词是障碍,因为你从上下文中孤立和抽象出来了。这可能也更符合大脑的工作方式。大脑在全球范围内快速运转。它着眼于整个事情。它观察整个空间,然后开始构建空间。它从整个复杂的句子开始,然后试图在时间上分割句子。已经证明了这一点。如果你的大脑进步是暂时的,那么它提取一些单词,一些其他区域提取单个句子,其他一些段落。你把它们放在一起,这给了你意义。
耶雷米·哈里斯(50:13):
哦,有意思。
格奥尔格·诺瑟夫(50:15):
你所谓的阻碍,你从外部感知它的方式,但可能确实有强大的…你的大脑有一个全球组织,地形辉光。就像地图这个词。当你看整个世界地图时,那么单一的大陆和国家就是整个世界的障碍。这就是大脑的工作方式。
耶雷米·哈里斯(50:39):
有意思。
格奥尔格·诺瑟夫(50:40):
这就是我们拥有大量信息的原因,它以一种压缩的方式对所有这些信息进行了统计编码。但是在随后的处理中,它提取某些东西。现在它提取非洲,好吧。下一个区域,提取非洲南部。下一个地区,提取南非。然后是另一个地区,纳米比亚等等。它变得越来越精细,越来越抽象,在空间尺度上也越来越有限。所以国家变得越来越小,时标也是如此。
杰里米·哈里斯(51:19):
有意思。好吧。我可能误解了自己的思维过程。但我想象,这几乎就像…我的感觉是,两个方向有时发生在不同的背景下。比如作为一个婴儿,如果听到杯子这个词,或者饿或者好。即使很好,也有人拍拍你的头说,“很好。”你得到了与“好”这个词联系在一起的奖励,所以你很早就构建了这些非常有限的、精细的实体。
Jeremie Harris (51:51):
最终,就像在生活经历中一样,你会经历一系列个人生活经历,有时你不得不缩小视野。然后有一个故事跃入眼帘,你会说,“哦,这是我可以从所有这些微观经历中吸取的重要教训。”然而,我也看到另一种情况,你从这个大的高层次的东西,然后你意识到,“哦,等等,但那是由于所有这些小的微观的东西。”然后你会变得更加精细。但是你会说,就像第一个例子是虚幻的,那是我告诉自己关于我的大脑实际上在做什么的错误故事吗?
格奥尔格·诺瑟夫(52:27):
不,回到你孩子的例子。宝宝说:“好的,太好了。”母亲说很好。但这在很大程度上取决于母亲的语气,她是如何轻拍婴儿的,当然是在什么样的背景下,因为你可以让同一个人用完全不同的语气说话。这是一种完全不同的情绪,在不同的背景下,用完全不同的拍法。
杰瑞米·哈里斯(52:55):
好的。
格奥尔格·诺瑟夫(52:57):
这决定了价值。有一个深层的生态社会因素。
杰里米·哈里斯(53:05):
有意思。
格奥尔格·诺瑟夫(53:08):
意思是如果你只是孤立了那件小事,你已经得到了回报,现在你应该高兴了,但是你为什么不高兴呢?
耶雷米·哈里斯(53:14):
对,对。
格奥尔格·诺瑟夫(53:14):
我母亲总是说:“是的,是的。现在你得到你的奖励。”
耶雷米哈里斯(53:18):
是啊。
格奥尔格·诺瑟夫(53:19):
那对婴儿来说不可行。婴儿对此非常敏感。[听不清 00:53:25]。
杰里米·哈里斯(53:26):
我笑是因为这真的让我意识到我的大脑在不知不觉中做了多少错误的计算,直到我说:“哦,这是回报。”那么你会说在人工智能中我们可能会希望看到一点范式的转变,比如从上到下而不是从下到上?
格奥尔格·诺瑟夫(53:46):
是的。我会说,首先,看看你的代理人必须运作的环境,这是你要做的第一件事。为此,你会说,好吧,如果你真的想让你的代理与上下文同步,看看你的上下文的时标。比方说,如果你想在一个充满背景音乐的环境中操作你的代理,看看它的时间尺度。现在你有一个学生,然后你说…好吧,你想让一个学生学习[听不清 00:54:19],我让它变得简单。然后,根据[听不清 00:54:30]的上下文,培训您的代理,在您的代理中设计时间表。
格奥尔格·诺瑟夫(54:31):
然后你就可以上场了。这就是你们工程师的聪明之处,这就是你们能做的。现在,您可以细化这些时间表,然后您可以去找您的学生,教他们将您的代理的时间表与您的学生的时间表联系起来。如果你制作一个具有前馈反馈效果的界面,那么你可以训练学生变得更加敏感,对[听不清 00:55:00]有更好的时间刻度。这当然是一个非常简单的例子。另一件事,正如我所说的,背景,看环境背景,看背景的时间尺度。你需要知道的。
格奥尔格·诺瑟夫(55:12):
这就是为什么我认为我们可以从大脑中学习,因为大脑非常聪明。大脑在很多方面都很笨,但是在那方面……简直不可思议。同样的窗口,我们可以处理各种各样的输入,并从中获得一些意义。目前的强化学习只有非常有限的时间范围,并且在一个特定的任务或几个任务中非常好,但是这种广泛的任务和人类,我们甚至可以适应和改变。难以置信。
Jeremie Harris (55:42):
这也很有趣,因为它也提出了大脑日常学习的差异。当你有了一个孩子…在我的例子中,我是这样的,“哦,假设一个孩子。”所以我们想象一个有大脑的婴儿,然后你正确地说,婴儿看着它的环境,然后从那里,它梳理出这些微观细节。我想这也是故事中缺失的一部分。至少我讲述这个故事的方式是,婴儿的大脑不是在真空中出现的。它是由进化在非常长的时间内编程的。我想,这个过程可能更像是 GPT 三人组的训练过程。这是一种进化算法。在那里,我们可以看到一些出现在大脑中的结构,它们是从更精细的颗粒开始的。这公平吗?
格奥尔格·诺瑟夫(56:32):
非常。我喜欢对这个问题的两个回答的评论。两个答案。一个神经的,一个心理的。很明显大脑中的某些时间尺度是进化保留下来的。不管我们愿不愿意,我们和老鼠有着相同的波动频率。甚至可能是恐龙,因为这是进化的一部分。进化对我和我认为我强有力的支持,它像一层,它像一个巢。这是一个层次的东西。毫无疑问,这是一种嵌套的新鲜感。例如,在心理上,这表现为跨代的创伤。我从我父母那里继承了他们无法承受的创伤。我有更多的经验证据来证明这一点。所以你对语义相关的线索非常敏感,而不是和你父母经历的创伤一样。
Jeremie Harris (57:33):
这是表观遗传吗,就像【相声 00:57:36】。
格奥尔格·诺瑟夫(57:38):
可能是遗传和某些事情,当然还有对你的时间尺度的钦佩,因为你对类似的环境线索很敏感。这里的上下文是关键,而不是安全本身。是啊。
杰里米·哈里斯(57:57):
有意思。是啊。这么多都是视角的改变,甚至只是为了思考这些问题,因为你开始意识到你的大脑自动填补了多少空白,随之而来的是多少假设?有时候有点吓人,也有点挑战性。我喜欢这次谈话。你有这么多有趣的见解。有什么地方人们可以查看吗…我认为你有一个有很多很棒内容的网站。你有什么特别推荐给那些想了解更多的人的吗?
格奥尔格·诺瑟夫(58:23):
是的。他们可以在网站上看看,www.georgnorthoff.com。你会看到很多 YouTube 上的谈话,诸如此类。然后还有我写的一本书,神经哲学和健康思维,2016,诺顿出版社面向更广泛的读者。最近意大利出版了一本书,时间和大脑,大脑的时间代码,也许你们中的一些人读过。不幸的是,它计划被翻译成英语,以及中文和日语。到目前为止,它上个月才以意大利语出版。只要看看我的网站,看看会谈。如果你愿意,你可以发邮件给我。
杰瑞米·哈里斯(59:02):
牛逼。我们会在博客中提供所有的链接。他们会附带一个播客。非常感谢。这真是令人兴奋。我喜欢这次谈话。
格奥尔格·诺瑟夫(59:09):
是的。很好。谢谢您们。
在生产中部署机器学习模型的注意事项
原文:https://towardsdatascience.com/considerations-for-deploying-machine-learning-models-in-production-89d38d96cc23?source=collection_archive---------3-----------------------
由朱尔斯·s·丹吉、迈克尔·加拉尼克
模型开发周期的各个阶段(图片由 Jules S. Damji 提供)
数据科学或机器学习研究人员或从业者中常见的抱怨是,将模型投入生产很困难。因此,一些人声称,很大一部分,87%的模型从未在生产中看到的曙光。
“我有一个模型,我花了大量时间在我的笔记本电脑上开发它。下一步是什么?我如何让它进入我们的生产环境?我应该为我的 ML 堆栈和工具考虑什么?”
这些问题经常出现在聚会或会议上,在关于机器学习操作(MLOps)的演讲之后。对于这个试图解决和补救这一关键问题的新兴领域,没有什么灵丹妙药或灵丹妙药。
然而,在考虑您的 ML 堆栈和工具时,有一些可接受的和常见的技术考虑和陷阱要记住。在将 ML 模型投入生产的系列文章的第一部分中,我们将讨论工具和最佳实践以及 ML 模型服务模式的一些常见注意事项和常见陷阱,它们是您从模型开发到在生产中部署的必不可少的一部分。
轻松发展
首先考虑你的开发环境。大多数数据科学家或 ML 工程师总是使用他们的笔记本电脑来开发、测试或调试代码。由于简单、易于访问和安装最新的 ML 库,从业者压倒性地倾向于使用笔记本电脑而不是集群进行开发。我们被 ide 和强调语法的编辑器宠坏了,这是有原因的。
Python 开发人员喜欢定制他们的环境来匹配他们的登台环境,使用 conda 或 Python 虚拟环境的库依赖。理想情况下,作为一种最佳实践,如果在他们的笔记本电脑上开发的相同代码可以在集群上的试运行或生产环境中以最小的改动运行,这将极大地提高端到端开发人员的工作效率。
考虑将您的笔记本电脑作为开发环境的首选,它有可能将您的代码扩展或同步到云中的集群环境。
克里斯汀·休姆在 Unsplash 上拍摄的照片
考虑因素#1 : 将笔记本电脑用于开发作为最佳实践
大规模训练和跟踪模型实验
与传统的软件开发周期不同,模型开发周期范式是不同的。许多因素会影响 ML 模型在生产中的成功。首先,模型的结果由它的度量来衡量,比如可接受的准确性。
第二,达到满足业务目标的准确性意味着在跟踪每个实验运行时,不仅仅使用一个模型或 ML 库,而是使用许多模型和 ML 库进行实验:度量、参数、工件等。准确性是至关重要的,开发人员选择 ML 库进行实验也是如此。
朱尔斯·s·丹吉的图片
第三,准确性与获取数据的质量直接相关:坏数据导致坏模型。如下图所示,数据准备-特征提取、特征选择、标准化或规范化特征、数据插补和编码-都是清理后的数据进入特征库之前必不可少的步骤,可用于模型训练和测试阶段或部署中的推理。
模型开发周期的各个阶段(图片由 Jules S. Damji 提供)
第四,选择一种编程语言,这种语言不仅为您的数据团队(数据分析师、数据科学家和 ML 工程师)所熟悉,而且还受到模型实验和培训阶段使用的许多 ML 库的支持。Python 似乎是事实上的选择。
除了选择编程语言,还可以选择 ML 框架来驯服计算密集型 ML 工作负载:深度学习、分布式训练、超参数优化(HPO)和推理,所有这些都是水平规模的,从您的笔记本电脑、单节点多核到多节点多核。
最后,能够在不同的环境中轻松地大规模部署模型:web 应用程序的一部分、移动设备内部、云中的 web 服务等。
考虑号#2:考虑使用模型生命周期开发和管理平台,如ml flowDVCWeights&bias,或SageMaker Studio。以及RayRay TuneRay Train(原 Ray SGD)py torch和tensor flow用于分布式、计算密集型和深度学习的 ML 工作负载。****
管理机器学习功能
特征库是现代机器学习开发周期中新兴的关键组件。随着越来越多的数据科学家和工程师共同努力,成功地将模型投入生产,作为模型开发周期的一部分,拥有一个单一的存储来保存经过清理和特征化的数据变得越来越必要。
用于管理 ML 特性的特性存储(图像源,Apache 2.0)
功能存储解决了运营挑战。它们在训练和推理之间提供了一组一致的数据。它们避免了任何数据偏差或无意的数据泄漏。在训练时的特征提取过程中,它们提供了在批处理和流数据上编写特征转换的定制能力。并且它们允许在推断时使用历史数据来增加请求,这在大型欺诈和异常检测部署模型或推荐系统中很常见。
除了将模型投入生产的挑战和考虑之外,操作 ML 数据同样重要。模型的准确性取决于良好的数据,要素存储有助于管理预先计算和清理的要素,以便在模型服务期间进行模型训练和生产推理。
考虑因素#3:将特征库视为模型开发过程的一部分。看向 盛宴泰克顿萨格马克 , 数据块 进行特色店铺。**
大规模部署、服务和推理模型
一旦模型被训练和测试,并确信它满足模型准确性的业务需求,可伸缩模型服务框架要考虑的七个关键需求是:
****框架不可知:一个服务选举框架的模型应该是 ML 框架不可知的。也就是说,它可以部署任何用通用 ML 框架构建的通用模型。比如 PyTorch,TensorFlow,XGBoost,或者 Scikit-learn,每个都有自己的算法和模型架构。
****业务逻辑:模型预测通常需要预处理、后处理或通过连接到特征存储或任何其他数据存储进行验证来扩充请求数据的能力。模型服务应该允许这作为其推理的一部分。
****模型复制:有些模型是计算密集型的或网络受限的。因此,选择的框架可以将请求分散到模型副本,在副本之间进行负载平衡,以支持高峰流量期间的并行请求处理。
****请求批处理:并非所有生产中的模型都用于实时服务。通常,模型在大批量的请求中被评分。例如,对于深度学习模型,将这些图像请求并行化到多个内核,利用硬件加速器来加快批量评分和利用硬件资源,这是值得考虑的。
****高并发和低延迟:生产中的模型需要低延迟的实时推理,同时处理突发的大量请求。这对于获得最佳用户体验以接收毫秒级预测请求响应至关重要。
模型部署 CLI 和 API:负责部署模型的 ML 工程师应该能够使用模型服务器的部署 API 或命令行界面(CLI)简单地将模型工件部署到生产中。这允许从现有的 CI/CD 管道或工作流中进行模型部署。
****生产中的模型模式:随着人工智能应用在工业的各个领域越来越普及,为这些人工智能应用训练的模型变得复杂而复合。它们的范围从计算机视觉到自然语言处理,再到推荐系统和强化学习。
也就是说,模型不是孤立存在的。他们也不会单独预测结果。相反,他们通常以四种模式联合运作:管道、合奏、商业逻辑和在线学习。每种模式都有其目的和价值。
生产中的 ML 模型模式(图像源)
机器学习工程师采用两种常见的方法在生产中部署这些模型模式。一种是将模型嵌入 web 服务器,另一种是卸载到外部服务。就上述七个考虑事项而言,每种方法都有自己的优点和缺点。
考虑数#4:看向 谢顿 ,KFServing,或者 雷 Serve 对于这七个要求。**
生产中的观察和监控模型
作为模型开发生命周期的一部分,模型监控通常是一个被忽视的阶段,它对于模型在部署后生产阶段的生存能力至关重要。这通常是事后的想法,由 ML 工程师承担风险。
模型有来世的生存能力。生产中可行的生命需要一个持续的警惕或哨兵的眼睛。事实上,作为一个阶段的监控只是模型服务的延续,如下图所示。
生产中的 ML 模型监控(显然是 AI 的图像
为什么要考虑模型监控?出于许多实际原因,这一阶段至关重要。我们简单讨论一下。
****数据随时间漂移:正如我们上面提到的,我们的模型的质量和准确性取决于数据的质量。数据是复杂的,从来不是静态的,这意味着随着时间的推移,用提取的特征训练的原始模型可能不再重要。可能会出现一些需要考虑的新特征。比如季节性的数据变化。数据中的这种特征漂移需要重新训练和重新部署模型,因为变量的分布不再相关。
****模型概念随着时间而变化:许多从业者称之为模型衰退或模型陈旧。当训练模型的模式不再适用于漂移数据时,该模型将不再有效,因为其输入特征的关系可能不一定会产生模型的预期预测。因此,它的精度会降低。
****模型故障时间:模型故障原因不明:某系统故障或网络连接不良;超负荷的系统;错误的输入或损坏的请求。如果用户收到错误或伪造的结果,及早检测这些故障的根本原因或其频率可以减轻用户的不良体验或阻止对服务的不信任。
****系统因负载过重而降级:时刻警惕您部署的专用模型服务器或服务的健康状况,这与监控传输数据的数据管道或整个数据基础架构的关键组件(数据存储、web 服务器、路由器、集群节点的系统健康状况等)的健康状况同样重要。
这些前述的监控模型概念统称为模型可观测性。在 MLOps 最佳实践中,这一步现在是可接受的必要步骤。监视数据和模型的健康状况永远不应该是事后才想到的。相反,它应该是你的模型开发周期的一部分。
考虑数#5:对于模型的可观测性,显然要看. ai,arize . ai,Arthur . ai, Fiddler.ai ,https://valohai.com/model-monitoring/,或why
结论
让我们回顾一下。为了避免常见的抱怨模型不能投入生产或让你的模型在生产中看到阳光,如果你想让你的模型旅行到他们想要的目的地,并有一个可行的来世,请在心中考虑所有上述因素。
每种考虑都有其优点。每个考虑事项都有解决每个问题的开源解决方案或来自供应商的托管解决方案。评估每个工具如何最好地适应和满足现有机器学习工具堆栈中的所有考虑因素。
但是将它作为 ML 模型开发工具栈的一部分是至关重要的;这将显著提高您将模型投入生产的端到端成功率。
在以后的博客中,我们将研究如何实现考虑事项#1 和#2,重点关注我们建议的一些工具。
原载于https://www.anyscale.com。**
选择机器学习模型时的考虑事项
原文:https://towardsdatascience.com/considerations-when-choosing-a-machine-learning-model-aa31f52c27f3?source=collection_archive---------5-----------------------
与许多人认为的相反,性能最佳的型号不一定是最佳选择
安娜斯塔西娅·切平斯卡在 Unsplash 上的照片
与许多人认为的相反,性能最佳的机器学习模型不一定是最佳解决方案。
在 Kaggle 比赛中,你需要的只是表现。在现实生活中,这只是另一个需要考虑的因素。
让我们从模型的性能开始,并回顾在选择模型来解决问题时要记住的其他一些考虑因素。
1.表演
模型结果的质量是选择模型时要考虑的一个基本因素。你要优先考虑能最大化性能的算法。
根据问题的不同,不同的指标可能有助于分析模型的结果。例如,一些最流行的指标包括准确性、精确度、召回和f1-分数。
请记住,不是每个指标都适用于所有情况。例如,在处理不平衡数据集时,精度并不合适。在我们准备开始模型选择过程之前,选择一个好的指标(或一组指标)来评估您的模型的性能是一项至关重要的任务。
2。可解释性
在许多情况下,解释模型的结果是至关重要的。不幸的是,许多算法像黑盒一样工作,无论它们有多好,结果都很难解释。
在这种情况下,缺乏可解释性可能会成为交易的破坏者。
当可解释性是一个问题时,线性回归和决策树是很好的选择。神经网络就没那么好了。
在选择一个好的候选模型之前,理解解释每个模型的结果有多容易是很重要的。
有趣的是,可解释性和复杂性通常在光谱的两端,所以让我们接下来处理复杂性。
3.复杂性
复杂的模型可以在数据中发现更多有趣的模式,但同时,维护和解释起来也会更加困难。
要记住几个松散的概括:
- 更高的复杂性可以带来更好的性能,但也会带来更大的成本。
- 复杂性与可解释性成反比。模型越复杂,就越难解释其结果。
将可解释性放在一边,构建和维护模型的成本是一个成功项目的关键因素。复杂的设置将在模型的整个生命周期中产生越来越大的影响。
4。数据集大小
选择模型时,可用的训练数据量是您应该考虑的主要因素之一。
神经网络非常擅长处理和综合大量数据。KNN(K-最近邻)模型具有较少的例子,要好得多。
除了可用数据的数量之外,一个相关的考虑因素是您真正需要多少数据来实现良好的结果。有时候你可以用 100 个训练例子构建一个很棒的解决方案;有时候,你需要十万。
使用关于您的问题和数据量的信息来选择能够处理它的模型。
5.维度
从两个不同的角度来看维度是很有用的:数据集的垂直大小代表我们拥有的数据量。水平尺寸表示特征的数量。
我们已经讨论了垂直维度如何影响好模型的选择。事实证明,水平维度也是需要考虑的重要因素:更多的特性通常会让您的模型提出更好的解决方案。更多的特征也会增加模型的复杂性。
维数灾难是理解维数如何影响模型复杂性的一个很好的介绍。
正如您可能想象的那样,对于高维数据集,不是每个模型的规模都相同。当高维数据集成为问题时,我们可能还需要引入特定的降维算法。PCA 是最流行的算法之一。
6.培训时间和成本
需要多长时间,训练一个模型要花多少钱?你会选择花费 10 万美元训练的准确率 98%的模型,还是花费 1 万美元训练的准确率 97%的模型?
当然,这个问题的答案取决于你的个人情况。
需要近实时整合新知识的模型无法承受长的训练周期。例如,需要随着每个用户的动作不断更新的推荐系统受益于廉价的训练周期。
设计可扩展的解决方案时,平衡时间、成本和性能至关重要。
7.推理时间
运行一个模型并做出预测需要多长时间?
想象一个自动驾驶系统:它需要实时做出决策,因此任何运行时间过长的模型都无法考虑。
例如,使用 KNN 开发预测所需的大部分处理都发生在推理时间。这使得运营成本很高。然而,决策树在推理时会更轻,在训练时需要更多的时间。
结论
许多人专注于他们最喜欢的模型。通常是他们最了解的人,在他们的上一个项目中给了他们很好的结果。
但是在机器学习领域没有免费的午餐。没有一个模型适用于所有情况,尤其是当我们考虑现实生活系统的约束时。
在选择一个好的模型时,理解一些不同的考虑对于确保一个成功的项目是至关重要的。作为总结,下面是我们刚刚讨论过的列表:
- 模型的性能
- 结果的可解释性
- 模型的复杂性
- 数据集的大小
- 数据的维度
- 培训时间和成本
- 推理时间
因果关系上的一致性
原文:https://towardsdatascience.com/consistency-causally-speaking-20dd78587370?source=collection_archive---------20-----------------------
为什么“一致性”在因果推断中很重要?
照片由 xespri 在拍摄 https://www . pexels . com/photo/photo-of-head-bust-print-artwork-724994/
一致性只是说你观察到的结果正是你认为你会观察到的结果。
C ausal 推论本周成为焦点:Joshua D. Angrist 教授和 Guido W. Imbens 教授因其在该领域的开创性工作刚刚获得诺贝尔奖。
正确进行因果推理所需的关键假设之一被称为一致性。(作为一名统计学家,我经常把这称为“因果一致性”,而不是“统计一致性”——一个非常不同的概念。)
一致性只是说你观察到的结果正是你认为你会观察到的结果。或者更准确地说,“一个人在她观察到的暴露历史下的潜在结果就是她观察到的结果。”(科尔和弗兰基斯,2009 年)
例如,假设 Y 是我一个月偏头痛的次数(即“偏头痛计数”),如果我服用一种标准药物来减轻偏头痛一个月,X=0,如果我服用一种新药,X=1。如果我服用标准药物,y⁰是我的潜在偏头痛计数,而如果我服用新药,y 是我的潜在偏头痛计数。
形式上,一致性声明 Y = X y + (1-X) y⁰,其中 y 是观察到的结果,y⁰是 X=0 时的潜在结果,y 是 X=1 时的潜在结果。所以如果我设置 X=1,我观察到的结果(Y)就是我认为我会观察到的结果(Y)。如果我服用新药(X=1),我观察到的偏头痛计数(Y)正是我认为我会观察到的偏头痛计数(Y)。
你想要确定你正在测量你认为你正在测量的东西。
我有一个基本问题…
一致性公式强调了一个事实,即在任何给定的时间点,我只能观察到一个或另一个潜在的结果。这就是所谓的因果推论的基本问题。我只能在任何给定的时间观察 y⁰或 y——所以仅仅使用一个月很难判断新药是否有效果。
如果我在没有其他偏头痛诱因的特别好的一个月后决定尝试这种新药,而我的偏头痛计数已经很低了,该怎么办?这种新药似乎并不比我的标准药物有更多的帮助,所以我停止使用它,因为它更贵。
我不知道的是,在有许多其他偏头痛触发因素的糟糕几个月后,它比标准药物更有效——当我不太可能尝试新药时,因为我不能拿我的健康和生活质量冒险一个月。我放弃得太早了,因为我只看到了一个可能的结果。(每月的偏头痛计数在这里被称为混杂因素。)
当然,我可以在两个月或两个月以上的时间里尝试标准药物和新药,一个接一个地交替使用——但这是另一个故事了,其中有一个转折😉
…但一致性不是其中之一?
这可能出错的一个关键方式(即“一致性”如何被违反)是在一项普通的临床研究中,该研究被称为随机对照试验 (RCT),类似于 A/B 测试。
标准的 RCT 分析被称为意向性治疗 (ITT)。它说你必须比较每组研究参与者的结果,就像你随机分配他们一样——你“打算治疗”他们的方式。
假设你希望新药比标准药物更能降低平均偏头痛次数。你运行一个 RCT,取所有随机服用新药的人的平均偏头痛计数(X=1),并将其与所有随机服用标准药物的人的偏头痛计数(X=0)进行比较。这种比较理想地告诉你新药相对于标准药物的可能因果效应(X=1 对 X=0),通常定义为两组平均值之间的差异。
现在假设 A 医生和一群其他医生决定他们不喜欢根据研究方案他们应该实施的治疗。或者,也许病人 B 和一群其他研究参与者认为他们被分配的治疗可能没有帮助。在这两种情况下,结果都是一些病人接受了相反的治疗。这可能有很好的原因——但是这些治疗上的转变没有被记录下来。
如果你做一个 ITT 比较,你可能不知道,一些 X=1 的人实际上服用了标准药物,反之亦然。对于每一个像这样在治疗中“穿越”的人,他们的新方程实际上是 y = xy⁰+(1-x)y——违反了一致性!
这不仅仅是学术上的。如果新药确实比标准药物效果好得多,进行 ITT 分析将揭示新药(相对于标准药物)的较弱效果,因为尽管进行了随机治疗分配,但每组实际服用的药物是混合的:
- 由于一些参与者交叉,X=0 组的偏头痛计数实际上低于(即,人为地好于)应有水平,而 X=1 组的偏头痛计数实际上高于(即,人为地差于)应有水平。
- 这使得两组的偏头痛计数更加接近,从而缩小了实际测量的效果。
你可能被开错了药物剂量…[或者]你不小心一天吃了两片而不是一片。
还有一个更加平凡的违反一致性的行为。用药错误是一种临床不良事件,在这种事件中,临床医生或医疗服务提供者给患者开出了错误的药物或提供了错误的治疗。患者不依从是指患者没有按照预期服药或接受治疗。
例如,你可能被开错了治疗偏头痛的药物剂量;这是一个用药错误。或者一个朋友可能被告知如何不正确地使用医疗设备,类似于用药错误。如果你不小心一天吃了两片药,而不是遵医嘱吃了一片,那你就没有坚持治疗。
假设在一个月后你的下一次门诊,你的医生忘记了他们将剂量加倍的用药错误,或者你忘记了你吃了两片而不是一片。然后你讨论你上个月的偏头痛次数,看看新药是否有帮助。
你们两个都认为你们从预期疗法 X=1 中观察到了 y。但是,由于双倍剂量 X=2,你无意中观察到了 y——一个你们都没有预料到的潜在结果。真正的一致性公式是 Y = y I(X=2)+y I(X=1)+y⁰ I(X=0),其中 I(。)是指标功能。希望你们俩都能发现实际接受治疗的变化。这将帮助你解释正确的潜在结果。
这也发生在 RCT。在我们上面的例子中,A 医生和其他医生故意违反研究方案犯了用药错误。病人 B 和其他参与者没有坚持指定的治疗。
所以是的,知道因果一致性很重要。套用埃莉诺·j·默里教授的话(因果推理中值得信赖的声音,你应该听从),你要确保你在测量你认为你在测量的东西。
关于出版后的修改,请参见响应/评论“ 出版后的文字修改 ”。
承认
我感谢 Jennifer Weuve 教授通过这条推文激发了这些想法:
参考
- 老科尔,法国人。因果推理中的一致性陈述:定义还是假设?。流行病学。2009 年 1 月 1 日;20(1):3–5.journals . lww . com/epidem/full text/2009/01000/The _ Consistency _ Statement _ in _ Causal _ Inference _ _ a . 3 . aspx
关于作者
Eric J. Daza 博士是数字健康领域的数据科学统计学家。他获得了应用统计学硕士学位和生物统计学博士学位,在临床试验、公共卫生和行为改变研究方面拥有 18 年以上的工作经验。Daza 为用于个性化健康建议的个人内(即,n-of-1,单病例,独特的)数字健康研究开发因果推断方法。| ericjdaza.com🇺🇸🇵🇭@埃里克森 linkedin.com/in/ericjdaza|statsof1.org@ stats of@ fsbiostats
双线性上采样层的一致性
原文:https://towardsdatascience.com/consistency-of-bilinear-upsampling-layer-76458f52d817?source=collection_archive---------31-----------------------
实践教程
TensorFlow-Keras 2.5 和 Apple Core ML 的代码,通过训练和预测产生一致的结果
照片由詹姆斯·哈里逊在 Unsplash 上拍摄
介绍
深度学习狂热者中众所周知,TensorFlow 中的双线性上采样层存在像素偏移问题。通过在 TensorFlow 2.x 中为它们添加“align_corner”属性,这一问题已得到部分修复。但问题仍然存在,当通过各种版本将 TensorFlow 中的训练模型导出到另一个 DL 框架时,会导致计算流不一致。
在我的例子中,当使用 coremltools 3.4 将训练好的模型从 TensorFlow 2.5 转换为 Apple Core ML 时,具有双线性上采样层的神经网络模型显示出怪异的行为。在无数次的编码、尝试、删除-删除-删除之后,我几乎放弃了 TensorFlow 和 Core ML 之间的上采样层的一致结果。
我想在最新的 TensorFlow 2.5 中使用 Keras 进行 Windows PC 中的训练,我想使用以前的 coremltools 3.4 将训练好的模型转换为 macOS 笔记本电脑的 Core ML。这是因为 2.5 版有稳定的自动混合精度计算,也是因为我因为 macOS 中 anaconda 和 pip 的依赖错误而无法使用 TF 2.5 的 coremltools 4.x。
什么是像素偏移问题?
一些尊敬的程序员对 TensorFlow 中定义的这个(麻烦的)规范提供了很好的解释。它们对我有帮助,也许对你也有帮助:
- Oleksandr Savsunenko——tensor flow 的 tf.image.resize 如何偷走了我生命中的 60 天
- Matthijs holle mans—岩心 ML 中的上采样
- 巴特·沃伦斯基——双线性下/上采样,对齐像素网格,以及臭名昭著的 GPU 半像素偏移
待解决的问题
"coremltools 3.4 无法正确转换 TensorFlow 2.5 中的双线性上采样图层。"
这并不奇怪,只是版本不匹配其中 TensorFlow 2.5 可以对齐该层中的图像角,但 coremltools 3.4 使用原始方法,倾向于像 TensorFlow 1.x 一样移动图像。
然而,无论如何,我必须在我的 macOS 中使用 TensorFlow 从我训练过的 Keras 模型中获得一致的结果,不管它们的版本如何…
实现双线性上采样层
我只是在这里上传我的努力。它们是用于双线性上采样的 TF-Keras 和 Core ML 的自定义层。
在喀拉斯
这是一个简单的自定义层,没有任何可训练的参数。您必须实现 call() 来计算张量。我用TF . compat . v1 . image . resize _ bilinear()但是TF . compat . v1 . image . resize()会等价。注意,必须使用 align_corners=True 。您可以在 TensorFlow 中使用其他上采样或图像缩放方法。
在核心 ML 中(目标 C)
注: 我在 2021 年 7 月 2 日更新了核心 ML 实现。也请参考底部的最新内容。
在您基于 MLCustomLayer 的自定义图层类中,您必须实现encodecommandbuffer方法来激活 GPU。苹果的金属性能着色器提供了效果很好的mpscnnupsampling 双线性 ,结果似乎与 tf 的一致...上面 Keras 中使用的 image.resize_bilinear 。多亏了这个mpscnnupnupsampling bilinear,我不用自己写 METAL 代码了。
老实说,我用的是MPSImageBilinearScale,不是 MPSCNN...,起初。结果明显不稳定,出乎意料。在我的理解中,它们应该是相同的“双线性”和“上采样(=重新缩放)”,具有对齐的角,但它们不是。我猜MPs CNN……是纯双线性上采样,因为结果也与 CPU 的裸代码一致。同时模拟...可能有一些定制,以保持在重新缩放的图像好看。
额外的工作是evaluateonpuwithinputs改为使用 CPU。对于计算机无法使用或其中没有 GPU 的情况,您必须实现方法。我基于 Matthijs 的网站实现了双线性上采样代码(他的指导很有帮助)。
在转换器中(coremltools 3.4)
使用之前的 coremltools 3.4 无法将 TF-Keras 2.5 的一个训练好的模型直接 转换成核心 ML 模型 。 coremltools…convert() 或 keras…load_model() 方法不起作用。但是可以通过如下方式间接使用:
- 我从我的神经网络代码中新建了一个裸模型,该代码已用于最新的 TF-Keras 2.5 中的训练。注意,这个空模型我用的是纯 Keras 2.2.x,而不是 TF-Keras。
- 因为 pure Keras 2.2.x 和 coremltools 3.4 的版本匹配,所以裸模型可以被 coremltools 3.4 转换成核心 ML 模型。但是该模型没有经过训练的参数。
- 我用 keras_model.load_weights()将 TF-Keras 2.5 训练好的参数加载到 pure Keras 2.2.x 新建的模型中,这个效果很好,coremltools 3.4 可以从中创建一个训练好的核心 ML 模型。
最后,
我感到欣慰的是,我可以通过 TensorFlow 2.5 和 Core ML 使用 coremltools 3.4 实现双线性上采样层,保持一致的计算结果。
我希望这将对尝试这个问题的人有所帮助。
P.S .我正在为即将到来的 MacBook Pro 2021 攒钱…但是当它到来的时候呢?
更新[2021 年 7 月 2 日]
我发现了一些上面的mpscnnupsamplingb 双线性显示不一致结果的情况,即使一开始在其他情况下看起来是一致的。因此,我尝试了另一个金属性能着色器函数,mpsnresizebilinear来实现内核 ML 中的 Keras 对应函数,,并发现具有更好的结果。
下图显示了使用上述 Keras 代码,使用双线性上采样层训练的神经网络模型的分割结果。
红色区域是 CPU 代码的结果,红线是mpsnresizebilinear的结果,黄色是mpscnnupsamplingb 双线性。
并且,我为核心 ML 更新了目标 C 代码,如下所示:
用 Python 实现约束逻辑回归
原文:https://towardsdatascience.com/constrained-logistic-regression-with-python-c694fcd7a029?source=collection_archive---------15-----------------------
照片由卡罗来纳·加西亚·塔维森在 Unsplash 拍摄
如何对逻辑回归的参数应用特定的约束
逻辑回归是一个基本但流行的分类模型。尽管简单,逻辑回归是一个强大的工具,在现实世界中使用。
这种方法的主要好处也许是它的可解释性,因为它的参数/系数很容易解释。因此,通过充分理解每个特性对模型的影响,人们可以从模型中获得洞察力。
在这篇博客中,我将分享如何对逻辑回归模型应用特定的限制。换句话说,如何在每个特征系数的给定范围内构建逻辑回归。
文章的其余部分将安排如下。
- 本文中使用的数据
- 动机:为什么我们首先需要对系数应用一些约束?
- 方法:如何实现逻辑回归的具体约束
- 后果:承认这样约束的效果
在我们继续之前,请注意,本文涉及的所有代码都可以在我的 GitHub repo 这里找到。
数据
我们将使用 IBM 电信客户流失数据。这个数据是关于一个虚构的电信公司的客户流失,基于各种可能的因素。该数据根据 Apache 自由软件许可证版本 2 [ 1 ]获得许可。因此,我们可以出于任何目的使用它,修改它,并分发它[ 2 ]。
数据可以从 IBM 社区网站这里下载。
我们将执行如下几个预处理步骤:
- 通过首先移除其值包含空白的行,将列
TotalCharges
转换为 float。 - 为简单起见,删除非重复值数量大于 2 的分类列。
- 此外,删除
TotalCharges
列以防止与tenure
的多重共线性问题(验证您自己😉).
上面的代码应该会产生下面的数据片段。
图 1:预处理数据(图片由作者提供)
为了让你的生活更容易,我把干净的/处理过的数据集放在我的 GitHub 这里。
动机
假设您的任务是基于数据集构建分类模型(re:预测客户流失)。
因为你是一个出色的数据科学家,你知道逻辑回归是可用的方法之一,所以你用 sklearn 库创建了一个。
您向您的利益相关者报告以下系数,以及相关的见解(关于系数的解释)。
产生的系数:
图 2:来自 sklearn 模型的系数(图片由作者提供)
本质上,你的见解可能是这样的:
- 该模型表明
gender male, SeniorCitizen, Partner, PaperlessBilling
和MonthlyCharges
与用户流失可能性的增加相关联 - 而
Dependents, tenure,
和PhoneService
与用户流失可能性的降低相关联(这是一件好事)
但是,他们(利益相关者)向您提出了以下挑战:
“你的模型的大部分输出对我来说是有意义的。我同意
Dependents, tenure
和PhoneService
应该有负系数(减少流失的风险)。然而,根据我多年的经验和知识,我坚定地认为,有配偶(
Partner
)也应该减少流失的风险,因为逻辑类似于有家属;你需要更多的电话来联系他们,因此你不太可能流失。因此,系数不得为正(最大值为零)。"
你将如何适应这种限制?
克洛斯蒂克来救援了!
clogistic 是一个约束逻辑回归的 Python 实现,带有一个类似 scikit-learn 的 API。在引擎盖下,库使用凸优化来实现这个目标。
第一步是具体化约束。也就是说,我们指定每个特征的系数的下限和上限。为了更好的可解释性,我们将约束定义为 pandas 数据框架。
图 3:约束数据框架(作者图片)
从上面的constraint_df
,我们知道:
- 对于特征
gender, SeniorCitizen, PaperlessBilling
和MonthlyCharges
,我们不而施加任何约束,即这些特征的系数可以是任何实数(从超大负数到超大正数) - 而对于特征
Partner, Dependents, tenure
和PhoneService
,我们要求系数永远不为正(最大值为零),如上限= 0 所示。
使用这个数据框架,我们可以使用 clogistic 进行模型训练。当然,先决条件是安装这个库(如果您还没有安装的话)。如果您使用的是 Google Colab Notebook,只需运行以下命令。
!pip install clogistic
我们现在准备训练模型。clogistic 中的 LogisticRegression API 与 sklearn 中的 API 非常相似,只是我们可以在训练模型时指定一个bounds
参数,它可以适应我们希望应用的约束。
得出的系数如下所示。
图 4:来自逻辑模型的系数(图片由作者提供)
看啊!约束得到了很好的满足!现在特性Partner
有一个负系数(实际上为零)。其他三个约束特征(Dependents, tenure, PhoneService
)也保持为负。你可以满怀信心地带着这个结果回到你的利益相关者那里。
接下来,出于本教程的目的,假设约束更新如下。
Partner, Dependents, tenure, PhoneService
仍需非正- 但是现在
Dependents and PhoneService
得到下限要求;Dependents > -0.2
,PhoneService > -0.5
别着急,我们需要做的只是更新约束数据框。
图 5:更新的约束(图片由作者提供)
之后,我们做同样的训练步骤。
接下来是检索模型系数。
图 6:带更新约束的系数(图片由作者提供)
请注意,模型已经满足了更新后的约束;我们有Dependents
系数= -0.2,和PhoneService
系数= -0.5。
霍雷。🎉
设置约束的效果
需要注意的重要一点是,通过施加约束,我们基本上是在一定程度的优化(模型性能)上进行权衡,以满足约束。如下所示,随着我们添加额外的约束,我们的模型在训练数据(F1 分数)中的性能下降。
F1 score on train set for sk_logreg model is 0.5593
F1 score on train set for cl_logreg model is 0.5575
F1 score on train set for cl_logreg_rev model is 0.5513
发生这种情况是因为约束会缩小适合作为解的系数值的可行区域。结果,与没有任何约束的原始(更大的)可行区域相比,评估度量(这里是 F1 分数)将是次优的。
在你走之前
恭喜你读到这里!
在本文中,我们学习了如何构建一个对系数有特定约束的逻辑回归模型。我们使用 clogistic Python 库实现了这一点。最后,我们承认在我们的模型性能上强加这样的约束的“副作用”。
作为一个友好的提醒,整个笔记本可以在我的 GitHub repo 这里获得,对于那些喜欢 GitHub 界面的人来说。
希望这篇文章在你遇到类似需求时有所帮助!总而言之,感谢您的阅读,让我们在 LinkedIn 上与我联系吧!👋
参考
[1]https://github . com/IBM/telco-customer-churn-on-ICP 4d # license。备注:IBM 在这个 GitHub 存储库中使用数据集,IBM 是数据集的所有者。整个存储库是根据 Apache 软件许可证版本 2 许可的,因此数据集也是如此。
[2]https://en . Wikipedia . org/wiki/Apache _ License # Apache _ License _ 2.0
用自然语言处理构建生物医学知识图
原文:https://towardsdatascience.com/construct-a-biomedical-knowledge-graph-with-nlp-1f25eddc54a0?source=collection_archive---------3-----------------------
实践教程
了解如何结合 OCR、命名实体链接、关系提取和外部丰富数据库来构建生物医学知识图
我已经演示了如何从维基百科页面中创建知识图表。然而,由于这篇文章引起了很多关注,我决定探索使用 NLP 技术构建知识图有意义的其他领域。在我看来,生物医学领域是一个很好的例子,当你经常分析基因、疾病、药物、蛋白质等之间的相互作用和关系时,用图表表示数据是有意义的。
显示抗坏血酸与其他生物医学概念关系的子图范例。图片由作者提供。
在上面的可视化中,我们有抗坏血酸,也称为维生素 C,以及它与其他概念的一些关系。例如,它表明维生素 C 可以用来治疗慢性胃炎。
现在,你可以让一组领域专家为你绘制药物、疾病和其他生物医学概念之间的所有联系。但是,不幸的是,我们中没有多少人能够负担得起聘请一组医生来为我们做这项工作。在这种情况下,我们可以求助于使用 NLP 技术来自动提取这些关系。好的方面是,我们可以使用 NLP 管道来读取所有的研究论文,坏的方面是,并不是所有获得的结果都是完美的。然而,鉴于我身边没有一组科学家准备好人工提取关系,我将求助于使用 NLP 技术来构建我自己的生物医学知识图。
在这篇博文中,我将用一篇研究论文来引导你完成构建生物医学知识图谱所需的所有步骤。
https://arxiv.org/abs/2110.03526
我将使用由穆罕默德·礼萨·艾哈迈迪撰写的皮肤再生和毛发生长的组织工程论文。文章的 PDF 版本在 CC0 1.0 许可下提供。我们将通过以下步骤来构建知识图:
- 使用 OCR 阅读 PDF 文档
- 文本预处理
- 生物医学概念识别和链接
- 关系抽取
- 外部数据库丰富
在本文结束时,您将使用以下模式构建一个图。
生物医学图表。图片由作者提供。
我们将使用 Neo4j 来存储我们的图形,Neo4j 是一个图形数据库,具有带标签的属性图模型。每篇文章可以有一个或多个作者。我们将文章内容拆分成句子,并使用 NLP 提取医疗实体及其关系。我们将实体之间的关系存储为中间节点而不是关系,这可能有点违背直觉。这一决定背后的关键因素是,我们希望对从中提取关系的源文本进行审计跟踪。使用带标签的属性图模型,您不能让一个关系指向另一个关系。为此,我们将医学概念之间的联系重构为一个中间节点。这也将允许领域专家评估关系是否被正确提取。
在这个过程中,我还将演示使用构建的图来搜索和分析存储信息的应用程序。
让我们开始吧!
使用 OCR 阅读 PDF 文档
如前所述,研究论文的 PDF 版本在 CC0 1.0 许可下对公众开放,这意味着我们可以轻松地用 Python 下载它。我们将使用 pytesseract 库从 PDF 中提取文本。据我所知,pytesseract 库是 OCR 中比较流行的库之一。如果你想跟随代码示例,我已经准备了一个 Google Colab 笔记本,所以你不必自己复制粘贴代码。
文本预处理
现在我们已经有了文章内容,我们将继续从文本中删除部分标题和图描述。接下来,我们将把课文分成句子。
生物医学命名实体链接
现在是激动人心的部分。对于那些不熟悉 NLP 和命名实体识别和链接的人,让我们从一些基础知识开始。命名实体识别技术用于检测文本中的相关实体或概念。例如,在生物医学领域,我们想要识别文本中的各种基因、药物、疾病和其他概念。
生物医学概念抽取。图片由作者提供。
在这个例子中,NLP 模型识别了文本中的基因、疾病、药物、物种、突变和途径。如前所述,这个过程称为命名实体识别。命名实体识别的升级是所谓的命名实体链接。命名实体链接技术检测文本中的相关概念,并试图将它们映射到目标知识库。在生物医学领域,一些目标知识库是:
- 网
- 车壁
- OMIM
- 恩森布尔
- 以及其他等等
为什么我们要将医疗实体链接到目标知识库?主要原因是它有助于我们处理实体消歧。例如,我们不希望在图中用单独的实体表示抗坏血酸和维生素 C,因为领域专家会告诉你这是一回事。第二个原因是,通过将概念映射到目标知识库,我们可以通过从目标知识库获取关于映射概念的信息来丰富我们的图模型。如果我们再次使用抗坏血酸的例子,如果我们已经知道它的 CHEBI id,我们可以很容易地从 CHEBI 数据库中获取额外的信息。
CHEBI 网站上关于抗坏血酸的浓缩数据。网站上的所有内容都可以在 CC BY 4.0 许可下获得。图片由作者提供。
我一直在寻找一个体面的开源预培训生物医学命名实体链接有一段时间了。许多 NLP 模型只专注于提取医学概念的特定子集,如基因或疾病。更罕见的是找到一个模型,检测大多数医学概念,并将它们链接到目标知识库。幸运的是,我偶然发现了BERN【1】,一个神经生物医学实体识别和多类型规范化工具。如果我理解正确的话,它是一个微调的 BioBert 模型,集成了各种命名实体链接模型,用于将概念映射到生物医学目标知识库。不仅如此,它们还提供了一个免费的 REST 端点,因此我们不必处理让依赖项和模型工作的头痛问题。我上面使用的生物医学命名实体识别可视化是使用 BERN 模型创建的,因此我们知道它可以检测文本中的基因、疾病、药物、物种、突变和路径。
不幸的是,BERN 模型没有为所有概念分配目标知识库 id。所以我准备了一个脚本,首先查看是否为一个概念给出了一个不同的 id,如果没有,它将使用实体名称作为 id。我们还将计算句子文本的 sha256,以便在以后进行关系抽取时更容易识别特定的句子。
我检查了命名实体链接的结果,不出所料,它并不完美。例如,它没有将干细胞确定为一个医学概念。另一方面,它检测到一个名为“心脏、大脑、神经和肾脏”的单一实体。然而,在我的调查中,BERN 仍然是我能找到的最好的开源生物医学模型。
构建知识图表
在查看关系提取技术之前,我们将仅使用实体构建一个生物医学知识图,并检查可能的应用。如前所述,我准备了一个 Google Colab 笔记本,你可以用它来跟踪本文中的代码示例。为了存储我们的图表,我们将使用 Neo4j。您不必准备本地 Neo4j 环境。相反,您可以使用免费的 Neo4j 沙盒实例。
https://neo4j.com/sandbox/
在沙箱中启动空白项目,并将连接细节复制到 Colab 笔记本中。
Neo4j 沙盒连接详情。图片由作者提供。
现在,您可以在笔记本中准备 Neo4j 连接了。
我们将从将作者和文章导入图中开始。文章节点将只包含标题。
如果打开 Neo4j 浏览器,应该会看到下图。
图片由作者提供。
您可以通过执行以下 Cypher 查询来导入句子和提到的实体:
您可以执行以下 Cypher 查询来检查构建的图形:
MATCH p=(a:Article)-[:HAS_SENTENCE]->()-[:MENTIONS]->(e:Entity)
RETURN p LIMIT 25
如果您已经正确导入了数据,您应该会看到类似的可视化效果。
存储为图形的实体提取。图片由作者提供。
知识图应用
即使没有关系提取流程,我们的图也已经有几个用例了。
搜索引擎
我们可以用我们的图表作为搜索引擎。例如,您可以使用下面的 Cypher 查询来查找提到特定医疗实体的句子或文章。
MATCH (e:Entity)<-[:MENTIONS]-(s:Sentence)
WHERE e.name = "autoimmune diseases"
RETURN s.text as result
结果
图片由作者提供。
同现分析
第二种选择是共现分析。如果医疗实体出现在同一个句子或文章中,您可以定义它们之间的共现。我发现一篇文章[2]使用医学共现网络来预测医疗实体之间新的可能联系。
https://pubmed.ncbi.nlm.nih.gov/25160252/
您可以使用下面的 Cypher 查询来查找经常在同一个句子中同时出现的实体。
MATCH (e1:Entity)<-[:MENTIONS]-()-[:MENTIONS]->(e2:Entity)
WHERE id(e1) < id(e2)
RETURN e1.name as entity1,
e2.name as entity2,
count(*) as cooccurrence
ORDER BY cooccurrence
DESC LIMIT 3
结果
显然,如果我们分析成千上万或更多的文章,结果会更好。
考察作者专长
您还可以使用这个图表,通过检查作者最常写的医学实体来找到作者的专业知识。有了这些信息,你也可以建议未来的合作。
执行下面的 Cypher 查询,检查我们的作者在研究论文中提到了哪些医疗实体。
MATCH (a:Author)-[:WROTE]->()-[:HAS_SENTENCE]->()-[:MENTIONS]->(e:Entity)
RETURN a.name as author,
e.name as entity,
count(*) as count
ORDER BY count DESC
LIMIT 5
结果
关系抽取
现在我们将尝试提取医学概念之间的关系。根据我的经验,关系提取至少比命名实体提取难一个数量级。如果您不期望命名实体链接有完美的结果,那么您肯定会期望关系提取技术有一些错误。
我一直在寻找可用的生物医学关系提取模型,但没有发现任何现成的或不需要微调的模型。看起来关系抽取领域处于前沿,并且希望在未来我们会看到更多的关注。不幸的是,我不是 NLP 专家,所以我避免对自己的模型进行微调。相反,我们将使用基于论文的零触发关系提取器,探索 few rel【3】的零触发限制。虽然我不建议将这个模型投入生产,但它对于简单的演示来说已经足够好了。该模型在 HuggingFace 上可用,因此我们不必处理培训或设置模型。
使用零触发关系提取器,您可以定义您想要检测的关系。在这个例子中,我使用了关联的和交互关系。我也尝试过更具体的关系类型,如款待、原因等,但结果并不理想。
使用这个模型,您必须定义您想要检测哪对实体之间的关系。我们将使用命名实体链接的结果作为关系提取过程的输入。首先,我们找到所有提到两个或更多实体的句子,然后通过关系提取模型运行它们以提取任何联系。我还定义了一个阈值 0.85,这意味着如果一个模型预测实体之间的关联概率低于 0.85,我们将忽略该预测。
我们存储关系以及用于提取图中关系的源文本。
存储在图中的提取关系。图片由作者提供。
您可以使用以下 Cypher 查询来检查实体和源文本之间的提取关系:
MATCH (s:Entity)-[:REL]->(r:Relation)-[:REL]->(t:Entity),
(r)<-[:MENTIONS]-(st:Sentence)
RETURN s.name as source_entity,
t.name as target_entity,
r.type as type,
st.text as source_text
结果
图片由作者提供。
如前所述,我用来提取关系的 NLP 模型并不完美,由于我不是医学博士,我不知道它遗漏了多少连接。然而,它检测到的似乎是合理的。
外部数据库丰富
正如我之前提到的,我们仍然可以使用外部数据库,如 CHEBI 或 MESH 来丰富我们的图表。例如,我们的图包含一个医疗实体大疱性表皮松解症,我们还知道它的网格 id。
您可以使用以下查询检索大疱性表皮松解症的网格 id:
MATCH (e:Entity)
WHERE e.name = "Epidermolysis bullosa"
RETURN e.name as entity, e.other_ids as other_ids
您可以继续检查网格以找到可用的信息:
https://id.nlm.nih.gov/mesh/D004820.html
作者截图。数据由美国国家医学图书馆提供。
以下是 MeSH 网站上关于大疱性表皮松解症的可用信息截图。如前所述,我不是医学博士,所以我不知道在图表中模拟这些信息的最佳方式。但是,我将向您展示如何使用 apoc.load.json 过程从 MeSH REST 端点获取信息,从而在 Neo4j 中检索这些信息。然后,您可以请领域专家帮助您对这些信息进行建模。
从 MeSH REST 端点获取信息的密码查询是:
MATCH (e:Entity)
WHERE e.name = "Epidermolysis bullosa"
WITH e,
[id in e.other_ids WHERE id contains "MESH" | split(id,":")[1]][0] as meshId
CALL apoc.load.json("https://id.nlm.nih.gov/mesh/lookup/details?descriptor=" + meshId) YIELD value
RETURN value
作为机器学习数据输入的知识图
作为最后一个想法,我将快速向您介绍如何使用生物医学知识图作为机器学习工作流程的输入。近年来,在节点嵌入领域已经有了大量的研究和进展。节点嵌入模型将网络拓扑转化为嵌入空间。
版权 2017 Manan Shah,SNAP Group。图片在 https://github.com/snap-stanford/cs224w-notes的麻省理工学院许可下提供。
假设您构建了一个生物医学知识图,其中包含医学实体和概念、它们之间的关系以及来自各种医学数据库的丰富内容。您可以使用节点嵌入技术来学习节点表示,这是固定长度的向量,并将它们输入到您的机器学习工作流中。从药物再利用到药物副作用或副作用预测,各种应用都在使用这种方法。我发现一篇研究论文使用链接预测新疾病的潜在疗法【4】。
结论
生物医学领域是知识图表适用的主要例子。有许多应用程序,从简单的搜索引擎到更复杂的机器学习工作流。希望通过阅读这篇博文,你能对如何使用生物医学知识图来支持你的应用有所启发。你可以开始一个免费的 Neo4j 沙盒并从今天开始探索。
和往常一样,代码可以在 GitHub 上获得。
参考
[1]丁·金等人。“一种用于生物医学文本挖掘的神经命名实体识别和多类型规范化工具”,载于 IEEE Access ,第 7 卷,第 73729–73740 页,2019,doi:10.1109/Access。20007.686686666607
[2] Kastrin A,Rindflesch TC,Hristovski D .网状共现网络中的链接预测:初步结果。学习健康技术信息。2014;205:579–83.PMID: 25160252。
[3]塞托利,A. (2020)。探索 FewRel 的零射击极限。在第 28 届国际计算语言学会议记录(第 1447-1451 页)。国际计算语言学委员会。
[4]张(r .)、赫里斯托夫斯基(d .)、舒特(d .)、卡斯特林(a .)、菲兹曼(m .)、基利科格鲁(h .)(2021 年)。通过知识图谱完成实现新冠肺炎的药品再利用。生物医学信息学杂志,115,103696。
基于电影剧本构建矩阵互动网络
原文:https://towardsdatascience.com/construct-the-matrix-interaction-network-based-on-the-movie-script-738b4fa9b46d?source=collection_archive---------15-----------------------
结合网页抓取、OCR 和实体识别来构建和分析 Neo4j 中的矩阵交互网络
圣诞节即将来临,随之而来的是最新的《黑客帝国》电影。我想不出比对第一部《黑客帝国》电影进行网络分析更好的等到电影上映的方法了。
议程
这篇博文将介绍如何结合 web 抓取、OCR 和 NLP 技术来构建矩阵交互网络。
- 用硒刮矩阵 fandom 页面
- 使用 PyTesseract 阅读黑客帝国电影脚本 PDF
- 使用空间的基于规则的匹配器提取每个场景中的角色
- 构建并分析 Neo4j 中人物的共现网络
我已经根据《T2》哈利波特系列进行了类似的分析,这次我们将使用《黑客帝国》电影剧本。
和往常一样,我准备了一个谷歌协作笔记本,你可以用它来学习这篇文章中的例子。
用硒刮矩阵 Fandom 页面
我们将从抓取 Matrix Fandom 页面开始,获取电影中出现的角色列表。如前所述,我们将使用 Selenium 库来实现这一点。fandom 页面的内容在 CC BY 4.0 许可下可用。
第一步,我们将提取出第一部《黑客帝国》电影中出现的角色的名字和链接。
正因为可以,我们也会从人物的个人页面中提取详细信息。
在继续之前,我们将把角色信息存储到 Neo4j 中。如果你使用的是 Colab 笔记本,那么最简单的方法就是创建一个免费的 Neo4j 沙箱或者免费的 Aura 数据库实例来存储结果。
一旦你创建了沙盒或光环环境,只需将连接细节复制到笔记本中。
现在您已经定义了到 Neo4j 实例的连接,接下来您可以导入角色的信息。
为了感受我们刚刚存储在 Neo4j 数据库中的信息,我准备了以下在 Neo4j Bloom 中制作的可视化。
人物信息在 Neo4j Bloom 中的可视化。图片由作者提供。
此时此刻,数据库中没有任何连接,只有孤独和孤立的节点。如果您愿意,您可以重构一些节点属性,比如将配偶重构为一个关系。然而,我们将跳过这一部分,继续根据电影剧本构建共现网络。
使用 PyTesseract 阅读黑客帝国电影脚本 PDF
电影剧本可以在每日剧本网页上以 PDF 格式获得。虽然没有明确的许可声明,但网页上说这些脚本可用于教育目的,所以我们可以开始了。
我们将使用 PyTesseract 库将 PDF 转换成文本格式。
这个过程大约需要 15 分钟,所以你可以利用这段时间休息一下,也许还可以伸伸腿。
在进入角色提取步骤之前,我们将执行一个简单的文本清理,并按场景分割脚本。
既然我们已经预处理了文本,我们将继续识别在特定场景中出现的所有字符。既然我们已经知道粉丝收集过程中会出现哪些角色,我们将使用 SpaCy 的基于规则的匹配器来识别角色。
角色名可以以两种形式出现。首先,如果角色在说话,它的名字在文本中是大写的。第二种形式是有标题的版本,其中一个角色被其他人提到或在场景描述中提到。SpaCy 使得描述这两种模式变得非常容易。
我们还将从模式定义中省略和两个字。例如,fandom 页面包含字符甲骨文。因此,我们将跳过单词和,只搜索甲骨文模式。
下面的代码将构造 SpaCy 的 matcher 对象,用于下一步识别字符。
我们已经准备好了文本和实体匹配器。我们会对场景进行迭代,识别出里面出现的所有角色,一步到位直接把结果存入 Neo4j。
从电影脚本中提取信息并将输出存储到 Neo4j 中就是这么简单。
现在,我们将继续本博客的网络分析部分。首先,我们将评估所有没有出现在任何场景中的角色。
MATCH (n:Character) WHERE NOT (n)--()
RETURN n.name AS character
结果
12 个角色在任何一个场景中都没有被辨认出来。除了那个穿红衣服的女人,我不记得任何角色。可能她在文本中被称为红衣女子或类似的东西,所以我们的模式匹配器没有识别出她。当然,我们可以对模式进行微调,以包含这些类型的异常,但总的来说,主要角色似乎已经确定。
接下来,我们将检查在大多数场景中出现的角色。
MATCH (s:Scene)
WITH count(s) as countOfScenes
MATCH (n:Character)
WITH n.name AS character,
size((n)-[:IN_SCENE]->()) as scenes,
countOfScenes
RETURN character,
scenes,
round(toFloat(scenes) / countOfScenes * 100, 2) AS scenePercentage
ORDER BY scenes DESC
LIMIT 5
结果
这里没什么令人震惊的。尼欧出现在超过一半的场景中,其次是墨菲斯和崔妮蒂。只有埃米尔·埃夫林出人意料地从这份名单中消失了。
我们可以将同现事件定义为出现在同一场景中的一对人物。在这种情况下,共现也可以理解为一种相互作用。角色阿朵出现的场景越多,他们在电影中的互动就越多。
我们可以通过执行下面的 Cypher 语句来评估哪些角色交互最多。
MATCH (n1:Character)-[:IN_SCENE]->()<-[:IN_SCENE]-(n2:Character)
WHERE id(n1) < id(n2)
RETURN n1.name AS character1,
n2.name AS character2,
count(*) AS count
ORDER BY count DESC
LIMIT 5
结果
大多数互动发生在尼奥、墨菲斯、三一和坦克之间。如果你看过这部电影,这一切都是有道理的。
最后,我们可以推断出字符之间的共现网络,并对其进行网络分析。我们将简单地计算一对角色之间的交互次数,并将信息存储为一个关系。
MATCH (n1:Character)-[:IN_SCENE]->()<-[:IN_SCENE]-(n2:Character)
WHERE id(n1) < id(n2)
WITH n1, n2, count(*) AS count
MERGE p=(n1)-[r:INTERACTS]-(n2)
SET r.weight = count
RETURN p
结果
矩阵共生网络。图片由作者提供。
图形数据科学图书馆
Neo4j 具有一个图形数据科学库,其中有 50 多种图形算法,包括中心性、社区检测和节点嵌入类别。
我们将使用 PageRank 来评估节点重要性,使用 Louvain 来确定推断的共现网络的社区结构。我们不是分别检查每个算法结果,而是存储结果,并构建一个网络可视化,以可视化节点重要性和社区结构。
首先,我们必须投影内存中的图形,以便能够在其上执行图形算法。请注意,我们将共现关系投影为无向关系。例如,如果 Neo 与 Trinity 互动,这直接暗示 Trinity 也与 Neo 互动。
CALL gds.graph.create("matrix", "Character",
{INTERACTS: {orientation:"UNDIRECTED", properties:"weight"}})
现在我们可以继续执行加权 PageRank 算法,并将结果存储回 Neo4j。
CALL gds.pageRank.write("matrix", {relationshipWeightProperty:"weight", writeProperty:"pagerank"})
最后,我们执行加权 Louvain 算法来推断社区结构,并将结果存储在数据库中。
CALL gds.louvain.write("matrix", {relationshipWeightProperty:"weight", writeProperty:"louvain"})
您可以使用 Neo4j Bloom 生成一个网络可视化,根据社区 id 为节点着色,并根据其 PageRank 得分计算节点大小。
查看官方文档了解如何在 Neo4j Bloom 中开发基于规则的可视化。
矩阵共生网络的网络可视化。节点的大小基于它们的 Pagerank 分数,颜色基于它们的社区。图片由作者提供。
结果比我预期的要好。黄色团体是尼布甲尼撒帮,尼欧、崔妮蒂和墨菲斯是最重要的成员。紫色社区由母体代理人组成,他们是尼布甲尼撒团伙的敌人。我们必须引入某种时间线来观察塞弗是如何从一个好人变成倒戈加入黑暗面的。最后,橙色社区由神谕、女祭司和勺子男孩组成,他们帮助尼奥超越了现实。
结论
我希望我们都同意,使用简单的假设作为共现交互可以产生令人难以置信的结果,可以帮助解释单一网络可视化中潜在的 150 页 PDF。所以今天就打开 Neo4j 沙盒自己试试吧。如果你在数据管道中发现任何能产生更好或更准确结果的调整,请告诉我。
节日快乐!
和往常一样,代码可以在 GitHub 上获得。
用 Docker 容器化你的应用程序
原文:https://towardsdatascience.com/containerize-your-application-with-docker-b0608557441f?source=collection_archive---------6-----------------------
在虚拟化操作系统上运行您的应用。
托德·克雷文在 Unsplash 上的照片
动机
假设您想将一个应用程序部署到服务器上。在您的本地系统中,应用程序运行良好,没有任何问题。但是一旦你将应用程序部署到服务器上,嘣!你的应用程序不工作。
许多因素都会导致这种情况。这可能是操作系统兼容性或不同的库版本。因此,您的应用程序永远不会被部署,您会因此而感到头疼。
怎么才能去除仅仅因为不兼容问题而头疼的问题?码头工人来救你了!
本文将向您展示如何使用 Docker 来封装您的应用程序,以便您可以在任何服务器上运行它们,而不管它们内部的操作系统是什么。没有进一步,让我们开始吧!
Docker 是什么?
在我们进入实现之前,让我向您解释一下 Docker。Docker 是一个部署应用程序的平台。它的工作原理是将应用程序隔离到一个映像中。该映像将由一个容器运行,其中包含操作系统和支持软件。
由于这种隔离,我们不必担心软件安装及其版本。您可以通过容器运行应用程序,而不管计算机中的操作系统和软件如何。因此,您可以专注于开发您的应用程序并直接部署它们。
履行
在你理解了 Docker 的概念之后,现在让我们进入实现。我们将执行几个步骤:
- 安装 Docker
- 创建名为 Dockerfile 的文件
- 建立形象
- 运行图像
安装 Docker
我们可以做的第一步是安装 docker 应用程序。你可以在这里下载 DockerT5并确保根据你的操作系统选择正确的。
安装 Docker 后,现在让我们测试 Docker 是否已经安装在您的计算机上。您可以运行命令“docker ”,如下图所示:
如果你的电脑显示如上提示,我们可以向你保证 Docker 已经安装在你的电脑上。现在让我们进入下一步。
创建 Dockerfile 文件
安装 Docker 后,下一步是创建一个名为 Dockerfile 的文件。Dockerfile 是一个用于构建 docker 映像的脚本。它包含了从安装库到运行我们的项目的设置映像的指令。
在本例中,我创建了一个基于 Flask 库的 API。这个 API 将被用作用户和机器学习模型之间的连接器,以返回预测结果。下面是 API 的代码:
要创建 docker 文件,请确保该文件与您的应用程序和机器学习模型文件夹位于同一位置。在我的例子中,文件夹位置如下所示:
**| app.py
| Dockerfile
| requirements.txt
|
+---resnet50_food_model
| | saved_model.pb
| |
| +---assets
| +---variables
| variables.data-00000-of-00001
| variables.index**
在该文件夹中,我们有用于运行我的应用程序的 app.py ,包含我们将使用的包列表的 requirements.txt,包含预训练模型的模型文件夹,以及用于构建 docker 映像的 docker 文件。
请记住,在创建 docker 文件时,请确保不要在文件名后添加任何扩展名。您只能写“Dockerfile”。
现在让我们编写 Dockerfile 脚本。以下是 Dockerfile 文件中的脚本:
让我解释一下脚本的每一行:
“FROM”指令将从 docker 注册表中获取 docker 映像。该映像将包含操作系统和 Python。
“WORKDIR”指令将设置我们将用来运行应用程序的默认工作目录。
“复制”指令会将当前目录中的每个文件复制到新的工作目录中。
“运行”指令将运行一个命令。在这种情况下,是“pip install”命令。
“EXPOSE”指令会将端口 5000 作为连接器暴露给 docker 映像。
最后,“CMD”指令将运行一个命令。在这种情况下,“烧瓶运行”命令。
旁注:
‘CMD’指令和‘RUN’指令有相同的功能,但是它们的用途不同。“CMD”指令用于在开始运行 docker 映像时运行命令。
同时,“RUN”指令用于在构建 docker 映像时运行命令。
建立 docker 形象
创建 docker 映像后,下一步是构建映像。要建立形象,真的很简单。你需要做的就是像这样运行“docker build”命令:
**docker build -t my-image .**
正如你在上面看到的,我在“docker build”命令旁边加上了“-t”标记。'-t '标记有两个参数。它们是图像名称和点字符,代表文件夹中的所有文件。
这是我们在构建 docker 映像时的预览(这将需要很长时间,所以请耐心等待) :
让我们运行“docker images”命令来显示已经构建的现有图像。以下是结果预览:
运行 docker 映像
从上面可以看到,图像已经存在。现在下一步是在我们的计算机上运行 docker 映像。要运行映像,您可以像这样使用命令“docker run ”,
**docker run -dp 5000:5000 my-image**
让我们等一会儿,等 3 到 5 分钟。要知道我们的映像是否已经在运行,我们可以使用' docker ps -a '命令来检查所有正在运行的映像。以下是预览:
正如你从上面看到的,图像已经上升了大约一分钟。这意味着映像已经在端口 5000 上运行。现在让我们使用 localhost:5000 或 127.0.0.1:5000 来访问映像。以下是预览:
正如您从上面看到的,我们的容器已经在我们的计算机上成功运行了。因为设置了'-d '参数,所以不能显示容器的日志。
要检查容器上的活动,可以使用“docker 日志”来完成。另外,请在旁边设置容器 id。您可以从“docker ps -a”命令中看到容器 id。该命令如下所示:
**docker logs bff6d3c8e2da**
下面是日志预览的样子:
如果你想停止容器,你可以使用' docker kill '命令,并在旁边设置容器 id。以下是停止 docker 命令的命令:
**docker kill bff6d3c8e2da**
停止容器后,它看起来像这样,
是的,我们的集装箱已经终止了。
结束语
干得好!您已经学习了如何将您的应用程序容器化为 docker 映像。我希望这篇文章能帮助你在你的项目中建立自己的 docker 形象。
如果你对这篇文章感兴趣,你可以关注我在媒体上的文章。如果你有任何问题或者想和我打招呼,你可以在 LinkedIn 上和我联系。
谢谢你看我的文章!
参考
[1]https://docs.docker.com/
【2】https://nickjanetakis . com/blog/docker-tip-7-the-difference-between-run-and-cmd
通过 AWS 上的 Docker 和 FastAPI 实现 GPU 推理的容器化 Huggingface 转换器
原文:https://towardsdatascience.com/containerizing-huggingface-transformers-for-gpu-inference-with-docker-and-fastapi-on-aws-d4a83edede2f?source=collection_archive---------18-----------------------
为 GPU 上的总结任务创建 docker 容器
图片由作者使用来自 Canva.com 的免费图片
在 docker 容器中使用 GPU 并不简单。容器和主机上的 CUDA 和 CuDNN 驱动程序之间不应该有任何不匹配,以实现无缝通信。
理想的方法是在您的 docker 中使用NVIDIA container toolkit image,它支持自动识别您的基本机器上的 GPU 驱动程序,并在 Docker 容器运行时将这些相同的驱动程序传递到您的 Docker 容器。在 roboflow 团队的这篇精彩文章中,你可以读到更多关于在 GPU 中使用 Docker 的内容。
在本文中,我们将看到如何使用 Docker 和 FastAPI 将来自 HuggingFace transformers 的摘要算法封装成用于 GPU 推理的容器,并将其部署在一台 AWS EC2 机器上。如果您想要更多的可伸缩性,您可以使用相同的 docker 容器来部署容器编排服务,如 AWS 提供的 ECS 。
Youtube 视频
如果你想看视频,这里有-
https://www.youtube.com/watch?v=I3kkQVNuXyc
汇总代码
首先,我们将使用 HuggingFace transformers 为摘要器编写代码。你可以看看这个 Colab 笔记本 自己运行一下看看总结。
总结的基本代码如下所示:
上述代码的输出是我们传递给它的文本的摘要-
**Elon Musk has shown again he can influence the digital currency market with just his tweets. The SpaceX CEO has in recent months often tweeted in support of Dogecoin, but rarely for Bitcoin. In a recent tweet, Musk put out a statement from Tesla that it was concerned about the rapidly increasing use of fossil fuels. A day later he again tweeted saying, To be clear, I strongly believe in crypto but it can't drive a massive increase in fossil fuel use, especially coal. Following the two distinct statements from him, the world's largest cryptocurrency hit a two-month low.**
现在,我们将看到在 AWS EC2 机器上将它作为 API 进行封装和部署的步骤。
集装箱化代码
在这个 Github repo 中提供了为上述摘要算法创建 GPU docker 容器所需的所有代码。
启动 AWS EC2 GPU 机器来服务 API
我们将从基础 AMI 映像(深度学习基础 AMI (Ubuntu 18.04)版本 42.0)启动一台 EC2 GPU 机器(g4dn.xlarge),创建 docker 映像,并运行该映像以在同一台机器上提供用于摘要的 API。
步骤 1: 登录 AWS 控制台,进入 EC2 仪表板。
步骤 2: 进入仪表板后,点击右上角的“启动实例”。
第三步:现在我们被要求选择一个 AMI。在搜索栏输入“深度学习基础 AMI”。我们没有自己安装 CUDA、CuDNN 和 Docker(这很难),而是选择亚马逊机器映像(AMI ),它已经为我们预装了所有东西。
从返回的选项中选择“深度学习基础 AMI (Ubuntu 18.04)版本 42.0”。您可以相应地选择任何更新的映像,与我们 docker 文件中提到的基础映像中使用的 CUDA 和 CuDNN 库版本相匹配。
来自作者 AWS 帐户的快照
步骤 4: 在下一个屏幕中选择实例类型。选择“g4dn”并从选项中选择 g4dn.xlarge 并继续。请注意,如果您以前没有使用过此 GPU,您需要在 AWS 中提出限额增加请求,以将此 GPU 分配到您的帐户所在区域。
为什么是 G4 实例类型?这是可用的 AWS 实例中最具成本效益的选项。点击阅读更多关于在 AWS 上选择合适 GPU 的信息。
然后单击“配置实例详细信息”
来自作者 AWS 帐户的快照
第 5 步:保留所有默认设置,然后单击“添加存储”。在“添加存储”部分,记住将根卷大小更改为 120 (GiB)等。我们需要这样做,因为我们的 docker 图像和其他必要的配置需要大量的空间。
来自作者 AWS 帐户的快照
第 6 步:接下来点击“添加标签”。这里没什么可改变的。
接下来点击“配置安全组”并点击“添加规则”来添加端口 80 的自定义 TCP,其来源可以来自任何地方。这将使我们能够在默认端口 80 上托管 API,并从任何地方访问 API。
来自作者 AWS 帐户的快照
第 7 步:接下来点击“审核并启动”,点击“启动”。创建“新的密钥对”或使用现有的密钥对。这用于 SSH,如果您在 Windows 上或从命令行,可以通过 Putty 等工具连接到 EC2 机器。
来自作者 AWS 帐户的快照
步骤 8: 一旦 EC2 机器准备就绪,您就可以通过任何 SSH 客户端连接到它。
来自作者 AWS 帐户的快照
步骤 9: 一旦你通过 SSH 进入 EC2 机器,运行“git clonehttps://github . com/ramsrigouthamg/GPU _ Docker _ Deployment _ HuggingFace _ summary . git”来克隆包含 Docker 文件的存储库,以将来自 hugging face 的摘要算法容器化。
第十步: CD 到“GPU _ Docker _ Deployment _ hugging face _ summary”文件夹,依次运行以下命令。
**pip3 install transformers==4.6.1
pip3 install torch==1.9.0
python3 download_HF_Question_Generation_summarization.py**
我们从 HuggingFace 本地下载摘要模型,并将其打包在 docker 容器中,而不是每次下载时都将代码放在容器中。
步骤 11: 完成上一步后,使用以下命令构建 docker 映像
**docker build -t summarization .**
建立映像需要一些时间,所以请耐心等待。
第 12 步:一旦构建了映像,使用以下命令运行容器—
**docker run -p 80:80 --gpus all summarization**
一旦一切准备就绪,只需在浏览器中访问 EC2 机器的基本 URL,您应该会看到一条“hello world”消息。
ec2–18–189–32–8.us-east-2.compute.amazonaws.com
接下来,通过像 Postman 这样的工具测试摘要 API。您可以传入任何文本,并获得它的摘要版本。记住传递文本以及最小 _ 长度和最大 _ 长度参数。
作者快照
如果您想无限期地运行 API,请使用控制台应用程序,如 Screen ,这样即使您关闭连接,API 也会继续运行。
创建 GPU Docker 的代码
将我们在开头展示的 Colab 笔记本转换成由 FastAPI 托管的 API 的主要代码如下所示
用于从基础 Nvidia 映像创建 GPU docker 的 docker 文件如下所示
**FROM nvidia/cuda:11.0-cudnn8-runtime-ubuntu18.04****#set up environment
RUN apt-get update && apt-get install --no-install-recommends --no-install-suggests -y curl
RUN apt-get install unzip
RUN apt-get -y install python3
RUN apt-get -y install python3-pip****# Copy our application code
WORKDIR /var/app****# . Here means current directory.
COPY . .****RUN pip3 install --no-cache-dir -r requirements.txt****ENV LC_ALL=C.UTF-8
ENV LANG=C.UTF-8****EXPOSE 80****# Start the app
CMD ["gunicorn", "-b", "0.0.0.0:80","app:app","--workers","1","-k","uvicorn.workers.UvicornWorker"]**
这是 requirements.txt 文件
**pydantic==1.8.2
uvicorn==0.14.0
gunicorn==20.0.4
fastapi==0.67.0
torch==1.9.0
sentencepiece==0.1.82
transformers==4.6.1**
点记:
如果您想要确定,请确保您创建的 docker 映像(NVIDIA container toolkit 基本映像)中的驱动程序(CUDA 和 CuDNN 版本)与运行容器映像的主机中的 GPU 驱动程序匹配(或兼容)。在 AWS 中,您可以选择一台主机作为 AMI,它与您用来创建 docker 映像的 NVIDIA container toolkit 映像兼容(请记住在您的 docker 文件中使用 NVIDIA/cuda:11.0-cud nn8-runtime-Ubuntu 18.04)。
您可以使用 GPU 兼容的 Amazon 机器映像(AMI)作为主机映像,在 ECS 等容器编排服务上可伸缩地部署 API
祝 NLP 探索愉快,如果你喜欢它的内容,请随时在 Twitter 上找到我。
如果你想学习使用变形金刚的现代自然语言处理,看看我的课程使用自然语言处理的问题生成
上下文管理器;Python 开发人员的最佳经理
原文:https://towardsdatascience.com/context-managers-the-best-managers-for-python-developers-a5809fb7e428?source=collection_archive---------10-----------------------
如何避免不关灯
亚历山大·奈特在 Unsplash 上拍照
介绍
你有没有饿着肚子去厨房,打开冰箱,拿出好吃的东西,又因为饿得忘记关冰箱?或者你有没有在晚上回到家,你的一些灯还亮着?我想我们都知道这种情况。
那么,当标题说我们要讨论 Python 时,我为什么要告诉你呢?作为一名数据科学家或机器学习从业者,你为什么会关心这个问题?原因是你会经常面临这样的情况。例如,当您连接到一个数据库以获取有价值的数据时,却忘记了关闭连接。或者假设您正在设置一个巨大的计算集群来训练您的模型,当您完成后,您让它继续运行。这些东西可能会变得非常昂贵,让你的经理或公司烦恼。
这让我想起了我们现实生活中忘记关冰箱或忘记开灯的情况。我们忘记做家务了!软件的不同之处在于,我们不会亲自回来,并有第二次机会来收拾残局。因此,后果可能会更加严重,比如系统变慢,甚至完全崩溃。最糟糕的是,这种情况可能发生在程序内部的任何地方,不一定靠近造成混乱的代码。这很难找到和调试。
那么在 Python 中我们能做些什么来避免遇到这些情况并且永远不要忘记清理资源呢?
使用上下文管理器!
在本文中,我将向您介绍上下文管理器以及如何用 Python 编写自己的上下文管理器。一旦你知道并应用它们,你将永远不会忘记做家务,因为它是自动为你做的。这当然只适用于代码,对提到的实际情况没有帮助😃你准备好了吗?我们开始吧!
上下文管理器
基本概念
管理资源是编程的一个重要部分,但我们有时容易忘记。资源是任何数量有限的可用资源。例子包括文件句柄、网络套接字或锁,仅举几例。对于这些资源来说,确保在你获得它们之后释放它们是至关重要的。如果它们没有被释放,您就有一个资源泄漏,您的系统可能会变慢或崩溃。
除了管理资源之外,在其他情况下,您也应该执行最后的清理操作。例如,关闭与获取数据的数据库的连接,向 Kafka 提交偏移量,或者在扩大计算资源后缩小计算资源。后一种方法可以真正节省成本,尤其是在讨论用于模型训练的大规模计算集群时。
总的来说,有一个我们正在寻找的属于下列行动的一般模式
Open
-Close
Lock
-Release
Change
-Reset
Enter
-Exit
Start
-Stop
Setup
-Teardonw
每当你发现自己处于这种情况时,上下文管理器将是你最好的朋友。这有助于你的程序始终处于良好状态。如果你使用它们,你不会忘记做家务,也不会意外地在失败的情况下不做家务。最后,当您应用上下文管理器时,您的代码也处于可读性更强、重复性更低的状态。
说得够多了,让我们在下一节看看如何在代码中使用上下文管理器。
如何使用 Python 上下文管理器
在我的工作中,我做过许多与 Python 相关的采访。在那里,我几乎总是问人们:“什么是上下文管理器?”。有趣的是,大多数受访者表示他们从未听说过这个术语。然而,如果我给他们看一个例子,他们都会说
照片由 Afif Kusuma 在 Unsplash 上拍摄
“那是上下文管理器吗?我经常用!”。我也想在这里和你做同样的事。这是一个例子
你是不是像“啊”一样走了?我想不是因为你已经知道什么是上下文管理器。如果没有,没问题,让我们快速消化我们在这里做的事情。
在本例中,open
是上下文管理器。[**with**](https://www.python.org/dev/peps/pep-0343/)
语句确保上下文管理器执行其打开和关闭动作。在这里,上下文管理器打开给定的文件something.json,
,并返回相应的文件处理程序。我们可以使用**as**
语句将上下文管理器的返回值赋给一个变量。当我们退出**with**
块时,上下文管理器确保所有东西都被清理了,即使在失败的情况下。很甜蜜,不是吗?
现在,如何编写上下文管理器呢?让我们在最后一节检查一下。
如何编写上下文管理器
在了解了如何使用上下文管理器之后,让我们更深入一层,看看如何编写上下文管理器。原则上,你要做的就是写一个类,并简单地实现两个 magic 或 dunder 函数__enter__
来设置一切,以及__exit__
来清理混乱。我认为最好的做法是__enter__
返回 self,这样您就可以将创建的对象赋给as
子句中的一个变量,并在以后使用它。
如果您正在使用现代 Python,并且希望在设置或拆除时进行一些异步调用,您必须编写一个异步上下文管理器。幸运的是,这几乎和同步调用一样简单。你只需要实现两个异步函数__aenter__
和__aexit__
。最后一点,要调用异步上下文管理器,只需调用async with YourManager() as a:
。很简单,不是吗?
现在,这是编写上下文管理器的正确方式。但是如果 Python 不能提供更多的语法糖来帮助以同步和异步方式编写上下文管理器,它就不是 Python 了。你所要做的就是写一个函数并使用一个装饰器。听起来很酷,不是吗?让我们看看这在代码中是怎样的
在这里,我以同步和异步方式创建了一个名为training_cluster
的上下文管理器。这个上下文管理器旋转一个假设的训练集群,并确保它在被使用后被关闭。要实现这一点,你只需要在某个时候写一个函数yield
,并用来自令人敬畏的 Python 内置 contextlib 模块的contextmanager
或acontextmanager
来修饰它。现在,您可以将它与两个训练功能中所示的with
和async with
关键字一起使用。完成了。就这么简单。
我喜欢这种方法的一点是,发生了什么非常清楚。在yield
之前的一切都是安装部分,之后的一切都是拆卸部分。为了确保拆除总是发生,你必须把它放到一个finally
块中。顺便提一下,如果您希望您的上下文管理器不返回任何内容,只需使用没有任何返回值的yield
。
最后,这种方法的另一个优点是,您可以轻松地为第三方类提供上下文管理器,而不必继承它们。这同样有助于编写清晰漂亮的代码。
照片由 Tim Mossholder 在 Unsplash 上拍摄
包裹
在本文中,我已经向您展示了 Python 中的上下文管理器及其用途。此外,我还为您提供了同步和异步上下文管理器的示例实现和用法。我希望你同意使用这个既超级有用,同时又非常简单。老实说,自动完成家务就像梦想成真一样😃
感谢您关注这篇文章。一如既往,如有任何问题、意见或建议,请随时联系我或关注我,无论是在这里还是通过 LinkedIn 。
背景很重要:为什么人工智能(仍然)不擅长做决定
原文:https://towardsdatascience.com/context-matters-why-ai-is-still-bad-at-making-decisions-975f2f797da7?source=collection_archive---------20-----------------------
意见
人工智能还不够聪明,不符合道德规范(尽管它足够聪明,可以收集你的大量数据),但这里有一个想法可能会让它朝着正确的方向发展。
这里有一个假设。
一个男人和一个女人住在一起。
那人每次说话都不耐烦,在你没听懂他的问题时大声咒骂你。他粗暴得近乎生气,只在深夜和你说话,只问关于夜总会和酒吧的事。
这位女士每次说话,要么流着泪,要么声音单调。她的问题更多地与家务相关——食谱、购物提醒、财务问题。她整天和你聊天,经常问心理健康问题。她过去的搜索查询甚至包括有关家庭暴力求助热线的信息。
一天早上,凌晨 3:00,在那个人向你问路去最近的酒吧 5 个小时后,他问你最近的枪支商店在哪里。
想象你是这些人的朋友。你会怎么说?
现在想象一下,男人和女人不是在和你说话,而是在和一个支持亚马逊 Alexa 的设备说话。你认为 Alexa 会说什么?
很有可能,你的两个答案截然不同——因为人工智能仍然没有足够的智能在这些类型的情况下做出合乎道德的行为。
伦理人工智能是难以想象的。
人工智能中的伦理如此困难的众多原因之一是,没有人能够就什么是普遍伦理或道德达成一致。(目前)我们能做的最好的事情是基于边缘案例或思想实验定义一个设计框架,就像上面展示的那样。我想说的是,Alexa 知道正在发生什么——有大量信息表明这个男人对女人来说是一个危险——但人工智能世界对 Alexa 应该做什么没有达成共识。粗略搜索一下伦理框架,你可能会找到一些术语,比如价值伦理(良好的品格定义了你的行为)道义论(你的职责定义了你的行为),或者结果主义(结果证明了你的行为),但在我看来,理想的设计要简单得多。语境意识。
“亚历克斯——嗯?”阿比纳夫·拉古纳坦。
有上下文意识的人工智能更好。
在任何真实的人类对话中,语境就是一切。背景是你不在葬礼上讲笑话或在生日聚会上谈论死亡的原因。为什么技术不能利用环境的力量做出更明智、更道德的决定呢?
在上面的场景中,Alexa 知道的事情(语音语调、音调、搜索历史等。)都是亚马逊收集或者已经可以收集的数据片段。他们利用这些信息来判断你是谁,以便更智能地推动他们的电子商务和广告。除此之外,他们还可以推动这种情境优先的方法做出道德决策。当人工智能能够收集数据,筛选可能的场景,并潜在地防止负面后果(无论这可能需要什么)时,会有更大的力量。
自然,这说起来容易做起来难。我列出的场景没有完美的答案,但是不考虑上下文就回答这个人的问题本身就是一个错误。也许 Alexa 提供了答案,但也通知警方作为预防措施。也许 Alexa 拒绝回答。当然,这个人可以稍后再用谷歌搜索,但是迫在眉睫的暴力不应该被激活或者让 T2 变得更容易。
我的观点很简单:
人工智能永远不应该在存在可访问的上下文信息时盲目行动。
这甚至适用于像机器学习这样的人工智能子集。数据集中总是有上下文的,无视这种上下文的算法根本不能被认为是可用的。这种情况可能包括数据偏差,如种族/性别代表性不足,或与犯罪记录或教育背景等有缺陷的来源有关。
我说这种方法绝对更好,因为如果从上下文中似乎没有任何可辨别、可学习的特征,它可以被忽略,AI 可以像正常情况下一样继续进行。如果 Alexa 确信给定的问题与上下文没有相关性或联系,它可以安全地回答该问题。
Abhinav Raghunathan 的《语境盲》。
背景是价值驱动因素。
上下文优先的人工智能为价值主张增加了额外的维度。就个人而言,如果我知道我的 Alexa 会在特定的情况和背景下做出合乎道德的故意反应,我可能会更愿意自愿提供我的数据。如果我看到它在工作,我甚至会更信任亚马逊的数据(即使他们仍然在后台执行他们不太值得信任的做法)。
如果你是一家数据公司,你的算法在提取见解之前考虑了数据集中的种族或性别背景,那就是增值。
如果你是一家机器人公司,你的机器人在行动之前会考虑社会背景,这就是一种增值。
如果你是一家支持语音的人工智能公司,并且你的产品在谈论枪支或毒品之前考虑到了你家里有小孩的事实,那就是增值。
具有上下文意识的人工智能很可怕,但却是必要的。
不可否认,让人工智能更多地了解你可能看起来令人毛骨悚然。也许是因为我的建议是,人工智能在判断情况和做出反应的能力上更像人类。不幸的是,我们在日常生活中越来越依赖技术要求这项技术的行为符合道德规范,不会危及或负面影响我们。我们也有一种“与机器建立友谊甚至亲密关系”的心理倾向[1]。如果这还不可怕,那就没什么可怕的了。这正是为什么我们需要更聪明、更有道德的人工智能。
从法律责任的角度来看,公司可能会担心。如果像谷歌、苹果和亚马逊这样的公司还没有通过 不断监听 你的每一次谈话来让自己成为见证人的话,这就说得通了。上下文意识的目的是以更聪明的方式使用这个“特性”。他们已经在收集所有这些数据,为什么不明智地使用这些数据呢?
它的美妙之处在于它是一份保险:大多数时候,没有特别麻烦的上下文。然而,如果环境需要,人工智能应该准备好做出相应的响应。
Abhinav Raghunathan 的“环境意识框架”。
我们需要实现上下文相关的框架。
在一个日益互联的世界里,功能性已经不够了。仅仅能够回答“最近的枪支商店在哪里”这个问题是不够的背景很重要。道德很重要。
环境意识就是认识到所有的技术都积极地影响着人们的生活方式——而这些人不会生活在泡沫中。因为人工智能已经发展出了超越功能的力量,所以设计和工程团队有责任构建理解和尊重环境的人工智能。无论是数据集中的隐藏背景还是机器人的社会背景。
我们需要让技术做它最擅长的事情并改变生活,但要为它提供环境意识,以确保它以积极的方式这样做。
参考
[1] C. Bartneck 等人,机器人学与人工智能中的伦理学导论,伦理学中的 SpringerBriefs,https://doi.org/10.1007/978-3-030-51110-4_7。
[2]原帖可以在这里找到。
语境理论 II:语义框架
原文:https://towardsdatascience.com/context-theory-ii-semantic-frames-f96693480779?source=collection_archive---------35-----------------------
对话管理的语义框架
在语境理论系列的前几篇文章中,首先我们发现了一些与语境相关的语言学概念。接下来,我们一头扎进对话结构;是什么让谈话变得有意义和连贯。在本文中,我们将关注一种结构化的对话管理方式,称为语义框架。顾名思义,语义框架是对话的单元,它们捕捉所有必要的信息来解析上下文。语义框架概念捕获了槽填充、共指解决、上下文相关的意图分类、解决错误路径以及分类/控制域切换的概念。
语义框架的诞生是为了给对话管理带来结构。我们先快速了解一下我们的 Chris,了解一下语义框架概念。
我们的克里斯
我们的克里斯是司机助理,由德国 Autolabs 打造。
用户在开车时与克里斯在车里交谈,因此话语通常简洁而中肯。以下是克里斯话语的一些例子:
Hey Chris, navigate
Play music
Send a message
Start the navigation
Make a call
结果,诸如导航目的地、消息的接收者姓名、要呼叫的联系人或要播放的艺术家的一些信息通常不在单个话语中提供。Chris 会跟进以填补所需的空缺。这是一个非常典型的对话片段:
User: Hey Chris make a call
Chris: OK, who do you want to call?
User: Alicia
Chris: Do you mean Alicia A?
User: Yes
Chris: Shall I call Alicia A on her mobile?
User: No, home
Chris: OK, I'm calling Alicia A on her home number.
虽然不太常见,但包含所有填充位置的话语也来自客户。我们称之为“一次性”话语。下面是上面的对话片段撞成的一句话:
Call Alicia on her home number
在语音助手中,通常有两种方式来设计和训练对话式 NLU;第一种方式是端到端对话管理,它输入话语并产生动作/响应。没有诸如 ASR(语音识别)输出或意图概率的中间步骤。这些系统很好,不需要单独处理 ASR 和 NLU 组件培训。此外,您不需要处理来自 ASR 组件的不良/噪声输出,不需要在 NLU 步骤中模拟噪声或无意义的 ASR 转录。
第二种方法显然是分别进行语音识别和 NLU。然后,人们可以明确地检查 ASR 转录,还可以看到每个步骤的输出,如意图分类和实体提取。克里斯会话 NLU 属于这一类。以下是对克里斯对话式 NLU 设计的高度描述:
克里斯对话 NLU 设计
每个话语首先访问语音引擎,然后变成文本。接下来,话语文本被提供给对话管理器进行识别和解析。然后触发一个响应和可能的系统动作,例如,在上面的对话片段中,当用户说出“不,家”时,Chris 用“好的,我正在用 Alicia A 家的号码呼叫她。”然后开始和艾丽西娅打电话。
正如我们所说,克里斯首先转录的演讲。车内环境非常嘈杂,因此处理噪音和可能的误解对克里斯 NLU 来说是一个挑战。语义框架就是这样诞生的。
上下文建模
典型的 Chris 对话以用户请求开始,然后是填充空位的话语。下面是一个对话示例:
User: Send a message
Chris: Who do you want to message?
User: Patrick
Chris: What do you want to say?
User: Hello Patrick, I'm on my way.
看看这个一次性的话语:
Send a message to Patrick saying hello
虽然,第一个对话片段实际上是 5 个话语的对话,而第二个句子只有一个话语,但语义上它们是等价的。最后,您知道收件人姓名和邮件正文;所以这两个语义框架是等价的。
没有适当的对话管理,生活有时会很困难。想想那些简短的话语,它们是后续;一般来说,它们没有任何意图,只是对前一个问题的回答。在传统系统中,每一个话语都必须被贴上意图标签。让我们考虑下面的例子,意图写在括号中的话语旁边:
User: Send a message [messages.write]
Chris: To who?
User: Patrick [calls.dial]
Chris: Do you mean Patrick?
User: yes [universals.accept]
这是来自传统系统的标记,其中联系人姓名的单个实体映射到呼叫意图(单个联系人姓名最有可能映射到呼叫或消息意图)。在这一点上,NLU 设计器只是放弃了意图,因为它是一个响应话语,并试图解析一个人名实体来填充收件人姓名槽。这就把我们带回了第一点,的确,“帕特里克”的话语根本不带有意图,这种处理方式看起来令人困惑和丑陋,尽管这个系统以某种方式工作。
如果出现不愉快的情况,比如 ASR 错误发生或者用户没有填写插槽,会怎么样?让我们看下面的例子:
User: Send a message [messages.write]
Chris: To who?
User: Britney [music.play]## oopsi do, now what ask the recipient name or play Britney Spears??
下面是上面发生的事情:
- 用户想要发送消息
- 克里斯接着问了收件人的名字
- 此时麻烦开始了。用户说出“Brittany”或“Betty ”,但是 ASR 进行了错误的转录,并将话语转录为“Britney ”,这在用户的本地音乐中出现为“Britney Spears”。单个艺术家姓名映射到“music.play”话语。
- 那怎么办呢?再次询问收件人姓名或跟随音乐。播放意图?
在设计一个语音机器人的时候,我们总是牢记会出现 ASR 错误。语音是一个物理量,在对物理世界建模时,我们始终需要记住一些事情可能(并将)变得不理想。
另一种上下文失败发生在噪音上。假设您有一个噪声(无法识别的语音)的占位符文本和相应的意图。在下面的片段中,噪音话语引起了许多“请你重复一遍好吗”来烦扰用户:
User: Make a call [calls.dial]
Chris: Ok, who?
User: <...> [universals.noise]
Chris: Could you repeat that?
User: <...> [universals.noise]
Chris: Could you repeat that?
User: <...> [universals.noise]
这里,用户未能在给定的时间框架内说出响应,或者车内噪音太大。无论如何,语音助理设计师应该在一些尝试之后结束当前的框架。此外,在这里说“你能重复一遍吗?”是没有意义的,后续应该宁愿是:“你要打电话给谁?”;当前上下文是关于填充联系人姓名槽。
什么是语义框架?
语义帧是对话片段中所有语义成分的总和,包括帧起始意图、与帧起始意图相关联的槽、到目前为止由用户填充的槽、使用的共同参照以及错误路径的当前展望。一个示例帧是:
一个示例语义框架从意图消息开始
因此,语义框架为克里斯对话带来了以下语境单位:
- 领域
- 帧起始意图
- 上下文相关意图
- 时间
- 实体
- 共同参照
- 槽填充
- 插槽校正
- 插槽确认
- 插槽误差
- 畴跳跃分布
- 行动
- 误差建模
语义框架为克里斯对话带来了结构,每个话语都承认一个上下文角色,如帧开始、槽填充、槽错误和槽确认。这段对话解释了话语角色:
User: send a message frameStarter
Chris: Who do you want to send a message?
User: Patrick slotFill
Chris: Do you want to text him on mobile?
User: ergghh arghhh slotError
Chris: Excuse me?
User: yes, mobile slotConfirm
让我们看看动作的语义框架:
保持流动
语义框架的首要目标是保持流动。再次考虑我们现在看到的第一个例子,一个单独的实体被标记了意图,尽管它是一个响应。现在,该话语具有良好定义的会话上下文角色作为空位填充者,因此我们用当前帧的意图来标记该话语:
User: Send a message [messages.write]
Chris: To who?
User: Patrick [messages.write] slot-filler
Chris: Do you mean Patrick?
User: yes [universals.accept]
布兰妮的第二个例子看起来也不同了。在这个例子中,发生了 ASR 转录错误,ASR 不理解联系人姓名和艺术家姓名,而是返回 Britney。传统系统可能会跳入音乐播放意图并进行错误的域切换,然而语义框架如下识别这种上下文:
User: Send a message [messages.write]
Chris: To who?
User: Britney [messages.write] slot-error
Chris: I didn't understand the recipient name, can you say again?
在这里,话语“布兰妮”是一个单一的实体,因此看起来像一个反应和一个真正的补缺;然而它的类型是艺术家,而不是联系人。我们在这里所做的是,我们将这个话语标记为时隙错误,并保留当前帧,即 messages.write。
有了双向标记——帧意图和上下文角色,NLU 的行为对于阅读对话日志的开发人员来说就一目了然了。我们还将当前话语的上下文角色(slot-filler)提供给上下文编码器(上下文编码器的细节将在另一篇文章中介绍)。它基本上是一个 LSTM 编码来自用户话语的当前上下文。
域开关
是保留当前框架还是删除当前框架并开始新的框架有时是一个复杂的交易。在会话的每一个话语中,下一个话语的语境角色分布都是不平凡的,总是有域跳转的可能性。尽管如此,从统计上来说,一些帧之间的一些跳跃更有可能发生,例如调用消息和消息调用。举例来说,《呼唤音乐》不太可能出现在上述布兰妮对话中。我们的上下文编码器在当前语义框架的帮助下生成域跳转概率。让我们看一些例子:
User: Send a message to Patrick frameStarter
Chris: Do you want to text Patrick on his mobile number?
User: Call him instead frameStarter
Chris: Do you want to call Patrick on mobile?
User: Yes, pleaseUser: Call Patrick frameStarter
Chris: Do you want to call Patrick on his mobile number?
User: No send a message frameStarter
Chris: Do you want to message Patrick on mobile?
User: Yes, please
这里,在这两个例子中,第三个话语显然是一个框架开始。在第二话语之后,上下文编码器输出第一对话中第三话语的上下文角色分布(按可能到不太可能排序),如下:
affirmative/negative answer
slot-confirmation(phone_type)
slot-correction
cancel the message sending
domain jump, calldomain jump, navigation.start
domain jump, music.play
.
.
.
第三个话语看起来很可能是 calls.dial,因此此时上下文编码器判定这是域跳转。这个例子怎么样:
User: Call Patrick
Chris: Do you want to call Patrick on his mobile number?
User: Play Moby ASR confidence: low
在这个对话片段中,第三个话语很可能是一个 ASR 错误。根据上面的上下文角色分布,这里的音乐播放意图是非常不可能的,并且话语置信度低。因此,上下文编码器将该话语标记为 ASR 错误。
错误校正
错误恢复是对话系统的重要组成部分。语义框架允许灵活和准确的错误跟踪。考虑下面的例子:
User: Make a call calls.dial
Chris: Who should I call?
User: <...> noise,slot-error
Chris: Who should I call?
User: <...> noise, slot-error
Chris: Who is it?
User: <...> too much errors in a row
Chris: I aborted the call
上下文相关意图
人类的语言是复杂的,同样的话语在不同的语境中可以表达完全不同的意思。让我们看一些例子:
User: Call Patrick calls.dial
Chris: Do you want me to call him on **mobile**?
User: **Mobile universals.accept**
在这里,用户通过确认 Chris 询问的槽值给出了肯定的答案。这不是一个槽填充或槽确认,这是一个肯定的回答。
这个例子怎么样:
User: **Anrufen** (make a call) **calls.dial**
Chris: Wen willst du anrufen? (Who do you wanna call?)
User: Patrick
Chris: Meinst du Patrick?
User: **Anrufen ** **universals.accept**
在这里,同一个字“安如芬”在第一行是框架启动符,在最后一行却是一个肯定的回答。这是一种显式的共指方式,“安如芬”是意向名“calls.dial”的同义词;因此指代画面中的动作,指代整个画面。
我知道这看起来很多(确实很多),但是对话管理从来都不容易。接下来是什么?首先,我们将看到我在文章中提到的上下文编码器架构。接下来的文章将提供更多关于槽和上下文相关槽提取的内容。我很高兴在这个非常好的关于语境理论的系列中见到你,我希望你和我一样喜欢这个系列。保持关注和健康,直到下一次!
使用 Python 进行上下文化主题建模(EACL2021)
原文:https://towardsdatascience.com/contextualized-topic-modeling-with-python-eacl2021-eacf6dfa576?source=collection_archive---------6-----------------------
将 BERT 和 friends 与神经变分主题模型相结合
图片作者。
在这篇博文中,我讨论了我们最新发表的关于主题建模的论文:
比安奇、特拉尼、霍维、诺扎和弗西尼(2021)。零镜头学习的跨语言语境化主题模型。计算语言学协会(EACL)欧洲分会。https://arxiv.org/pdf/2004.07737
假设我们有一小组葡萄牙语文档,这些文档不够大,无法可靠地运行标准的主题建模算法。但是,我们在同一个域中有足够多的英文文档。使用我们的跨语言零触发主题模型( ZeroShotTM ),我们可以首先学习英语主题,然后预测葡萄牙语文档的主题(只要我们使用预先训练的表示法,既考虑英语又考虑葡萄牙语)。
我们还发布了一个 Python 包,可以用来运行主题建模!看看我们的 github 页面和我们的 c olab 教程 !
我们的标志:)由西尔维娅用爱制成
热身:什么是话题建模?
主题模型允许我们从文本中提取有意义的模式,使浏览文本数据更容易,并更好地理解隐藏在下面的主题的潜在分布。假设您想要获得手头一组文档的鸟瞰图;一个接一个地阅读它们不是一个好主意,对吗?
主题模型可以有所帮助:它们查看您的文档集合,并提取重复出现的主题。
图片作者。
一些细节
主题模型通常有两个主要假设。
首先,一个文档可以以不同的比例谈论不同的主题。例如,假设我们有三个主题,即“人类”、“进化”和“疾病”。一个文档可以讲一点人类,一点进化,剩下的讲动物。用概率的话来说,我们可以说它讲了 20%的人类,20%的进化,60%的动物。这可以很容易地用主题的多项式分布来表示。这种概率分布称为文档主题分布。
描述人类进化的文档如何分类到不同主题的例子。图片作者。
其次,主题建模中的主题不是无序的单词列表:在像“动物、猫、狗、小狗”这样的主题中,词汇表中的每个单词都有特定的权重。换句话说,主题也可以由多项式分布来表示,其中具有最高概率的词汇是对给定主题贡献最大的词汇。这种分布称为词-主题分布。
最著名的主题模型是 LDA (Blei et al .,2003),它也假设文档中的单词是相互独立的,即被表示为单词包(BoW)。多年来已经提出了几个主题模型,解决了各种各样的问题和任务。最先进的主题模型包括基于变分自动编码器(VAE)的神经主题模型(金玛&韦林,2014)。
标准主题建模的两个问题
然而,这种模型通常必须处理两个限制:
- 一旦经过训练,大多数主题模型就不能处理未见过的单词,这是因为它们是基于单词包(BoW)表示的,无法解释缺失的术语。
- 如果不结合多种语言的词汇,很难将主题模型应用于多语言语料库(Minmo 等人,2009;Jagarlamudi 等人,2010),使得该任务在计算上非常昂贵,并且不支持零射击学习。
我们如何解决这个问题?
情境化话题模式:邀请伯特和朋友们入席
我们新的神经主题模型 ZeroShotTM ,解决了我们刚刚举例说明的两个问题。ZeroShotTM 是一个神经变分主题模型,它基于语言预训练的最新进展(例如,BERT 等上下文化单词嵌入模型)。
是的,你答对了!我们建议将基于深度学习的主题模型与最近的嵌入技术(如伯特或 XLM)相结合。
ZeroShotTM:我们的具有情境化嵌入的神经变分主题模型。图片作者。
文档的预训练表示被传递到神经架构,然后用于重建文档的原始弓形。一旦模型被训练,ZeroShotTM 可以生成测试文档的表示,从而预测它们的主题分布,即使文档在训练期间包含看不见的单词。
此外,如果我们在训练期间使用多语言预训练表示,我们可以在测试时获得显著优势。使用共享相同嵌入空间的表示允许模型学习不同语言文档共享的主题表示。然后,经过训练的模型可以在训练期间预测看不见的语言文档的主题。
我们扩展了基于变分自动编码器的神经主题模型 ProdLDA (Srivastava & Sutton,2017)。ProdLDA 将文档的 BoW 表示作为输入,并学习高斯分布的两个参数μ和σ。从这些参数中采样连续的潜在表示,然后通过 softplus,从而获得文档的文档主题分布。然后,使用这个主题-文档表示来重构原始文档 BOW 表示。
我们不是使用文档的 BoW 表示作为模型输入,而是将预先训练的文档表示传递给神经架构,然后使用它来重建文档的原始 BoW。一旦模型被训练,ZeroShotTM 可以生成测试文档的表示,从而预测它们的主题分布,即使文档在训练期间包含看不见的单词。
我们的 ZeroShotTM,由于多语言表示,可以有效地预测在训练期间没有见过的语言文档的主题。图片作者。
TL;速度三角形定位法(dead reckoning)
ZeroShotTM 有两个主要优点:1)它可以处理测试集中缺失的单词,2)继承了最近预训练的多语言模型的多语言能力。
使用标准的主题模型,您经常需要从数据中删除那些在测试集中有但在训练集中没有的单词。在这种情况下,由于我们依赖于一个上下文化的模型,我们可以使用它来构建测试文档的文档表示,表达这些嵌入的全部功能。此外,标准的多语言主题建模需要考虑多语言词汇。
ZeroShotTM 可以在英语数据(这是一种数据丰富的语言)上进行训练,并在更低资源的数据上进行测试。例如,你可以在英文维基百科文档上训练它,并在完全看不见的葡萄牙语文档上测试它,正如我们在论文中所示。
情境化主题建模:一个 Python 包
我们围绕这款车型打造了一整套套件。您可以运行主题模型并使用几行代码获得结果。在软件包主页上,我们有不同的 Colab 笔记本,可以帮助您运行实验。
你可以在这里或者直接在 colab 上看例子。
根据用例的不同,您可能想要使用特定的上下文化模型。在这种情况下,我们将使用distiluse-base-multilingual-cased模型。
当使用主题模型时,执行文本预处理总是更好,但是当我们处理上下文化的模型时,如 BERT 或通用句子编码器,最好不要做太多预处理(因为这些模型是上下文并且大量使用上下文)。
今天的任务
我们将在英语维基百科文档上训练一个主题模型,并预测意大利语文档的主题。
您需要做的第一件事是安装软件包,从命令行您可以运行:
确保为您的系统安装正确的 PyTorch 版本,另外,如果您想使用 CUDA,请安装支持 CUDA 的版本(您可能会发现使用 colab 更容易)。
数据
让我们下载一些数据,我们将从在线存储库中获取它们。这两个命令将下载英文摘要和意大利文文档。
如果您打开英文文件,您看到的第一个文档应该包含以下文本:
The Mid-Peninsula Highway is a proposed freeway across the Niagara Peninsula in the Canadian province of Ontario. Although plans for a highway connecting Hamilton to Fort Erie south of the Niagara
Escarpment have surfaced for decades,it was not until The Niagara...
现在,让我们应用一些预处理。我们需要这一步来创建单词包,我们的模型将使用它来表示主题;尽管如此,我们仍将使用未经预处理的数据集来生成来自distiluse-base-multilingual-cased模型的表示。****
让我们训练人们
我们的预处理文档将只包含 2K 个最常用的单词,这是一个优化步骤,允许我们删除可能不太有意义的单词。对象允许我们创建数据集来训练主题模型。然后使用我们的 ZeroShotTM 对象,我们可以训练这个模型。
玩模型
我们可以快速检查的一件事是我们的主题。运行下面的方法应该会在输出中得到一些主题
他们很吵,不是吗?
**[['house', 'built', 'located', 'national', 'historic'],
['family', 'found', 'species', 'mm', 'moth'],
['district', 'village', 'km', 'county', 'west'],
['station', 'line', 'railway', 'river', 'near'],
['member', 'politician', 'party', 'general', 'political'],
...
...**
如果你想有一个更好的视觉效果,你可以使用这个:
图片作者。
是的,但是多语种的在哪里?
所以现在,我们需要做一些推论。尽管如此,我们还是可以从一些新的看不见的英文文档中预测主题,但我们为什么不试试意大利语呢?
这个过程类似于我们已经看到的;在这种情况下,我们将收集每个文档的主题分布,并提取每个文档最可能的主题。
该文档包含以下文本,关于一部电影:
**Bound - Torbido inganno (Bound) è un film del 1996 scritto e diretto da Lana e Lilly Wachowski. È il primo film diretto dalle sorelle Wachowski, prima del grande successo cinematografico e mediatico di Matrix, che avverrà quasi quattro anni dopo**
看预测题目:
**['film', 'produced', 'released', 'series', 'directed', 'television', 'written', 'starring', 'game', 'album']**
有道理,对吧?
这篇博文到此结束,如果你有问题或者有什么想讨论的,欢迎给我发邮件:)你也可以在 Twitter 上找到我。
参考
布莱博士,Ng,A. Y .,&乔丹,M. I. (2003 年)。潜在狄利克雷分配。 JMLR 。
Jagarlamudi 和 h . daumé(2010 年)。从未对齐的可比语料库中抽取多语言主题。 ECIR 。
金马博士和韦林博士(2014 年)。自动编码变分贝叶斯。 ICLR 。
米米诺博士、瓦拉赫博士、纳拉多斯基博士、史密斯博士和麦卡勒姆博士(2009 年 8 月)。多语种主题模型。 EMNLP 。
斯利瓦斯塔瓦和萨顿(2017 年)。主题模型的自动编码变分推理。 ICLR 。
学分
这篇博文的内容主要由我和西尔维娅·特拉尼撰写。非常感谢 Debora Nozza 和 Dirk Hovy 对本文之前版本的评论。
列联表、卡方检验和克拉默 V
原文:https://towardsdatascience.com/contingency-tables-chi-squared-and-cramers-v-ada4f93ec3fd?source=collection_archive---------1-----------------------
如何轻松检查类别之间的关联
作者图片
简介
在最近的一个项目过程中,我不得不检查一个特性与多个其他特性的关联(缺乏独立性)。为了方便起见,我编写了几个函数来执行并帮助解释这些分类特征之间的关联测试。在这篇文章中,我将演示这一过程,并提供代码示例,读者可以使用自己的数据。
数据
本次演示的数据集是开放大学学习分析数据集。数据集由 7 个 csv 文件组成,包含学生人口统计、评估和注册数据;以及表格形式的课程、课程评估和学习环境数据。我们将查看来自studentInfo.csv 文件的两个分类特征, final_result 和higher _ education,。本演示假设该数据已经加载到数据帧 df 中。
测试的特性
final_result 特征是授予该课程的最终成绩(未通过、退出、通过、优秀),而 highest_education 是学生完成的最高教育水平。这些(英国)教育资格类别的排名如下(从最低到最高):无正式资格,低于 A 级,A 级,he 资格,研究生资格。
作者图片
从图表中可以看出,较低的教育水平与退缩和失败的结果正相关,而较高的教育水平与通过和优秀正相关。我们想测试和量化这些概念,如果可能的话,使用统计方法。
列联表
我们将通过使用pandas . crosstab为我们的数据创建一个列联表来开始我们的研究,并实例化一个stats models . stats . table对象来为我们提供查找和显示任何关联的便利方法。Table 类使用皮尔森卡方检验来评估任何关联。
# *creating crosstab data frame*tabs = pd.crosstab(df.highest_education, df.final_result)# creating a statsmodels table objecttable = sm.stats.Table(tabs)
table_orig 方法将返回一个原始数据的列联表。列联表中的数字单元格表示相应行和列对的观察次数。**
table.table_orig
作者图片
fittedvalues 方法将从数据的最佳拟合独立分布中返回值的列联表。
table.fittedvalues
作者图片
resid_pearson 方法返回残差表,该表将揭示数据中存在的任何关联。如果要素是独立的,正值表示观察值比预期值多,负值表示观察值少。
table.resid_pearson
作者图片
从列联表中可以看出,一般来说,成绩和及格与教育水平直接相关。学生的受教育程度越高,就越有可能通过或以优异成绩通过。相反,退缩和失败与教育水平成反比。一般来说,学生的教育水平越低,越有可能失败或退学。
接下来,我们将执行假设检验来验证我们的结果。
假设检验
我们将使用scipy . stats . chi2 _ contingency测试独立性。与 Table 类类似,chi2_contingency 使用皮尔逊卡方检验来评估数据中的任何关联。
让我们首先定义测试的无效假设和替代假设,并指定显著性水平。
Ho = 最高学历和最终成绩是独立的。
Ha = 最高 _ 学历和最终 _ 成绩不是独立的。
显著性水平α= 0.05。
既然我们已经准备好了,我们就来进行测试。我写了一个小函数,可以很好的打印结果。
def chi_sq_test(cross_tabs):
"""
Prints the Chi-Squared Statistic, p-value, and degress of freedom from a Chi-Squared test.
Args:
cross_tabs: A crosstab dataframe.
"""
chi2, p, dof, con_table = stats.chi2_contingency(cross_tabs)
print(f'chi-squared = {chi2}\np value= {p}\ndegrees of freedom = {dof}')
将该函数应用于交叉表数据框会返回:
chi-squared = 962.2117100356752
p value= 2.4827414817328365e-198
degrees of freedom = 12
由于返回的 p 值小于我们的 alpha,我们拒绝零假设,并得出结论最高学历和最终结果不是独立的,从而证实了我们上面的发现。
最后,我们将检查我们的功能的影响大小。
效果大小
效果大小是对两个特征之间关联强度的度量。我们将使用我编写的函数来测量影响大小,以计算和显示数据的克莱姆 V 值、克莱姆 V 自由度和影响大小阈值。
def cramers_v(cross_tabs):
"""
Prints the degrees of freedom, effect size thresholds, and Cramer's V value.
Args:
cross_tabs: A crosstab dataframe.
"""
# *effect size data frame for cramer's v function*
data = np.array([[1, .1, .3, .5],
[2, .07, .21, .35],
[3, .06, .17, .29],
[4, .05,.15,.25],
[5, .04, .13, .22]])
sizes = pd.DataFrame(data, columns=['Degrees of Freedom', 'Small Effect', 'Medium Effect', 'Large Effect'])
# *getting the chi sq. stat*
chi2 = stats.chi2_contingency(cross_tabs)[0] # *calculating the total number of observations*
n = cross_tabs.sum().sum() # *getting the degrees of freedom*
dof = min(cross_tabs.shape)-1 # *calculating cramer's v*
v = np.sqrt(chi2/(n*dof)) # *printing results*
print(f'V = {v}')
print(f'Cramer\'s V Degrees of Freedom = {dof}')
print(f'\nEffect Size Thresholds\n{sizes}\n')
将该函数应用于交叉表数据会返回:
V = 0.10148164448653103
Cramer's V Degrees of Freedom = 3
Effect Size Thresholds
Degrees of Freedom Small Effect Medium Effect Large Effect
0 1.0 0.10 0.30 0.50
1 2.0 0.07 0.21 0.35
2 3.0 0.06 0.17 0.29
3 4.0 0.05 0.15 0.25
4 5.0 0.04 0.13 0.22
根据自由度进行调整后,Cramer 的 V 结果表明最高教育程度对最终结果有微小的、统计上显著的影响。
结论
希望这个演示能让我们了解一个简单而强大的例程来检查关联的分类特征。为了您的方便,请随意使用和修改上述功能。特别感谢 Sgr Folge 在我的原始帖子中指出了 Cramer 的 V 代码块中的一个遗漏。
来源
开放大学学习分析数据集。Sci 数据 4,170171(2017)https://doi.org/10.1038/sdata.2017.171。
该数据集可以通过 CC-BY 4.0 许可在https://analyse.kmi.open.ac.uk/open_dataset免费获得。
Python 中的连续和离散均匀分布—统计
原文:https://towardsdatascience.com/continuous-and-discrete-uniform-distribution-in-python-statistics-82b5aa5c20b1?source=collection_archive---------33-----------------------
布莱恩·麦高恩在 Unsplash 上的照片
在本教程中,我们将探索 Python 中的连续和离散均匀分布。
目录
- 介绍
- 什么是均匀分布
- 连续均匀分布示例
- Python 中的连续均匀分布示例
- 离散均匀分布示例
- Python 中的离散均匀分布示例
- 结论
介绍
为了继续学习本教程,我们需要以下 Python 库:scipy、numpy 和 matplotlib。
如果您没有安装它,请打开“命令提示符”(在 Windows 上)并使用以下代码安装它:
pip install scipy
pip install numpy
pip install matplotlib
什么是均匀分布
有两种类型的均匀分布:
- 连续均匀分布-使用连续值
- 离散均匀分布-使用离散(有限)值
连续均匀分布
连续均匀概率分布是具有恒定概率的分布,这意味着测量被观察的相同概率。
连续均匀分布也称为矩形分布。这是为什么呢?让我们一起探索吧!
这种类型的分布由两个参数定义:
- —最小值
- b —最大值
并且写成: U(a,b) 。
https://en .维基百科. org/wiki/Continuous _ uniform _ distribution
b 和 a 的区别是音程长度: l=b-a 。由于这是一个累积分布,区间长度内的所有区间都是等概率的(假设这些区间具有相同的长度)。
连续均匀分布的 PDF(概率密度函数)由下式给出:
作者图片
否则为 0。
连续均匀分布的 CDF(累积分布函数)由下式给出:
作者图片
用 0 代表x<a用 1 代表x>b。****
离散均匀分布
离散均匀概率分布是具有恒定概率的分布,这意味着有限数量的值同样可能被观察到。
这种类型的分布由两个参数定义:
- —最小值
- b —最大值
并且写成: U(a,b) 。
https://en.wikipedia.org/wiki/Discrete_uniform_distribution
b 与a+1 之差为观测数: b 与 a 之差为区间长度: n=b-a+1 。所有的观察都是同样可能的。
对于任一×x∈【a,b】,离散均匀分布的 PMF(概率质量函数)由下式给出:
作者图片
而对于任意一个∈【a,b】,一个离散均匀分布的 CDF(累积分布函数)由下式给出:
作者图片
连续均匀分布示例
让我们考虑一个例子:你住在一栋 10 层的公寓楼里,刚刚回家。你进入大厅,准备按电梯按钮。你知道你可能需要 0 到 20 秒的时间来等待电梯,如果电梯在一楼(无等待)需要 0 秒,如果电梯在十楼(最长等待)需要 20 秒。这将是连续均匀分布的一个例子,因为等待时间可以以相同的概率取任何值,并且是连续的,因为电梯可以在建筑物中第一层和第十层之间的任何地方(例如,在第五层和第六层之间)。
这里我们有最小值 a = 0,最大值 b = 20。
连续均匀分布 PDF
知道了 a 和 b 的值,我们就可以很容易地计算出连续均匀分布的 PDF:
作者图片
使用 f(x) 公式和给定参数我们可以创建以下连续均匀 PDF 的可视化:
作者图片
那么在连续均匀分布的情况下,这到底告诉了我们什么呢?让我们在区间[0,20]的任何地方取两个 1 秒的区间。例如从 1 到 2(i1 =【1,2】)和从 15 到 16(I _ 2 =【15,16】)。重要的是要注意,这两个间隔的长度相同,都等于 1。使用 PMF 结果,我们可以说这些区间以 0.05 的概率同样可能发生。换句话说,电梯在 1 到 2 秒之间到达的可能性与在 15 到 16 秒之间到达的可能性一样大(概率为 0.05)。
连续均匀分布 CDF
现在,让我们考虑在本节的示例中添加一个内容。你还在公寓楼里等电梯,但现在你想知道你按下按钮后,电梯 6 秒或更短时间到达的概率是多少。
使用本节中的连续分布 CDF 公式,我们可以求解:
作者图片
我们观察到电梯在 6 秒或更短时间内(0 到 6 之间)到达的概率是 0.3。
使用 F(x) 公式和给定参数我们可以创建以下连续均匀 CDF 的可视化:
并且我们观察到累积概率和随机变量 X 之间的线性关系,其中函数以 f(x) 的速率单调递增(在我们的例子中 f(x)=0.05 )。
Python 中的连续均匀分布示例
在前面的一节中,我们手工计算了连续均匀分布的概率密度函数。在本节中,我们将使用 Python 再现相同的结果。
我们将从导入所需的依赖项开始:
接下来,我们将创建一个介于 0 和 20(最小和最大等待时间)之间的连续值数组。从数学上来说,有无限多的值,因此在本例中,我们将创建 4,000 个范围在 0 到 20 之间的值。我们也将打印前三个只是为了看看。
您应该得到:
**[0\. 0.00500125 0.0100025 ]**
现在我们必须使用 scipy.stats.uniform 创建一个均匀连续的随机变量:
在接下来的章节中,我们将重点介绍使用 Python 计算 PDF 和 CDF。
Python 中的连续均匀分布 PDF
为了使用 Python 计算累积均匀分布 PDF,我们将使用。scipy.stats.uniform 生成器的 pdf()** 方法:**
您应该得到:
**[0.05 0.05 0.05 ... 0.05 0.05 0.05]**
所以现在我们发现每个值的概率是相同的,等于 0.05,这和我们手工计算的完全一样。
使用 Python 绘制连续均匀分布 PDF
使用 matplotlib 库,我们可以使用 Python 轻松绘制连续均匀分布 PDF:
您应该得到:
Python 中连续均匀分布 CDF
为了用 Python 计算连续均匀分布的 CDF,我们将使用。scipy.stats.uniform 生成器的 cdf()** 方法:**
由于我们将有 4,000 个值,如果我们想要仔细检查我们手工计算的正确性,您将需要找到与等于 6 的值相关联的累积概率。确实在 0.3 左右。
使用 Python 绘制连续均匀分布 CDF
使用 matplotlib 库,我们可以很容易地用 Python 绘制出连续均匀分布的 CDF:
您应该得到:
离散均匀分布示例
让我们考虑一个例子(这是我们大多数人自己做的):掷骰子。基本上,滚动单个 6 面骰子的可能结果遵循离散的均匀分布。
这是为什么呢?这是因为你只能从 6 个可能的结果中选择 1 个结果(你可以选择 1、2、3、4、5 或 6)。可能结果的数量如果是有限的,并且每个结果被观察到的概率是相等的,即 1/6 。
离散均匀分布 PMF
已知所有可能结果的数量 n ,我们可以很容易地计算出离散均匀分布的 PMF:
作者图片
使用 f(x) 公式和给定参数,我们可以创建以下离散均匀 PMF 的可视化:
在本例中,骰子的每一侧被观察到的机会相等,等于 0.16。
离散均匀分布 CDF
现在让我们考虑这个例子的补充。你正在掷出同一个 6 面骰子,现在想知道你观察到的结果等于或小于 2(意味着 1 或 2)的概率。
已知所有可能结果的数量 n ,我们可以很容易地计算出离散均匀分布的 CDF:
作者图片
这告诉我们,如果我们掷出一个 6 面骰子,观察到小于或等于 2 的值的概率是 0.33。
使用 F(x) 公式和给定的参数我们可以创建以下可视化的离散均匀 CDF:
作者图片
我们观察到一种逐步的关系,因为我们有离散的值作为可能的结果。
Python 中的离散均匀分布示例
在前面的一节中,我们手工计算了连续均匀分布的累积分布函数。在本节中,我们将使用 Python 再现相同的结果。
我们将从导入所需的依赖项开始:
接下来,我们将创建一个 1 到 6 之间的值的数组(最小和最大骰子值),并打印出来看看。
您应该得到:
**[1 2 3 4 5 6]**
现在我们必须使用 scipy.stats.randint 创建一个均匀连续的随机变量:
在以下章节中,我们将重点介绍如何使用 Python 计算 PMF 和 CDF。
Python 中的离散均匀分布 PMF
为了使用 Python 计算离散均匀分布 PMF,我们将使用。scipy.stats.randint 生成器的 pmf()** 方法:**
您应该得到:
**[0.16666667 0.16666667 0.16666667 0.16666667 0.16666667 0.16666667]**
这正是我们手工计算的 0.16。
使用 Python 绘制离散均匀分布 PMF
使用 matplotlib 库,我们可以使用 Python 轻松绘制离散均匀分布 PMF:
您应该得到:
Python 中的离散均匀分布 CDF
为了用 Python 计算离散均匀分布的 PMF,我们将使用。scipy.stats.randint 生成器的 cdf()** 方法:**
您应该得到:
**[0.16666667 0.33333333 0.5 0.66666667 0.83333333 1\. ]**
我们在这里看到,数组中的第二个值是 0.33,这与我们手工计算的值完全相同。
使用 Python 绘制离散均匀分布 CDF
使用 matplotlib 库,我们可以使用 Python 轻松绘制离散均匀分布 CDF:
您应该得到:
结论
在本文中,我们探讨了累积均匀分布和离散均匀分布,以及如何在 Python 中创建和绘制它们。
如果你有任何问题或对一些编辑有建议,请随时在下面留下评论,并查看更多我的统计文章。
原载于 2021 年 11 月 29 日 https://pyshark.comhttps://pyshark.com/continuous-and-discrete-uniform-distribution-in-python/。****
使用 Github Actions、Docker 和 AWS 的持续部署管道
原文:https://towardsdatascience.com/continuous-deployment-pipeline-using-github-actions-docker-and-aws-185bb3bf41b?source=collection_archive---------5-----------------------
将 Flask ML 应用程序自动部署到 AWS Elastic Beanstalk
马文·迈耶在 Unsplash 上的照片
介绍
公司越来越多地寻找机器学习工程师。但是机器学习工程师和数据科学家有什么区别呢?数据科学家纯粹关心训练机器学习模型。他们处理数据,评估数据,并更详细地探索数据。他们试图从中产生附加值。另一方面,机器学习工程师应该将这个训练好的模型转化为最终可用的应用程序。他们必须将 Jupyter notebook 等环境中的代码转换成可用的应用程序。这个应用程序可以是任何东西,从移动应用程序到复杂的网站或普通的 API。这个应用程序也应该得到维护,最好是不断扩展和改进。它还应该在新的更新后重新部署,以便最终用户始终拥有可用的最佳和最新版本。整个部署过程可以而且应该自动化。这就叫做持续集成和部署。集成部分是第一次测试新代码的部分,以确保一切正常工作。如果是,那么代码可以被交付/部署。
在本文中,我想与您分享一个连续部署管道的示例,其中我首先创建了一个 Docker 容器,该容器运行我的 Birds Classifier Flask 应用程序,然后通过使用 Github 操作将该 Docker 容器自动部署到 AWS Elastic Beanstalk。因此,每当一个新的代码状态被推送到我的主分支时,首先创建 Docker 容器以确保一切正常,然后通过 AWS Elastic Beanstalk 部署这个容器。
如果你想知道我是如何从零开始训练鸟类图像分类器的,我可以推荐这篇文章。在这篇文章中,我描述了如何用 Flask 创建 Web API。包括 Dockerfile 和 Github Actions 文件的完整代码可以在我的 Github 库这里找到。
在本文的第一部分,我将更详细地解释 Docker、Github Actions 和 AWS Elastic Beanstalk,并展示它们的优势。然后,我将向您展示如何创建 Docker 映像,以及如何在本地创建和测试容器。之后,我将向您展示如何创建一个能够运行 birds 分类器 API 的 AWS Elastic Beanstalk 应用程序。最后,我将解释如何使用 GitHub Actions 在每次新代码被推送到主分支时自动部署 Docker 容器。
码头工人
好吧,让我们从 Docker 开始。什么是 Docker,为什么要使用 Docker?我觉得下面这句话你们每个人听起来都很熟悉:你在网上发现了有趣的 Python 代码,想在本地运行。但是首先你需要一个版本正确的 Python 环境。例如,Anaconda 可以用于此目的。现在,如果你有了正确版本的 Python,首先要做的就是创建一个新的环境,希望代码的开发者已经创建了一个 requirements.txt,其中包含了运行程序的所有依赖项。如果没有,在一些错误消息告诉您缺少哪些包之后,必须逐个安装所需的 Python 包。如果一些包不能通过 Conda 或 Pip 安装,情况会变得更糟。然后,必须费很大力气手动安装它们。因此,可能需要几个小时才能最终运行 Python 程序。这就是 Docker 发挥作用的地方。Docker 希望通过为应用程序创建容器来改善这一点。然后,一个容器包含所有的依赖项和正确的 Python 版本,这样最终用户就可以运行这个容器,而不必担心所有的依赖项。如果他不想再在本地拥有这个应用程序,他可以简单地删除容器。
容器可以被看作是一个独立的环境,它自己的资源运行在主机上。图 1 显示了一个具有三个不同容器的示例设置,其中每个容器运行一个应用程序,每个应用程序在硬盘驱动器中有自己的内存区域,其他容器无法访问(除非您告诉容器共享它们的内存)。
图 Docker 是什么的概述,灵感来自https://www.docker.com/resources/what-container(图片由作者提供)。
Docker 可以在 Windows、Linux 和 MacOS 上使用。要在 Windows 上安装和运行 Docker,首先必须安装 Windows 子系统 Linux 2。这是一个在 Windows 上运行 Linux 的轻量级虚拟机。在本页阅读更多关于安装 Docker for Windows 的信息。要在 MacOS 上安装 Docker,可以跟着阅读这一页。
Github 操作
现在让我们来看看 Github Actions。在介绍中,我说过应用程序的集成和部署应该是自动化的,这样,当执行新的主分支时,应用程序会自动进行测试,然后重新部署。这就是 Github Actions 发挥作用的地方。Github Actions 是一个直接集成到 Github 中的 CI/CD 工具。它允许在检测到 Github 存储库的变化后直接运行测试和预定义的步骤。我真的很喜欢这个直接集成到 Github!这避免了必须处理另一个工具,如 Travis CI。Github Actions 已经有很多例子和库,可以用来快速创建 CI/CD 管道。管道本身被定义为 YAML 文件中的代码。这允许对您的管道进行版本控制,这在您想要恢复到旧版本的情况下是非常重要的。
AWS 弹性豆茎
图 AWS 弹性豆茎概述(图片由作者提供)。
AWS Elastic Beanstalk 是来自 Amazon Web Services 的一项服务,允许轻松部署用 Java、PHP、Node.js、Python、Docker 等编写的应用程序。代码可以简单地上传到 AWS Elastic Beanstalk,它会自动处理诸如容量供应、负载平衡、自动伸缩和应用程序健康监控之类的事情。AWS Elastic Beanstalk 本身使用 EC2 实例来运行您的应用程序,使用 S3 存储来存储数据,但是作为用户,您不必为这些事情费心。你可以简单地上传你的 Docker 图片,AWS Elastic Beanstalk 会帮你处理剩下的事情。
关于如何创建持续部署管道的分步说明
好了,现在你知道了所用环境和工具的基本知识。现在让我们从创建最终的持续部署管道开始。我将经历所有需要的步骤,这样最终你有希望理解所有这些,并且能够将它们应用到你自己的项目中。首先,我将向您展示如何为 Flask 应用程序创建 Docker 映像,以及如何在本地构建和测试容器。然后,我将向您展示如何为 Flask 应用程序创建 AWS 环境。最后,我将指导您创建 Github 动作管道和所有必要的配置,以通过 Github 动作运行持续部署。
步骤 1:创建 Docker 映像
作为第一步,我们必须创建 Docker 图像。为此,我们需要创建一个名为“Dockerfile”的文件。该文件定义了如何使用 Docker 映像设置 Docker 容器的所有必需步骤。代码 1 显示了创建的 Dockerfile 的全部内容。
代码 1: Dockerfile,用于为鸟类分类器 Flask 应用程序定义 Docker 图像(由作者编写代码)。
来自 python:3.9
这一行定义了应该使用的基本图像。基础图像就像是容器的起点。它定义了一些应该安装的基本安装,比如 Python。
工作目录/usr/src/app
这里我们说我们想要使用指定路径上的文件夹作为工作目录。我们现在以后用“T4”时。”,我们总是把这个工作目录称为根目录。
复制。/requirements.txt。/
需求文件现在被复制到 Docker 容器的工作目录中。
运行 pip 安装—升级 pip &运行 pip 安装—no-cache-dir-r requirements . txt
这几行首先升级 pip,然后安装 requirements.txt 文件中列出的所有依赖项。这确保了 Flask ML 应用程序所需的所有包都安装在 Docker 容器上。
添加和复制步骤
在添加步骤中,目录被复制到容器的工作目录中,而 COPY 只复制单个文件,不会保留正确的文件夹结构。application.py 文件包含 Flask ML 应用程序,data 文件夹包含带有所有类名的 csv 文件,model 文件夹包含已训练 Tensorflow 模型,templates 文件夹包含前端 HTML 文件。
曝光 5000
EXPOSE 步骤告诉容器他应该监听端口 5000 上的传入连接和数据。这对于在主机上调用网页和与容器通信是很重要的。
CMD ["python "," application.py" ]
这一行定义了 Docker 容器启动时要执行的命令。在这里,我们想执行 Flask ML 应用程序,然后启动网页。
既然已经创建了容器的映像,那么让我们也在本地创建容器,并运行它来尝试是否一切都按预期运行。为此,请遵循以下步骤:
- 运行docker build-t
/<应用程序名称>。 在包含 Dockerfile 的目录下的命令行中。使用 -t 标志,您可以标记 docker 容器,以便在以后运行该容器时方便地引用它。 < docker_id > / <应用名称> 只是 docker 的一个命名约定,但是你可以给你的容器加上任何你想要的名字。在我的例子中,我用 ga63qes/flask-ml-app 标记它。还有别忘了“”。“结束了!这告诉 Docker 在当前目录中搜索 Docker 文件。 - 当一切都解决了,运行docker run-p 5000:5000****
/<应用程序名称> 之后。这将启动您的 Docker 容器,并将您机器上的端口 5000 映射到 Docker 容器的端口 5000。这很重要,因为 Docker 容器监听该端口上的传入连接(如 Docker 文件中所定义的)。
您应该在终端上看到如图 3 所示的输出。
图 3:启动 Docker 容器后的终端输出(图片由作者提供)。
现在,在浏览器中输入“ http://127.0.0.1:5000 ”即可打开网页。
好吧。现在我们必须做最后一步来完成 Docker 部分。我们必须创建一个 docker-compose 文件,因为 AWS Elastic Beanstalk 将使用这个文件来最终创建和运行 docker 容器。Docker-compose 是一个来自 Docker 的 CLI,用于将多个单个 Docker 步骤合并到一个文件中。只需创建一个“docker-compose.yml”文件,并添加代码 2 中的内容。
代码 2: Docker-compose 文件的鸟类分类器烧瓶毫升应用程序(代码由作者)。
这里,作为构建上下文,Dockerfile 被链接,并且作为根目录,当前工作目录被选择。这意味着“docker-compose.yml”文件必须放在与 docker 文件相同的目录中。此外,端口 80 被映射到容器的端口 5000。这是因为网页将被托管在 AWS Elastic Beanstalk 上,默认情况下在端口 80 上监听传入的连接,而创建的容器在端口 5000 上监听。
现在,您还可以通过在包含 docker-compose 文件的目录中运行以下步骤来检查 docker-compose 文件是否正常工作:
- 运行 docker-compose build 来构建 docker 容器。
- 运行docker-组合来运行 Docker 容器。现在,您应该能够通过在浏览器中输入“http://127 . 0 . 0 . 1:80”连接到该网页。重要提示:您现在必须使用端口 80 而不是 5000,因为我们将这个端口映射到容器的端口 5000。
呸,太多了!但这是最重要的部分!现在,应用程序可以在每台安装了 Docker 的机器上执行。因此,没有人需要首先手动安装依赖项和设置环境。
步骤 2:创建一个 AWS 弹性 Beanstalk 应用程序
第二步,您首先需要创建一个 AWS 帐户。这个账户本身是完全免费的,但是你必须给你的账户添加一张信用卡。创建账户后,你可以进入 AWS 起始页,在搜索栏中搜索“AWS Elastic Beanstalk”。然后,您可以点击“创建应用程序”。选择您想要创建一个 Web 应用程序,然后您应该会看到如图 4 所示的窗口。您可以添加所需的信息。在我的例子中,我还必须打开“配置更多选项”并选择其他实例类型,因为默认实例类型(t2.micro 和 t2.nano)对我的应用程序来说内存太少。然后我选择了实例类型 c5d.2xlarge 和 c5a.2xlarge。
图 AWS 弹性豆茎应用程序的设置(图片由作者提供)。
当您添加了所有必需的信息并选择了正确的实例类型后,单击“创建应用程序”。您的应用程序应该需要几分钟才能设置好并准备好运行。当您的环境完成后,您应该会看到类似于图 5 的内容,您可以开始使用您的应用程序了。
图 5:已经可以使用的 AWS 弹性 Beanstalk 环境(图片由作者提供)。
然后您可以点击环境,一个新的窗口将会打开(图 6)。此窗口包含到您的网站的链接。部署应用程序后,可以与最终用户共享这些信息。
图 6:在 AWS Elastic Beanstalk 中创建的应用程序的环境窗口(图片由作者提供)。
你也可以在这里直接上传申请。这有助于查看 Docker 容器是否在 AWS 上正常运行。为此,您可以选择文件夹中所有相关的文件夹和文件,并将它们放入 zip 文件夹中。重要的是,在打开文件夹后,Dockerfile 和 docker-compose 文件位于根目录下。
好了,接下来的步骤只需要在你想继续用 Github 动作自动部署应用程序的情况下完成。为此,我们首先必须在 AWS 中创建一个用户,允许他将代码部署到创建的 Elastic Beanstalk 应用程序中。为此,在 AWS 搜索栏中搜索“IAM ”,然后单击“Users”和“Add users”。然后你可以添加一个用户名(在我的例子中是 birds-classifier-api)并选择“访问键-编程访问”。点击“Next: Permissions”并选择如图 7 所示的选项。
图 7:允许将应用程序部署到创建的弹性 Beanstalk 环境的 IAM 用户设置(图片由作者提供)。
然后,您可以一步一步地完成 IAM 用户的设置。创建用户后,您将看到一个“访问密钥 ID”和一个“秘密访问密钥”。您将需要这些用于您的 Github repo,稍后将在那里推送代码。将它们下载为 CSV 文件,以便您以后可以访问它们。然后进入你的 Github repo,点击“设置”,导航到“秘密”。这里您必须添加图 8 中的两个变量。作为值,您可以插入在 AWS 中创建的用户的值。
图 8:自动将新的应用程序代码部署到 AWS Elastic Beanstalk 需要添加的存储库秘密(图片由作者提供)。
第三步:创建 Github 动作文件
现在我们终于到了最后一步。我们现在可以创建包含代码的 YAML 文件,告诉 Github Actions 每当执行 master 上的 push 时,它应该自动构建 Docker 容器并将其部署到 AWS Elastic Beanstalk 应用程序。如果你不熟悉 Github 动作,那么我可以向你推荐这个关于如何使用 Github 动作的 Youtube 教程。代码 3 显示了创建自动部署的完整代码。该文件必须在名为“”的文件夹中创建。github/workflows”被 Github Actions 认可。
代码 3:定义 Github Actions 持续部署管道的 YAML 文件(作者代码)。
在第 16 到 18 行中,定义了 checkout。我还添加了 git lfs checkout,因为我将我的存储库配置为 git lfs repo,以便有效地存储我的大型 Tensorflow 模型。在这里阅读更多关于 git lfs 的内容。
该管道的不同阶段在结帐后定义。每个新阶段以“ - ”和阶段名称开始。关键字“使用”表示加载并使用了另一个用户的库。
构建 Docker 映像
在这个阶段,Docker 映像被构建。这是为了确保在将 Docker 容器部署到 AWS Elastic Beanstalk 之前,构建 Docker 容器的一切工作正常。
生成部署包
在这个阶段,repo 的内容被压缩,因为 AWS Elastic Beanstalk 需要上传一个包含应用程序和 docker 文件的压缩文件夹。
获取时间戳
这里加载了当前时间戳。这随后用于向新部署的应用程序添加版本。
运行管柱更换
这个阶段获取时间戳,并应用一些格式将其转换成一种良好的格式。
部署到 EB
在最后一个阶段,通过使用之前创建的 AWS 用户凭证和所创建环境的一些必需信息,最终将压缩的应用程序文件夹部署到 AWS Elastic Beanstalk。关于环境的所有必需信息都可以在图 5 中找到。
现在,您可以将这个创建的 YAML 文件推送到 Github,并在浏览器中打开您的 repo。然后,您可以导航到“Actions”选项卡,您应该会看到一个正在进行的构建。构建完成后,您应该会看到类似于图 9 的内容。
图 9:完成的 Github 动作构建管道的示例视图(图片由作者提供)。
因此,现在无论何时在主服务器上执行推送,应用程序都会自动重新部署到 AWS Elastic Beanstalk。这太棒了!机器学习工程师现在不必再为部署而烦恼了。
现在,您可以使用 AWS Elastic Beanstalk 环境中提供的 web 链接导航到创建的网页。你可以看看我的情况:
Gif 1:如何在 AWS 部署的网页上打开的示例(图片由作者提供)。
重要提示:我建议最后删除在 AWS 上创建的应用程序,以避免产生成本。我删除了我的资源,因为我还有更大的实例类型,并且已经为我的应用程序支付了一些费用。因此,当您现在查看我的 Github 操作结果时,您可以看到我的最新构建在部署阶段失败了。
未来的工作
目前只使用默认的 Flask 服务器,它应该只在开发期间使用,而不在生产中使用(如图 3 中的命令行输出所示)。所以当你真的想把你的 Flask 应用程序投入生产时,我会推荐你阅读 Flask 的这篇文章。
结论
现在您已经看到了这样一个自动化部署管道的样子。你也知道 Docker 的优点,以及如何使用 Github 动作。现在是时候实施您自己的机器学习项目并考虑部署了!
谢谢你把我的文章看完!我希望你喜欢这篇文章和我参与的项目。如果你想在未来阅读更多类似的文章,请关注我,保持更新。
接触
LinkedIn|Github
连续科学
原文:https://towardsdatascience.com/continuous-science-6b5ed833ab23?source=collection_archive---------41-----------------------
约翰·施诺布里奇在 Unsplash 上的照片
业内笔记
软件工程实践如何解决科学再现性
这篇文章是关于通过实施现代软件工程实践来提高计算生物学的可重复性和生产率。
我写这封信是因为很明显,科学界正变得越来越依赖公共软件解决方案——这些解决方案可以通过在软件工程中大量投资不断发展但令人兴奋的解决方案而得到更好的支持。
介绍
计算生物学家花在基准测试和评估代码上的时间比他们写基本功能的时间还多。
幸运的是,我们的软件工程师面临许多类似的问题,并且已经开发了无数的解决方案来确保软件在其生命周期内继续良好运行。
持续集成和持续交付(CI/CD) 是这些解决方案的顶峰,允许敏捷软件开发社区中的软件开发人员比以往更快、更安全地交付解决方案。
CI/CD 是一种文化和实践的集合,可以为科学界提供大量的东西。
在过去的一年里,我作为一名数据科学家,在与经验丰富的行业软件开发人员一起工作的同时,构建生物信息管道并对其进行基准测试。在此期间,我越来越清楚地认识到,在科学计算领域引入 CI/CD 或类似的系统可能有很多好处。
我称之为“持续科学”,它提供了一个机会,通过数据驱动的科学来提高再现性、减少浪费并加速我们的集体理解。
科学软件当前面临的挑战
众所周知,现代科学正面临一场再现性危机,科学软件也不例外。
虽然复制一篇已发表的论文通常很困难,但复制计算尤其难以实现。通常,科学家必须检索现有解决方案的所有开放源代码、所有数据输入和所有数据输出,然后才能与他们的新提案进行比较。
检索所有这些资源不仅是一项困难而漫长的任务,而且由于数据的不良记录、有限的代码共享或版本控制以及缺乏以不同编码语言实现的现有解决方案的专业知识,这通常是不可能的。
再现性的挑战严重地影响了个人,因为它减缓了他们的研究,并耗费了他们必须花费在验证软件完整性上的宝贵时间。
然而,公共效应更严重,因为这减缓了领域的进展,阻碍了蛋白质组学等重要科学领域的进展。
不幸的是,所有这一切意味着像我这样编写科学代码的人往往会花更多的时间来尝试实现算法和代码之间的有效比较,而不是构建新的令人兴奋的解决方案。
当我们考虑到全球实验室之间发生了多少重复工作时,这是令人难以置信的浪费。
此外,如果工具构建者很难进行比较,那么很可能几乎不可能相信像生物学家这样的用户能够被恰当地告知他们正在使用的工具。
输入 CI/CD 和连续科学的发展(双关语)。
在 Unsplash 上科学高清拍摄的照片
什么是持续集成/持续交付,为什么我们需要这样的东西?
CI/CD 是一种软件工程文化,围绕着随着新解决方案的交付而自动检查代码的任务而构建。这意味着代码可以随时更新,工程师可以确信,无论代码发生多大的变化,它都会运行良好。
我将用一个类比来解释这一点——我爱我的 Fitbit。
我用它来跟踪对我的健康有意义的指标,比如我每天的步数和我的平均心率。当然,我的 Fitbit 从来不会强迫我锻炼,但当我的好习惯开始消失,我需要更多外出时,它就变得非常明显。
自动跟踪某些东西的状态,如身体的健康状况或代码的健康状况,因为它会发生变化,这使得维护它并保持在您的目标的轨道上变得更加容易。代码健康是真实的,因为随着时间的推移,算法可能会失去与常见输入格式的兼容性,或者在编辑时变得杂乱无章、错误百出。就像身体健康一样,如果没有得到适当的照顾和监控,算法和工具也会随着时间的推移而失去优势。
在 Mass Dynamics,我见过托管服务器应用 CI/CD,详细说明如何在每次更改代码时运行和测试代码。通过这样做,我们能够自动获得我们的代码在任何时候都工作的信心。如果检查不是自动的,我们不可能保持它的健康。
相比之下,在科学界,我们看到一个非常不同的场景。
虽然许多科学工具都很棒,但每年构建的新算法/工具的数量不仅通过不断的比较和评估为开发人员社区创造了工作,也为用户区分哪些工具最适合他们的需求创造了工作。
一个复杂因素是,许多工具不能自动运行,另一个复杂因素是,即使对于相同的科学问题,它们也经常采用不同的输入,产生略有不同的输出,这使得比较变得困难。
这意味着对新方法的信心是缓慢的,并且是由构建基准测试脚本的个体社区成员辛苦获得的(这些脚本本身发布的频率低于工具代码本身)。通常,这些脚本的结果是惊人的论文,讲述了一个创新解决方案的故事,但这些努力是重复的(通常它们本身很难比较)。
回到健康类比,科学软件工具可能是健康的,但我们只知道这一点,因为我们支付了偶尔复杂的医疗评估——或更糟——手术!
知道哪些科学工具起作用应该不难。不难知道哪种科学工具更适合给定的用户或问题。
那么我们如何解决这个问题呢?我们如何减少科学开发人员创建和测试新解决方案所需的时间和精力,同时确保该软件的消费者对其使用充满信心?
持续科学解决方案
为了更好地阐述我提出的解决方案,我画了一个图形,希望它能传达出持续科学概念的模块化和优雅。
图 1 显示了如何将数据集、算法和评估指标全部模块化,并在单个服务器上运行。这个服务器可以是一个公共的、透明的资源,以显示给定计算挑战的进展。
图 1:作者的原始数据(约瑟夫·布鲁姆)
具体来说,连续科学服务器可以通过共享基础设施和公共数据格式来工作,以允许使用公共数据集和公共基准对算法进行相互比较。数据集、算法和基准都可以独立提交,但被一个共同的问题联系在一起。应该公开列出每个算法在指标和数据集上的性能。
虽然 CI/CD 强调检查代码的健康状况,但 Continuous Science 可以在公共基准和数据集上评估算法性能,这些基准和数据集对社区是透明和可访问的。
如果社区能够走到一起,就解决个别问题(如蛋白质推理问题)的算法的通用格式和基准达成一致,那么合乎逻辑的下一步将是建立公共服务器,在所有提交的算法和数据集上执行这些基准。
结果可以实时显示在网站上,这些解决方案的用户可以浏览,就像一个科学健康的仪表板。
此外,建立包含数据、算法和评估指标模块的管道的一个好处是,我们可以使解决方案民主化。如果一个新的解决方案在一个新的、合法的、但以前没有预料到的指标或数据集类型上表现良好,那么可以将它们提交给工具,并由所有人来审查结果。
一个类似的令人敬畏的概念的例子是 Kaggle ,这是一个数据科学竞赛平台,人们可以提交数据问题,并设置基准以与提交的答案进行比较。数据科学家通过提交不同算法的结果来竞争。
虽然“Kaggle”有一种连续的味道,因为每个上传的结果集都会被自动评估以检查解决方案的质量,但连续科学在众包测试数据集和评估指标方面走得更远。
可能的挑战和希望的理由
想法往往在一开始就不切实际。考虑到我最近工作过的一些领域,一些迫在眉睫的挑战跃入脑海。
这些是:
- 最流行的解决方案必须是开源的,这样社区才会关心比较的结果。
- 要使运行状况检查自动化,解决方案必须是自动化的。
- 解决方案必须共享共同的输入和输出,以便进行公平的比较。
最终,为了克服这些技术挑战,我们需要在可扩展解决方案的开发上进行开放和诚实的分享和合作,这与资助系统可能强加给我们的竞争文化相反。
尽管研究人员被迫竞争资金,但科学家们共同努力创造了许多倡议,以提高科学的可及性和透明度。
尤其是,将“”开放科学作为解决可复制性危机的驱动力令人振奋。创建公平数据(可发现、可访问、可互操作和可重复使用)的努力正通过像本文这样的论文进入蛋白质组学这样的高科技领域,它清楚地表明了全球共同的善意和共同的愿望,即减少研究的竞争,加强合作。
一个竞争更少、合作更多的研究社区正是那种可以通过持续的科学来分担维护我们算法健康的责任的社区。
总之:
可复制性危机是真实的,我们可以从令人敬畏的软件开发文化中获得灵感来帮助我们解决它。
通过“持续科学”服务器跟踪和比较我们算法的健康状况的公共努力,可以解决科学中软件的可再现性和可访问性,就像我们用健康设备跟踪和维护我们身体的健康,用 CI/CD 服务器跟踪和维护我们的代码一样。
这些公共资源可以加速同行的共识和标准化,就像开源更广泛地影响了技术世界一样。
将 CI/CD 文化引入科学是未来之路。它将为科学开发人员提供一个公共资源,用于维护和比较支持非计算科学家做出有益于所有人的发现的解决方案。
如果你觉得这篇文章有趣,我很乐意与你讨论。你可以在 joseph@massdynamics.com 找到我。
非常感谢我所有了不起的同事和朋友们,他们编辑了这篇文章并给了我反馈!
国立癌症研究所在 Unsplash 上拍摄的照片
机器学习系统的连续测试
原文:https://towardsdatascience.com/continuous-testing-for-machine-learning-systems-a8519eede545?source=collection_archive---------21-----------------------
通过 ML 产品生命周期验证机器学习系统的正确性和性能。
托尔加·乌尔坎在 Unsplash 上拍摄的照片
目录
- 机器学习系统中的测试
- ML 测试的范围
- 我们什么时候进行不同类型的测试?
- 结论
机器学习系统中的测试
软件行业中的测试是一个经过充分研究的成熟领域。从不计其数的失败项目中吸取的好的实践帮助我们频繁地发布,并且有更少的机会看到产品中的缺陷。像 CI、测试覆盖和 TDD 这样的行业惯例被很好地采用,并为每个项目量身定制。
然而,当我们试图将 SWE 测试哲学借用到机器学习领域时,我们必须解决一些独特的问题。在这篇文章中,我们将讨论 ML 模型(系统)测试中的一些常见问题,并讨论潜在的解决方案。
ML 系统在这里代表一个生成可供用户使用的预测(洞察)的系统(管道)。它可能包括一些机器学习模型。例如,OCR 模型(系统)可以包括一个用于检测文本区域的 ML 模型、一个用于判断当前文本区域类别的 ML 模型(汽车牌照与路标)以及一个用于从图片中识别文本的模型。
ML 测试的范围
模型由代码(算法、预处理、后处理等)、数据和促进运行时的基础设施组成。
ML 系统测试的范围,图片由作者提供
不同类型的测试涵盖了系统不同组件的质量保证。
数据测试:确保新数据满足你的假设。在我们训练模型和进行预测之前,需要进行这种测试。在训练模型之前,X 和 y(标签)
管道测试:确保你的管道设置正确。这就像 SWE 中的集成测试。对于 ML 系统,它也可以测量一致性(再现性)。
模型评估:评估你的 ML 管道有多好。取决于您使用的指标和数据集,它可能指不同的东西。
- 对维持/交叉验证数据集的评估。
- 部署管线和地面实况的评估(连续评估)。
- 基于系统用户反馈的评估(与业务相关的指标,而不是可测量的 ML 代理)
有许多技术可以应用于该过程,如基于切片的评估、MVP(数据的关键子集)组/样本分析、消融研究、基于用户分组的实验(如 Beta 测试和 A/B 测试)。
模型测试:包括对我们期望模型遵循的行为的明确检查。这种类型的测试不是为了告诉我们与准确性相关的指标,而是为了防止我们在生产中出现不良行为。常见的测试类型包括但不限于:
- 不变性(扰动)测试:输入的扰动不影响模型的输出。
- 方向性期望测试:为了实现我们的应该对模型输出有一个可预测的效果。例如,如果手术中失血量增加,输血量也应该增加。
- 基准回归:使用预定义的样本和精度门来确保模型版本不会引入疯狂的问题。
- 过度拟合(记忆)测试:尝试用整个数据集的一小部分来过度拟合模型,并确认模型是否能够记忆数据。
我们什么时候进行不同类型的测试?
我们什么时候进行测试?作者图片
有些人可能会问,为什么我们需要使用维持评估和持续评估来衡量 CI 和服务时间方面几乎相同的指标。
一个原因是,我们无法通过查看预定义维持数据集的指标来全面评估模型性能,因为数据泄漏有时比看起来更难检测。例如,一些预期在服务时间内存在的特征被证明具有获取的高延迟,因此我们的训练模型不能习惯于看到该特征总是为空。
有时模型评估可能非常昂贵,因此将全周期维持评估集成到 CI 中是不可行的。在这种情况下,我们可以在 CI 中定义一个子集回归评估,并且只在重要的里程碑之前进行完整的评估。
模型测试不是一次性的步骤,相反,它应该是一个与自动化设置持续集成的过程。一些测试用例可以在 CI 过程中执行,所以每次代码提交都会触发它们,我们可以保证 repo 的主要分支中的代码/模型质量。其他的可以在服务环境中进行,所以我们不会对系统的性能视而不见,当我们有问题时,我们可以有相对充足的时间来解决问题。有时,服务环境中正在进行的测试可以被视为监控组件的一部分,我们可以与警报工具集成以结束循环。
结论
机器学习系统不容易测试,不仅因为它包括更多要验证的组件(代码+数据),而且它具有动态性。虽然我们没有改变任何东西,但我们的模型可能会因为数据变化(数据漂移)或事物的本质随着时间的推移而变化(概念漂移)而变得陈旧。
自动化测试是 CI / CD 中的一个重要组成部分,用于以较小的占用空间验证管道的正确性。虽然在我们说一个新的 ML 流水线已经可以生产之前,手工测试和人在回路中的验证仍然是至关重要的步骤。管道投产后,持续的监控和评估可以确保我们不会盲目行动。最后,基于客户反馈的测试(即 A/B 测试)能够告诉我们,我们试图解决的问题是否真的有所改善。
在 ML 系统测试中没有银弹,持续地尝试覆盖边缘情况将帮助我们减少犯错误的机会。希望有一天我们能找出一个简单的度量标准,比如代码覆盖率,来判断我们的系统是否足够好。
参考:
- 机器学习系统的有效测试。
- 使用反模式避免 MLOps 错误
- CS 329S:机器学习系统设计
对比对比学习方法
原文:https://towardsdatascience.com/contrasting-contrastive-learning-approaches-c3eab8a4728c?source=collection_archive---------17-----------------------
思想和理论
深入探讨哪些计算机视觉任务是很好的基准,数据集如何影响模型性能,以及哪种编码器是最好的通用主干。
链接:Github论文
近年来,我们看到了计算机视觉领域新的自我监督学习方法的爆炸式增长——研究人员已经成功训练了神经网络,这些网络在公共基准上表现非常好,如使用大部分未标记数据的 ImageNet 分类。
图文由温森韩
事实证明,理解是什么使一幅图像与其他图像不同,就足以产生该图像的抽象表示,这种表示可用于现实世界的任务,如语义分类。这种方法的早期成功引发了大量描述这一主题的变体的出版物,这些变体彼此之间都有微小的改进。
我们现在有诸如 PIRL 、 CPC 、 SimCLR 、 MoCo 和 SwAV 等方法,这些方法都使用一种称为对比学习的特定类型的自我监督学习来产生显著的结果,在对比学习中,编码器被训练来识别同一图像的稍微视觉增强版本,因为它们彼此相似,而与其他图像不同。
虽然这种爆炸性的研究速度对于推进一个新的想法很有帮助,但它也产生了许多难以比较或整合的独立线索。在这篇博客中,我想谈谈自我监督的计算机视觉研究的现状和我最近发表的一篇论文的问题,以及旨在解决其中一些问题的论文和 Gabriel Ilharco 、 Ludwig Schmidt 、 Kiana Eshani 和 Roozbeh Mottaghi 。
在我们深入探讨之前,让我们快速回顾几个关键术语,以及我将如何在本文中使用它们:
预训练算法:虽然术语“预训练算法”在深度学习中的定义相当松散,但在这篇文章中,我将使用它来描述最近流行的作品(如 MoCo 和 SwAV)提出的整个预训练管道。
预训练数据:这是用于计算机视觉编码器自我监督预训练的数据集。大部分作品为此使用 ImageNet。
编码器:在计算机视觉中,我们通常将我们的网络分为两个组件:通用特征提取器,它将图像的原始像素数据编码为有用的抽象表示;以及终端任务网络,它使用该抽象表示来完成一些现实世界的任务。前者就是我在这篇博文中所说的编码器。
终端任务网络:如上所述,终端任务网络是我们的模型的一部分,它被定制来执行特定的现实世界任务,如图像分类,因此它必须针对每个任务分别进行调整。
结束任务:结束任务是我们的模型可以执行的一些有用的任务。通常,这些都是实际的事情,比如从图像中估计房间的深度或者对狗的品种进行分类。最终任务是一种将我们的抽象模型与现实世界的工作联系起来的方式,人们可以从中受益。
终端任务数据:这是与特定终端任务相关联的训练数据集,用于训练终端任务网络对编码器产生的抽象图像表示做一些有用的事情。
所以总而言之,像 SwAV 这样的预训练算法使用一个预训练数据集来训练一个编码器,这是一个从图像中提取抽象表示的通用工具。结束任务网络然后在结束任务数据上被训练,以使用这些抽象表示来执行一些有用的现实世界结束任务。
图表来自对比自我监督对比模型
既然我们都已经掌握了术语,让我们深入探讨一下自我监督视觉领域的快速创新带来的几个关键问题。
1。苹果、橘子和香蕉
虽然各种建议的训练算法都试图创建良好的通用图像编码器,但它们共享非常少的兼容数据点,这意味着将该算法应用于完全相同的模型架构,使用完全相同的端点使用完全相同的预训练数据。
像这样的完全匹配的数据点集合通常会减少到只有一个:使用在 ImageNet 数据上训练的 ResNet50 的 ImageNet 分类性能。虽然这是一个很好的基准,但如果它是我们唯一关心的基准,它可能会变得极其危险。除此之外,不同的论文提供了最终任务、预训练数据集和模型架构的非重叠子集的结果,因此比较不同论文之间的数字常常会导致比较苹果和橙子。
2.我们到底在追求什么?
由于 ImageNet 分类是大多数计算机视觉社区可以同步并达成一致的唯一基准,因此似乎真正追求的目标不是生产一个好的通用图像编码器,而是生产一个在 ImageNet 分类上表现良好的编码器,以及类似的最终任务。在某种程度上,任何开发新算法的研究人员都被迫追求这一基准,因为高分将给予算法更多的关注,但这无意中导致社区优化“ImageNet 性能”的代理目标,而不是“良好的视觉编码器”的真正目标。结合大多数论文使用 ImageNet 作为训练数据的事实,我们有一个强大的反馈回路的配方,该反馈回路产生擅长学习数据集(如 ImageNet)的底层分布统计的编码器,而不是擅长理解图像中的内容。
我们的工作
希望这足以让你相信,在自我监督的计算机视觉领域存在着重大的不一致。现在让我们谈谈解决这些问题的方法。具体来说,我将谈论我最近的论文对比对比自我监督表示学习模型的方法和发现。
为了获得一个标准化的参考框架来比较各种自监督算法和预训练数据集,我们必须固定许多实验变量。我们所有的测试都是使用相同的编码器架构(ResNet50)完成的。在训练终端任务网络时,我们还冻结了编码器的权重。
尽管冻结了这些变量,我们仍然使用数千小时的 GPU 时间运行了 700 多个实验。我们在 4 个不同的预训练数据集( ImageNet 、 Places 、 Taskonomy 和 Kinetics400 )和 4 个组合上测试了由 4 个不同的预训练算法( SwAV 、 MoCo v1 、 MoCo v2 和 PIRL )产生的总共 30 个编码器。我们在 20 个最终任务训练集上为每个编码器训练了最终任务网络,并报告了这些编码器在最终任务测试集上产生的结果(参见下面的最终任务图)。
更多详情请参考文件。
现在让我们深入研究结果…
ImageNet 是一个好的基准吗?
如上所述,在 ImageNet 分类结束任务中评估在 ImageNet 数据集上训练的模型似乎是相当循环的。为了衡量这一指标的好坏,我们对 ImageNet 上编码器的性能和其他终端任务进行了相关性分析。这意味着,对于任何给定的编码器,我们计算了 ImageNet 上的性能与其他终端任务的性能之间的关系。我们发现 ImageNet 根本不是一个很好的指标。虽然它在预测类似任务(如加州理工学院和 CIFAR-100 分类)的性能方面相当不错,但在预测不同任务(如深度预测)的性能方面确实很差。
我们根据任务类型(语义或结构)和输出形式(图像级或像素级)将任务大致分为四类。下面是我们所有最终任务及其相应分类的图示:
来自对比自我监督对比模型的图形
下图描绘了 ImageNet 分类准确性与其他终端任务性能的关系。它说明了 ImageNet 性能对于其他图像级语义任务是一个很好的指标,但是对于所有其他终端任务类别是一个很弱的信号。此外,我们甚至看到一些负相关的结果,表明将编码器调优为非常擅长 ImageNet 分类会导致它忽略一些对其他任务类型至关重要的信息。
图片来自对比自我监督对比模型
总而言之,这表明仅报告模型的 ImageNet 分类性能是非常有限的。
所有预训练数据集都是平等的吗?
我们想探索的另一个领域是预训练数据对最终模型的质量有多大影响。由于这个领域的绝大多数工作都是在 ImageNet 上预先训练他们的编码器,所以在这个轴上没有太多的探索。我们在 4 个数据集上训练了 MoCo v2 和 SwAV 编码器:ImageNet、Places、Taskonomy 和 Kinetics400。我们对所有数据集进行子采样,以匹配 ImageNet 的大小,并对 4 个数据集的组合进行了训练。
首先,我们发现在 ImageNet 上训练的编码器倾向于最好地解决语义终端任务,而在 Places 上训练的编码器倾向于最好地解决结构终端任务。这很有意义,因为 ImageNet 包含许多不同的图像,而 Places 包含房间和建筑物的图像。此外,Places 和 ImageNet 都对数据进行了策划、标记和组织,而 Kinetics 是从 youtube 视频中捕获的一系列帧,Taskonomy 是一系列 Matterport 3d 扫描。这表明,尽管我们没有明确使用标签,但使用一个整洁有序的数据集仍然可能有一些优势。这就对在来自互联网的随机完全无监督数据上训练视觉模型的可行性提出了质疑——这是自我监督计算机视觉的伟大承诺之一。虽然最近的一些工作显示了在从互联网上收集的大型数据集上进行训练的成功,但尚不清楚这些数据有多干净和有组织。
其次,我们测试了在类似于我们的终端任务数据的大型数据集上使用自我监督方法预训练我们的编码器是否会产生更好的编码器。对于我们的每个预训练数据集(ImageNet、Kinetics、Places 和 Taskonomy),我们找到了使用相似数据集或相同数据集的子集(分别为加州理工学院分类、Kinetics 动作预测、太阳场景分类和 Taskonomy 深度预测)的相应最终任务。我们绘制了我们在以下 4 个数据集上训练的所有编码器的最终任务性能:
来自对比自我监督对比模型的图形
这个结果对于监督学习来说有些明显,但是在我们的工作中,我们也验证了它对于对比学习也是成立的。有趣的是,我们发现组合数据集平均产生的编码器在所有任务中都相当好,但在任何任务中都不是最好的。事实上,我们还发现,在 ImageNet 和 Places 上训练的编码器平均性能优于组合编码器,因此混合数据集给我们带来的好处似乎少于缺点。
数据集平衡重要吗?
除了上面提到的预训练数据集,我们还使用 ImageNet 的非平衡版本测试了预训练的效果,我们通过对每个类别中的图像数量进行对数采样来产生该非平衡版本(例如,我们从几个类别中获得许多样本,从许多类别中获得少量样本)。我们发现,如果我们在 ImageNet 的严重不平衡的子集上预训练我们的编码器,我们的最终任务性能不会比在相同大小的 ImageNet 的完全平衡的子集上预训练差。我们测试了每个数据集的 3 个不同样本,没有非常大的差异,这表明所有子采样都一样好,并且如果我们从子样本中的特定类获得许多样本,没有神奇的类会为我们提供巨大的性能提升。为了稍微破坏这一发现的兴奋,重要的是要提到我们只使用了 200 个时期训练的小数据集(250,000 个样本),因此需要进一步的工作来验证更大数据集和更长训练运行的这一趋势。
不同的预训练算法是否表现出不同的实力?
我们详细描述的两种训练算法是 MoCo v2 和 SwAV。虽然不是我们工作的主要焦点,但我们的分析提出了两种算法的一些有趣的对比特性。
MoCo v2 往往更擅长于结构性任务,而 SwAV 在图像级任务上表现出色。关于为什么会发生这种情况,我的高层次假设是,由于 SwAV 在最后一层使用聚类方法,它往往会丢失一些空间图像信息。这个理论的一些支持来自我们对编码器进行的分层 CKA 分析的结果。我们发现,平均而言,用 MoCo v2 训练的编码器在早期和晚期层表示之间具有更强的一致性,这表明在最终编码中保留了更多的空间信息。下图展示了 MoCo 和 SwAV 编码器在像素级和图像级任务中的性能差异:
图片来自对比自我监督对比模型
如果我们试图为需要空间信息的任务构建自定义编码器,这可能是一个有用的数据点,因为我们现在有证据表明 MoCo v2 是这项工作的更好的预训练算法。在这里,我们看到了将 ImageNet 分类性能作为我们的基准的另一个缺点。由于 SwAV 在这一特定的最终任务上优于 MoCo v2,许多人可能会认为它总体上更好,而我们的研究表明现实并不是如此清晰。
自我监督编码器对所有下游任务都有用吗?
简单来说,答案是肯定的。对于我们测试的每个任务,自我监督模型都表现得非常好,事实上,除了 3 个任务,它们都优于监督的 ImageNet 基线。受监督编码器表现较好的 3 个最终任务是 ImageNet 分类、ImageNet v2 分类和 Pets 分类(与 ImageNet 非常相似)。由于我们没有为手头的任务微调编码器,这个结果一点也不奇怪,因为在 ImageNet 上训练的监督编码器在编码器训练期间有效地微调了任务。对于其他一切,自我监督的方法表现更好,这给了我们一个强烈的迹象,他们产生更好的通用编码器。
此外,我们发现一些终端任务从使用自我监督模型中获得了比其他任务更大的提升,即结构性任务。下图显示,虽然一些自监督编码器在每个任务类别中都优于监督基准,但几乎所有的自监督编码器在结构化任务方面都优于监督基准,甚至那些预训练数据集和预训练算法与最终任务不匹配的编码器也是如此:
图片来自对比自我监督对比模型
那么我应该使用什么编码器呢?
在考虑了所有上述结果之后,很明显当前的标准计算机视觉编码器(在 ImageNet 上用监督学习训练的 ResNet50)通常不是最好的通用编码器。我们发现,一些经过自我监督学习训练的编码器在解决最终任务方面几乎总是更好,并且一个特定的编码器(在 ImageNet 上经过 SwAV 训练)在超过 75%的最终任务方面更好。
下图显示了自监督模型相对于监督 ImageNet 的相对改进水平。它还表明,ImageNet 和 Places 往往是实现上述最佳结果的两个数据集。
图片来自对比自我监督对比模型
更多未回答的问题
虽然我们在工作中进行了 700 多次实验,但我们只描绘了自我监督计算机视觉整体前景的一小部分。为了获得我们所做的详细结果,我们需要修正许多变量,这给我们留下了许多未解决的问题,例如:
- 模型架构如何影响不同自监督算法的性能?
- 微调整个编码器会显著影响性能吗?
- 如果我们为更多的时代训练编码器,我们观察到的趋势会消失还是变得更明显?
这些都是未来工作的良好起点,将进一步帮助我们理解自我监督计算机视觉的优点和缺点。
结论
虽然这篇博文指出了自我监督视觉领域当前工作的许多缺陷,但庆祝它的许多成就也很重要。我们的论文发现证据表明,对比学习方法在产生良好的通用编码器方面优于监督学习,进一步验证了这不仅仅是一个巧妙的技巧,而是一个真正的重要进步。然而,我们也已经表明,在单一维度(ImageNet 分类)中衡量进展可能会导致我们忽略更大画面的某些部分(比如 MoCo v2 在我们测试的近一半最终任务中优于 SwAV 的事实)。
总之,我想从这项工作中提供 4 个关键的收获,可能对计算机视觉研究人员和工程师未来的计算机视觉项目有所帮助:
- 自监督图像编码器是伟大的通用特征提取器,你应该考虑在你的下一个项目中使用它。我会推荐一个 ResNet50,在 ImageNet 上用 SwAV 训练 800 个历元(或者 Places,如果你的项目是结构化的)
- 如果您的领域中有大量的数据,考虑用它来训练一个自我监督的编码器,因为这可能会给您带来更大的性能提升。
- 如果你正在开发一个新的自我监督模型,确保在各种各样的任务上对它进行评估。考虑使用我们在项目中发布的 ViRB 代码库。
- 如果您正在开发一个新的数据集(或训练 webly 监督模式),您的数据类的平衡可能不那么重要,但拥有一些不同的样本是重要的。
对增长的贡献—分解百分比变化的 SQL 框架
原文:https://towardsdatascience.com/contribution-to-growth-a-sql-framework-for-breaking-down-percent-change-d0573e0f7d7?source=collection_archive---------14-----------------------
现在你终于可以回答:“每个资产/组件/模因对整体百分比变化的贡献是多少?”
这是一个非常基本的概念,我想知道其他人是否已经知道了,那天的数学课我一直在睡觉。但后来我想起,如果我只是想通了这一点,可能还有其他人和我处于同一浪潮中。如果他们和我在同一个波段上,那就意味着他们可能顺便来看看我,别挡我的路,傻瓜🤙🏾 🌊
话虽如此,这是一个非常简单的框架,但我觉得最简单的框架是最强大的,因为即使对那些没有强大数据背景的人来说,它们也是直观的。
我经常面临一个非常常见的分析难题——假设给定的指标有很大的百分比变化。也许你的股票投资组合上涨了 200%。为了这个例子,让我们说业务收入,因为如果有一件事每个人都关心,那就是面包。
通常情况下,第一个问题是“每只资产/组件/meme 股票对整体的百分比变化贡献多少?”
一个可能让你挠头的增长图表的例子。除非另有说明,所有图表均由作者绘制
如果你有多种收入来源,那么通常的第一步是查看不同收入来源的收入,然后查看每个收入来源与前一时期的百分比变化。
我在这里提供了一些我自己公司的例子,亲爱的(这些数字是随机的,不能以任何方式反映现实)。我们有几个附属合作伙伴(也编辑和随机化)提供了我们的大部分收入。这里的每个缩写代表一个附属合作伙伴
按合作伙伴列出的与前 3 个工作日平均值相比的百分比变化
我们可以开始看到哪些合作伙伴增加了或减少了——百分比方面
这很好,但假设你有一些小土豆,它们波动很大,但对整体变化没有任何实际影响。以 IA 为例,在上图中👆🏾与前几周相比,12 月 12 日的百分比有大幅增长,但如果我们看一下每日总收入👇🏾内部调查甚至没有记录为一个信号。
每日收入的总值给了我们一个权重应该是多少的概念
来自的 meme know your meme
我们可以使用一些心理体操来说,哦,让我们只考虑大型网络的运动,以确定它如何影响总数,但这不是我们的分析能力。
我们如何更好地沟通?
我从这里借用的概念被称为对增长的贡献,这是一个最常用来衡量不同行业或 GDP 组成部分对前一时期整体增长或收缩的影响的指标。
有了下面的这个可视化,也许我们可以看到它对我们的难题的应用。
来自 OECD 的图片
每个条形图表示“对增长的贡献”,或组件带动总体增长的百分点数。因此,在 2016 年第 2 季度,我们可以看到私人消费比上一时期的总体国内生产总值增长了约 0.45 个百分点,而库存变化降低了 0.15 个百分点的增长。
所有增长贡献的总和等于总量。
GDP 增长=私人消费+政府消费+投资+ NX +库存变化
≈我在这里盯着它。. 45+. 06+. 05+-. 02+-. 15)∞. 39(顶部的黑线
如何计算对增长的贡献
仅此而已!
如果我们这样做只是为了 LS,它会看起来像
现在让我们看看这在实践中是什么样子
我们可以在 10 月 31 日看到,尽管 LS 较 3 周平均值变化了+24%(未显示),但对总收入百分比变化的总体影响仅为+3.7% CTG,而 CJ 对-2.1% CTG 有很大的下行吸引力。如果我们看看 10 月 31 日的 CTG 总和(3.7%+3% %-2.1%)=+1.9%
幽灵般的对吗?
SQL 时间
现在让我们看看如何将它组合成一个查询!(如果你想看整件事,就跳到最后)
这样做的主要技巧是窗口功能,如果您需要复习请在此处勾选
第一步是计算要与给定的当前值进行比较的先前值。就我们的情况而言,这是最近 3 周的平均值。我们这样做是因为它是一个稳定的指标,允许我们查看与一周中的最近几天相比,今天是好是坏。这很方便,尤其是当有两个星期的季节性时——例如,周一可能是你一周中最好的一天,而周末稍微慢一点。
这有点棘手,但大多数情况都会比这个简单——所以让我们从最难的开始吧!
AVG(Commission) OVER (PARTITION BY providerId, weekday ORDER BY date ASC ROWS BETWEEN 3 PRECEDING AND 1 PRECEDING) AS rolling_3_week_avg
这个函数是说我们想要得到平均佣金。PARTITION 子句告诉我们,我们需要每个提供商的平均值,按工作日对其进行分区可以让我们比较一周中同一天的收入。ROWS BETWEEN 子句定义了我们希望平均为前 3 行直到前 1 行的行——但是只针对那些具有相同 providerid 和 weekday 的分区。我试着在下表中列出它👇🏾
窗口函数允许我们获取最近 3 个工作日的佣金,给我们一个标准化的数字进行比较
撇开这个不谈,我们实际上能够写出我们的 CTG 计算——这是最简单的部分:
记得这个人吗?
(commission — rolling_3_week_avg) / SUM(rolling_3_week_avg) OVER(partition by date) as CTG
你做到了!这是一个金 star⭐️
额外信用:比率变化 CTG
⚠️警告:高级分析区域⚠️
几乎可以肯定的是,可能有一种比我更简单的方法,有人已经在我之前找到了,但不管怎样,我还是来了。
从算术的角度来看,这部分不太直观。有些情况下,您会有与上述相同的问题,但您不是在跟踪数字指标(如收入)的增长,而是在调查一个比率(如点击率或转换率)的变化,您希望按组件细分(如浏览器平台的点击率,或电子邮件副本的转换率)?
某些成分会增加变化,而其他成分会减少变化。除此之外,我们还有每个分量的相对权重,所以我们也需要考虑到这一点。这有点令人生畏,但我保证最终所有的逻辑都会变得有意义。
我们在这里使用的例子是跨两种浏览器(Chrome 和 Firefox)的点击率(CTR)
在第一阶段(我们称之为 P0 ),两个浏览器的点击率相当于 30%。我们将用表格而不是图表来做这件事,因为这样更容易理解。完整的床单文件可以在这里找到。
到目前为止一切顺利 ‘
当跟踪比率变化时,需要理解的一个关键指标是加权系数。你可能熟悉加权,比如说,根据家庭作业和期末考试来计算你的期末成绩。权重因子越大,对最终结果的影响越大
现在让我们来看一个不同时期的变化——P1
FF 向上,CH 向下,整体向下
在我们的例子中,Chrome 有一个大得多的用户群,所以它有一个更高的权重因子,这个权重因子是用它的节目数/所有节目数的和来计算的
对于铬合金= 9000/(1100+900) = 0.89
我们对 Firefox 做了同样的事情来获得每个平台的权重。
所有加权因子的总和应该等于 1,见上文
在 P1,我们看到总体比率从 30%的 CTR 下降到 20%。然而,当按浏览器分类时,我们看到 Firefox 上升,Chrome 下降。火狐的崛起在多大程度上抵消了整体下跌?答案比你想象的要难,因为分母随着分子一起变化,导致相对权重也随之变化。🤔
为了理解 P1 权重背景下的 P0 比率,我们需要调整 delta。
原始增量只是相对于 P0-P1
的总百分比变化,对于 FF 来说是 0.55–0.3 = 0.25,这意味着 FF 的 CTR 增加了 25%的绝对百分比。
但是我们然后通过乘以新的 P1 权重来调整它,所以
0.25 * .11 = 0.03
这是权重调整后的δ(WAD?).这个重量调整的增量是一个等价的概念,我们的 CTG,你可以看到,所有 WAD 的总和给我们-10%,CTR 的综合下降。现在让 GFTO 超越自我,进入有趣的部分。
SQL 时间
通常,当我发现自己在做这种分析时,我会查看两个特定的日期范围,然后寻找它们之间差异的贡献者。这里的场景是在商店级别上跟踪点击率的急剧下降。
所以我们的 SQL 方法会记住这个方法。第一步是将两个日期范围转换成一行。
WITH step1 as (
select
name store_name
-- case statements allow us to group each date range into a given label - p0 and p1
, case
when day between "2020-10-27"
and "2020-10-28"
then 'p1'
when day between "2020-10-19"
and "2020-10-20"
then 'p0'
else null
end as week
, sum(clicks) as shows
, sum(shows) as sessions
from
base
group by
store_name
, week
having
-- limiting to sessions > 0 will help remove divide by 0 errors down the road
sessions > 0
)
, period_split as (
select
store_name
-- kind of a pain, but this is the best way I know to pivot
, sum(if(week = "p1", shows, 0)) as p1_shows
, sum(if(week = "p0", shows, 0)) as p0_shows
, sum(if(week = "p1", sessions, null)) as p1_sessions
, sum(if(week = "p0", sessions, null)) as p0_sessions
from
step1
group by
1
)
这将为我们提供一个很好的数据透视表来开始我们的原始值。下一步相当简单,唯一棘手的部分来自构建窗口函数来寻找权重。
sum(p1_shows) over (partition by store_name) / sum(p1_shows) over() as weight_p1
窗口函数将首先返回为给定商店over partition by store_name
划分的节目,然后用over ()
子句将其除以所有商店的所有节目的总和。布埃诺?
select
*
-- this is the critical step where we adjust the raw ratio change and multiply it by the P1 weighting to get the adjusted delta
, ratio_change * weight_p1 as weight_adjusted_delta
from
(
select
store_name
-- get ratios from raw values
, p0_shows / p0_sessions as p0_ratio
, p1_shows / p1_sessions as p1_ratio
-- get the raw ratio change
, p1_shows / p1_sessions-p0_shows / p0_sessions as ratio_change
-- use a window function to find the weighting factor of each individual store
, sum(p1_shows) over(partition by store_name) / sum(p1_shows) over() as weight_p1
from
period_split
where
-- for the sake of presentation, let's ignore the super small potatoes
p0_shows > 10
)
这给了我们漂亮的完整图表
只要打破我们所有的图表。做就是了
在这里,我们可以清楚地看到耐克导致点击率大幅上升,而 Urban Planet 由于完全崩溃导致点击率大幅下降。这里有一些古怪的数字,所以绝对有理由深入调查这两家商店。这里的一个好方法是从主要指标计算中删除这两家商店,看看行为是否正常,这样您就可以明确地将责任归咎于这两个坏蛋🥚
再见,数据牛仔……🤠
附录
Pt 1 的完整代码
#standardSQL
with
TRANS_TRANS as (
select
A.affiliate_Provider_Id as providerId
, cast(trx_time as date) as date
, cast(sum(A.affiliate_Sale_Value) / 100 as numeric) as gmv
, round(cast(sum(A.affiliate_Commission) / 100 as numeric), 0) as Commission
from
`honey-production.dbt.fct_affiliate_transactions` as A
left join `honey-production.analytics.stores_master` as B on
A.store_id = B.storeid
where
1 = 1
and cast(trx_time as date) >= '2020-01-01'
group by
1
, 2
)
, base as (
(
select
date
, weekday
, providerid
, Commission
, avg(Commission) over(partition by providerId, weekday order by date asc rows between 3 preceding and 1 preceding) as rolling_3_week_avg
from
(
select
date
, extract(DAYOFWEEK from date) as weekday
# date_trunc(A.Date, month) as month,
, providerId
, sum(Commission)*(rand()/2) as commission
, sum(gmv) as gmv
from
TRANS_TRANS where providerId in ("CJ","IA","LS", "AW")
and
date >= '2020-01-01'
group by
1
, 2
, 3
)
)
)
, final as (
select
date
, weekday
, providerid, Commission as provider_commission
,(Commission-rolling_3_week_avg) / rolling_3_week_avg as pct_change
, sum(commission) over(partition by date) as total_commission
, sum(rolling_3_week_avg) over(partition by date) as total_commission_3_week_avg
, (commission - rolling_3_week_avg) / sum(rolling_3_week_avg) over(partition by date) as CTG
from
base
where
rolling_3_week_avg > 0
order by
commission desc
)
select
*
from
final
where
date between "2020-12-03" and "2020-12-12"
union all-- this union is necessary in Periscope to make the "total" line show up. It's pretty annoying
(
select
date
, weekday
, "total" as providerid, null as provider_commission
, null as pct_change
, null as total_commission
, null as total_commission_3_week_avg
, sum(ctg) as ctg
from
final where
date between "2020-12-03" and "2020-12-12"
group by
date
, weekday
, providerId, provider_commission
, pct_change
, total_commission
, total_commission_3_week_avg
)
Pt 2 的完整代码
#standardSQL
with
click as (
select
date(timestamp, 'America/Los_Angeles') as date
, user_id
, store.session_id
, store.name
from
`honey-production.sdata_events_partitioned.ext_apply_codes_click`
where
date(timestamp, 'America/Los_Angeles') between "2020-10-19"
and "2020-10-28"
and cta.type = 'c0_g0'
and cta.img is not null
and cta.img_text is not null
and cta.btn_text is not null
)
, show as (
select
date(timestamp, 'America/Los_Angeles') as date
, user_id
, version
, store.session_id
, store.name
from
`honey-production.sdata_events_partitioned.ext_apply_codes_show`
where
date(timestamp, 'America/Los_Angeles') between "2020-10-19"
and "2020-10-28"
and cta.type = 'c0_g0'
and cta.img is not null
and cta.img_text is not null
and cta.btn_text is not null
)
, base as (
select
date day
, name
, count(distinct click.session_id) as clicks
, count(distinct show.session_id) as shows
from
show
left join click using (date, name)
group by
day
, name
)
, step1 as (
select
name store_name
-- case statements allow us to group each date range into a given label - p0 and p1
, case
when day between "2020-10-27"
and "2020-10-28"
then 'p1'
when day between "2020-10-19"
and "2020-10-20"
then 'p0'
else null
end as week
, sum(clicks) as clicks
, sum(shows) as shows
from
base
group by
store_name
, week
having
-- limiting to sessions > 0 will help remove divide by 0 errors down the road
shows > 0
)
, period_split as (
select
store_name
-- kind of a pain, but this is the best way I know to pivot
, sum(if(week = "p1", clicks, 0)) as p1_clicks
, sum(if(week = "p0", clicks, 0)) as p0_clicks
, sum(if(week = "p1", shows, null)) as p1_shows
, sum(if(week = "p0", shows, null)) as p0_shows
from
step1
group by
1
)
select
*
-- this is the critical step where we adjust the raw ratio change and multiply it by the P1 weighting to get the adjusted delta
, ratio_change * weight_p1 as weight_adjusted_delta
from
(
select
store_name
-- get ratios from raw values
, p0_clicks / p0_shows as p0_ratio
, p1_clicks / p1_shows as p1_ratio
-- get the raw ratio change
, p1_clicks / p1_shows-p0_clicks / p0_shows as ratio_change
-- use a window function to find the weighting factor of each individual store
, sum(p1_shows) over(partition by store_name) / sum(p1_shows) over() as weight_p1
from
period_split
where
-- for the sake of presentation, let's ignore the super small potatoes
p0_clicks > 10
)
order by-- this way we can see the big hitters
abs(ratio_change * weight_p1) desc
Google Sheets with the whole thang
用手势控制 DJI·泰洛无人机
原文:https://towardsdatascience.com/control-dji-tello-drone-with-hand-gestures-b76bd1d4644f?source=collection_archive---------2-----------------------
使用 MediaPipe 手关键点检测器和简单的神经网络来识别手势和控制无人机
在 Unsplash 上剂量媒体拍照
使用手势控制无人机是一个非常常见的主题。但是大多数解决方案都集中在旧的 OpenCV 上。因此,这是快速的解决方案(如果你想直接在无人机上运行它),但很难添加自定义手势,甚至是动作。在这篇文章中,我想介绍一种基于手部关键点检测模型的解决方案,它由 MediaPipe 和简单的多层感知器(神经网络)组成。
介绍
该项目依托两个主要部分——DJI 泰洛无人机和 MediaPipe 快手关键点检测。
DJI·泰洛是任何一种编程实验的完美无人机。它有一个丰富的 Python API(也有 Swift 和 JS APIs 可用),这有助于几乎完全控制无人机,创建无人机群,并利用其相机进行计算机视觉。
MediaPipe 是一个令人惊叹的 ML 平台,拥有许多强大的解决方案,如面部网格、手关键点检测和 Objectron。此外,他们的模型可以在具有设备上加速的移动平台上使用。
这是你需要的启动包:
图片作者| DJI·泰洛,笔记本电脑和人手(狗爪子正在开发中)
进场说明
该应用分为两个主要部分:手势识别和无人机控制器。这些都是独立的实例,很容易修改。例如,添加新的手势或改变无人机的移动速度。
让我们仔细看看每个部分!
手势识别
当然,这个项目的主要部分是致力于手势检测器。这个项目中识别方法的想法受到了这个 GitHub repo 的启发。这里是它如何工作的一个快速概述。
MediaPipe 为他们的手关键点检测器提供了 python 实现。正在返回 20 手界标的三维坐标。像这样:
来自开放媒体管道库的 GIF(链接)
在这个项目中,将只使用 2D 坐标。在这里,您可以看到所有 20 个要点。
图片来自开放媒体管道库(链接
然后,将这些坐标展平并归一化。手势的 ID 被添加到每个点列表中。
作者图片|此类积分列表示例
当我们为每个手势收集了大约20–100 个例子时,我们就可以开始训练我们的神经网络了。
MLP 只是一个简单的 5 层 NN,有 4 个全连接层和 1 个 Softmax 层用于分类。
图片作者|神经网络结构
因为这样简单的结构,我们可以用少量的例子得到极好的精度。我们不需要在不同的光照下为每个手势重新训练模型,因为 MediaPipe 接管了所有的检测工作。
作者图片
在我的实验中,我可以对 8 种不同的手势中的每一种获得超过 97%的准确率。
因为网络的结构非常简单,您可以很容易地使用网格搜索来找到最适合神经网络的超参数。
这是我在这个项目中使用的 Tensorboard 的一个例子:
作者图片|网格搜索可视化示例
无人机控制器
好了,我们有了无人机的图像和基于检测到的关键点返回手势 ID 的模型。但是如何控制我们的无人机呢?
泰洛最棒的地方在于他有现成的 Python API 来帮助我们完成这项工作。我们只需要将每个手势 ID 设置为一个命令。
尽管如此,为了消除错误识别的情况,我们将创建一个手势缓冲区。当这个缓冲区主要包含一个特定的手势 ID 时,我们可以发送一个命令来移动无人机。
以下是项目代码的功能实现示例:
这里可以看到,我们只是根据每个 ID 设置不同方向的期望速度。这使得无人机能够朝着一个方向飞行而不会颠簸。
演示
这是最甜蜜的部分🔥
但是首先,运行项目需要一些准备工作:
设置
首先,克隆存储库
# Using HTTPS
git clone [https://github.com/kinivi/tello-gesture-control.git](https://github.com/kinivi/tello-gesture-control.git)
# Using SSH
git clone [git@github.com](mailto:git@github.com):kinivi/tello-gesture-control.git
1。媒体管道设置
然后,安装以下依赖项:
ConfigArgParse == 1.2.3
djitellopy == 1.5
numpy == 1.19.3
opencv_python == 4.5.1.48
tensorflow == 2.4.1
mediapipe == 0.8.2
图像处理需要 OpenCV,djitellop 是 DJI 官方 Python API 的一个非常有用的包装器
2。泰洛设置
打开无人机并将电脑连接到其 WiFi
作者图片
接下来,运行以下代码来验证连通性
成功连接后,您将看到以下内容
1\. Connection test:
Send command: command
Response: b'ok'2\. Video stream test:
Send command: streamon
Response: b'ok'
运行应用程序
有两种控制方式:键盘和手势。在飞行过程中,你可以在不同的控制类型之间转换。下面是对这两种类型的完整描述。
运行以下命令启动 tello 控件:
python3 main.py
该脚本将启动 python 窗口,显示如下:
作者图片
键盘控制
为了将你的无人机定位到一个完美的地方或者在紧急情况下,你可以使用键盘控制。默认情况下,起飞后,键盘的控制方式是在上
检查以下按键和动作描述列表:
k
- >切换键盘控制g
- >切换手势控制Space
- >起飞无人机(如果降落)或降落无人机(如果飞行中)w
- >向前移动s
- >向后移动a
- >向左移动d
- >向右移动e
- >顺时针旋转q
- >逆时针旋转r
- >上移f
- >向下移动Esc
- >结束程序,降落无人机
手势控制
按下g
激活手势控制模式。以下是我的回购中可用手势的完整列表:
图片作者|手势列表
飞行🚀
现在你已经准备好飞翔了。按下Space
起飞,享受🛸
作者 GIF |演示
项目回购
https://github.com/kinivi/tello-gesture-control.git
参考
- MediaPipe 手关键点检测器
- DJI 泰洛 API 包装库
- 使用手关键点的手势识别(Kazuhito00)
附言。这个项目也可以很容易地添加你自己的手势。只需查看自述的这一部分。
P.S.S. 在不久的将来,我将使用一个 整体模型 来检测大距离的手势,并使用 TensorFlow JS 来利用智能手机上的 WebGPU 加速(用智能手机上的摄像头控制无人机)。所以,如果你对它感兴趣,请在 GitHub 上关注我。
控制梯度下降
原文:https://towardsdatascience.com/controlling-gradient-descent-fb5e494ab1ea?source=collection_archive---------19-----------------------
…就像驾驶一辆旧车
拉夫(拉维)凯登在 Unsplash 上的照片
与 Adam 优化算法相比,将要讨论的算法将允许您以大约 10 ⁰的因子常规地达到更低的成本函数值。
继续看下去,看看为什么像“开旧车”!
介绍
在科学和技术领域,有许多计算都需要最小化成本函数(CF)。人们使用 CFs 是因为它们易于构建,并且因为它们的最小值对应于他们寻求了解的内容。它们已经被用于机器学习(ML)、物理学和许多其他领域。事实证明,梯度下降(GD)算法对于寻找 CF 的最小值特别方便。回想一下,GD 通过以下方式对函数 f(θ) 进行运算:将其自变量从 θ_old 更新为 θ_new
其中 α 为学习率,梯度为 ∇f = ∂ f / ∂ θ 。重复这种更新,直到满足停止条件。如图所示,只需要计算梯度,并将 α 设置为一个适当的小数值。
然而,找到 α 的“最佳”值证明是一个问题。通常,人们会使用不同的 α 值进行几次试验优化,看看哪一个看起来会导致最佳行为,然后只选择那个值。然而,即使仅仅是在整个优化运行中使用单个值 α 的想法也是有缺陷的。我认为这相当于试图以单一速度在两个城市之间行驶。例如,在芝加哥和圣路易斯之间开车的最佳速度是每小时 10 英里、40 英里还是 70 英里?当然,对于旅行的不同部分,不同的速度是优选的。这与寻找整个优化运行的最佳 α 的情况类似。
本文的计划是这样的:首先,引入诊断 ρ ,它将洞察 α 是否过大或过小。接下来,将通过一个例子来演示,只是为了建立直觉。之后,给出了一些伪代码来展示如何计算 ρ 而实际上没有额外的成本。最后将展示如何在大家最喜欢的测试题上使用 ρ :对数字进行分类!使用它的算法(NeogradM)优于 Adam,CF 值低了许多数量级。
ρ诊断
我们用下图来解释一下 ρ
作者图片
蓝色 曲线为 CF,两个参数值( θ_old 和 θ_new )标有 红色 圆点。这些值对应的 CF 值为 f_old 和 f_new 。此外,定义 f_est 为基于 GD 算法的估计 CF 值,如下所示
其中 dθ = (θ_new -θ_old) 。注意,这真的只是一个线性方程,就像大家熟悉的“ y = mx + b ”,除了这里的 y = f_est,m = ∇f,x = dθ,b = f_old 。由于 dθ 从 0 到 (θ_new -θ_old) 变化,导致 f_est 的值范围在图中显示为一条 绿色 线。
然而,我们真正感兴趣的是那个图中的 橙色 线。它代表估计值 f_est 和正确值 f_new 之间的差距或“偏差”。在图中,这个偏差表示α是太大还是太小。但是,要让它真正有用,应该是无量纲的。在这里,这是通过将其除以来自 f_est 的垂直落差来实现的。这导致了 ρ 诊断测量:
这里使用绝对值,因为我们只关心大小。
注意,该度量相对于平移和缩放 f 是不变的(同时保持 dθ 不变),这正是所需要的。因此, ρ 作为 α 大小适当性的一种“通用度量”。
如何看待 ρ
你可能在想,我应该用什么值来表示 ρ ?当然,非常小的值将导致低效的更新,而非常大的值将导致相对不稳定和不受控制的更新。
但是,在直接回答 ρ 的一个“最佳值”之前,先考虑一下这个类比。想象一下,有人开着一辆旧车,试图尽可能快地行驶。他甚至不会看速度计;他只注意汽车何时开始高速晃动。这位司机的理由是,“如果车晃动得很小,我可以开得更快,但如果晃动得很大,我就应该减速”。GD 也是这种情况,只不过现在 ρ 是抖音 α 是油门。在这两种情况下,“震动”都是我们希望控制的变量的代理,无论是油门踏板还是学习速率 α 。
这位司机的理由是,“如果车晃动得很小,我可以开得更快,但如果晃动得很大,我就应该减速”。GD 也是这种情况,只不过现在 ρ 是抖音 α 是油门。
总结一下,控制算法变成:如果 ρ 太大,减小 α ,如果 ρ 太小,增大 α 。当然,理想的是将 ρ 保持在一个固定值。在下一节的示例中,将展示如何做到这一点。这被称为“常数 ρ ansatz”,达到这个值的一个 α 被称为理想学习率。
一个例子
证明 ρ 有用的一个很好的例子是一维四次 CF。我们需要计算 ρ 的变量是:
一个简单的计算揭示了
其中 q = αθ 。需要注意的最重要的特征是 ρ 现在取决于 θ 。这意味着单个 α 将根据在 θ=0 处接近最小值而产生不同的效果。更有趣的是,这个等式可以很容易地倒过来有利于 α。假设小 q,
虽然相当简单,但这其实相当了不起。我们现在有一个公式,在给定 ρ 的期望值的情况下,通过该公式来设置 α 。随着 GD 算法的每次迭代,随着 θ 的变化,该公式保证保持 ρ 的目标值。这被称为“理想 GD”算法,如下图所示;它显示了 Adam 和理想 GD 的 log f 和 logρ 与迭代。
作者图片
在图中,目标值是 ρ = 0.1。S o,在理想 GD 的每次迭代中,根据上述公式将 α 设置为 0.1/(6θ),。(两种算法的初始 θ 都是 -3 。)该图显示,仅经过 150 次迭代后,用理想 GD 达到的值比来自 Adam 的值小超过 10 倍。显然,运行时间越长,这个因素就变得越大。此外,它还显示,对于 Adam,它开始趋于平稳的阶段与它的 ρ 下降的阶段一致。在图中,这发生在第 50 次迭代附近。这个特征在亚当身上反复出现。由于 ρ 没有用 Adam 控制,所以是自由进化;在这种情况下,它变得非常小,导致低效的更新。本质上,亚当有内置的正则化,因为它的 ρ 自然变得非常小。这类似于提前停止,也是它趋于“停滞”的原因。此外,运行 Adam 也是一个挑战,因为必须进行大量的试运行来为 α 选择一个合适的值。关于理想的 GD 算法,主要问题是它使 CF 变得如此之小,以至于人们不得不担心机器精度误差,因为数字变得那么小。
本质上,Adam 有内置的正则化,因为它的 ρ 自然变得非常小。这类似于提前停止,也是它趋于“停滞”的原因。
高效计算 ρ
在上一节中,我们给出了一个简单成本函数的示例,并确定了 ρ 和 α 之间的精确关系。利用这一点,可以将 α 设置为 ρ 目标值的函数。在实际应用中,CF 变得极其复杂,并且这种关系的计算变得不可能。相反,测量值 ρ 将用于设置 α 。现在看来, ρ 的公式使得每次迭代需要两次 CF 计算。然而,每次迭代只需一次计算就可以轻松测量 ρ 。首先,让我们从 GD 的一些基本伪代码开始:
INIT: θ, num
FOR: i = 1 to num+1
f = f(θ)
g = ∇f(θ)
dθ = -αg
θ = θ + dθ
RETURN: θ
鉴于到目前为止的讨论,它应该是不言自明的。现在,这个版本最重要的是 FOR 循环中以下操作的顺序:(1)求值 f , (2)求值 g , (3)更新 θ 。
这个" f - g -update "序列现在被修改,因此在循环之前有一个初始的" evaluate f ",在循环内部的顺序是" g -update- f "。这种重写允许访问更新前后的值,并且不需要额外的计算。经过这些更改,伪代码显示为
INIT: θ_old, num
f_old = f(θ_old)
FOR: i = 1 to num
g = ∇f(θ_old)
dθ = -αg
θ_new = θ_old + dθ
f_new = f(θ_new)
f_est = f_old + g.dθ
ρ = get_rho( f_old, f_new, f_est )
f_old = f_new
θ_old = θ_new
RETURN: θ_new
其中 get_rho 是我们等式 ρ 的一个实现。最后,如果这种重写对你没有吸引力,还有其他的方法。例如,您可以在诸如“IF i > 1”的条件中评估 ρ ,以确保 f_old 和 f_new 都可用。
近似 α
这样一来,下一步就是理解如何使用原来的 ρ 公式来设置 α 。事实证明,它可以以近似的方式使用,同样没有显著的开销。记住 ρ 的定义,通过定义数量 A 和 B
这样做是为了抽出对 α 的前导顺序依赖,并使其显式化。因此, A 和 B 都是常量,以 α 为前导顺序。但是注意一般情况下 A 保留 α 依赖,而 B 没有 α 依赖。使用这些等式和 ρ 的定义,很容易得出 α 的表达式
注意,在更新之后,这个等式完全成立。但是 ρ 的值很可能会过大或过小。因此,作为第一近似值(参见 Neograd_v0,单位为秒)。6.3 此处)我们将通过替代 ρ 的目标值来获得新的 α 。只要这两个 ρ 值(目标值和当前值)相差不大,这种方法就能很好地工作。此外,它是近似值的原因是因为一般来说, A 有一些 α 依赖性。最后,请注意我们正在做的技巧是将 α 视为相关变量,将 ρ 视为独立变量,而实际情况正好相反。
让我们考虑一个例子来说明这一点。假设第 7 次迭代后 α=0.1 , B=5 , A=10 , ρ=0.2 。注意到这些值完全满足上述 α 的等式,因为它们必须满足(即 0.1=(5/10)0.2 )。现在,我们希望 ρ 值更接近于 0.1 的目标值,因此我们将 0.1 与相同的 A 和 B 一起代入等式,并将 α 的新值计算为 0.05 。这个新值将用于第 8 次迭代。当然, 0.05 的这个值可能并不理想,因为我们忽略了 A 中的 α 依赖性,但是只要 CF 变化不太快,它就能很好地工作。顺便提一下,您可能会注意到,由于这种技术涉及到在随后的迭代中α的近似值,所以“晚了一天,少了一美元”的说法浮现在脑海中。尽管如此,它仍然工作得很好。
由于这项技术涉及到后续迭代中 α 的近似值,所以“晚了一天,少了一美元”的说法浮现在脑海中。尽管如此,它仍然工作得很好。
下一级近似是,不要试图通过代入 ρ 目标值来获得新的 α ,而是使用与原始值相差不大的 ρ 值。这在我的论文里叫做 Neograd_v1。最后,我们可以把这个算法和现有的结合起来。我发现最有效的方法是将这些想法和动力结合起来;它叫 NeogradM。
这里有一个 NeogradM 应用于数字识别问题的例子(数据来自 Scikit-Learn )。CF 是在神经网络的输出和训练标签之间构造的交叉熵惩罚。从图中可以看出
作者图片
使用 NeogradM 得出的 CF 值比使用 Adam 得出的值大约小 10⁸倍。另外,如图 13 中的我的论文【1】所示, ρ 的值主要停留在目标附近;对于 Adam 来说, ρ 的值要低大约 100 倍。同样,Adam 的情况是 ρ 变得很小,CF 曲线有一个平台。
最终意见
本文的目的是向您介绍 Neograd 系列算法的全文中的主要概念。也许最重要的一点是 ρ 诊断指标易于实施,是学习率的有效代表。如果你继续在你自己的梯度下降程序中实现它,那就是成功了一半。然后,您可能会发现您当前的程序可能会运行得更快。在这一点上,也许你会愿意采取下一步,实施 NeogradM 示例代码在我的 Github 上。
除了这里已经回顾的,全文包括许多其他有用的结果,例如其他度量,GD 的另一个推导,等等。
希望你喜欢这篇文章!
参考文献
[1] M.F. Zimmer, Neograd:具有接近理想学习率的梯度下降(2020) ,arXiv 预印本,arXiv:2010:07873。(已提交出版)
Conv1D 和 Conv2D:你知道 Conv1D 是 Conv2D 的子类吗?
原文:https://towardsdatascience.com/conv1d-and-conv2d-did-you-realize-that-conv1d-is-a-subclass-of-conv2d-8819675bec78?source=collection_archive---------13-----------------------
比较和评估 Conv1d 和 Conv2D
照片由像素上的负空间拍摄
很可能,阅读本文的大多数人已经实现了一些基于 CNN 的神经网络,并想知道在进行时间序列分析时是使用 Conv1D 还是 Conv2D。在这篇文章中,我将解释和比较这两种卷积类型,并回答以下问题:为什么我说 Conv1D 是 Conv2D 的子类?
如果你不能轻易地回答这个问题,我想这篇文章会让你感兴趣的。一如既往,欢迎任何问题/评论。
几个月前,我被要求为一个基于时间序列的挑战创建一个神经网络。数据大概是这样的:
- 数据数量:500
- 长度:3200
- 频率:40
- 频道:1
基于时间序列的长度,我决定实现短时傅立叶变换进行分析。一个数据看起来类似于图 1 所示的曲线图。此外,输出具有如下所示的形状。
- 输入形状:(500,1,3200)
- 输出 STFT 形状:(500,20,160)
一个数据的 STFT
在与几个人交谈后,我意识到在日常生活中与图像打交道的人建议使用 Conv2D,在 Conv2D 中,数据被视为图像。另一方面,处理时间序列的人表示 Conv1D 是最佳解决方案,类似于多通道时间序列任务,其中每个通道对应一个频率。在 PyTorch 的符号中,神经网络的输入是:
- CNN: ( N =256, Cin =20,林 =160)
- 2D CNN: ( N =256, Cin =1,欣 =20,胜 =160)
因此,我们可以实现两种可能的 2 层神经网络来解决这个任务:
正如所观察到的,1D CNN 的参数数量是 8160,而 2D CNN 是 18816,这两种方法都是时间序列分析的有效方法。
然而,在写报告的时候,我想到了以下问题:有没有可能创建一个类似于 1D CNN 的 2D CNN?如果有,执行情况如何?
虽然这一开始听起来很奇怪,但这是可能的,而且为了理解这种说法,有必要了解卷积层是如何工作的。
使用参数内核大小、填充、步幅和膨胀来定义卷积层:
- 内核大小:指滤镜蒙版的形状。
- 填充:添加到图像中的像素数量。
- 步距:输入矩阵上移动的像素数。
- 膨胀:内核中值之间的间距。
每个卷积层的输出取决于这些参数,并使用以下 PyTorch 公式进行计算。
Conv1D
塑造 1D·conv。参考
Conv2D
塑造 2D·conv。参考
因此,即使首先要获得两种类型卷积的相同结果似乎很困难,但问题的答案最终还是要为参数设置正确的值。
让我们用上面提到的例子来研究这个问题。如果我定义一个具有 32 和 64 个过滤器的两层 1D CNN,参数和形状如下所示。
- 输入:( N =256,= 20,林* =160)*
- Conv1d-1: kernel_size=3,padding=1,stride=1,dilation=0
- Conv1d-2: kernel_size=3,padding=1,stride=1,dilation=0
因此,我们的目标是找到 2D CNN 的参数,其输出结果类似于 1D CNN:
- 输出层 1: ( N =256,= 32,林 =160)**
- 输出第二层:( N =256,= 62,林 =160)**
在 2D 有线电视新闻网,翻译为获得:
- 输入 2D: ( N =256, Cin =1,欣 =20,赢 =160)
- 输出层 1: ( N =256, Cin =32,欣 =1,赢 =160)
- 输出层 2: ( N =256, Cin =62,欣 =1,赢 =160)
总之,本文提出的问题的答案非常简单:
设置正确的参数,我们可以创建一个具有与 Conv1D 相同功能的 Conv2D。
特别是,要设置的主要参数是内核大小。对于这种特殊情况,Hin 的内核必须设置为 20,类似于 1D CNN 的频率或频道总数。此外,需要将该维度的填充固定为 0,因此我们得到维度 1 作为该层的输出。
实现如下:
Conv2D
总之,我们能肯定 1D CNN 是 2D CNN 的一个子类吗?正如我在这篇文章中试图解释的那样,我们总是可以创建一个 2D CNN,其功能与 1D CNN 相同,并设置正确的内核大小、填充和步幅。作为一个说明性的例子,我们有这个最后的 2D CNN,它的参数数量类似于上面实现的 1D CNN。
然而,这一结论并不意味着我们应该总是使用 2D CNN 而不是 1D CNN,因为后者在处理例如多通道时间序列时更容易实现。我只是试图表达 Conv1D 和 Conv2D 最终是相同的。
如果你喜欢这个帖子,请考虑 订阅 。你将获得我所有的内容+所有其他来自牛逼创作者的文章!
对话式人工智能聊天机器人,带有使用 Pytorch 的预训练变压器
原文:https://towardsdatascience.com/conversational-ai-chatbot-with-pretrained-transformers-using-pytorch-55b5e8882fd3?source=collection_archive---------11-----------------------
了解如何使用 Huggingface Transformers 构建一个具有 DialoGPT 功能的对话聊天机器人
在 Unsplash 上由 Fitore F 拍摄的照片
介绍
会话系统,或者说 对话系统,已经在现代【NLP】社区中获得了巨大的兴趣。看到机器人可以如此接近地模仿我们的思想、逻辑和情感,就像它们的语言所显示的那样,这真是令人兴奋。今天,我们知道在我们的智能手机中,数字助理就在我们的手掌中,如苹果 Siri 、谷歌助理和微软 Cortana 。它们都能够倾听用户的语言并做出反应,尽管并不完美。
在这篇文章中,我们将教你如何利用 DialoGPT 这样的预训练转换器来实现你自己的对话聊天机器人。我们将使用 Huggingface 提供的变形金刚库来构建这个系统。
所以事不宜迟,让我们开始吧!
教程概述
- 步骤 1:安装库
- 步骤 2:导入库
- 步骤 3:构建对话管道
- 步骤 4:添加开始对话
- 步骤 5:添加连续对话
步骤 1:安装库
我们正在使用的库是拥抱脸变形金刚。要安装它,您只需:
pip install transformers
确保有一个工作版本的 Pytorch 或者 Tensorflow ,这样变形金刚就可以使用其中一个作为后端。
步骤 2:导入库
安装了 Transformers 之后,现在是时候用 Python 脚本导入它了。我们没有使用整个 Transformers 库,而是引入了一个[pipeline](https://huggingface.co/transformers/main_classes/pipelines.html)
模块,它基本上提供了一个非常简单的 API 来完成各种 NLP 任务,而不需要理解复杂的代码。我们还导入了[Conversation](https://huggingface.co/transformers/main_classes/pipelines.html#transformers.Conversation)
对象,稍后我们将把它用于对话管道。
要导入它们,您可以:
from transformers import pipeline, Conversation
步骤 3:构建对话管道
导入相关组件后,现在我们可以通过以下方式开始构建对话系统的管道:
conversational_pipeline = pipeline(“conversational”)
这行代码将使用 DialoGPT 作为模型,一个在对话数据集上训练的 GPT2 模型来设置对话管道。
步骤 4:添加开始对话
现在,我们可以开始和机器人说话了!首先,让我们开始与机器人的两次对话,并询问它电影推荐以及它最喜欢的书是什么:
对话 1:我们今晚去看电影吧——有什么推荐吗?
对话 2:你最喜欢的书是什么?
conv1_start = “Let’s watch a movie tonight — any recommendations?”
conv2_start = “What’s your favorite book?”
然后,我们使用定义的变量构建两个对话:
conv1 = Conversation(conv1_start)
conv2 = Conversation(conv2_start)
之后,我们将两个对话都放入列表中,然后将其提供给对话管道:
conversational_pipeline([conv1, conv2])
最后,我们可以看到机器人返回的每个对话的结果:
【对话 id:a9ba e572-cc11–48 c8-b36f-d 88 BCD 49 b 8 c 0
用户> >今晚一起看电影吧——有什么推荐吗?
bot > > The Big Lebowski,
对话 id:e6ee2d 97–5ee 7–404 b-b2e 5–4dd 527 F9 e9 DD
用户> >你最喜欢的书是什么?
bot>T20【饥饿游戏】
步骤 5:添加连续对话
我们可以通过向之前的对话添加新的用户输入来继续与机器人的对话,然后再次处理对话管道。
想象一下,我们想通过在对话 1 中询问电影是关于什么的以及在对话 2 中询问书的类型来跟进机器人。
对话 1:是关于什么的?
对话 2:酷,这本书是什么类型的?
conv1_next = “What is it about?”
conv2_next = “Cool, what is the genre of the book?”
要在之前的对话中添加新的用户输入,我们可以先做:
conv1.add_user_input(conv1_next)
conv2.add_user_input(conv2_next)
之后,我们可以简单地重用之前的代码,用新的对话集更新对话管道:
conversational_pipeline([conv1, conv2])
最后,您应该看到机器人能够返回与主题相关的新响应:
【对话 id:a9ba e572-cc11–48 c8-b36f-d 88 BCD 49 b 8 c 0
用户> >今晚一起看电影吧——有什么推荐吗?
bot > >大李博斯基
用户> >它讲的是什么?这是一部喜剧,讲的是一个人在电影院找到了一份工作,并得到了一堆工作。、
对话 id:e6ee2d 97–5ee 7–404 b-b2e 5–4dd 527 f 9 e 9 DD
用户> >你最喜欢的书是什么?
bot > >饥饿游戏
用户> >爽,书的流派是什么?
bot > >我不确定,但我觉得是幻想。]
结论
这就是本文的全部内容!希望你学到了有用的东西。在这篇文章中,我们讨论了如何使用 Huggingface 提供的预训练模型实现自己的对话机器人。如果你正在寻找它,为了你的方便,我在下面附上了一个 Jupyter 版本的全部代码:
希望你喜欢这篇文章!如果你喜欢我的作品,请订阅电子邮件列表,这样你就可以在我创作新内容时收到更新!如果感兴趣,也可以随意浏览我的其他帖子:
参考
[1] 苹果 Siri 官网,苹果
[2] 谷歌助手官网,谷歌
[3] 微软 Cortana 官网,微软
[4] 变形金刚 Github ,拥抱脸
[5] 变形金刚官方文档,拥抱脸
[6] Pytorch 官网,脸书艾研究
[7] Tensorflow 官网,谷歌大脑
[8]张,,等.“对话概念:大规模生成性会话应答生成的预训练” arXiv 预印本 arXiv:1911.00536 (2019)。
[9]拉德福德、亚历克等“语言模型是无人监督的多任务学习者。” OpenAI 博客 1.8 (2019): 9。
对话式人工智能:2022 年的趋势和预测
原文:https://towardsdatascience.com/conversational-ai-trends-and-predictions-for-2022-8be05e15e713?source=collection_archive---------9-----------------------
在这篇文章中,我提出了 2022 年市场发展的 6 个趋势和预测。
由于当前疫情形势带来的新的个人和职业生活方式,数字化转型正在快速加速。对话助手是这种转变的一部分,它实现了支持和自助服务请求的自动化。
马修·施瓦茨在 Unsplash 上的照片
在健康状况的推动下,对业务流程自动化的需求持续增长,不幸的是,这种情况可能还要持续几个月甚至几年。2020 年是充满疑问的一年,2021 年是前前后后的过渡年。由于远程工作而导致的团队分散,给公司带来了数字化转型,以及随时随地访问其功能的问题。
支持功能被过度订阅,授权团队为自己做事的需求非常重要。根据您是客户还是解决方案提供商,这种方法被称为自助服务或左移,它包括让客户、供应商和员工能够全天候自己获得答案、解决问题或执行某些操作。
在自动化手段的类别中,我们发现由人工智能驱动的对话助手。这些允许自动处理几个用例,例如:回答重复出现或偶然出现的问题,执行或多或少的简单操作,帮助解决一般的计算机问题,在某些操作中帮助人类,等等。
预测 1:需求将继续增长
尽管全球形势严峻,公司(尤其是业务部门)仍需要找到节约资源和提供服务的方法,这推动了对业务流程自动化(BPA)的需求不断增长。一些支持解决方案从语言处理的角度来看是成熟的,但从使其工作所需的工具的角度来看也是成熟的。
这种成熟度增加了这些项目的成功率。如果这些优势不断得到其他自动化解决方案的补充,例如智能文档处理(IDP ),这些解决方案可以自动处理用户发送的文档(发票、订单、身份证、简历等),那么这些优势将更加有趣。),并且能够与用户就所收集的数据进行交互;以及机器人流程自动化(RPA)脚本,无需开发新的连接器即可访问系统。
2022 年,欧洲(不包括英国)的市场增长预计将是 2021 年的 1.5 至 2 倍。
预测 2:扩大规模
一些公司已经试验了对话辅助解决方案,特别是在消费者和专业服务部门(BFSI、电信运营商、某些公共管理部门),在这些部门部署了几个涵盖不同领域的对话实例。在零售/营销领域,通常有一个单独的实例负责回答网站上买家的问题。机器人通常通过基于文本的界面访问,很少通过语音访问。管理许多日常关系的组织当然最容易接受这些技术。
到 2022 年,随着更多具体案例的出现,使用量将会增加,因此,那些已经启动项目并对这些解决方案的优势和劣势有了良好认识的公司的部署将会成倍增加。优先领域:IT 支持(一般请求、问题解决、订购设备等)。)、HR(一般问题、招聘、新进人员等。)、销售(客户服务)、某些特定业务领域(对我的存款账户的操作、投诉等。).
尚未尝试这些技术的公司将不得不考虑解决方案的实施。市场上的大量解决方案不会让他们容易选择,尤其是因为第一个销售人员提出解决方案通常会有溢价,这可能会导致负面和令人失望的体验。
预测三:机器人大师的出现
随着实例的扩散和所涵盖的不同业务领域的增加,对不同机器人的可访问性将成为问题,并将需要在单个界面中对不同的入口点进行分组。这种通用助手,也称为 Master-Bot,将帮助用户解决需要访问不同业务领域的多个问题或任务。
主-Bot 关系和业务领域(作者的图表)
主机器人是各种服务的单一入口点。它是用户和业务领域之间交流的控制塔。该设备允许用户避免在不同的地方寻找所需的专家来回答他的问题。主机器人根据请求联系这些域。
市场上的几种解决方案已经实现了这种机制,并将在 2022 年首次使用。
预测 4:增加语音测试
普通大众对亚马逊 Echo 或谷歌 Home 这样的语音助手设备很熟悉。然而,这些设备不适合在专业环境中使用。尽管如此,语音在专业领域的用途是多种多样且相关的:作为标准客户电话支持(Callbot)的补充,或者在车间、实验室或车辆等场合作为免提助手(Voicebot)。
部署语音助手所需的技术比传统的“Chabot”更复杂,这使得这些解决方案更难掌握,项目也更难成功。
2022 年,公司将继续测试语音,以了解如何使用这一通道和相关技术(电话、语音识别、语音合成、语音对话管理……)。
预测五:互联助手的幻灭
对过去 4 年中在 Google 中(通过 Google Trend)对几个连接的发言者的名字所做的请求的分析显示,在美国的请求总体上减少了。
【2017 年以来美国联网说话人查询趋势(来源:谷歌趋势)
这些扬声器存在几个问题,这些问题减缓了它们的使用,例如对个人数据的使用缺乏信任,不透明或过于笼统的服务(除非你是音乐爱好者或想在亚马逊上订购产品),以及家庭中的家庭自动化设备水平低下。它们被视为圣诞礼物,而不是家中的重要设备。
这种情况预计将在 2022 年持续。
预测六:新人的没落
自动语言处理的进步和统计模型的可用性使得每个人都可以创建助手。然而,助手不仅仅是一个语言处理单元,还是:对话建模工具,引导工具,允许企业自己监督操作,用户和信息系统的连接器,对话历史,高级角色管理,行为分析单元,等等。市面上的解决方案大多背后都有几年的经验和开发,对新人造成了很高的准入门槛。他们需要有其他解决方案还没有的突破性创新,这将变得越来越难找到。
此外,项目的成功不仅基于技术,还基于对项目周期的掌握,这导致市场的高度专业化,需要在整个项目期间及之后提供支持。尤其是因为公司越来越关注这些解决方案的投资回报。公司在开始创建特定的解决方案之前必须三思。特别是因为一些免费的开源解决方案允许以较低的许可成本实现聊天机器人(但具有较高的项目阶段和维护成本)。
唯一的 FAQ 类型的解决方案将不会成功地在这个生态系统中生存,除非提供极低的价格和/或拥有庞大的基础,这将导致长期盈利能力的问题。
因此,到 2022 年,应该很少有新的进入者,最基本的解决方案将会消失。人工智能技术的当前状态不应该允许重大技术突破迅速出现(至少对于工业用途而言)。今年,我们肯定会看到新的整合,尤其是在解决方案提供商层面,以增加他们的服务组合。
在封闭域上使用微调过的多维语言模型还不允许有保证的结果,例如在支持上下文中可以预期的结果。基于知识图的向导可以很好地工作,但是问题在于填充和维护知识图,这限制了它们的部署和使用。
增刊
如果你想了解更多关于这些话题的内容,以下是我的一些文章:
</14-criteria-for-well-choosing-a-chatbots-solution-2e788aace3b8>
转换升力试验已经停止;过渡到地理实验
原文:https://towardsdatascience.com/conversion-lift-tests-are-dead-transitioning-to-geo-experiments-5496a5450204?source=collection_archive---------26-----------------------
行业笔记
本文是与 Leo Ubbiali 共同撰写的,他是 Babylon Health 的营销分析师,专门研究计量经济学和因果推理在营销中的应用。
iOS 14.5 的影响
已经有很多文章讨论了 iOS 14.5 和 IDFA 弃用对效果营销的影响。这些文章讲述了苹果的变化如何将归因建模的负担转移到广告平台上,降低了广告定位的有效性,并导致 iOS 和 Android 设备之间的 CPM 定价发生变化。
然而,iOS 14.5 的一个很少受到关注的结果是,这些变化对转换升力测试产生了影响。Lift 测试曾经为脸书广告客户提供了增量测量的黄金标准,但现在它们已经被完全否决,没有替代方案。
让我们看看什么是转换升力试验,为什么他们被脸书否决,以及如何地质实验提供了一个前进的方向。
什么是转换提升测试?
转换提升试验(或简称为提升试验)在市场上相当于随机对照试验。
他们试图了解一个广告活动的影响,方法是将广告随机展示给一组用户,让另一组用户拿着它,并在预定的一段时间内寻找两组用户之间的行为差异。
电梯测试寻找行为的什么不同?这完全取决于进行电梯测试的广告商。一个典型的电子商务品牌可能希望了解他们的脸书广告是否推动了本来不会发生的销售,因此他们希望在提升测试中跟踪购买情况作为 KPI。
对照组和治疗组
如果看过该电子商务品牌广告的用户群(T8 治疗组)继续从该品牌购买的比率高于那些没看过该品牌广告的用户群(T10 对照组),那么这将表明该活动产生了增量销售。
作者图片
如果上述情况不成立,即治疗组不会比对照组更有可能购买该品牌的产品,那么可以说该活动没有增加销售额。在这种情况下,任何归因于该活动的销售(通过点击后或观看后归因)都可能是无论如何都会发生的销售。
多少增量?
仅仅因为一个活动产生了递增的结果并不意味着它是一个值得进行的活动。为了评估这一点,我们需要了解活动的每增量转换成本。
从上面的例子可以看出,电子商务品牌在他们的活动上花费了 10 万美元。他们测量了他们活动的治疗组的 7500 次销售(包括活动期间和活动后的一段固定时间),以及他们活动的对照组的 5000 次销售。
简单地说,这些销售数字之间的差异(2,500)是由活动推动的增量销售的估计数字。如果我们将活动成本除以增量销售的数量,我们将得到每增量购买成本的估计值(CPiP);$40.
作者图片
如果这个 CPiP 对品牌来说是可以忍受的(意味着它低于他们的 LTV,并且他们乐于以这个价格获得客户),那么这个活动就可以被认为是成功的。请注意,如果治疗组和对照组之间的销售差异较小,CPiP 将按比例增加,因此活动成功的可能性降低。
改装升力试验的死亡
能够进行转换提升测试的一个相当重要的部分是能够测量两组人的转换量;你的治疗组(看过你的广告)和你的对照组(没看过你的广告)。
IDFA 折旧,ATT,和 SKAD 网络本身并没有提供任何理由,为什么你仍然不能报告(或至少估计)你的治疗组的转换量。他们对广告互动和转换之间的时间延迟提出了一些限制,并要求您至少有一个小的观察期,在此期间转换回发可以慢慢进入。也就是说,没有根本原因阻止您测量治疗组转换量。
对于测量对照组转换体积,情况更复杂;也就是一群没看过某个品牌广告的用户的购买次数。由于各种原因——尤其是 SKAD Network 回发需要一个活动 ID 来确定转化的归属——不可能从 lift 测试的对照组中测量转化量。
有一个提升测试的处理组的转换体积,但没有它的控制组,是没有多大用处的。正如我们之前看到的,这些数字之间的差异才是真正令人感兴趣的,因此,仅仅拥有治疗组转化量甚至不如常规的互动后归因方法有用(因为它忽略了转化和广告互动之间的时间)。
脸书的回应
尽管脸书在今年早些时候宣布,在 iOS 14.5 推出后,广告商将无法创建新的提升测试,但他们几乎没有宣传这一事实。除了广告管理器中的实验页面中的一个小注释,脸书只对他们的电梯测试文档进行了微小的编辑,以警告广告商即将到来的变化。
脸书建议,广告客户用常规的 A/B 测试(无法衡量增量)或品牌提升测试(旨在衡量一项活动对品牌指标的影响,而不是转化率)来取代衡量策略中的提升测试。这相当于脸书放弃了转换提升测试,并迫使广告商寻找其他方法来衡量他们的广告活动的增量。
提示地质实验
随着转化率提升测试的取消,广告客户又回到了绘图板上,寻找一种新的方法来衡量他们广告活动的有效性。
虽然没有因果推断方法可以被认为是普遍的“下一个最佳选择”,但地理实验特别适合在线广告;它们具有很强的统计严密性,并且易于理解、设计和实现。
什么是地理实验?
地理实验是一种准实验方法,其中将非重叠的地理区域( geos )随机分配给对照组或治疗组。由于地理定位,广告只在治疗组的地理区域提供,而对照组地理区域的用户不会看到广告。
作为一个简单的例子,我们可以在美国进行一个州级地理实验,将每个州随机分配给对照组或治疗组。然后,我们会在组成治疗组的州投放广告,而在组成对照组的州暂停广告。
你如何实施地理实验?
假设你可以将广告定位到相关的位置级别(街区、城市、州等),那么建立地理实验就相当容易。)并在地理水平上测量转化率。所有主要的广告网络/跟踪平台都允许这些功能。
步骤 1:地理标识
第一步是决定运行测试的粒度级别..如果您感兴趣的市场是整个美国,那么将州作为您的地理位置可能是有意义的。如果你的市场是一个州,你可以使用 DMAs 或邮政编码将你感兴趣的区域划分成更小的区域。
为了确保测量的统计稳健性,建议不要选择太小的地理区域(即 z ip 代码),因为人们可能会跨越地理边界,转换量可能太低。
步骤 2:地理随机化和分配
一旦我们定义了我们的市场和它的划分,我们需要将每个地区随机分配给治疗组或对照组。
在理想情况下,所有地理位置在过去具有相似的表现,随机化是基本的,因为它确保了除了广告服务之外的两个组之间的可能差异最小化。这起到了防止偏见的护栏的作用。
想法是在运动开始前(预试验期)治疗组和对照组尽可能相似,它们在试验期只有一个因素不同;接触广告。
作者图片
然而,geo 中的差异可能存在,并损害测试的设计和准确性。出于这个原因,通常需要进行初步分析,以便我们可以找到哪些是最好的 geo,以纳入治疗组和对照组。
如何衡量一个地理实验
一旦我们建立了实验,我们可以使用计量经济学方法,如差异差异或综合控制来量化广告增量;如果不投放广告,有多少转化不会发生。
作者图片
这些方法背后的直觉很简单:
- 我们估计了试验期间治疗组的反事实:如果干预没有发生会发生什么(黄色虚线)
- 我们计算实际治疗效果(黄色实线)和反事实之间的差异
尽管这种方法得出的结果不会像转化率提升测试那样准确,但地理实验是一种面向未来的衡量广告效果的方法,因为它们不需要用户跟踪,并且可以应用于不同的渠道。这甚至包括线下渠道。
网上有大量的教程来分析准实验结果,技术演练不在本文的讨论范围之内。有了基本的编码技能,营销人员可以利用非常抽象的软件包,如 CausalImpact (由谷歌开发)或其增强版本 MarketMatching 。
最近脸书发布了 GeoLift,这是一个新的开源包,通过地理实验来测量升力。
展望未来
虽然地理实验需要更多的技术工作来设计、设置和运行,但它们为希望复制转换提升测试的营销人员提供了一条清晰的前进道路。虽然没有广告平台提供开箱即用的地理实验,但脸书过去曾在私人测试版中玩弄过这个想法,他们有可能在未来公开这种工具。
然而,在此之前,有必要熟悉一下作为测量增量工具的地质实验,尤其是在脸书等平台上不再提供的转换提升测试。
最初发表于【https://mackgrenfell.com】。
本文是与 Babylon Health 的营销分析师 Leo Ubbiali 合作撰写的,他专门研究计量经济学和因果推理在营销中的应用。
将 Tensorflow2 模型转换为 OpenVINO
原文:https://towardsdatascience.com/convert-a-tensorflow2-model-to-openvino-c498f526c60b?source=collection_archive---------19-----------------------
装有无数芯片神经计算棒 2。图片作者。
在任何地方运行您的模型的简要指南
如今,机器学习的应用层出不穷。那里有已经训练好的模型和只需要拟合的数据。
当一个人处理机器学习应用程序时,通常很难决定哪个硬件训练模型并卸载推理。
英特尔推出了 openVINO,帮助将模型(主要与计算机视觉相关)部署到任何英特尔设备,无论它们是 CPU、GPU、FPGAs 还是带有无数芯片的神经计算棒。
https://software.intel.com/content/www/us/en/develop/tools/openvino-toolkit.html
这项技术的一个常见用途是使用 openVINO 进行快速推理(即从网络摄像头预测视频中的实时对象)。一些模型需要一个强大的硬件来训练,但是一个更小更便宜的硬件来执行推理就足够了。例如,你可以使用一个复杂的预训练模型,然后在 轻型硬件上运行它,就像一个 RaspberryPi 。
OpenVINO 是一个强大的工具,但它需要一些段落才能正常工作。我们将经历转换模型的过程,将它加载到推理引擎插件中并执行推理。
定制模型
英特尔框架有一个集合可以使用的预训练和优化模型。但是如果你想训练一个定制模型呢?
我们将考虑使用 Tensorflow 进行模型训练,即使 openVINO 支持许多其他框架。步骤大多相似。
我会用 Google Colab 来描述这一切,它应该很容易被复制。
在 Colab 上下载 OpenVINO
首先,我们需要下载 openVINO repository,安装 Tensorflow 的先决条件。
!git clone https://github.com/openvinotoolkit/openvino!cd openvino/model-optimizer/install_prerequisites/ && ./install_prerequisites.sh tf2
你习惯使用 keras 吗
在这一步你可以做任何你想做的事情。创建一个定制 keras 模型,带有定制层。编译它。在任何数据集上训练它等等。
当你对你的训练感到满意时,你可以准备将模型加载到推理机插件中。那么该模型可以用于任何类型设备上的推理。
从 h5 中保存模型
第一步是将模型保存到一个 .h5 文件中。使用 keras API 很容易做到这一点。
model = tf.keras.models.load_model(“/content/model.h5”)tf.saved_model.save(model,’model’)
转换模型
模型需要被转换成推理机可以加载到设备中进行推理的表示。这个步骤可以使用所谓的模型优化器来完成,如下所示。
模型优化器需要输入一些参数,比如 input_shape。
python3 openvino/model-optimizer/mo_tf.py --saved_model_dir model/ --input_shape=\[1,28,28\]
此时,您应该有两个文件 model.xml 和 model.bin ,它们包含对您的定制模型执行推理所需的所有信息。
例子
以下笔记本中提供了此转换步骤的示例:
https://colab.research.google.com/drive/1wiFilpyXv947kLOqFJh_oqEp2224y8IL?usp=sharing
执行模型
当转换后的模型准备好了,下一步就是使用它进行推理。这可以在任何支持的设备上完成。没有必要使用与您执行培训时相同的设备。
安装 openVINO 进行推理
为了运行推理,有必要安装 openVINO 框架。这可以通过 pip 轻松完成。
!pip install --upgrade pip
!pip install openvino
将模型加载到插件中
我们需要将模型加载到设备上进行推理。
推理引擎核心对象具有读取的能力。xml 和。将绑定到网络对象中。
这个网络可以加载到任何设备中,无论是 CPU、GPU 还是 MYRIAD。这是这个 API 的强大之处之一,它可以毫不费力地在任何设备上透明运行。
from openvino.inference_engine import IECore, IENetworkie = IECore()net = ie.read_network(model=model_xml, weights=model_bin)exec_net = ie.load_network(network=net, device_name="MYRIAD")
获取关于拓扑的信息
我们可以检查网络拓扑。这个 API 只支持单个输入,无论如何,如果你在一个视频上运行这个,你需要一次对一个帧进行推理,所以这不是一个大问题。
此外,我们可以检查输入或输出形状,这对于由其他人训练的模型特别有用。我们需要确保数据处于正确的状态。
assert len(net.input_info.keys()) == 1, "Sample supports only single input topologies"assert len(net.outputs) == 1, "Sample supports only single output topologies"input_blob = next(iter(net.input_info.keys())) out_blob = next(iter(net.outputs))net.batch_size = len([0])net.input_info[input_blob].input_data.shape
推理
最后,是进行推理的时候了。给定一个对象 X_test[0] 我们准备在网络上使用 infer 方法来推断它。
res = exec_net.infer(inputs={input_blob: X_test[0]})res[out_blob].reshape(1,10)
结论
我们训练了一个定制模型。
使用 openVINO 模型优化器,我们将转换成将模型加载到推理引擎模块所需的新表示。
当训练好的模型准备好使用推理机来推断输入数据时,它几乎是微不足道的。另外,这可以在任何设备上进行。
使用 Dask 将大型 JSON 转换为拼花地板
原文:https://towardsdatascience.com/convert-large-json-to-parquet-with-dask-58c1e6a4e4fc?source=collection_archive---------25-----------------------
使用 Coiled 将 75GB 数据集上的 ETL 管道扩展到云
图片由阿德里安·匡威通过unsplash.com拍摄
TL;博士;医生
这篇文章演示了一个 75GB 数据集的 JSON 到 Parquet 的转换,它无需将数据集下载到本地机器上就可以运行。首先在本地迭代 Dask 来构建和测试你的管道,然后将相同的工作流程转移到云计算服务中,如 Coiled 和最小的代码变更。
免责声明:我在 Coiled 工作,是一名数据科学传道者实习生。 Coiled 由Dask的最初作者 Matthew Rocklin 创立,是一个面向分布式计算的开源 Python 库。
为什么要将 JSON 转换成 Parquet
从 web 上抓取的嵌套 JSON 格式的数据通常需要转换成表格格式,用于探索性数据分析(EDA)和/或机器学习(ML)。Parquet 文件格式是存储表格数据的最佳方法,允许像列修剪和谓词下推过滤这样的操作,这极大地提高了工作流的性能。
本文展示了一个 JSON 到 Parquet 的管道,用于 Github Archive 项目中的 75GB 数据集,使用 Dask 和 Coiled 将数据转换并存储到云对象存储中。该管道不需要将数据集本地存储在您的计算机上。
完成这篇文章后,你将能够:
- 首先在本地构建并测试您的 ETL 工作流,使用一个简单的测试文件,这个文件可以很容易地放入本地机器的内存中。
- 使用 Coiled 将相同的工作流扩展到云中,以处理整个数据集。
剧透——y你将在两种情况下运行完全相同的代码,只是改变了计算运行的位置。
你可以在本笔记本中找到完整的代码示例。要在本地运行笔记本,使用位于笔记本存储库中的 environment.yml 文件构建 conda 环境。
在本地构建您的管道
首先在本地构建管道是一个很好的实践。上面链接的笔记本一步一步地引导你完成这个过程。我们将在这里总结这些步骤。
我们将在 2015 年使用来自 Github 档案项目的数据。这个数据集记录了 Github 上的所有公共活动,在未压缩的情况下占用大约 75GB。
1.
首先从 Github 档案中提取一个文件。这代表 1 小时的数据,占用大约 5MB 的数据。这里不需要使用任何类型的并行或云计算,所以现在可以在本地迭代。
!wget [https://data.gharchive.org/2015-01-01-15.json.gz](https://data.gharchive.org/2015-01-01-15.json.gz)
只有在必要时才扩展到云,以避免不必要的成本和代码复杂性。
2.
太好了,你已经从源头提取了数据。现在,您可以将它转换成表格数据帧格式。数据中有几个不同的模式重叠,这意味着您不能简单地将其转换为 pandas 或 Dask 数据框架。相反,您可以过滤掉一个子集,比如 PushEvents,并使用它。
records.filter(lambda record: record["type"] == "PushEvent").take(1)
您可以应用 process 函数(在笔记本中定义)将嵌套的 JSON 数据展平成表格格式,现在每一行代表一个 Github 提交。
records.filter(lambda record: record["type"] == "PushEvent").take(1)flattened = records.filter(lambda record: record["type"] ==
"PushEvent").map(process).flatten()
然后使用.to_dataframe()
方法将这些数据转换成数据帧。
df = flattened.to_dataframe()
3.
现在,您已经准备好使用 Dask DataFrame .to_parquet()
方法将数据帧作为. parquet 文件写入本地目录。
df.to_parquet( "test.parq", engine="pyarrow", compression="snappy" )
利用卷绕式 Dask 集群进行横向扩展
伟大的工作建立和测试你的工作流程在本地!现在让我们构建一个工作流,该工作流将收集一整年的数据,对其进行处理,并将其保存到云对象存储中。
我们将首先在云中启动一个 Dask 集群,它可以在整个数据集上运行您的管道。要运行本节中的代码,您需要登录 Coiled Cloud 获得一个免费的 Coiled 帐户。你只需要提供你的 Github 凭证来创建一个帐户。
然后,您需要用正确的库创建一个软件环境,以便集群中的工作人员能够执行我们的计算。
import coiled # create Coiled software environment coiled.create_software_environment(
name="github-parquet",
conda=["dask", "pyarrow", "s3fs", "ujson", "requests", "lz4", "fastparquet"]
)
您还可以使用 Docker images、environment.yml (conda)或 requirements.txt (pip)文件创建 Coiled 软件环境。更多信息,请查看 盘绕文档 。
现在,让我们启动您的盘绕式集群,指定集群名称、它运行的软件环境以及 Dask 工作线程的数量。
# spin up a Coiled cluster
cluster = coiled.Cluster(
name="github-parquet",
software="coiled-examples/github-parquet",
n_workers=10
)
最后,让 Dask 在您的盘绕式集群上运行计算。
# connect Dask to your Coiled cluster
from dask.distributed import Client
client = Client(cluster) client
我们期待已久的时刻!您的集群已经启动并运行,这意味着您已经准备好运行您在整个数据集上构建的 JSON to Parquet 管道。
这需要对您的代码进行两处细微的更改:
- 下载Github 的所有存档文件,而不仅仅是一个测试文件
- 将 df.to_parquet()指向 s3 存储桶,而不是本地存储桶
请注意,下面的代码使用了一个文件名列表,其中包含 2015 年的所有文件和上面提到的流程函数。关于这两个物体的定义,请参考笔记本。
%%time
# read in json data
records = db.read_text(filenames).map(ujson.loads) # filter out PushEvents
push = records.filter(lambda record: record["type"] == "PushEvent") # process into tabular format, each row is a single commit
processed = push.map(process) # flatten and cast to dataframe
df = processed.flatten().to_dataframe() # write to parquet
df.to_parquet( 's3://coiled-datasets/etl/test.parq', engine='pyarrow', compression='snappy' )
CPU times: user 15.1 s, sys: 1.74 s, total: 16.8 s
Wall time: 19min 17s
太好了,这很有效。但是让我们看看是否可以加快一点速度…
让我们纵向扩展我们的集群以提升性能。我们将使用cluster.scale()
命令将集群中的工作线程数量增加一倍。我们还将包括一个对client.wait_for_workers()
的调用,它将阻塞活动,直到所有的工人都在线。这样,我们就可以确信我们在计算中已经竭尽全力了。
# double n_workers
cluster.scale(20) # this blocks activity until the specified number of workers have joined the cluster
client.wait_for_workers(20)
现在,让我们在扩展后的集群上重新运行相同的 ETL 管道。
%%time
# re-run etl pipeline
records = db.read_text(filenames).map(ujson.loads)
push = records.filter(lambda record: record["type"] == "PushEvent") processed = push.map(process)
df = processed.flatten().to_dataframe()
df.to_parquet( 's3://coiled-datasets/etl/test.parq', engine='pyarrow', compression='snappy' ) CPU times: user 11.4 s, sys: 1.1 s, total: 12.5 s
Wall time: 9min 53s
我们已经将运行时间减少了一半,干得好!想象一下,如果我们将 n_workers 增加 10 倍或 20 倍,会发生什么!
将大型 JSON 转换为拼花摘要
在这个笔记本中,我们将原始 JSON 数据转换成扁平的数据帧,并以高效的 Parquet 文件格式存储在云对象存储中。我们首先在本地的单个测试文件上执行这个工作流。然后,我们使用 Coiled 上的 Dask 集群将相同的工作流扩展到云上运行,以处理整个 75GB 的数据集。
主要要点:
- Coiled 允许您将常见的 ETL 工作流扩展到大于内存的数据集。
- 仅在需要时扩展到云。云计算带来了自己的一系列挑战和开销。因此,要战略性地决定是否以及何时导入 Coiled 和 spin up 集群。
- 纵向扩展您的集群以提高性能。通过将我们的集群从 10 个工人扩展到 20 个工人,我们将 ETL 功能的运行时间减少了一半。
我希望这篇文章对你有帮助!在 Twitter 上关注我获取每日数据科学内容。
或者来我的博客打招呼:
https://crunchcrunchhuman.com/2021/12/22/kaggle-xgboost-distributed-cloud/
原载于 2021 年 9 月 15 日https://coiled . io。
使用 PyMuPDF 将 PDF 转换为 Python 中的图像
原文:https://towardsdatascience.com/convert-pdf-to-image-in-python-using-pymupdf-9cc8f602525b?source=collection_archive---------9-----------------------
NLP 工具
一个从 pdf 生成 png 的简单实用的工具。
米切尔·伦辛克在 Unsplash 上拍摄的照片
最近,我在玩亚马逊 Textract 的时候遇到了一个小问题。Textract 的同步操作要求输入文档为图像格式。我有一堆(数百个)pdf 文件要处理;我该如何毫不费力地将它们转换成 png 呢?
PyMuPDF 来救援了!
让我们启动一个终端,键入以下内容:
pip install PyMuPDF
然后,让我们启动一个 Jupyter 笔记本,键入以下代码:
不要忘记更改第 8 行的源路径(pdf)和第 15 行的目标路径(pngs)。
作者截图
就是这样!
谢谢你过来看我的帖子。希望 PyMuPDF 能像帮助我一样帮助你!在我随后的文章中,我会尝试将这些代码移植到 AWS 上…也许吧。
敬请期待!
如果你想了解更多关于我从懒鬼到数据科学家的旅程,请查看下面的文章:
如果你正在考虑改变方向,进入数据科学领域,现在就开始考虑重塑品牌:
你可以通过 Twitter 或 LinkedIn 联系我。
参考
https://pymupdf.readthedocs.io/en/latest/faq.html
使用 Python 将照片转换为像素艺术
原文:https://towardsdatascience.com/convert-photo-into-pixel-art-using-python-d0b9bd235797?source=collection_archive---------4-----------------------
如何使用 python 从照片中生成像素艺术的分步教程
介绍
随着 NFTs 和加密艺术越来越受欢迎,对能够执行图像处理和生成程序艺术的程序员的需求也在增加。
像素艺术最近也重新流行起来,特别是在数字艺术鉴赏家中间。
在本文中,我将解释如何用 python 执行图像处理,将任何照片转换成像素艺术。
照片由米卡·鲍梅斯特在 Unsplash 上拍摄
出于演示的目的,我将使用上述图像的裁剪版本(800px X 800px)。
开始编码吧!
所需的库
我们将使用 枕库进行图像操作,使用Matplotlib库进行图像显示和保存。
*#Import Libraries
from PIL import Image
import matplotlib.pyplot as plt*
读取图像
通过提供图像的路径作为枕库的图像模块的打开函数的参数,可以读取图像。因为我们的图像和笔记本在同一个文件夹中,所以只需要图像的名称就足够了。**
一旦图像被读取,就可以使用 matplotlib 的 imshow 函数显示。
*#Read image
img=Image.open('mario.jpg')#show image
plt.imshow(img)
plt.show()*
输入图像(裁剪后的图像 800 像素 X 800px 像素)
转换成小图像
创建像素化图像的第一步是使用 双线性插值 重采样技术将输入图像图像转换成小图像。
您可以访问下面的页面,了解更多关于不同的图像重采样技术。
*https://www.cambridgeincolour.com/tutorials/image-interpolation.htm
这可以通过提供大小和重采样技术作为参数,使用 resize 方法来实现。
我们可以将 800px X 800px 图像转换为 8px X 8px 图像,如下所示:
small_img=img.resize((8,8),Image.BILINEAR)
小图像(8px X 8px)
调整到所需的输出尺寸
然后,再次使用 resize 函数,将小图像调整到所需的输出大小。
我们将使用 最近邻 重采样技术,本质上是放大每个像素。
默认的重采样技术是双三次插值,这将锐化图像。下面的代码将把小图像(8px X 8px)转换成尺寸为 1000 px X 1000px 的图像。
#resize
o_size=(1000,1000) #output size
res=small_img.resize(o_size,Image.NEAREST)#save image
res.save('mario_8x8.png')#display image
plt.imshow(res)
plt.show()
mario_8x8.png,生成的输出图片(图片由作者提供)
请注意,我们已经使用保存功能将图像保存到本地,文件名为 mario_8x8.png.
上面的图像只包含原始图像的 0.01%的数据。因此,如果你不能从这个图像中识别出原始图像也就不足为奇了。
好的像素艺术必须包含足够的来自原始图像的数据,这样才能被识别。然而,在这个过程中,细微的特征将会丢失。
如果原始图形有许多需要保留的细微特征,我们应该使用大得多的尺寸进行初始调整。
合适的小图像尺寸可以通过试错法获得。
创建一个函数来生成像素艺术
下一步是通过创建一个从任何图像生成像素艺术的函数来简化上面讨论的处理。
该功能必须包含以下功能:
i .读取照片
ii。以小图像 尺寸和输出图像尺寸为参数
iii 转换为像素艺术。保存生成的图像
iv。并排显示原始图像和像素图片以进行比较
photo2pixelart 功能(作者要点)
该功能可用于为马里奥图像尝试不同的小图像尺寸,以找到合适的尺寸,从而获得视觉上最愉悦的像素艺术。
函数调用
我们将图像转换为 32px X 32px 大小,以像素化图像。
img.size 可以用来获取原始图像的大小。
通过提供 img.size 作为输出尺寸,我们可以生成与原始图像尺寸相同的像素艺术。
photo2pixelart(image='mario.jpg',i_size=(32,32),
o_size=img.size)
photo2pixelart 函数的输出(图片由作者提供)
我们可以看到,新的像素艺术显示更多的细节相比,最初的。与 8px 版本相比,该图包含的数据量是前者的 16 倍。然而,它只包含来自原始图像的 0.16%的数据。
我们将图像的长度和宽度缩小 10%,即下一张图像为 80px X 80px。这个数字将包含原始图像的 1%的数据。
#Function Call
photo2pixelart(image='mario.jpg',i_size=(80,80),
o_size=img.size)
photo2pixelart 函数的输出(图片由作者提供)
此图像比前一个图像更平滑,图像的特征更容易识别。
资源:
本教程的代码以及所有使用和生成的图像都可以在我的 GitHub Repo 中找到。
成为会员
我希望你喜欢这篇文章,我强烈推荐 注册中级会员 来阅读更多我写的文章或数以千计的其他作者写的各种主题的故事。
你的会员费直接支持我和你看的其他作家。你还可以在 Medium 上看到所有的故事。*
你可能会对作者的其他文章感兴趣
*
封面图片(作者图片)*
将图片转换为 ASCII 图片
原文:https://towardsdatascience.com/convert-pictures-to-ascii-art-ece89582d65b?source=collection_archive---------14-----------------------
关于图像如何工作以及如何将像素表示为 ASCII 字符的简要指南—包括代码示例
由 freestocks 在 Unsplash 发布的原始图片的 ASCII 版本
我相信你们很多人都听说过 ASCII art ,这是一种图形设计技术,使用可打印的 ASCII 字符集来组成图片。这种艺术最简单的形式是表情符号,如:-)
或:-3
。但是,您能用可打印的 ASCII 字符表示更复杂的图像吗?
图像到底是什么
首先,澄清图像在计算机系统中是如何表现的是很重要的。图片通常以.png
或.jpg
等格式存储在磁盘上。所有这些文件类型都有相似的结构:它们大致由一个头和一个数据段组成。前者存储关于图像的有用信息,例如其格式签名%20file%20formats.-,Magic%20number,-%5Bedit%5D),而后者存储实际的像素数据。
你看到的实际图像是由像素组成的,像素是我们都熟悉的光栅图像的最小可寻址元素。它们通常被表示为一组通道,也称为颜色。最常见的颜色值有经典的 RGB(红绿蓝)和 RGBA(红绿蓝 Alpha)。两者的区别在于,后者有一个额外的通道,称为“alpha”,用于指定图像的不透明度。RGBA 是我们将要使用的,因为它也可以用来表现一个空白的背景。
如何将像素转换成 ASCII 码
现在我们已经看到了图像是如何表示的,是时候讨论如何将像素转换成实际的 ASCII 字符了。为了理解这一点,我们必须首先看看像素颜色强度。该值是指所有像素通道的总和,除以通道可以具有的最大值的总和(在本例中为 255)。
从现在开始,我将使用 Python 作为代码示例,因为它简单易读,但是您可以随意使用您喜欢的任何技术。我还将使用
PIL
图像库来保持代码尽可能的简单和抽象。
第一行导入了清晰所需的静态类型。如果你不知道它们是什么,看看我关于类型提示的文章。
在这段代码中,我定义了一个新的Pixel
类型,一个由四个整数组成的Tuple
,每个整数代表一个 RGBA 像素中的一个通道。然后我定义了一个函数来提取给定像素的亮度。它首先将所有通道值相加,然后将结果除以像素通道可以达到的最大值,从而有效地获得强度百分比。
一旦我们计算了像素的亮度,就该把它映射到一个 ASCII 字符了。为此,我们必须定义一个用来表示像素的字符集。
字符集从最轻的空格到最重的 T3 排序。这意味着像素越密集,其对应的 ASCII 字符占用的空间就越大。
该函数将给定的像素亮度映射到集合中的一个字符。因为索引必须是整数,所以intensity * len(CHARACTERS)
的结果被四舍五入。
现在,让我们用一个简单的脚本将这些代码片段粘在一起:
查看 ASCII 图片
一旦我们获得了图像的 ASCII 字符串表示,我们必须找到一种图形化查看它的方法。最简单的方法是将它打印到控制台。由于图像通常是按像素行组织的,所以在打印时,我们也必须相应地使用换行符。
在这里,我编写了一个简单的函数,将 ASCII 图片打印到控制台,并说明了如何从 main 函数中调用它:
让我们看看这个脚本的运行情况!我们将转换一个像这样的简单图像:
剑(由 Flaticon 的 Freepik 制作的图标)
假设我们已经调用了图像文件image.png
和脚本converter.py
,该命令将如下所示:
python converter.py image.png
# Or if you are on a Unix-like system and the script is executable
./converter.py image.png
这将向控制台生成以下输出:
Freepik 在https://www.flaticon.com/)发布的原始图片的 ASCII 版本
正如你所看到的,由于线条之间的间隔,图片有点失真。这是许多终端模拟器的局限性,但是有一个简单的解决方案。
使用 HTML 的视觉改进
我们已经看到了如何将图像转换成 ASCII 表示,但是如果能将结果保存到一个实际的文件中会更好。但是为什么是 HTML 呢?
- 所有的网络浏览器都支持它。
- 您可以根据图像的比例轻松放大和缩小。
- 它仍然可以只由 ASCII 字符组成。
让我们编写一个函数来将结果图像保存到 HTML 文件中:
现在我们已经完成了我们的图像转换器,让我们花点时间看看一些很酷的图片和它们的 ASCII 版本:
马修·施瓦茨在 Unsplash 上的照片
由马修·施瓦茨在 Unsplash 拍摄的原始图像的 ASCII 版本
Jacques Bopp 在 Unsplash 上拍摄的照片
由 Jacques Bopp 在 Unsplash 上制作的原始图像的 ASCII 版本
freestocks 在 Unsplash 上拍摄的照片
freestocks 在 Unsplash 上发布的原始图片的 ASCII 版本
这是我这篇文章所基于的项目的 GitHub 库的链接。我还会在下面的要点中直接包含源代码,以防您时间不够:
图像转换的完整脚本
如果有人感兴趣,我还建立了一个简单的免费网站,可以将你的图片转换成 ASCII 码。虽然我否认这不是一个严肃的项目,可能包含错误和漏洞,所以不要想依靠它做任何事情。
结论
在这篇文章中,你简要地学习了图像文件是如何构造的,最重要的是,如何将单个像素转换成相应的 ASCII 字符。
例如,这种 ASCII 艺术可以用作网页中的设计元素。ASCII 图像转换也可能是一些用于社交媒体的酷照片过滤器和视频效果的基础。此外,即使您不能利用这项技术,它仍然是一个很好的编码练习。
我希望您喜欢这篇文章,并在此过程中学到一些新东西,
感谢阅读!
将您的情绪识别笔记本转换为 API,无需额外代码
原文:https://towardsdatascience.com/convert-your-emotion-recognition-notebook-into-an-api-without-extra-code-bc13421d2ed5?source=collection_archive---------22-----------------------
在 Jupyter 笔记本中训练情感识别,并使用 Cuttle 将其转换为 Flask API 项目,无需额外代码
来源: Unsplash
对于经常使用 Jupyter 笔记本进行开发和测试的人来说,您可能已经习惯了一直复制和粘贴代码。
删除测试代码片段,使用不同的 IDE 来编译和测试您的代码,以及开发 API 只是 ML 开发人员所习惯的一些耗时的任务。
如果我们能够自动化构建一个 API 项目所需的样板代码的苦差事,那不是很好吗?这里我们将在 Jupyter 笔记本中训练一个情绪识别模型,并将其转换为 Flask API 项目,完全不需要额外的代码!
属国
pip install
tensorflow==2.5.0 Keras==2.4.3 numpy==1.19.5 opencv-python==4.4.0.44
我们还需要安装卡特尔来将我们的 ML 笔记本转换成 Flask API 项目。
pip install cuttle
资料组
你可以在情感识别上使用任何数据集,也可以创建自己的数据集。在本文中,我们使用 Kaggle 上的情感识别数据集。你应该在这里找到它。该数据集包含 7 类图像:愤怒、厌恶、恐惧、快乐、中性、悲伤和惊讶。如果您想添加另一个类,只需创建一个新目录并添加属于该类的图像。
在与您下载的数据集相同的目录中创建笔记本,其中包含“train”和“validation”文件夹。
进口
数据集扩充
ImageDataGenerator 允许您在每个训练图像上使用图像增强、变换来拟合模型,还可以传递任何预处理函数(如果可用)。
我们重新缩放图像是因为颜色的范围是从[0–255],重新缩放图像会转换范围为[0–1]的每个像素值。这里,我们将模型的目标大小定义为 48x48,将 batch_size 定义为 64。
模特培训
我们在这里定义一个 CNN,但是你可以选择使用任何预先训练好的模型,比如 VGG16 或者 ResNet,或者也可以使用迁移学习。
完成训练后,您的模型会保存在给定的路径中。
情感识别
我们现在加载模型,给它一个图像并测试它。在这一步,让我们引入 cuttle,并将结果函数转换成任何前端应用程序都可以访问的 API。
让我们使用一个测试图像“test.jpeg”。
来源: Unsplash
我们从模型预测中得到的输出是‘恐惧’。继续用更多的图像进行测试,直到你对模型的准确性和结果满意为止。让我们看看如何将它转换成一个 API 项目。
初始化卡特尔
如下用“cuttle init”初始化 cuttle,并输入正在使用的笔记本的名称。
来源—作者
创建卡特尔环境
在这一步中,您命名环境,指定您正在使用的平台,以及您想要使用的转换器。我们想在这个场景中使用烧瓶变压器。您可以选择一个方便的环境名称。我用了“情感记录”作为例子。
来源—作者
此时,您的应该是这样的:
来源—作者
完成配置创建后,就该编辑 Jupyter 笔记本以包含 cuttle 配置了。我们只需要编辑代码的最后一部分来定义 API 路由并设置输出配置。
向单元格添加配置:
我们使用 Cuttle config 来执行两个主要操作,如这里的和所示。
- 禁用训练步骤并从保存的模型文件中加载,这样就不用每次运行脚本时都重新训练。
- 指定每次调用 API 时要执行的单元以及必需的参数
要禁用单元格,请在单元格的开头添加此配置。
#cuttle-environment-disable emotion-rec
现在添加 config 将您的脚本转换成 API,如下所示:
我们正在设置两个配置:切割环境设置配置和切割环境分配配置。它们分别是单元格范围和行范围。单元范围的配置设置了在转换单元期间所需的配置。行范围的配置允许我们配置变量。
在第一行中,我们设置了单元范围的配置,指定了我们选择的环境名称、方法和路由。我们还配置了变量“file ”,允许我们从请求方法和将作为我们响应的“output”变量中获取-config。
改变
我们的最后一步是使用我们一直使用的环境名进行 cuttle-transform。让我们来看看如何:
来源—作者
在这个步骤之后,您应该会看到一个输出目录,它由另一个包含环境名称的子目录组成。转到这个目录,找到您转换成 API 的代码。以下列身份运行该文件:
来源—作者
现在我们的代码默认运行在本地主机端口 5000 上。通过使用 Postman 发送图像来测试这一点,以获得您的响应。
test.jpeg 通过 POST 请求发送到我们的 flask API。来源—作者
您的 API 项目现在可以部署了!Cuttle 还允许您将笔记本转换为脚本或管道。
资源
卡特尔网站: cuttle.it
Github: 情感识别 API 源卡特尔源:卡特尔 CLI 源
你也可以在推特上找到我们@https://twitter.com/cuttlehq
将 conda/pip 环境转换为 Docker 图像
原文:https://towardsdatascience.com/converting-conda-pip-environments-into-docker-images-d02aa22e872c?source=collection_archive---------17-----------------------
使用 Coiled 作为 Docker 图像管道
图片来自 Unsplash
TL;博士;医生
构建 Docker 映像是大多数数据科学家工作流程中必不可少但极具挑战性的一部分。简化这个过程的一个方法是将 Coiled 连接到您自己的 Docker 注册表(如 DockerHub ),创建一个管道,将您的 conda 或 pip 环境转换成可以在其他地方使用的 Docker 映像。这篇文章向你展示了如何使用coiled.create_software_environment()
命令并通过在你的 Coiled cloud 仪表板的“帐户”设置中设置容器注册后端来实现。
你也可以观看下面的视频,获得一步一步的指导:
免责声明:我在 Coiled 工作,是一名数据科学传道者实习生。 Coiled 由Dask的最初作者 Matthew Rocklin 创立,是一个面向分布式计算的开源 Python 库。
为什么您可能需要 Docker 图像
许多数据科学家需要将 conda 和/或 pip 环境转换为 Docker 映像,以便跨团队协作或将本地工作环境迁移到云上运行。大多数人使用越来越复杂的工作流手动实现这一点(例如,看看这篇中等的文章)。)虽然这在技术上可行,但并不是每个人都能使用。作为一名数据科学家新手,我知道我一开始发现这种体验很复杂,很难掌握。
如何盘绕可以让你更容易
作为为数据科学家设计的基于云的服务, Coiled 需要能够将 conda 和 pip 环境转换成 Docker 映像才能正确运行。[**coiled.create_software_environment()**](https://docs.coiled.io/user_guide/software_environment_creation.html)
命令将一个**environment.yml**
(conda)或 requirements.txt (pip)文件转换成 Docker 映像,然后分发给所有 Dask workers,以确保整个盘绕集群的一致性。
下面是两个代码片段:一个用于 conda,一个用于 pip:
# using conda .yml files
import coiled
coiled.create_software_environment(
name='my-env',
conda='<path/to/environment.yml>'
) # using pip .txt files
import coiledcoiled.create_software_environment(
name='my-env',
pip='<path/to/requirements.txt>'
)
本着社区和开源开发的精神,Coiled 工程师并没有把这个功能藏起来,而是把它变成了一个通用工具。这意味着您可以将 Coiled 连接到您自己的 Docker 注册中心(如 DockerHub)来创建 conda/pip-to-Docker 构建服务。然后,您可以在任何喜欢的地方使用使用 Coiled 创建的 Docker 图像。
如何将 Coiled 连接到 Docker 容器注册表
默认情况下,Coiled 将您创建的软件环境存储在您正在运行的云服务的容器注册表中:AWS、GCP 或 Azure。 您可以在 Coiled Cloud dashboard 的“Account”选项卡中更改此设置,将您的软件环境作为 Docker 映像保存到您的 Docker Hub。
任何支持 Docker 注册表 API V2 的注册表都应该可以工作。在我们文档的“后端”页面阅读更多细节。
请注意:使用 Docker Hub 以外的注册中心是一个正在积极开发中的实验性功能。如果您想在support @ Coiled . io或通过Coiled Community Slack channel讨论您的用例,请联系我们。
我在这里偷偷给你一个额外的提示:创建软件环境实际上并不需要你启动一个集群。这意味着你可以使用你的 conda/pip-to-Docker 管道,而不会烧掉你的任何。
什么都不发明的价值
这就是我喜欢 Python 生态系统的原因。产品不可或缺的功能可以开放给更广泛的公众使用。它遵循了 Matt Rocklin 经常宣称的关于开源库 Dask 的反直觉的最低创造力原则:“什么都不发明。”
这个咒语看起来似乎违反直觉,但实际上包含了一个简单的教训:不要试图重新发明轮子,而是创造与人们已经在使用的工具相集成的产品,从而为已经存在的丰富的生态系统增加额外的一块砖。
我希望这篇文章对你有帮助!在 Twitter 上关注我获取每日数据科学内容。
或者来我的博客打招呼:
https://crunchcrunchhuman.com/2021/12/22/kaggle-xgboost-distributed-cloud/
原载于 2021 年 8 月 23 日https://coiled . io。
在 Pandas 中将数据转换为数字类型的 10 个技巧
原文:https://towardsdatascience.com/converting-data-to-a-numeric-type-in-pandas-db9415caab0b?source=collection_archive---------2-----------------------
熊猫帮助你开始数据分析的提示和技巧
照片由罗斯·芬登在 Unsplash 上拍摄
在进行数据分析时,确保正确的数据类型非常重要。否则,您可能会得到意外的结果或错误。在熊猫的例子中,它将在许多情况下正确地推断数据类型,并且您可以继续您的分析,而无需对该主题进行任何进一步的思考。
尽管 pandas 工作得很好,但在数据分析过程中的某个时候,您可能需要显式地将数据从一种类型转换为另一种类型。本文将讨论如何将数据转换为数值类型。更具体地说,您将学习如何使用 Pandas 内置方法astype()
和to_numeric()
来处理以下常见问题:
- 将 string/int 转换为 int/float
- 将 float 转换为 int
- 转换混合数据类型的列
- 处理缺失值
- 将货币列转换为浮动
- 将布尔值转换为 0/1
- 一次转换多个数据列
- 读取 CSV 文件时定义数据类型
- 创建自定义函数来转换数据类型
astype()
对to_numeric()
为了进行演示,我们创建了一个数据集,并用一个函数加载它:
import pandas as pd
import numpy as npdef load_df():
return pd.DataFrame({
'string_col': ['1','2','3','4'],
'int_col': [1,2,3,4],
'float_col': [1.1,1.2,1.3,4.7],
'mix_col': ['a', 2, 3, 4],
'missing_col': [1.0, 2, 3, np.nan],
'money_col': ['£1,000.00','£2,400.00','£2,400.00','£2,400.00'],
'boolean_col': [True, False, True, True],
'custom': ['Y', 'Y', 'N', 'N']
})df = load_df()
作者图片
请查看 Github repo 获取源代码。
检查数据类型
在我们深入研究更改数据类型之前,让我们快速了解一下如何检查数据类型。如果我们想在一个数据帧中看到所有的数据类型,我们可以使用dtypes
属性:
>>> **df.dtypes**string_col object
int_col int64
float_col float64
mix_col object
missing_col float64
money_col object
boolean_col bool
custom object
dtype: object
这个属性在 Series 中也是可用的,我们可以用它来检查特定列上的数据类型。例如,检查 int_col 的数据类型:
>>> df.**int_col.dtypes**dtype('int64')
如果我们想研究数据,那么info()
方法可能更有用,因为它提供了 RangeIndex、总列数、非空计数、dtypes 和内存使用情况。这是大量有价值的信息,可以帮助我们更全面地了解数据。
>>> **df.info()**RangeIndex: 4 entries, 0 to 3
Data columns (total 8 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 string_col 4 non-null object
1 int_col 4 non-null int64
2 float_col 4 non-null float64
3 mix_col 4 non-null object
4 missing_col 3 non-null float64
5 money_col 4 non-null object
6 boolean_col 4 non-null bool
7 custom 4 non-null object
dtypes: bool(1), float64(2), int64(1), object(4)
memory usage: 356.0+ bytes
1.将字符串转换为整型/浮点型
将 Pandas 列转换为不同类型的最简单方法是使用 Series 的方法astype()
。例如,要将字符串转换成整数,我们可以这样调用它:
# string to int
>>> df['string_col'] = df['string_col']**.astype('int')**
>>> df.dtypes**string_col int64**
int_col float64
float_col float64
mix_col object
missing_col float64
money_col object
boolean_col bool
custom object
dtype: object
我们可以看到它默认使用的是 64 位整数。在某些情况下,当处理大型数据集时,使用较短的整数会更节省内存。为此,你可以简单地调用astype('int8')
、astype('int16')
或astype('int32')
同样,如果我们想将数据类型转换为 float,我们可以调用astype('float')
。默认情况下,它使用的是 64 位浮点数。我们可以使用'float128'
来获得更高的精度,或者使用'float16'
来获得更高的内存效率。
# string to float
>>> df['string_col'] = df['string_col']**.astype('float')**
>>> df.dtypes**string_col float64**
int_col int64
float_col float64
mix_col object
missing_col float64
money_col object
boolean_col bool
custom object
dtype: object# For more precision
>>> df['string_col'] = df['string_col']**.astype('float128')**# For more memory efficiency
>>> df['string_col'] = df['string_col']**.astype('float16')** >>> df['string_col'] = df['string_col']**.astype('float32')**
2.将 float 转换为 int
如果我们想将一个浮点列转换成整数,我们可以尝试使用上面使用的astype()
。
df['float_col'] = df['float_col']**.astype('int')**
作者图片
然而,有一个小问题。通过显示 DataFrame,我们可以看到该列被转换为整数,但所有值都被向下舍入。这可能没问题,但在大多数情况下,我会认为这是不对的。如果我们想转换成整数,并按照我们期望的方式四舍五入,我们可以先做round()
。
df['float_col'] = df['float_col']**.round(0)**.astype('int')
作者图片
现在,数字4.7
被四舍五入为5
。
3.转换混合类型的列
让我们继续看一列混合的字符串和数字。当运行astype('int')
时,我们得到一个值错误。
# Getting ValueError
df['mix_col'] = df['mix_col'].astype('int')
作者图片
该错误表明值'a'
有问题,因为它不能转换为整数。为了解决这个问题,我们可以使用带参数errors='coerce'
的 Pandas to_numeric()
函数。
df['mix_col'] = pd.**to_numeric**(df['mix_col'], **errors='coerce'**)
但是当检查dtypes
时,你会发现它被转换为float64
。
>>> df['mix_col'].dtypesdtype('**float64**')
在某些情况下,你不希望输出浮点值,你希望它是整数,例如转换一个 ID 列。我们可以叫astype('Int64')
。注意它有一个大写字母I
并且不同于 Numpy 'int64'
。这样做的目的是将 Numpy 的NaN
改为 Pandas 的NA
,这样它就可以是一个整数。
>>> df['mix_col'] =
pd.to_numeric(df['mix_col'], errors='coerce').**astype('Int64')**>>> df['mix_col'].dtypesInt64Dtype()
或者,我们可以用另一个值替换 Numpy nan
(例如用0
替换NaN
)并调用astype('int')
df['mix_col'] = pd.to_numeric(
df['mix_col'],
errors='coerce'
).**fillna(0)**.**astype('int')**
4.处理缺失值
现在,我们应该完全具备处理缺失值的能力。在 Pandas 中,缺失值被赋予值NaN
,这是“不是一个数字”的缩写。由于技术原因,这些NaN
值总是属于float64
。
df.**missing_col.dtypes**dtype('**float64**')
当将带有缺失值的列转换为整数时,我们还会得到一个 ValueError ,因为NaN
不能转换为整数。
作者图片
为了避免这个错误,我们可以像上面那样调用astype('Int64')
(注意它是大写的I
,和上一节提到的一样)。这样做的是将 Numpy 的NaN
改为 Pandas 的NA
,这允许它是一个整数。
df['missing_col'] = df['missing_col'].**astype('Int64')**
或者,我们可以用另一个值替换 Numpy NaN
(例如用0
替换NaN
)并调用astype('int')
df['mix_col'] = df['missing_col'].**fillna(0)**.**astype('int')**
如果您想了解有关处理缺失值的更多信息,可以查看:
5.将货币列转换为数字
让我们转到钱这一栏。问题是,如果我们使用上面的方法,我们将得到所有的NaN
或NA
值,因为它们都是带有符号£
和,
的字符串,并且它们不能转换成数字。所以我们要做的第一件事就是删除所有无效的符号。
>>> df['money_replace'] =
df['money_col']**.str.replace('£', '').str.replace(',','')**
>>> df['money_replace'] = pd.to_numeric(df['money_replace'])
>>> df['money_replace']0 1000.0
1 2400.0
2 2400.0
3 2400.0
Name: money_replace, dtype: **float64**
我们链接 2 个replace()
调用,一个用于£
,另一个用于,
,用空字符串替换它们。
如果你熟悉正则表达式,我们也可以用正则表达式替换那些符号。
>>> df['money_regex'] =
df['money_col'].str.replace(**'[\£\,]', '', regex=True**)
>>> df['money_regex'] = pd.to_numeric(df['money_replace'])
>>> df['money_regex']
replace('[\£\,]', '', regex=True)
表示我们想用一个空字符串替换£
和,
。参数regex=True
假设传入的模式是一个正则表达式(注意它默认为True
)。
6.将布尔值转换为 0/1
我们有True
/ False
,但是您可以想象一种情况,我们需要这些作为0
和1
,例如,如果您正在构建一个机器学习模型,这是您的输入特征之一,您需要它是数字,您将使用0
和1
来表示False
和True
。这个其实很简单,你可以直接叫astype('int')
:
df['boolean_col'] = df['boolean_col']**.astype('int')**
7.一次转换多个列数据类型
到目前为止,我们一直在一次转换一列的数据类型。例如
# Converting column string_col and int_col one at a time
df['string_col'] = df['string_col'].astype('float16')
df['int_col'] = df['int_col'].astype('float16')
有一个 DataFrame 方法,也称为astype()
,允许我们同时转换多个列数据类型。当您有一堆要更改的列时,这很节省时间。
df = df.astype({
**'string_col': 'float16',
'int_col': 'float16'**
})
8.定义读取 CSV 文件时每列的数据类型
如果您想在读取 CSV 文件时为每一列设置数据类型,可以在加载数据时使用参数dtype``read_csv()
:
df = pd.read_csv(
'dataset.csv',
**dtype={
'string_col': 'float16',
'int_col': 'float16'
}**
)
dtype
参数取一个字典,键代表列,值代表数据类型。此方法与上述方法的区别在于,此方法在读取过程中进行转换,可以节省时间并提高内存效率。
9.创建自定义函数将数据转换为数字
当数据转换有点复杂时,我们可以创建一个自定义函数,并将其应用于每个值,以转换为适当的数据类型。
例如,在 money_col 列中,有一个我们可以使用的简单函数:
>>> **def convert_money(value):
value = value.replace('£','').replace(',', '')
return float(value)**>>> df['money_col']**.apply(convert_money)**0 1000.0
1 2400.0
2 2400.0
3 2400.0
Name: money_col, dtype: **float64**
我们也可以使用λ函数:
df['money_col']
.apply(**lambda v: v.replace('£','').replace(',','')**)
.astype('float')
10.astype()
与to_numeric()
的区别
将数据类型从一种转换到另一种最简单的方法是使用astype()
方法。熊猫数据框架和系列都支持这种方法。如果您已经有了数字数据类型(int8
、int16
、int32
、int64
、float16
、float32
、float64
、float128
和boolean
),您也可以使用astype()
进行以下操作:
- 将其转换为另一种数字数据类型(int 到 float,float 到 int,等等。)
- 使用它向下转换到较小的字节大小,或者向上转换到较大的字节大小
然而,astype()
对混合类型的列不起作用。例如,混合列有a
,而缺失列有NaN
。如果我们尝试使用astype()
,我们将得到一个值错误。从熊猫 0.20.0 开始,这个错误可以通过设置参数errors='ignore',
来抑制,但是你的原始数据将原封不动地返回。
Pandas to_numeric()
函数可以更优雅地处理这些值。与其失败,我们可以设置参数errors='coerce'
将无效值强制为NaN
:
pd.to_numeric(df['mixed_col'], **errors='coerce'**)
结论
我们已经看到了如何使用astype()
和to_numeric()
将 Pandas 数据列转换为数字类型。astype()
是最简单的方法,在转换方式上提供了更多的可能性,而to_numeric()
具有更强大的错误处理功能。
我希望这篇文章能帮助你节省学习熊猫的时间。我建议您查看一下astypes()
和to_numeric()
API 的文档,并了解您可以做的其他事情。
感谢阅读。请查看笔记本获取源代码,如果你对机器学习的实用方面感兴趣,请继续关注。
你可能会对我的其他一些熊猫文章感兴趣:
- 熊猫 json_normalize()你应该知道的扁平化 JSON
- 所有熊猫切()你应该知道把数值数据转换成分类数据
- 使用熊猫方法链接提高代码可读性
- 如何对熊猫数据帧进行自定义排序
- 为了数据分析你应该知道的所有熊猫移位()
- 何时使用 Pandas transform()函数
- 你应该知道的熊猫串联()招数
- 所有熊猫合并()你应该知道
- 在 Pandas 数据帧中处理日期时间
- 熊猫阅读 _csv()你应该知道的招数
- 用 Pandas read_csv()解析日期列应该知道的 4 个技巧
更多教程可以在我的 Github 上找到
将表情符号转换为文本
原文:https://towardsdatascience.com/converting-emojis-to-text-a28b69ed9f45?source=collection_archive---------19-----------------------
使用表情符号将表情符号转换为文本描述
伯纳德·赫曼特在 Unsplash 上的照片
你有没有收到过一个你不知道或者不明白是什么的表情符号?我知道这发生在我们所有人身上。有很多我们不理解的表情符号,在创建 NLP 模型时使用这些数据会导致差异。
如果我告诉你,你可以把这些表情符号改成文字,会怎么样?是的,你没听错,你可以这么做。这不仅易于理解,而且可以为 NLP 建模准备好数据。
Emot 是一个开源的 python 库,我们可以用它来将表情符号转换成文本描述。在本文中,我们将探讨如何使用 Emot。
让我们开始吧…
安装所需的库
我们将从使用 pip 安装 Emot 开始。下面给出的命令可以做到这一点。
pip install emot
导入所需的库
在这一步,我们将导入所需的库,即 Emot。
import emot as e
将表情符号转换为文本
这是最后一步,我们将把一些包含表情符号的文本传递到表情库,并将表情符号转换为文本。
text = "I am a coder😎"
con = e.emoji(text)
con
来源:作者
这里你可以看到它是多么容易地将表情符号转换成文本。让我们尝试更多的表情符号。
text = "😁😆😅😂😇🙃"
con = e.emoji(text)
con
来源:作者
你看表情符号有多棒,用表情符号创造文字。让我们尝试最后一个非常独特的表情符号。
text = "🤡"
con = e.emoji(text)
con
来源:作者
在将文本数据传递给 NLP 模型之前,可以用它来预处理文本数据。继续尝试使用不同的表情符号,并在回复部分让我知道您的评论。
本文是与皮尤什·英加尔合作完成的。
在你走之前
感谢 的阅读!如果你想与我取得联系,请随时通过 hmix13@gmail.com 联系我或我的 LinkedIn 个人资料 。可以查看我的Github*简介针对不同的数据科学项目和包教程。还有,随意探索* 我的简介 ,阅读我写过的与数据科学相关的不同文章。
将科学 Kaggle 笔记本转换为友好的 Python 包
原文:https://towardsdatascience.com/converting-kaggle-training-notebooks-to-sharable-code-1cc59fec2414?source=collection_archive---------29-----------------------
插图照片由奥利娅·丹尼利维奇从派克斯拍摄
这篇文章展示了如何轻松地将笔记本转换为标准 Python 包,并在培训脚本中包含一个简单的命令行界面(CLI ),以实现更快的超参数交互。
在之前的文章中,我们分享了如何筛选给定的数据集,并展示了如何将类似文件的数据集包装到 PyTorch 类数据集,这是数据处理的核心。此外,我们基于一个 TorchVision 模型在 PyTorchLightning 中编写了一个基本的图像多标签分类模型,并在 GPU 上无缝地训练它,而无需在 Jupyter 笔记本中编写额外的代码。
笔记本电脑非常适合快速原型开发或数据探索,但对于大规模开发来说不太实用。笔记本电脑的单元式结构使得寻找不同的参数配置来优化模型具有挑战性。笔记本结果不一定是可重复的,因为您可能会交换一些编辑单元格或不按顺序运行它们。笔记本不支持版本控制,这使得与同事或更广泛的开源社区的协作变得困难。
将笔记本转换为可共享的 Python 包
使用 PyTorch Lightning,将一个笔记本转换成一个基本的 python 包是很简单的事情,并将其作为 GitHub 存储库共享。PyTorch Lightning 实施了最佳实践,并通过其功能(数据处理和模型架构)暗示了自然的代码组织。
python 包是一种组织函数、类等的结构。,到 python 模块中,可以在任何地方导入和使用它们。这种包装是紧凑的和单元的,适于与 Pip 或 Conda 一起分配。所以在我们的例子中,我们创建了两个 python 模块— data
和models
,并复制粘贴了之前实现的类。
使用 [setup.py](https://packaging.python.org/tutorials/packaging-projects/)
我们可以安装我们的软件包,并将其导入我们环境中的任何地方。否则,我们需要将包的路径添加到我们的 Python 系统路径中。通过将数据和模型实现移动到我们自己的包中,我们可以通过导入在我们的笔记本中使用它,并将所有培训简化为以下几行:
来自共享的库的代码片段。
这使您能够在 GitHub 上共享您的库/包,使人们能够轻松地在您的工作基础上进行构建。
将 PL 实现移动到包中,然后通过导入使用它们的模式。
模板/初学者存储库
作为你下一个项目的灵感,我创建了这个stater/template repository,它用一个演示包challenge_xyz
建立了一个基本的项目结构。它包括测试、代码格式化和 Github 问题/公关模板的基本工作流程。您可以从该模板创建以下存储库;参见分步文档。
https://github.com/Borda/kaggle_sandbox https://medium.com/geekculture/thought-on-why-code-formatting-is-important-even-more-for-open-source-476829b54eaf
包装实体的小技巧
现在我们开源了我们的代码,我们已经准备好让他们贡献或修复问题。这听起来不错,但是如何确保新的修改不会破坏其他东西呢?
标准的软件工程答案是通过测试(单元测试或集成测试)。在提交/发布每一个新的贡献之前,我们可以在存储库中运行所有的测试,并验证所有的工作都如预期的那样。就我个人而言,我在我的大部分项目中使用的都是 pytest 包,reed 紧随其后进入。
使用标准框架又一次变得很方便,在我们的例子中是 Pytoch Lightning,它已经进行了数百次测试来保证正确的行为。我们只需要编写一小组测试用例来覆盖我们的解决方案,因为 lightning 已经完成了剩下的工作。例如,我们可能想要实例化所有的类。
如下所示,我们添加了参数化,它使用不同的网络调用相同的测试两次——第一次获取 network 作为实例,第二次获取 networks 作为字符串名称:
来自共享库的代码片段。
为了测试训练能力,我们可以通过设置下面的Trainer
的标志fast_dev_run=True
,在一些样本图像上测试负载并运行您的模型。
来自共享库的代码片段。
测试的最后一个技巧是包括几个样本图像和类似注释的文件来模拟实际的数据集。这允许您更真实地测试正确的用例。
将笔记本转换为 CLI 可配置的 Python 脚本
将笔记本转换成 python 脚本的一种方法是通过 JupyterLab——选择“下载为-> Python”。简化笔记本应更短,主要关注数据/模型/教练配置(如果我们跳过所有数据探索部分)。
不幸的是,它会生成一个带有硬编码参数的脚本。为了解决这个限制,我们需要编写自己的argparser
,并将所有 CLI 参数映射到模型/数据模块/训练器。幸运的是,Lightning 最近推出了自己的极简LightningCLI
界面,为你处理争论投标。
https://devblog.pytorchlightning.ai/auto-structuring-deep-learning-projects-with-the-lightning-cli-9f40f1ef8b36 [## 使用 Lightning CLI 自动构建深度学习项目
devblog.pytorchlightning.ai](https://devblog.pytorchlightning.ai/auto-structuring-deep-learning-projects-with-the-lightning-cli-9f40f1ef8b36)
LightningCLI
几乎不需要额外的代码就能为 Lightning 脚本提供简单的参数解析!它被设计成接受这些主要的组件/角色:LightningModule
、LightningDataModule
和Trainer
,解析命令行参数并实例化这些角色。最终,LightningCLI
执行了训练。最终的脚本如下所示:
来自共享库的代码片段。
使用 CLI,您可以在任何终端中运行 python 脚本。
python kaggle_plantpatho/cli_train.py \
--model.model 'resnet34' \
--data.base_path /home/jirka/datasets/kaggle_plant-pathology \
--trainer.max_epochs 5
由于我们计划试验不同的模型架构,我们可能需要调整每个模型的批量大小,以使用最大的资源(对于较小的模型,例如 *resnet18*
,我们可以使用比 *resnet101*
大得多的批量)。这可以通过在方法 *before_fit(...)*
中实现的闪电训练器 [*tune*](https://pytorch-lightning.readthedocs.io/en/1.4.0/common/trainer.html?highlight=tune#auto-scale-batch-size)
来实现,因为它会找到适合 GPU 内存的最大 *batch_size*
并使用它进行训练。
来自共享库的代码片段。
在这篇文章中,我们展示了如何将科学笔记本转换成可以共享的标准 python 包。我们已经讨论了添加最小测试的动机,以便在不意外破坏它的情况下促进任何未来的包增强。最后,我们展示了从普通 python 脚本到公开所有命令行参数的通用脚本的简单转换。
在未来,我们将展示如何使用这个简单的脚本在 Grid.ai 上并行运行跨多台机器的超参数搜索,并在线观察训练表现。
敬请关注,并跟随我了解更多!
https://devblog.pytorchlightning.ai/best-practices-to-rank-on-kaggle-competition-with-pytorch-lightning-and-grid-ai-spot-instances-54aa5248aa8e
关于作者
Jirka boro vec已经在几家不同的 IT 公司从事机器学习和数据科学工作好几年了。特别是,他喜欢探索有趣的世界问题,并用最先进的技术解决它们。此外,他开发了几个开源 python 包,并积极参与其他知名项目。在 Grid.ai 工作,担任研究工程师,是pytorchlightning . ai的主要撰稿人。
使用 m2cgen (Python)将机器学习模型转换为 SAS
原文:https://towardsdatascience.com/converting-machine-learning-models-to-sas-using-m2cgen-python-190d846090dc?source=collection_archive---------32-----------------------
在 SAS 中部署经过训练的 ML 模型(如 XGBoost 和 LightGBM)的方法
m2cgen 是一个非常友好的包,可以将许多不同的训练模型转换成支持语言的语言,比如 R 和 VBA。但是,m2cgen 还不支持 SAS。本文是为那些需要在 SAS 环境中部署经过训练的模型的人准备的。本文介绍的方法是首先将模型转换为 VBA 代码,然后将 VBA 代码转换为 SAS 脚本。
本教程中使用的脚本上传到我的 Github repo ,随意克隆文件。
克里斯·劳顿在 Unsplash 上的照片
包裹
m2cgen
功能
m2cgen
(Model 2 Code Generator)——是一个轻量级的库,它提供了一种将训练好的统计模型转换成本机代码(Python、C、Java、Go、JavaScript、Visual Basic、C#、PowerShell、R、PHP、Dart、Haskell、Ruby、F#)的简单方法。
示范
- 将 XGBoost 模型转换为 VBA,然后转换为 SAS 脚本
- 将 XGBoost 模型转换为 VBA,然后转换为 SAS 脚本(缺少值)
数据
从 sklearn 加载的虹膜数据集
任务 1:将 XGBoost 模型转换为 VBA 模型
# import packages
import pandas as pd
import numpy as np
import os
import refrom sklearn import datasets
from xgboost import XGBClassifier
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_scoreimport m2cgen as m2c# import data
iris = datasets.load_iris()
X = iris.data
Y = iris.target
首先,我们导入这个任务所需的包和数据。
# split data into train and test sets
seed = 2020
test_size = 0.3
X_train, X_test, y_train, y_test = train_test_split(X, Y, test_size=test_size, random_state=seed)# fit model on training data
model = XGBClassifier()
model.fit(X_train, y_train)
然后,我们来训练一个简单的 XGBoost 模型。
code = m2c.export_to_visual_basic(model, function_name = 'pred')
接下来,将 XGBoost 模型转换为 VBA 模型。使用 m2cgen 的 export_to_visual_basic 函数,可以得到你训练好的 VBA 语言的 XGBoost 模型。转换成其他语言的脚本也和转换成 VBA 语言的脚本一样简单。
照片由 cyda 拍摄
接下来是本教程的核心,在将模型转换为 VBA 之后,需要一些步骤来将 VBA 代码转换为 SAS 脚本,例如删除 SAS 环境中不使用的许多不必要的行,如“模块 xxx”、“函数 yyy”和“Dim var Z As Double”,并插入“;”以遵循 SAS 中的语法规则。
# remove unnecessary things
code = re.sub('Dim var.* As Double', '', code)
code = re.sub('End If', '', code)# change the script to sas scripts
# change the beginning
code = re.sub('Module Model\nFunction pred\(ByRef inputVector\(\) As Double\) As Double\(\)\n',
'DATA pred_result;\nSET dataset_name;', code)# change the ending
code = re.sub('End Function\nEnd Module\n', 'RUN;', code)# insert ';'
all_match_list = re.findall('[0-9]+\n', code)
for idx in range(len(all_match_list)):
original_str = all_match_list[idx]
new_str = all_match_list[idx][:-1]+';\n'
code = code.replace(original_str, new_str)
all_match_list = re.findall('\)\n', code)
for idx in range(len(all_match_list)):
original_str = all_match_list[idx]
new_str = all_match_list[idx][:-1]+';\n'
code = code.replace(original_str, new_str)# replace the 'inputVector' with var name
dictionary = {'inputVector(0)':'sepal_length',
'inputVector(1)':'sepal_width',
'inputVector(2)':'petal_length',
'inputVector(3)':'petal_width'}
for key in dictionary.keys():
code = code.replace(key, dictionary[key])# change the prediction labels
code = re.sub('Math.Exp', 'Exp', code)
code = re.sub('pred = .*\n', '', code)
temp_var_list = re.findall(r"var[0-9]+\(\d\)", code)
for var_idx in range(len(temp_var_list)):
code = re.sub(re.sub('\\(', '\\(', re.sub('\\)', '\\)', temp_var_list[var_idx])), iris.target_names[var_idx]+'_prob', code)
逐步解释:
# remove unnecessary things
code = re.sub('Dim var.* As Double', '', code)
code = re.sub('End If', '', code)# change the beginning
code = re.sub('Module Model\nFunction pred\(ByRef inputVector\(\) As Double\) As Double\(\)\n',
'DATA pred_result;\nSET dataset_name;', code)# change the ending
code = re.sub('End Function\nEnd Module\n', 'RUN;', code)
前三部分非常简单。我们简单地使用正则表达式去掉不需要的行,然后将脚本的开头改为“DATA pred _ result\ n 设置数据集名称;"其中,pred_result 是指运行 SAS 脚本后的输出表名称,dataset_name 是指我们需要预测的输入表名称。最后一部分是将脚本的结尾改为“RUN”。
# insert ';'
all_match_list = re.findall('[0-9]+\n', code)
for idx in range(len(all_match_list)):
original_str = all_match_list[idx]
new_str = all_match_list[idx][:-1]+';\n'
code = code.replace(original_str, new_str)
all_match_list = re.findall('\)\n', code)
for idx in range(len(all_match_list)):
original_str = all_match_list[idx]
new_str = all_match_list[idx][:-1]+';\n'
code = code.replace(original_str, new_str)
遵循 SAS 中的语法规则,";"需要指示每个语句的结束。
照片由 cyda
# replace the 'inputVector' with var name
dictionary = {'inputVector(0)':'sepal_length',
'inputVector(1)':'sepal_width',
'inputVector(2)':'petal_length',
'inputVector(3)':'petal_width'}
for key in dictionary.keys():
code = code.replace(key, dictionary[key])
利用字典,我们可以将“输入向量”与输入数据集中的变量名进行映射,并一次性更改所有的“输入向量”。
# change the prediction labels
code = re.sub('Math.Exp', 'Exp', code)
code = re.sub('pred = .*\n', '', code)
temp_var_list = re.findall(r"var[0-9]+\(\d\)", code)
for var_idx in range(len(temp_var_list)):
code = re.sub(re.sub('\\(', '\\(', re.sub('\\)', '\\)', temp_var_list[var_idx])), iris.target_names[var_idx]+'_prob', code)
转换步骤的最后一部分是更改预测标签。
由 cyda 拍摄
# save output
vb = open('vb1.sas', 'w')
vb.write(code)
vb.close()
最后,我们可以用后缀“.”保存输出。sas "
第一个任务到此结束,现在,您应该能够将您训练的模型转换成 SAS 脚本了。要仔细检查创建的 SAS 脚本是否有任何问题,您可以使用以下脚本来检查 python 预测和 SAS 预测的差异。请注意,预测的概率(python vs SAS)显示了一点差异,但差异应该不是非常显著。
# python pred
python_pred = pd.DataFrame(model.predict_proba(X_test))
python_pred.columns = ['setosa_prob','versicolor_prob','virginica_prob']
python_pred# sas pred
sas_pred = pd.read_csv('pred_result.csv')
sas_pred = sas_pred.iloc[:,-3:]
sas_pred(abs(python_pred - sas_pred) > 0.00001).sum()
照片由 cyda 拍摄
任务 2:将 XGBoost 模型转换为 VBA,然后转换为 SAS 脚本(缺少值)
如果您的数据在训练数据中没有缺失值,XGBoost 在生成树时默认将“缺失值”放在左边的节点上(如下树图所示)(引用)。从 m2cgen 生成的脚本中,您可以发现,如果变量大于或等于给定的数字,测试的条件总是 be。因此,如果测试或预测数据集中有缺失值,脚本会将“缺失值”留给 else 部分。例如,在我们从任务 1 生成的 SAS 脚本中,第一个测试条件是“If(petal _ length)>=(2.45)Then var 0 =-0.21827246;否则 var0 = 0.42043796",所以如果 petal_length 缺失,不大于等于 2.45,var0 会赋为 0.42043796。另一个例子如下所示。
照片由 cyda
照片由 cyda
如果您的训练数据包含缺失值,该怎么办?XGBoost 会根据训练结果将“缺失值”放到左侧或右侧节点。(因此,您可以看到 SAS 脚本中显示的条件有时是" = ")
由 cyda 拍摄
由 cyda 拍摄
您可以使用以下脚本创建带有缺失值的数据集,并重复任务 1 中的步骤,以查看和比较 SAS 和 python 的预测输出。
from random import sample
from sklearn import datasets# import data
iris = datasets.load_iris()
X = iris.data
Y = iris.target# assume that there are missing values in the first 2 columns of the data
sequence = [i for i in range(len(X))]
subset0 = sample(sequence, 30)
subset1 = sample(sequence, 50)
subset2 = sample(sequence, 40)
subset3 = sample(sequence, 60)
X[[(subset0)],0] = np.nan
X[[(subset1)],1] = np.nan
X[[(subset0)],2] = np.nan
X[[(subset1)],3] = np.nan
我做了测试,发现一些行具有相同的预测输出,而一些行显示出很大的差异(见下图)。
照片由 cyda
我比较了 SAS 脚本的中间步骤中生成的 var。让我们以下面显示的第二行为例。如果测试的条件是“If (petal_length) >= (2.45)那么 var 0 =-0.217358515;Else …”并且缺少了 petal_length,所以不满足条件,转到 Else 语句,那么测试的第二个条件是“If(petal _ width)> =(0.84999996)Then var 0 =-0.155172437;Else …”并且 petal_width 是 0.2,同样,它不满足条件并转到 Else 语句。接下来,我们进入第三个条件,“If (sepal_length) < (11.600001) Then var0 = 0.411428601; Else …” and we see that sepal_length is missing, it should not fulfill the condition but SAS somehow accept it as True and the var0 is 0.411428601.
Photo by cyda
cyda 拍摄的照片
因此,为了迎合这种情况,我添加了一些脚本来强制脚本首先检查值是否丢失。
# handle missing values
all_match_list = re.findall('If.*Then', code)
for idx in range(len(all_match_list)):
original_str = all_match_list[idx]
new_str = ' '.join(original_str.split()[:-1] + [**'and not missing'**, original_str.split()[1], ' Then'])
code = code.replace(original_str, new_str)
因此,将 VBA 转换为服务协议的手动脚本将更改为以下脚本。你可以在我的 GitHub repo 中找到完整版。
# remove unnecessary things
code = re.sub('Dim var.* As Double', '', code)
code = re.sub('End If', '', code)# change the beginning
code = re.sub('Module Model\nFunction pred\(ByRef inputVector\(\) As Double\) As Double\(\)\n',
'DATA pred_result;\nSET dataset_name;', code)# change the ending
code = re.sub('End Function\nEnd Module\n', 'RUN;', code)# insert ';'
all_match_list = re.findall('[0-9]+\n', code)
for idx in range(len(all_match_list)):
original_str = all_match_list[idx]
new_str = all_match_list[idx][:-1]+';\n'
code = code.replace(original_str, new_str)
all_match_list = re.findall('\)\n', code)
for idx in range(len(all_match_list)):
original_str = all_match_list[idx]
new_str = all_match_list[idx][:-1]+';\n'
code = code.replace(original_str, new_str)# handle missing values
all_match_list = re.findall('If.*Then', code)
for idx in range(len(all_match_list)):
original_str = all_match_list[idx]
new_str = ' '.join(original_str.split()[:-1] + ['and not missing', original_str.split()[1], ' Then'])
code = code.replace(original_str, new_str)# replace the 'inputVector' with var name
dictionary = {'inputVector(0)':'sepal_length',
'inputVector(1)':'sepal_width',
'inputVector(2)':'petal_length',
'inputVector(3)':'petal_width'}
for key in dictionary.keys():
code = code.replace(key, dictionary[key])# change the prediction labels
code = re.sub('Math.Exp', 'Exp', code)
code = re.sub('pred = .*\n', '', code)
temp_var_list = re.findall(r"var[0-9]+\(\d\)", code)
for var_idx in range(len(temp_var_list)):
code = re.sub(re.sub('\\(', '\\(', re.sub('\\)', '\\)', temp_var_list[var_idx])), iris.target_names[var_idx]+'_prob', code)
在本教程中,我使用 m2cgen 包将 XGBoost 模型转换为 VBA 代码,然后转换为 SAS 脚本,但没有必要首先转换为 VBA 代码,如果您愿意,可以选择其他语言,如 C 或 JAVA。本教程只是演示了如何将脚本从一种语言转换成另一种语言。
想了解更多关于使用 m2cgen 的知识,请前往官方 Github 资源库。
用 Python 和 Numpy 实现卷积层黑客攻击
原文:https://towardsdatascience.com/convolutional-layer-hacking-with-python-and-numpy-e5f64812ca0c?source=collection_archive---------35-----------------------
用 python 从头开始创建一个卷积层,用自定义内核破解其权重,并验证其结果与 pytorch 生成的结果相匹配
梅里达勒在 Unsplash 上拍摄的照片
如果你开始在深度学习中使用卷积层,你可能会对所涉及的参数、计算和通道的混合感到困惑。从条纹到填充,输入和输出通道,内核和可学习的参数,有很多事情正在进行。在这篇文章中,我们将深入到这些 conv 层的最底层。我们将:
- 用 python 从头编码一个卷积层到一点一点理解当我们通过其中一个层传递数据时是怎么回事。
- 黑掉 convnet 的参数,生成自定义内核和随机内核的混合。
- 使用 Pytorch 和 Python-numpy 比较结果,验证我们获得了完全相同的输出。准备好了吗?让我们开始吧。
初始设置
跳到 https://colab.research.google.com/的 google colab 或者任何其他可以用 python 和 pytorch 编码的平台。
首先,我们初始化我们需要的库。这将允许我们用 pytorch 和 numpy 库进行编码,这样我们可以在以后比较它们的结果。
import torch
from torch import nn
from torchvision import transforms
from torchvision.transforms.functional import pad
import numpy as np
import time
import numpy.testing as npt
from PIL import Image
from matplotlib import pyplot as plt
好了,现在我们做两件事:
- 设置种子以便结果一致且可重复(可选)
- 上传图像到系统。我们使用 PIL 库加载它,并将其与 R、G 和 B 三个通道一起可视化。在这个例子中,我使用了一朵花的 128x128 像素的图像。
img = Image.open("flower128.jpg")
plt.figure()
plt.axis('off')
plt.imshow(img)
fig, axs = plt.subplots(nrows=1, ncols=3, figsize=(12,4))
for i, ax in enumerate(axs.flatten()):
plt.sca(ax)
plt.axis('off')
plt.imshow(np.array(img)[:, :, i], cmap='gray', vmin = 0, vmax = 255)
plt.show()
帕特里克·康纳·克洛夫在 Unsplash 上拍摄的照片
是时候设置我们卷积层的主要参数了:
- 首先,我们将图像的原始宽度和高度存储在 w_in 和 h_in 中,在本例中是 128x128 像素。
- c_in 为 3,因为输入数据有 3 个通道。 c_out 将会是 5 因为我们想要在 conv 层的输出中产生 5 个通道。这可能是 4,7,11 或任何数字。在这个例子中,我选择 5。
- k 是 3 因为我们将使用一个 3x3 的内核大小。
- 我决定在这个例子中我想产生一个宽度为高度为和宽度为 64 像素的输出。为了做到这一点,我们将步幅设置为 2** 并将填充设置为 1 ,因此我们将以 2 为增量移动我们的内核,并且我们将创建 1 的外部填充以确保最终尺寸是初始尺寸的一半。**
- 为了验证(并且预先计划)我们的输出宽度和高度,我们可以使用这个简化的公式: (n+2*pad-ks)//stride +1 ,我们将输出尺寸存储在 w_out 和 h_out 中。
w _ out=(128+2 * 1–3)//2+1 =64
h _ out=(128+2 * 1–3)//2+1 =64
w_in=img.size[0]
h_in=img.size[1]
c_in=3
c_out=5
k=3
stride=2
padding=1
# (n+2*pad-ks)//stride +1
w_out = (w_in+2*padding-k)//stride +1
h_out = (h_in+2*padding-k)//stride +1
pytorch conv2d 层
现在,我们创建一个 pytorch conv2d 层,并根据正态分布初始化其参数:
- 将图像数据转换成张量。这将产生形状为 3,128,128 的张量。然后我们使用 unsqueeze_(0)在开头添加一个额外的维度,然后获得最终的形状: 1,3,128,128 。第一维表示我们正在用一批图片做这个实验。
- 然后,我们声明函数 init_weights ,该函数将使用从正态分布采样的值初始化 conv 层的权重和偏置参数。
- 最后我们使用 pytorch nn。Conv2d 函数创建 Conv 层,我们调用 init_weights 函数初始化它的权重。这将创建 pytorch conv 层: 【Conv2d(3,5,kernel_size=(3,3),stride=(2,2),padding=(1,1))
#### Pytorch Conv2d layer
data = transforms.ToTensor()(img).unsqueeze_(0)def init_weights(m):
if isinstance(m, nn.Conv2d):
torch.nn.init.normal_(m.weight, 0.0, 0.02)
torch.nn.init.normal_(m.bias, 0.0, 0.02)convlayer=nn.Conv2d(c_in, c_out, k, stride=stride, padding=padding)
convlayer=convlayer.apply(init_weights)
print(convlayer)
numpy conv2d 层设置
挑战仍在继续。现在让我们设置使用 python 和 numpy 库创建 conv2d 层所需的数据。
- 我们复制了一张图片,并使用填充函数在其周围创建一个 1 像素的填充(遵循我们在 pytorch 中使用的填充策略)。请注意,我使用了 torchvision 函数来进行填充,但是您可以用许多其他方式来完成此操作,而无需使用 torchvision。
- 然后我们转置通道维度,并使用 expand_dims 在开头添加一个额外的维度。此时,我们将拥有:
Numpy 输入数据 : 1x3x130x130
Pytorch 输入数据 : 1x3x128x128
请注意,Numpy 数据包含填充,而 Pytorch 数据不包含填充,因为 pytorch convd2d 层会自行应用填充。 - 最后,我们将 numpy 数据除以 255.0,使其值介于 0 和 1 之间。
- 此时,pytorch 和 numpy 数据具有相似的结构和值。是行动的时候了!
img2= img.copy()
img2=pad(img2, (1,1))
data2 = np.array(img2).transpose((2, 0, 1))
data2 = np.expand_dims(data2, axis=0)
data2 = data2/255.0
破解重量
现在,我们将有一些乐趣黑客这些层的权重。
首先让我们打印 pytorch 层的权重和偏差的形状。
我们可以看到权重的结构是:5,3,3,3 ( c_out,c_in,k,k )。偏差要简单得多,我们只要有尽可能多的输出通道。
所以我们有 135+5=140 个参数,每个输出通道一个,每个输入通道一个,每个内核维度一个,加上偏置参数。然后我们使用 np.zeros 命令用 numpy 初始化类似的结构,最初用零填充它们。
print(convlayer.weight.shape)
print(convlayer.bias.shape)
# Print Output:
# torch.Size([5, 3, 3, 3])
# torch.Size([5])w=np.zeros((c_out, c_in, k, k))
b=np.zeros((c_out))
此时,在 pytorch 数据结构的情况下,我们的内核的参数值被初始化为从正态分布采样的值,在 numpy 结构的情况下被初始化为零。
我们知道,无论我们在内核中拥有什么,都将决定我们从图像中提取什么样的模式。因此,我们将执行以下操作:
- 我们将黑掉连接图像前 3 个输出通道和输入通道的前 3 个内核。
- 我们将让与最后 2 个输出通道连接的另外 2 个内核具有来自正态分布的随机值。
让我们首先在前 3 个内核中创建参数的值。
- 我们创建一个名为 ker 的列表。
- 然后我们给它添加三个内核结构。
- 第一个是一个将检测水平线的内核。
- 第二个是一个内核,它将模糊图像
- 第三个是内核,它将锐化图像的边缘
ker=[]
ker.append(np.array([[-1.1,-1.1,-1.1],[2.2,2.2,2.2],[-1.1,-1.1,-1.1]]))
ker.append(np.array([[1/9,1/9,1/9],[1/9,1/9,1/9],[1/9,1/9,1/9]]))
ker.append(np.array([[0.0,-1.0,0.0],[-1.0,6.0,-1.0],[0.0,-1.0,0.0]]))
现在是时候侵入 pytorch 层权重和改变参数的值,这些参数与连接到前 3 个输出通道的内核相对应,以便它们成为我们手动创建的内核。
最后的两个内核将保持它们之前具有的来自正态分布的相同随机值。
with torch.no_grad():
for w0 in range(convlayer.weight.shape[0]):
for w1 in range(convlayer.weight.shape[1]):
if (w0<len(ker)):
convlayer.weight[w0][w1]=torch.from_numpy(ker[w0])
现在我们对 numpy 卷积数据结构做同样的事情。我们对前 3 个输出通道和内核进行了同样的操作,对最后两个输出通道,我们从 pytorch conv2d 层复制了正态分布的采样数据(因此 pytorch 和 numpy conv 层具有完全相同的参数)。
for w0 in range(c_out):
for w1 in range(c_in):
if (w0<len(ker)):
w[w0][w1]=ker[w0]
else:
w[w0][w1]=np.around(convlayer.weight[w0][w1].detach().numpy(),decimals=4)
b[w0]=np.around(convlayer.bias[w0].detach().numpy(),decimals=4)
这样,两种数据结构具有相同的参数。
- 将前 3 个输出通道连接到数据输入通道的前 3 个内核具有我们创建的手动内核值,它将检测水平线,产生模糊并锐化边缘。
- 最终 2 个内核具有从正态分布中采样的随机值,并且在 pytorch 和 numpy 结构中是相同的。
如果我们打印 pytorch conv2d 层权重的值和 numpy 权重的值,我们会看到它们是相同的。例如,这些是 numpy 数据结构:
## Showing 2 decimals for visual clarity
print(np.around(w,decimals=2))###### FIRST KERNEL, detect horizontal lines #####
[[[[-1.1 -1.1 -1.1 ]
[ 2.2 2.2 2.2 ]
[-1.1 -1.1 -1.1 ]][[-1.1 -1.1 -1.1 ]
[ 2.2 2.2 2.2 ]
[-1.1 -1.1 -1.1 ]][[-1.1 -1.1 -1.1 ]
[ 2.2 2.2 2.2 ]
[-1.1 -1.1 -1.1 ]]]###### SECOND KERNEL, blurring #####
[[[ 0.11 0.11 0.11]
[ 0.11 0.11 0.11]
[ 0.11 0.11 0.11]][[ 0.11 0.11 0.11]
[ 0.11 0.11 0.11]
[ 0.11 0.11 0.11]][[ 0.11 0.11 0.11]
[ 0.11 0.11 0.11]
[ 0.11 0.11 0.11]]]###### THIRD KERNEL, sharpen #####
[[[ 0\. -1\. 0\. ]
[-1\. 6\. -1\. ]
[ 0\. -1\. 0\. ]][[ 0\. -1\. 0\. ]
[-1\. 6\. -1\. ]
[ 0\. -1\. 0\. ]][[ 0\. -1\. 0\. ]
[-1\. 6\. -1\. ]
[ 0\. -1\. 0\. ]]]###### FOURTH KERNEL, random values #####
[[[-0\. -0.01 -0\. ]
[ 0.04 -0.01 -0.03]
[-0.01 0.01 0.02]][[-0.01 0\. 0\. ]
[-0.02 -0\. 0.02]
[ 0.02 -0.02 0.01]][[ 0.02 -0.01 -0.02]
[-0.02 -0\. -0.02]
[ 0.02 0.02 -0.04]]]###### FIFTH KERNEL, random values #####
[[[-0.03 -0.02 0.01]
[ 0.01 0.03 0.01]
[ 0\. 0.01 -0.07]][[ 0.02 -0.03 0.01]
[-0.03 0.03 -0.01]
[ 0.01 -0.01 0.01]][[-0.01 -0\. -0.02]
[-0.01 -0\. -0.05]
[ 0.01 0.01 -0\. ]]]]
因此,当我们获得两个 conv 层的输出并可视化产生的 5 个通道时,我们应该在前三个通道中看到水平线检测、模糊和锐化的影响,在后两个通道中,我们应该看到后两个内核中的随机值产生的不同结果。
黑客攻击完成后,我们现在可以开始创建 numpy 卷积层。
python 中的 conv 图层
我们将创建一个函数来执行标准深度学习卷积层的整个过程,它用纯 python 来完成。事情是这样的:
- 首先,我们创建一个数据结构来保存我们的结果。它的结构会是: 1,c_out,w_out,h_out。第一维是 1,因为我们用的是一批只有 1 张的图片。第二维是我们在输出中接收的通道数,最后二维是图像的输出宽度和高度。在我们的例子中,我们知道这些最终的维度是:1,5,64,64。
- 现在,有趣的事情来了。我们将用一种简单的方式来做这件事,以便尽可能清楚地看到正在发生的事情。女士们先生们,准备好你们的圈圈,系好安全带,开始狂野之旅。
- 该版本的代码旨在尽可能简单明了,以促进理解。我选择从结尾开始,然后后退。所以我们将从输出尺寸和开始,然后向后移向起点。这是我们可以用来解决这些计算的许多可能性之一。
- 对于我们将要产生的输出结果的输出尺寸的每个位置( w_out 和 h_out
- 输出通道 ( c_out )的每个的
- 以及连接到每个输出通道的输入通道的每个的
- 对于我们的 内核 ( k x k )的维度中的每一个,将在每个输入通道中移动数据
- 没错,那一共是 6 个循环,确实没错。现在,在我们看到这些循环的底部发生了什么之前,还有一些事情要考虑。
- 对于每个输出通道,您将初始化一个变量,该变量将累积数据,这些数据将从与该输出通道连接的所有相应输入通道中收集(姑且称之为总计)。****
- 对于每个输入通道,,您将初始化另一个变量,该变量将累积正在收集的值,,因为内核移动通过每个通道中的数据(让我们称之为 kt )。
- 所以现在,一直到那套循环的底部。
- 取对应于你正在查看的当前输出通道和当前输入通道以及你正在考虑的内核中的当前位置的权重。(储存在重量中)
- 通过结合与内核相关的位置、输出和使用的步幅,计算数据中的位置。(存储在位置 1 和位置 2 中)
- 访问与我们正在寻址的当前输入通道和我们刚刚计算的那些位置的组合相对应的数据值( 0,ci,pos1,pos2 ,并将其存储在值中。
- 最后,将权重乘以值,并将其添加到变量 kt 中,该变量为每个输入通道累积计算值。
- 在变量 kt 中收集了来自每个输入通道的所有计算后,我们会将它们添加到与每个输出通道相关的计算中(这些计算存储在每个输出通道的变量 total 中)。
- 然后加上与我们考虑的输出通道相对应的偏置值。
- 最后,我们将最终总计值分配到输出结构中的正确位置: res[0,co,o1,o2] ,我们正在查看的当前输出通道的组合以及我们正在考虑的输出结果中的当前位置。
作者贾维尔·Ideami@ideami.com 制图
**def python_conv(data):
res=np.zeros((1, c_out, w_out, h_out))
for o1 in range(w_out):
for o2 in range(h_out):
for co in range(c_out):
total=0
for ci in range(c_in):
kt=0
for k1 in range(k):
for k2 in range(k):
weight = w[co,ci,k1,k2]
pos1=k1+o1*stride
pos2=k2+o2*stride
value = data[0, ci, pos1 ,pos2]
kt+= weight * value
total+=kt
res[0,co,o1,o2]=total+b[co]
return res**
唷!我们成功了,恭喜:)
有一件特别简单的事情。我们还将创建一个 sigmoid 函数,它将允许我们获得从 0 到 1 范围内的输出数据。然后我们就可以将我们的结果与 Pytorch 产生的结果进行比较。
**def sigm(data):
z = 1/(1 + np.exp(-data))
return z**
所以当有人问你深度学习 conv 层发生了什么时,你可以这样说:
哦,那很简单,是的,让我告诉你。因此..对于每个输出维度、每个输出通道、每个输入通道以及每个内核维度,选择与所有这些值的当前组合相对应的权重,并将其乘以由内核和输出位置的组合确定的位置处的数据值(最后一个值由跨距值修改)。我们在所有输入通道中累计这些计算结果,并将相应的偏置参数值与该结果相加,以获得与特定输出通道和我们所观察的输出尺寸部分相对应的最终值。然后,我们继续相同的过程,继续通过其余的输出通道和输出维度。”
只有一个问题。如果你提供了这样的解释, 人们可能会担心你最近没有睡好,他们可能会建议你开始服用褪黑激素,并开始一个深度的瑜伽和冥想计划。因此,最好你只展示视觉图形,简单告诉他们:
“你瞧, 不过是用一组循环 包裹起来的一堆乘法和加法,这不是非常简单吗?”
让我告诉你,那样会更好。
这太令人兴奋了。我们准备运行两个 conv 层并比较结果。我们开始吧!
测试 pytorch 和 python conv 图层
是时候运行两个 conv 层了。准备,稳住,开始!
**start=time.time()
ptorch_out = convlayer(data)
ptorch_out = nn.Sigmoid()(ptorch_out)
end=time.time()
print("conv2d completed")
print("Pytorch: time taken: ",end-start)start=time.time()
numpy_out = python_conv(data2)
numpy_out = sigm(numpy_out)
end=time.time()
print("Python: time taken: ",end-start)**
Pytorch : 耗时:0.0009734630584716797
Python:耗时:0.5253609657287****
当然 Pytorch 在速度上是最好的,但是我们的 python 版本是如此的甜美可爱!(因为这有助于我们一步一步地了解情况)。
那么现在,让我们来比较结果吧!
首先让我们检查输出尺寸。
**print("Pytorch in shape: ",data.shape)
print("Python in shape: ",data2.shape)
print("Pytorch out shape: ",ptorch_out.shape)
print("Python out shape: ",numpy_out.shape)**
形状 py torch:火炬。大小([1,3,128,128])
蟒蛇在形状: (1,3,130,130)
Pytorch 出来形状:火炬。尺寸(【1,5,64,64】)
蟒蛇出形: (1,5,64,64)
维度看起来不错,现在让我们来看看两种方法的输出数据片段的子集。
**pytorch_verify=ptorch_out[0][0][0].cpu().detach().numpy()
pytorch_verify=np.around(pytorch_verify,decimals=3)
numpy_verify=np.around(numpy_out[0][0][0],decimals=3)print("pytorch: ",pytorch_verify[:25])
print("python: ",numpy_verify[:25])
assert np.allclose(pytorch_verify, numpy_verify)**
py torch 0.997 0.997 0.997 0.997 0.997 0.997 0.997 0.997 0.997 0.997 0.997 0.997 0.997 0.997 0.997 0.997 0.997 0 0.997 0 0.997 0.997 0 0.997 0 0.997 0 7 0.997 0 7 0.997 0 7 0.9997 0 7 0.9997 0 7 0
看起来不错!但是最好的测试是简单地在 pytorch 和 python 输出中可视化 5 个输出通道。让我们去争取吧。
**%matplotlib inlinenc=5plt.figure(figsize=(15, 15), dpi=80)fig, axs = plt.subplots(nrows=1, ncols=nc, figsize=(12,4))
for i, ax in enumerate(axs.flatten()):
plt.sca(ax)
plt.axis('off')
im=transforms.ToPILImage(mode='L')(ptorch_out[0][i])
plt.imshow(im, cmap='gray')
#plt.tight_layout()
plt.show()fig, axs = plt.subplots(nrows=1, ncols=nc, figsize=(12,4))
for i, ax in enumerate(axs.flatten()):
plt.sca(ax)
plt.axis('off')
im = Image.fromarray(numpy_out[0][i]*255)
im = im.convert("L")
plt.imshow(im, cmap='gray')
plt.show()**
我们到了。py torch 和 python conv 图层的结果相同。在前 3 个输出通道中,在这两种情况下,我们都可以看到对水平线的检测,模糊和锐化内核处理。在最后 2 个通道中,我们看到 2 个相同的随机变换,它们来自我们在最后 2 个内核结构的参数中设置的随机正态分布值。
结论和下一步措施
从零开始构建事物是详细了解事物的最佳方式之一。通过这个简单的练习,我们可以一步一步地了解深度学习标准卷积层中的计算流程。现在你已经为下一步做好了准备:****
- 你可以将类似的策略应用于深度学习生态系统中你感兴趣的其他部分。
- 你也可能开始认为卷积层已经过时了。所以你可以发明一些新的方法来从数据中提取模式,就像我们在这里做的那样,使用普通的 python 和 numpy,然后使它适应像 JAX / JIT 这样的东西,使它飞行并将其集成到一个自动微分的过程中,等等。
这篇文章的所有代码都可以在这个 github 库获得:****
****https://github.com/javismiles/convolutional-layer-hacking
如果您喜欢这篇文章,您可能也会对我发表的关于在 transformer 架构中进行计算的方式的文章感兴趣:
****
卷积层与全连接层
原文:https://towardsdatascience.com/convolutional-layers-vs-fully-connected-layers-364f05ab460b?source=collection_archive---------0-----------------------
深度学习基础
当您使用卷积层与全连接层时,实际情况是怎样的?
作者图片
一开始,神经网络的设计是一件很难理解的事情。设计神经网络包括选择许多设计特征,如每层的输入和输出大小、何时何地应用批量标准化层、丢弃层、使用什么激活函数等。在本文中,我想讨论全连接层和卷积背后真正发生的事情,以及如何计算卷积层的输出大小。
介绍
随着计算能力的提高和模型架构的进步,深度学习是一个在过去几年中飞速发展的研究领域。当阅读深度学习时,你会经常听到两种网络,即全连接神经网络(FCNN)和卷积神经网络(CNN)。这两个是深度学习架构的基础,几乎所有其他深度学习神经网络都源于此。在本文中,我将首先解释全连接层如何工作,然后是卷积层,最后我将通过一个 CNN 的例子。
完全连接的层(FC 层)
神经网络是一组相关的非线性函数。每个单独的功能由一个神经元(或感知器)组成。在完全连接的层中,神经元通过权重矩阵对输入向量进行线性变换。然后通过非线性激活函数 f 对产品进行非线性变换。
作者图片
这里我们取权重矩阵 W 和输入向量 x 之间的点积,偏差项(W0)可以添加到非线性函数中。我将在本文的其余部分忽略它,因为它不影响输出大小或决策,只是另一个权重。
如果我们以输入大小为 9、输出大小为 4 的 FC 神经网络中的一个层为例,则操作可以如下所示:
作者图片
激活函数 f 在该层的输入和该层的权重矩阵之间包装点积。注意,权重矩阵中的列将具有不同的数字,并且将随着模型的训练而被优化。
输入是 1×9 向量,权重矩阵是 9×4 矩阵。通过取点积并利用激活函数应用非线性变换,我们得到输出向量(1×4)。
人们也可以通过以下方式来可视化该层:
作者图片
上图显示了为什么我们称这种类型的层为“完全连接”或有时称为“密集连接”。所有可能的层到层的连接都存在,这意味着输入向量的每个输入都会影响输出向量的每个输出。然而,并非所有权重都会影响所有输出。看上面每个节点之间的连线。橙色线代表该层的第一个神经元(或感知器)。这个神经元的权重只影响输出 A,对输出 B、C 或 d 没有影响。
卷积层(Conv 层)
作者图片
卷积实际上是一种滑动点积,其中内核沿着输入矩阵移动,我们将两者之间的点积视为矢量。下面是上面显示的卷积的矢量形式。您可以看到为什么橙色字段之间的点积会输出一个标量(1x44x 1 = 1x1)。
作者图片
同样,我们可以将这个卷积层想象为:
作者图片
卷积不是密集连接的,不是所有的输入节点都影响所有的输出节点。这使得卷积层在学习中具有更大的灵活性。此外,每层的权重数量要少得多,这对于图像数据等高维输入非常有帮助。这些优势赋予了 CNN 在数据中学习特征的众所周知的特性,例如图像数据中的形状和纹理。
与 CNN 合作
在 FC 层中,通过选择权重矩阵中的列数,可以非常简单地指定层的输出大小。对于 Conv 层就不一样了。卷积有许多可以改变的参数,以适应运算的输出大小。
我强烈推荐你查看这个链接到弗朗切斯科对卷积的解释。在这本书里,他解释了卷积的所有变体,比如有和没有填充的卷积、步长、转置卷积等等。这是迄今为止我所见过的最好的,最直观的解释,我仍然经常回头参考它。
Conv 输出大小
要确定卷积的输出大小,可以应用以下公式:
作者图片
输出大小等于输入大小加上两倍的填充减去步幅上的内核大小加上 1。大多数时候我们处理的是方阵,所以这个数字对于行和列是一样的。如果分数不是整数,我们就向上取整。我建议试着理解这个等式。除以步幅是有意义的,因为当我们跳过操作时,我们是将输出大小除以该数字。两次填充来自于填充被添加到矩阵的两侧,因此被添加两次。
转置 Conv 尺寸
根据上面的等式,输出将总是等于或小于输出,除非我们添加大量填充。然而,添加太多填充来增加维度将导致学习中的巨大困难,因为每层的输入将非常稀疏。为了解决这个问题,转置卷积被用来增加输入的大小。示例应用例如在卷积 VAEs 或 GANs 中。
作者图片
上述等式可用于计算转置卷积层的输出大小。
有了这两个方程,你就可以设计一个卷积神经网络了。让我们看看 GAN 的设计,并使用上面的等式来理解它。
GAN 示例
在这里,我将介绍一个使用卷积层和转置卷积层的生成式对抗网络的架构。你会明白为什么上面的等式如此重要,为什么没有它们你就不能设计 CNN。
我们先来看看鉴别器:
作者图片
鉴别器的输入大小是 3x64x64 图像,输出大小是二进制 1x1 标量。我们大幅降低了维度,因此标准卷积层是这种应用的理想选择。
注意,在每个卷积层之间(PyTorch 中表示为 Conv2d ),指定了激活函数(在本例中为 LeakyReLU ),并应用了批量归一化。
鉴别器中的 Conv 层
nn。Conv2d(nc,ndf,k = 4,s = 2,p = 1,bias=False)
第一卷积层将“ndf”卷积应用于输入的 3 层中的每一层。图像数据通常有 3 层,分别用于红绿蓝(RGB 图像)。我们可以对每一层应用一些卷积来增加维度。
应用的第一个卷积的内核大小为 4,跨距为 2,填充为 1。将此代入等式得出:
作者图片
因此输出是一个 32x32 的图像,正如代码中提到的。您可以看到,我们已经将输入的大小减半。接下来的 3 层是相同的,这意味着每层的输出大小是 16x16,然后是 8x8,然后是 4x4。最终层使用的内核大小为 4,步幅为 1,填充为 0。代入公式,我们得到 1×1 的输出大小。
发生器中的转置 Conv 层
nn。ConvTranspose2d( nz,ngf * 8,4,1,0,bias=False)
作者图片
让我们看看发生器中的第一层。发生器有一个 1x1x100 矢量(1xnz)的输入,想要的输出是 3x64x64。我们正在增加维度,所以我们想使用转置卷积。
第一个卷积使用的内核大小为 4,步长为 1,填充为 0。让我们把它代入转置卷积方程:
作者图片
如代码所示,转置卷积的输出大小为 4x4。接下来的 4 个卷积层是相同的,核大小为 4,步长为 2,填充为 1。这使每个输入的大小加倍。于是 4x4 转 8x8,然后 16x16,32x32,最后 64x64。
结论
在本文中,我解释了全连接层和卷积层是如何计算的。我还解释了如何计算卷积和转置卷积层的输出大小。不了解这些,就无法设计自己的 CNN。
支持我👏
希望这对你有所帮助,如果你喜欢,你可以 关注我!
你也可以成为 中级会员 使用我的推荐链接,获得我所有的文章和更多:https://diegounzuetaruedas.medium.com/membership
你可能喜欢的其他文章
可微发电机网络:简介
傅立叶变换:直观的可视化
卷积神经网络冠军第 3 部分:VGGNet (TensorFlow 2.x)
原文:https://towardsdatascience.com/convolutional-neural-network-champions-part-3-vggnet-tensorflow-2-x-ddad77492d96?source=collection_archive---------56-----------------------
这是关于最流行的卷积神经网络(CNN)架构的多部分系列的第 3 部分,包含可复制的 Python 笔记本
卷积神经网络是一种特殊类型的神经网络,用于对具有强空间相关性的数据进行建模,例如图像、多元时间序列、地球科学研究(地震分类和回归)以及许多其他应用。自 1998 年以来,卷积网络经历了重大变化,在这一系列文章中,我的目标是再现著名的模型架构冠军,如 LeNet、AlexNet、ResNet 等。我的目标是与更广泛的受众分享我的发现和研究,并提供可复制的 Python 笔记本。
里卡多·弗兰茨在 Unsplash 上的照片
第一部分:tensor flow 中的 Lenet-5 和 MNIST 分类:
第二部分:ImageNet 和 Tensorflow 上的 AlexNet 分类:
本研究的 Python 笔记本位于我的 Github 页面: 链接
在本系列的前几部分中,我们回顾了 LeNet-5 和 AlexNet 型号。这些部分讨论了一些基本概念,如 conv 层、池层和激活函数。如果读者对这些概念不熟悉,我强烈建议在阅读本文之前先回顾一下。
在这篇文章中,我将讨论卷积神经网络架构的下一个主要发展,称为 VGGnet 。Simonyan 等人[2014]首先在 ILSVRC (ImageNet 大规模视觉识别挑战赛)上发表了来自牛津大学工程科学系视觉几何小组(VGG)的两个神经网络架构的结果,在这次比赛中获得了第一名和第二名。完井中输入的两个 VGGnets 具有 16 和 19 个隐藏层。VGGnet 结构与 AlexNet 结构相比没有多少优势:
- 网络深度:根据 VGG 小组的实验,深度越大,性能越好。
- 更小的滤波器尺寸:前身神经网络 ZfNet 提出,更小的滤波器尺寸可以提高 CNN 的性能。因此,VGG 用 3×3 的滤镜取代了 11×11 和 5×5 的滤镜。减小核的大小导致了参数的减少和计算复杂度的降低。
VGG 集团提出的六个模型有 11 到 19 个不同的层,最著名的 16 和 19 层模型(VGG16,VGG19)实现了卓越的性能。下图总结了这两种模型的体系结构。两个模型之间的唯一区别是在区块 3、4 和 5 中增加了三个 conv 层。他们有 1.38 亿和 1.43 亿个可训练参数,而 AlexNet 有 6200 万个可训练参数。在每个块中堆叠 conv 图层有助于模型从输入数据中提取多个高级特征。
使用 Tensorflow 的 VGG16、VGG19 模型架构
批量大小设置为 256,动量设置为 0.9。学习率最初设置为 0.01,然后当验证
设置精度停止提高时,学习率降低 10 倍。然后使用 SGD 优化器对该模型进行 74 个时期的训练。网络最初使用具有随机权重的较浅网络进行预训练。然后,使用浅预训练网络的权重来初始化每个深网络的权重(这稍后被 Glorot 初始化算法所取代)。
Tensorflow 中的列车 VGG16
下面的示例演示了如何在 Tensorflow 中对 VGG16 模型进行定型。因为训练深度学习模型的计算量很大,所以我演示了如何使用本地资源和仅 10 个 ImageNet 类来训练模型。VGG
函数在 Tensorflow 中建立模型。很容易看到该模型有三个主要组件Conv2D
、MaxPooling2D
和Dense
层堆叠在一起以实现高性能。有关在 Tensorflow 中构建模型的更多细节,请参考本系列的前两节。
在 Tensorflow 2.x 中构建 VGG 模型的代码片段
在这个例子中,我只训练了 40 个时期的模型(与 VGGnet 开发人员提到的 74 个时期相反)。模型的学习曲线可以在下图中看到。对于前 20 个时期,模型似乎在学习特征,因此损失减少,准确性增加。在第 20 个时期之后,模型过度适应训练数据,并且在验证集上的性能在将来不能被提高。这种现象可以通过 Tensorflow 中的EarlyStopping
回调函数来缓解(更多信息在此),该函数试图监控验证损失,如果损失函数没有进一步改善,则停止训练过程。
在 10 个 ImageNet 课程上培训的 VGG16 的学习率
评估结果
评估模型最简单的方法是在 Tensorflow 中使用model.evaluate
提示符。从下图可以看出,该模型在测试集上的性能为 42%。
模型损失和准确性
模型精度并没有给我们关于每个类的模型性能的详细信息。评估分类性能的最常用方法之一是使用所谓的混淆矩阵。混淆矩阵是一个简单的计数矩阵,它展示了每个标签的实例是如何分类的。该矩阵的对角线代表正确分类的实例,而非对角线的实例表明错误分类。
下图演示了 VGG16 10 类的混淆矩阵示例。每个类包含 50 幅图像。可以看出,经过训练的模型在两个类别上具有良好的准确性,而在另外两个类别上具有非常低的准确性。模型精度是正确预测的样本占样本总数的比例。
10 类模型的混淆矩阵
VGG16 -10 级模型精度
从下面的图片可以看出,准确率最低的两个类属于两种不同类型的猴子。两个猴子类的误差最高。分类错误率高的其他类别是桶和篮子。值得注意的是,与原始的 VGGnet 在 1000 个类上训练相比,该模型只看到了 10 个类,因此我们训练的模型的准确性要低得多。
错误分类的图像示例(在 ImageNet 2014 之后修改)
超越 VGGnet
VGG 模型在研究界非常受欢迎,因为它的方法简单,而且预先训练的权重可以在网上免费获得,便于在新任务中对这个强大的模型进行微调。VGG 展示了简单和准确。然而,VGG 模式有几个缺点:
- 训练很慢。模型培训在配备了四个 NVIDIA Titan 黑色 GPU 的系统上进行,为期 2-3 周
- VGG 模型拥有超过 1.36 亿个参数,是最大的 CNN 模型架构之一。因此,VGG-16 训练的 imageNet 权重大小的模型是 528 MB。因此,它需要相当多的磁盘空间和带宽,使其效率低下。
- VGGnet 模型的内存使用率在模型开发期间非常高。VGG16 需要至少 1gb 的内存,更多信息[ 链接。
VGG 在 ImagNet 数据集上展示了良好的精度性能,但是,所有上述限制导致了不同模型结构的发明,如 ResNet,这将在本系列的下一部分中讨论。
感谢阅读!我叫 阿米尔·内贾德,博士。 我是一名数据科学家,也是QuantJam的编辑,我喜欢分享我的想法,并与其他数据科学家合作。可以在GithubTwitter和LinkedIn上和我联系。****
你可以在以下网址看到我的其他作品:
**http://amirnejad.medium.com/ **
参考
- 西蒙扬,凯伦和安德鲁·齐泽曼。“用于大规模图像识别的非常深的卷积网络。”arXiv 预印本 arXiv:1409.1556 (2014)。
- Russakovsky,Olga 等人“Imagenet 大规模视觉识别挑战。”国际计算机视觉杂志 115.3(2015):211–252。
- 卷积神经网络硬件加速器的内存需求。2018 IEEE 工作负载表征国际研讨会(IISWC)。IEEE,2018。
所有图片均由作者制作,除非另有说明。
卷积神经网络:对层的良好理解和图像分类示例
原文:https://towardsdatascience.com/convolutional-neural-network-good-understanding-of-the-layers-and-an-image-classification-example-a280bc02c13e?source=collection_archive---------12-----------------------
艾莉娜·格鲁布尼亚克在 Unsplash 上的照片
包含了大量的信息
卷积神经网络(CNN)是一种多层神经网络,已知能够检测模式和复杂特征。它在人脸检测、自动驾驶汽车和许多非常复杂的任务中非常有用。在本文中,我将向您介绍卷积神经网络是如何工作的。
本文将涵盖:
- 卷积层如何在正向过程中工作。
- 池层如何工作。
- 用于图像分类项目的卷积神经网络的完整模型结构。
- 模型总结分析。
- 训练模型并显示结果。
CNN 是如何运作的?
CNN 可以用于很多不同的领域,但是在这篇文章中,我们将讨论图像分类的例子。图像数据可以表示为数字像素值。然后这些数值被传入 CNN 进行处理。普通的神经网络也能够检测图像,但 CNN 在准确性和速度方面更有效。
卷积层
卷积层是 CNN 中非常重要的层,因为这是它成为卷积神经网络的原因。在这一层中,使用过滤器或内核来检测重要的特征。目的是使数据集更小,并且只将重要的要素发送到下一个图层。这样节省了密集层的大量计算,也保证了较高的精度。让我们来看一张图。
作者图片
上图是深度 3 的输入数据,一个深度和偏置项相同的核。
这个内核如何过滤输入数据?
接下来的几张图片将一步步展示这一点。
作者图片
计算是这样进行的:
作者图片
让我们把剩下的三个输出填满。下面是如何移动过滤器或内核来计算 y12。
作者图片
我没有展示计算部分。这是相同的项目-明智的乘法,然后求和,如前所示。下图显示了 y21 的内核位置和偏差:
作者图片
最后,y22 计算的内核和偏差:
作者图片
在上图中,只使用了一个内核。但是在真实模型中,可以使用几个内核。在这种情况下,相同大小的输出会更多。我在这里使用的填充类型称为“有效”。这意味着我实际上没有使用任何填充。还有另外两种主要类型,称为“全”和“相同”。我不打算在本文中讨论这些。但是在练习部分,我会用‘有效’。在 high label 思想中,填充“相同”意味着在输入数据的所有边上添加一个零层,然后在其上使用内核。
汇集层
汇集层减少了数据的维数,并且还检测特征,而不管特征在图像中的位置如何。下面是一个 MaxPooling2D 如何工作的例子。
作者图片
上图展示了 MaxPooling 的工作原理。紫色方框的最大值是 15,所以只需要 15。绿框最多 19 个,所以只剩 19 个了。另外两个盒子也是如此。还有其他类型的池,如平均池或最小池。这个名字表明了它们是如何工作的。在平均池中,我们取每个盒子的平均值,在最小池中,我们取每个盒子的最小值。
这些是理解本文练习的重要思想。
卷积神经网络练习
在这个练习中,我将使用 TensorFlow 库自带的免费“cifar”数据集。该数据集包括对象图像的像素值,标签包括数字。每个对象由一个数字表示。我们将首先训练网络,并使用测试数据集检查准确性。数据集已经由训练集和测试集分隔。我正在加载数据:
import tensorflow as tf
(X_train, y_train), (X_test, y_test) = tf.keras.datasets.cifar10.load_data()
数据集包含以下类:
'airplane', 'automobile', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck'
每一类都用一个数字来表示。
如果打印 y_train 数据,它看起来像这样:
从训练集中检查一个图像:
import matplotlib.pyplot as plt
image=X_train[3]
plt.imshow(image)
plt.show()
输出:
作者图片
缩放输入数据总是好的。因为我们有像素值,我会把它们除以 255。
X_train = X_train/255
X_test = X_test/255
让我们检查一下训练输入的形状:
X_train.shape
输出:
(50000, 32, 32, 3)
从这个形状我们知道什么?
我们有 50000 个训练数据。输入大小为 32x32,深度为 3。这意味着图像是彩色图像。我们有 RGB 值。
CNN 结构
对于这个项目,我将使用 3x3 的内核大小,我将在第一个卷积层使用 32 个输出窗口。下面是它的样子:
作者图片
在之前的演示中,为了简单起见,我只解释了一个内核。但是您可以根据需要使用任意数量的内核。在这个练习中,我将使用 32 个内核。
为了澄清,上图显示的是 3x3 和深度 3 的输入数据。我们的数据也有三个深度,正如您从 X-train 形状中看到的。但是尺寸是 32x32 而不是这张图所示的 3x3。
图中所有的内核都是 2x2。但是我会用 3x3 内核。你可以试试其他尺寸的。事实上,核不一定是正方形的。它们可以是 4x2 或任何其他矩形形状。
但是内核肯定不能比输入形状大。在此示例中,输入形状为 32x32。所以,内核不能比这个大。
此外,当我们使用一个内核时,我们有一个输出窗口。因为我在这里使用了 32 个内核,所以我将有 32 个输出窗口。
卷积层之后,会有一个 MaxPooling 层。我用了一个 2x2 的过滤器。此外,步幅为 2 意味着将有 2 个步骤。可以尝试不同的步幅。
我将有另外两个卷积和最大池层。然后会有一个'扁平化'层。它确实如其名。它会将三维数据展平为一维列。因为之后我们会把这个一维数据传到致密层。我假设你知道常规神经网络。密集层采用一维数据。对于这个项目,将有三个密集层。最终,输出层。
输出层将使用“softmax”激活。所有其他层将使用“relu”激活功能。
模型如下:
model = tf.keras.Sequential([
tf.keras.layers.Conv2D(32, (3, 3), padding="valid",
activation="relu", input_shape=(32, 32, 3)),
tf.keras.layers.MaxPooling2D((2, 2), strides=2),
tf.keras.layers.Conv2D(48, (3, 3), padding="valid", activation="relu"),
tf.keras.layers.MaxPooling2D((2, 2), strides=2),
tf.keras.layers.Conv2D(48, (3, 3), padding="valid", activation="relu"),
tf.keras.layers.MaxPooling2D((2, 2), strides=2),
tf.keras.layers.Flatten(),
tf.keras.layers.Dense(100, activation="relu"),
tf.keras.layers.Dense(100, activation="relu"),
tf.keras.layers.Dense(100, activation="relu"),
tf.keras.layers.Dense(10, activation="softmax")]
)
以下是该模型的总结:
model.summary()
输出:
Model: "sequential_25"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
conv2d_81 (Conv2D) (None, 30, 30, 32) 896
_________________________________________________________________
max_pooling2d_79 (MaxPooling (None, 15, 15, 32) 0
_________________________________________________________________
conv2d_82 (Conv2D) (None, 13, 13, 48) 13872
_________________________________________________________________
max_pooling2d_80 (MaxPooling (None, 6, 6, 48) 0
_________________________________________________________________
conv2d_83 (Conv2D) (None, 4, 4, 48) 20784
_________________________________________________________________
max_pooling2d_81 (MaxPooling (None, 2, 2, 48) 0
_________________________________________________________________
flatten_27 (Flatten) (None, 192) 0
_________________________________________________________________
dense_98 (Dense) (None, 100) 19300
_________________________________________________________________
dense_99 (Dense) (None, 100) 10100
_________________________________________________________________
dense_100 (Dense) (None, 100) 10100
_________________________________________________________________
dense_101 (Dense) (None, 10) 1010
=================================================================
Total params: 76,062
Trainable params: 76,062
Non-trainable params: 0
_________________________________________________________________
让我们试着理解这个总结。为了便于理解,我将讨论一个卷积层和一个 MaxPooling 层。第一个卷积层输出后的形状是(无,30,30,32)。
让我们来理解一下 30,30 和 32。这里最后一个元素是 32。这很容易理解。因为我们使用了 32 个内核,所以预期有 32 个输出窗口。
这是什么 30,30?因为我们使用了“有效”的填充,所以输出形状应该是:
输入大小—内核大小+ 1
这里输入大小为 32,内核大小为 3,因此,
32–3+1 = 30
此公式仅用于“有效”的填充。如果你使用“相同”或“完整”的填充,公式是不同的。
下一个元素是 MaxPooling 层。第一个 MaxPooling 层的输出形状是(无,15,15,32)。如前所述,32 来自 32 个内核。因为我们在 MaxPooling 层中使用了 2x2 过滤器,所以数据在两边都变成了一半。所以,卷积层的 30,30 变成了 15,15。
在我开始训练模特之前。我想用一个提前停止的条件。
什么是提前停止?
假设,我将我的模型训练设置为 100 个时期,但是我的模型不需要 100 个时期。可能它在 50 个纪元后收敛。在这种情况下,如果我让它运行 100 个纪元,就会导致过度拟合。我们可以用我们选择的耐心值来设置提前停止条件。我将在这里使用耐心值 5。这意味着,如果模型损失在 5 个时期内没有足够的变化,则模型将停止训练,即使它仅运行 30 个时期或 50 个时期。
from tensorflow.keras.callbacks import EarlyStopping
callbacks=[EarlyStopping(patience=5)]
训练模型
首先,我们需要编译,然后开始训练:
model.compile(optimizer="adam",
loss=tf.keras.losses.SparseCategoricalCrossentropy(),
metrics=['accuracy'])
history = model.fit(X_train, y_train, epochs = 50,
validation_data=(X_test, y_test), callbacks=callbacks)
我设定了 50 个纪元的模型。但是它在 17 个周期后停止,因为提前停止条件节省了大量时间。
以下是结果摘要:
met_df1 = pd.DataFrame(history.history)
met_df1
输出:
作者图片
这是每个历元的训练准确度和验证准确度的曲线图:
met_df1[["accuracy", "val_accuracy"]].plot()
plt.xlabel("Epochs")
plt.ylabel("Accuracy")
plt.title("Accuracies per Epoch")
plt.show()
作者图片
从上面的图中可以看出,训练精度一直在上升,但验证精度在几个时期后几乎稳定下来。
模型改进
在这篇文章解释的思想范围内,你可以尝试很多事情。如果你想尝试一下,这里有一些想法给你:
- 改变内核形状。您可以尝试 2x2、4x4、2x4、3x2 或您选择的任何其他形状。
- 请随意尝试使用“相同”或“完整”作为填充值,而不是“有效”。
- 更改内核数量,并使用不同的数字,如 48、64、56 或任何其他数字,而不是 32、48 和 48。
- 添加或移除卷积层。
- 尝试用平均池代替最大池。
- 添加或删除密集层,并改变神经元的数量。
- 尝试其他激活功能,如 tanh、elu 或 leakyRelu。
我敢肯定,如果你足够努力,你可能会得到比我在这里显示的结果更好的验证准确性。
结论
我试图让卷积神经网络的想法,它如何在幕后工作。尽管如果你不得不从头开始实现它,会涉及到更多的数学问题。尤其是参数更新。但幸运的是我们有张量流。这为我们更新了参数,我们不需要对所有的元素做偏导数。请随意尝试我上面建议的一些不同的模型架构,如果你觉得有趣,请分享你的发现!
欢迎随时关注我的推特(Twitter)和我的新 T2 YouTube 频道(T3)。
更多阅读
https://pub.towardsai.net/text-data-visualization-with-wordcloud-of-any-shape-in-python-8cec334e5c4f
平面场景的坐标
原文:https://towardsdatascience.com/coordinates-of-a-flat-scene-b37487df63ca?source=collection_archive---------18-----------------------
从像素转换到毫米,反之亦然
你有没有想过生活在平原会是什么样子?我不知道你怎么想,但是我不想把宇宙降级到二维。我对 3D 空间提供的可能性感到满意,比如在我的鞋带上打结和其他拓扑满足感。
当编码自动化检查时,通常不得不冒险进入平原。例如,您可以考虑一个检测系统,其中零件在传送带上移动,摄像机从顶部捕捉图像。在这个场景中,感兴趣的对象被限制在传送带平面上,因此场景本质上是二维的。另一个例子是待检查的物体具有平坦表面的情况。可能希望在图像中定位这些表面,以检查缺陷的存在或验证某些特征是否存在。
在由单个相机拍摄的 3D 场景的一般情况下,场景中的点的 3D 坐标和图像中的 2D 坐标之间没有一对一的关系。多个 3D 点将被投影到给定的图像点。你可以通过想象你正在通过一系列多个透明的窗口拍照来想象这一点。如果每个窗户上都有一只苍蝇,而且每只苍蝇都对准相机的焦点,那么你只能看到一只苍蝇。最近的一个会遮挡其他的,因为苍蝇占据的所有 3D 点都被投影到同一个像素。换句话说,场景中的 3D 坐标和图像中的 2D 坐标之间存在多对一的关系。
图片由 Fl á 维奥康卡发自 Unsplash
在单个平面中具有有趣特征的情况下,情况是不同的。您可以记下感兴趣的平面(位于 3D 世界中)和图像平面(坐标以像素为单位)之间的线性关系。在这种特殊情况下,感兴趣平面上的点的 2D 坐标(去掉 Z 坐标,我们将它任意设置为 0)和图像中的 2D 坐标之间存在一一对应关系:这是一个单应。让我们考虑相机图像平面和 3D 场景中感兴趣的平面之间的映射。
图片来自 Unsplash
一个同性恋?听起来很棒。现在,如何计算呢?
关键是在平面上具有已知坐标(通常以毫米为单位)的点与它们在图像中的坐标(以像素为单位)之间有对应关系。我们知道,用一个型号的针丨孔丨摄像机,这些对应点以线性关系联系在一起。
T 是从像素到毫米的 3x3 变换矩阵。(X,Y)是约束到感兴趣平面的点的 2D 坐标(参考轴在该平面内),而(X,Y)是其对应的像素坐标。
为什么我们要添加第三个总是设置为 1 的虚拟坐标呢?
该变换是缩放、剪切、旋转和平移的组合。这些操作可以用 2×2 矩阵和一个附加的 2×1 矢量来表示。通过引入虚拟第三坐标(即齐次表示),我们可以用一个 3×3 矩阵封装复合转换。
这是一个紧凑的问题。
我们的目标将是计算变换矩阵 T ,,这将允许我们从图像中的相应坐标获得场景中点的坐标。让我们显式地写出转换方程,对于给定的对应关系( X ᵢ ,Y ᵢ ,x ᵢ ,y ᵢ):
将方程重组为 Az = b 的形式后,其中 z 包含我们的未知数{t₀₀,… t₁₂}:
我们看到,每封信都为我们提供了两个 6 个未知数的线性方程。为了解这个线性方程组,我们需要至少三个对应,以得到最少 6 个线性独立的方程。在实践中,我们将尝试获得三个以上的对应,并用最小二乘法求解超定系统。
下面的代码和图片可以在这个 github 库中找到。
图像checkerboard.png显示的是一个平面。X 和 Y 轴用蓝线标注。
作者 checkerboard.png
对物理对象的测量允许我们将 2D 坐标(以毫米为单位)与其对应的坐标(以像素为单位)进行映射。
将(798,67)手动识别为真实世界坐标(214.2 毫米,178.5 毫米)的对应关系
有了四个这样的对应(彼此尽可能远),超定方程组可以用 numpy 函数numpy . linalg . lstsq()来求解
有了{t₀₀,… t₁₂}矩阵条目(在上面的代码片段中用向量 z 表示),我们就有了我们的变换矩阵 T 。有了它,我们可以得到一个点的毫米坐标,我们有像素坐标。例如,将像素坐标(399,500)与 T:
预测值(72.3 毫米,74.8 毫米)与测量坐标(71.4 毫米,71.5 毫米)的误差在 4 毫米以内。4 mm)。相反,通过反转 T,我们可以得到一个点的像素坐标,我们有毫米坐标。例如,点(107.1 毫米,107.1 毫米)位于原点右侧三个方格处。
逆变换预测其舍入后的像素坐标应为(496,370):
绿色十字表示预测位置(107.1 毫米,107.1 毫米)。它落在离实际位置几毫米的地方(向右三格,原点向上三格)
正如我们所见,预测很接近,但不准确。这可能是因为我们假设了一个简单的针丨孔丨摄像机模型。为了超越针丨孔丨照相机模型,我们的成像系统的校准将需要考虑任何非线性失真。
我们已经介绍了构建变换矩阵的步骤,当我们处理平面场景时,变换矩阵给出了像素坐标和毫米坐标之间的线性关系。这是一项基本的计算机视觉操作,需要在自动化检测中经常执行。在实践中,待检查的零件可能具有一些易于定位的基准标记或独特特征。平面上特征的已知 2D 位置(以毫米为单位)及其检测到的图像位置(以像素为单位)将构成一组对应关系,用于计算变换矩阵 T 。然后,已知真实世界坐标的平面上的任何物体都可以在图像中定位,即使这个物体很难检测到,甚至不存在。
请随意试验代码,并且让我知道您认为
可能适用的用例。
假设感兴趣的平面不通过照相机的焦点
针丨孔丨相机模型忽略了镜头失真和失焦模糊。它是真实相机的一阶近似。
冠状病毒相关性
原文:https://towardsdatascience.com/coronavirus-correlations-5f49e5bb9710?source=collection_archive---------30-----------------------
探索新冠肺炎国家死亡率与各种社会经济指标之间的相关性。
冠状病毒(新冠肺炎)扰乱了现代世界,这在近代史上是前所未有的。这种病毒的影响只能与二十世纪世界大战造成的破坏相提并论。这种感染已经肆虐地球一年多了,但是关于这种疾病的起源、传播和严重性的许多问题仍然没有答案。持续激烈辩论的一个关键问题是“为什么病毒对一些国家的影响比其他国家更大?”。这篇文章的目的是用数据来说明答案可能非常复杂和令人费解。
下图显示了受疫情影响最严重的 20 个国家。在 x 轴上,我们绘制了一个国家的“每 10 万人口累计死亡人数”(CDP)。这一数字已相对于人口进行了标准化,并取自世界卫生组织(世卫组织)的官方网站,用于冠状病毒更新[1]。CDP 的全球平均值为 30.79。然而,从下文可以清楚地看出,许多国家的情况比这糟糕得多。令人惊讶的事实是,这些受影响严重的国家大多来自拥有良好卫生保健设施的高收入国家,如比利时(第 4 位)、英国(第 5 位)和美国(第 10 位)。即使在这些国家中,趋势也不一致。英国、意大利、西班牙和法国的 CDP 分别为 1651、1505、1300 和 1200,而邻国德国的 CDP 为 734,几乎低了一半。
作者图片
为了进一步分析,使用 python 的WB DataAPI[2,3],从世界银行的开放数据存储库中提取了关于各种社会经济指标的数据。目的是找出 CDP 和这些指标之间的相关系数。我们在这项研究中同时使用了 Spearman 和 Pearson 系数,因为数据中有异常值,并且不能假定变量和 CDP 之间存在线性关系。一般来说,皮尔逊系数(P)略低于斯皮尔曼系数(S)。让我们先来看看 2019 年一个国家的 CDP 与其使用购买力平价(GDPP)的人均 GDP 的相关性[4]。下面的散点图显示了两个变量之间的关系。CDP 与 GDPP 呈正相关(S=0.54,P=0.36)。与直觉相反的是,数据显示,与较贫穷国家相比,较富裕国家的人均新冠肺炎死亡率更高。
作者图片
世界银行的“营商便利度”(EDB)排名是一个相对较新的综合指标,它考虑了一个国家的各种经济因素。在 EDB,高职位代表着一个运转良好的监管和法律体系,拥有高效的公共官僚机构[5]。该指数排名最高的国家是发达的高收入国家,如新西兰(第 1)、新加坡(第 2)、美国(第 6)和英国(第 8)等。同样矛盾的是,EDB 的国家排名与 CDP 显著负相关(S=-0.45 和 P=-0.44)。EDB 排名靠前的国家在新冠肺炎相关死亡人数方面表现更差。这里需要强调的是,这些相关性并不表明新冠肺炎相关死亡与国家财富之间存在因果关系。但数据分析确实提出了一些附带问题,即来自中低收入国家的新冠肺炎报告数据的可靠性问题。这也暗示了可能影响感染严重程度的更深层的社会经济因素的存在。
一个非常重要的因素是人口统计学和新冠肺炎相关死亡之间的联系。研究已经表明,这种病毒对老年人更加危险。一个国家的预期寿命与 CDP 的相关性相当高且显著(S=0.57,P=0.50)[6]。下图显示了这种关系。CDP 与人口增长的相关性也很高且为负(S=-0.52,P=-0.48)[7]。人口增长率较高的县比人口增长率较低的国家要好得多。较高的城市人口占总人口的百分比也与 CDP 有很强的正相关性,表明生活在城市的人受到疾病的不利影响更大(S=0.48,P=0.40)[8]。该数据表明,新冠肺炎相关死亡与人口统计学之间有很强的联系,这方面应该是严格研究的主题。
作者图片
总之,我们试图强调一些与新冠肺炎人口标准化死亡率统计相关的社会经济指标。人口统计学就是这样一个重要因素。还有一些违反直觉的观察结果,对中低收入国家报告的新冠肺炎数据的准确性提出了质疑,需要进行调查。在此必须指出,这一分析绝非详尽无遗。在未来的研究中,肯定还有其他指标需要考虑,事实上,这些数据确实支持这些隐藏变量的存在。数据是用来分析的,愿力量与数据探索者同在!
注:使用了社会经济指标的最新数据,有些指标的数据是几年前的。
此分析的代码可在以下网址公开使用:
https://github . com/janjuatest/Public-Sector/blob/main/corona . ipynb
参考文献和脚注:
- https://covid19.who.int/table
世卫组织冠状病毒病(新冠肺炎)仪表板,数据检索于 2021 年 2 月 8 日。 - 世界银行公开数据,
https://data.worldbank.org/ - 世界银行数据 Api,
https://Data help desk . world Bank . org/knowledge base/topics/125589 - 世界银行按购买力平价计算的人均国内生产总值指标 ID 为 NY。GDP.PCAP.PP.CD
这种相关性是用 168 个国家的数据计算出来的。 - https://www.doingbusiness.org/en/rankings
世界银行 EDB 指标 ID 为 IC。这种相关性是用 174 个国家的数据计算出来的。 - 世界银行关于一个国家预期寿命的指标 ID 是 SP。在
中,相关性是用 181 个国家的数据计算出来的。 - 世界银行指标 ID 人口增长率为 SP。这种相关性是根据 186 个国家的数据计算出来的。
- 世界银行城市人口占总人口百分比的指标 ID 为 SP。这种相关性是根据 185 个国家的数据计算出来的。
企业需求和人工智能的未来,第一部分
原文:https://towardsdatascience.com/corporate-imperatives-and-the-future-of-ai-development-part-i-773f5a1a352b?source=collection_archive---------15-----------------------
思想和理论
经济意识形态有没有拉拢 AI 研发?
企业追求股东价值最大化是在慢慢破坏人的价值吗?照片由雷扎·哈桑尼亚在 Unsplash 上拍摄
新冠肺炎·疫情标志着人类与数字技术关系的一个转折点。在线合作、远程学习和远程工作成为新的常态。我们现在每天的平均屏幕时间可能比以往任何时候都长。包括传感器、设备和应用在内的新技术的巨大网络,加上 5G 、物联网 (IOT)、边缘计算和 AI/ML 的进步,为自动化数据收集和影响用户行为以实现公共政策和企业目标提供了新的可能性。在这里,我考虑基于强化学习(RL)的技术,因为它在商业上应用于个人和社会。
为什么关注 RL?根据 deep mind 的大卫·西尔弗 T19 和理查德·萨顿最近的一篇论文 T17,人工智能很可能是我们实现人工智能的最佳机会。当然,Deepmind 是谷歌母公司 Alphabet Inc .的一部分。
这篇文章探讨了以下问题:
- 公司对股东价值最大化的追求,加上新自由主义经济思想,是否正在将人工智能的研究、开发和应用推向潜在的病态方向?
- 我们应该相信市场驱动的“私人利益”人工智能研究和开发将符合透明、公正、公平、责任、问责、信任、尊严、可持续和团结的以人为本的价值观吗?
强化(学习)简介
今天,由行为主义心理学家给出的对强化的最初定性描述可以——并且越来越多地——以数字方式实现,并以公司利润最大化为目标。这些数字干预对他们的目标——使用数字系统并与之互动的个人——来说是有效的隐形。在我们的个人设备和应用程序上,我们孤立无援地在 信息圈 中导航,不知道我的谷歌是如何或者为什么以这种方式“个性化”而你的是那种方式。然而,数据平台可以看到、知道并分析所有信息。这个平台在数字上无所不知,几乎无所不能,但显然不是仁慈的。
最初作为强化的语言学描述,被称为桑代克的 效应定律已经逐渐演变成一种精确的算法。“定律”指出,过去导致积极奖励的行为在未来更有可能重复,而导致消极奖励(惩罚)的行为则不太可能重复。至关重要的是,这种想法现在可以由计算机来实现,以自动学习在大规模上操纵人类个体和集体的行为。最近的一篇论文为 RL 在人类身上的“对抗性”使用提供了关键的经验证据。
RL 是一种看似简单的形式主义。它的算法通过提供一种算法机制,允许理想化的代理根据过去的经验,使其行为最佳地适应其环境,从而使效果法则变得清晰。然而,RL 算法的理论和实践性质是复杂的。计算机科学、统计学、经济学和认知科学等不同的领域都有大量的相关文献。但直到现在,这些科学见解才渗透到面向消费者的技术中。
把 RL 看成是解决问题的通用方法。它通过学习感知刺激(状态)和行动之间的工具关联来工作,以便最大化算法设计者确定的一些积极回报。一个基本的交互序列看起来是这样的:代理观察环境的状态,选择一个动作,环境转换到一个新的状态。代理人的目标是找出哪种状态下的哪种动作序列导致最大的累积奖励。与监督学习范式,不同的是,智能体只通过奖励信号接收关于其在给定状态下行动质量的“评估性”反馈——没有“基本事实”告诉它什么是“正确的”行动。
RL 不仅仅是动物学习中一个有趣的话题。RL 已成功应用于机器人、临床决策和个性化医疗、能源网格优化和“及时”行为干预中的问题。RL 是一种优化控制任何复杂系统的手段,包括由数百万用户组成的数字平台。任何你可以想象为决策序列的东西都可以用 RL 形式来建模。
RL 也可以说是我们关于动物如何通过试错来学习复杂行为的最佳理论。例如,在计算神经科学中,RL 模型的参数可以非常精确地拟合实验收集的人类(和猴子)行为数据,这表明我们大脑的某些区域实现了类似 RL 算法的东西。事实上,腹侧被盖区(VTA)的多巴胺神经元的阶段性活动被认为编码了奖励预测误差(对应于对事件的惊讶,并随后驱动各种对我们环境变化的注意机制)。奖励预测误差的概念也用于基于时间差异学习 g 更新 RL 中的状态值估计,从而将 AI 与神经科学联系起来。
基于 RL 的个性化的经济含义
如果我们的大脑真的实现了 RL 算法,那么当我们在社交媒体平台上与基于 RL 的系统交互时,我们就参与了类似多代理 RL 的场景。但是我们的利益一致吗?我们是在合作,还是陷入彼此的冲突?
如果我们处于冲突中,对个人的长期认知影响以及对社会的政治和社会影响是什么?肖珊娜·祖博夫、卡伦·杨和米蕾尤·希尔德布兰特和其他学者关心的是,通过几十年的动物学习、反馈控制、人工智能/人工智能和计算神经科学研究获得的知识如何部署在社交媒体平台上。他们的工作表明,经济需求如何使科学知识的应用偏向于以牺牲人类长期福祉为代价来产生短期、直接利润的技术。
但是,对预测复杂系统(特别是经济和自然生态系统)行为失败的仔细历史考察应该提醒我们谦逊认知的重要性。控制可能是理解复杂自然现象的必要条件,但不是充分条件。气候变化和金融危机,有人知道吗?
下面是一个非常简单的示意图,说明反馈控制的基本过程如何通过社交媒体平台上的个性化推荐系统来实现。
平台更好和更多的数据行为收集意味着对“系统状态”更精确的测量,这是在平台上交互的人类用户的集合。对未来状态的更好的预测使得更容易引导、推动或“控制”系统朝着期望的方向发展。基于强化学习的推荐系统在旨在实现公司目标的平台上充当用户“环境”的自适应控制器。来源:作者。
行为主义、科学和深度神经网络
行为主义者是第一个看到概率、统计和强化之间联系的人,尽管他们依赖一种避开大样本和统计推断的古怪方法。然而,随着 Herrnstein 的 匹配定律 的发现,行为主义者意识到,通过对最初随机试错行为的适当强化,动物可以学会“匹配”它们环境中的统计规律。也就是说,动物(和人类)似乎会自然地调整行为频率,以接近环境的潜在回报统计。
通过在正确的时间以正确的方式进行干预,动物的行为可以被逐渐塑造或控制,以解决任意的任务,例如鸽子通过奖励塑造学习堆叠木块以达到食物分配杆。这表明,当我们行为时,无论我们的大脑做什么,它们都会实现类似 RL 算法的东西。
行为主义基于一种以工程为中心的科学哲学,这种哲学起源于奥地利物理学家恩斯特·马赫,后来被物理学家 T2·珀西·布里奇曼改编,最后由 T4 的 BF·斯金纳普及。马赫认为,科学应该致力于压缩知识,而不是不必要地扩大其理论词汇——除非这样做可以解释更广泛的经验观察到的现象。一种严格的科学方法理想地去除了所有的噪音和冗余,只保留信号,然后将信号传达给未来的科学家,以进一步压缩和理解,直到可能找到万物的统一理论。
马赫有影响力的观点结合了进化论和信息论的一些方面来解释科学知识的积累和压缩。他的思想后来也影响了科学的实证主义哲学,这种哲学消除了对不可观察的原因的谈论以及其他源自康德和黑格尔哲学的“形而上学的、先验的晦涩难懂的东西”。行为主义要求将 意向性 的精神术语替换为 由实验者定义的操作性定义的行为。例如,在 1938 年的一篇论文中,爱德华·托尔曼将老鼠在迷宫中的“来回张望”等同于“意识的行为主义定义”。不可观察的精神状态,如关于的“信念”、“欲望”或“意图”,或代表生物体环境的特征的,现在在理论上是禁区。**
但是行为主义并不完全错误。虽然今天经常受到批评,行为主义的见解已经渗透到各个领域。它的主要罪过在于它急于将人类经历的所有降低到无意识的僵尸般行为的水平,而事实上,我们的行为中只有是由这些次个人的、目标导向的过程驱动的。人文主义者不喜欢这种不公正地贬低自我意识在人类思考中的作用,并把人类的自主性、自由意志和道德责任归结为一系列环境互动,这些互动可能受到并不总是仁慈的社会工程师的控制和塑造。**
控制平台用户的强化计划
行为主义与深度学习的进步相结合,标志着一个基于平台的观察、预测和控制用户的新时代。JB Watson、Skinner、Egon Brunswik、Edward Tolman 和其他人的行为主义守卫者依赖于发射行为的共时定义。他们只关心是否有老鼠或鸽子在某个时间点按下了控制杆。老鼠用左臂还是右臂并不重要。就操作定义而言,这两项行动是相同的。要了解行为主义对当今个性化研究的影响,只需将“杠杆按压”替换为“点击”同样的想法也适用。
剥皮器盒子。来源:维基百科。
早期的行为主义者缺乏技术来分析导致特定杠杆按压的行为(状态)的复杂时间序列。纸笔根本效率不高。BF 斯金纳将开发斯金纳盒子来处理这个问题。这个设备实际上实现了一个特定的强化计划,它是描述在操作性条件反射中某些目标行为如何被奖励或惩罚的规则。通常使用固定或可变的时间间隔或试验比率。
在 1958 年发表在美国心理学家杂志上的一篇文章中,斯金纳描述了强化时间表是如何被一个用物理术语描述的“程序系统”执行的。我用加粗的关键词和短语来说明与 RL 的联系,因为它可能会被一个旨在加强有利于其业务目标的用户行为的社交媒体平台所应用。
由一个 编程系统 安排一个加固进度,该进度可以用物理术语来指定。在钥匙和弹匣之间的电路中引入一个时钟,以便在给定的时间间隔后对钥匙的第一个响应将是 加强 。在电路中引入一个计数器,根据每个强化发出的响应数量来建立一个偶然性。
由于精心安排的结果,鸽子、老鼠和猴子在过去的五年里做了它们物种成员从未做过的事情。这并不是说他们的祖先没有这种行为的能力; 大自然从来就没有安排过有效的序列表 。
…从强化研究中涌现出来的新的原理和分析方法可能被证明是二十世纪最有成效的社会工具之一。
强化学习的创新
斯金纳的原始“编程系统”今天已经演变成以商业为中心的 RL。RL 的商业价值源于它能够无形地自动干预数字空间,从而推广昂贵的 A/B 测试。事实上,RL 技术的进步越来越吸引企业和政府对实现财务和公共政策目标的兴趣(例如,自动化和个性化的“轻推”)。
然而令人担忧的是,现在基于递归神经网络 (RNNs)(包括lstm和更新的基于注意力的变压器)的深度神经网络(DNN)架构,可以以自我监督的方式发现和编码这些复杂的行为交互序列,如 RL 形式中的状态。DNNs 允许我们应用黑盒函数逼近器来自动生成状态表示,以调节 RL 代理的动作。DNNs 可以处理非线性用户-项目关系和未标记的非结构化数据,如图像、文本和交互序列,极大地扩展了个人数据收集的可能性。**
这些新技术进一步允许我们放松 RL 中使用的传统马尔可夫决策过程的严格“马尔可夫”假设。这些漫长而复杂的行为序列中的规律可以被自动而有效地发现——几乎不需要人类理解——平台可以通过正确选择旨在实现奖励的行动来指导或塑造它们。从平台的角度来看,控制就是在给定用户处于特定状态(以 RNN 为代表)的情况下,选择一个最优的行动,以获得最大的累积奖励。
效用和平台经济学
平台数据科学家假设“停留时间”和“点击率”等行为指标允许他们窥视平台用户的内心世界。数百万美元花费在数据科学研究上,专注于以业务为中心的“参与度”指标,这些指标来自大杂烩式的营销理论(将可观察到的行为等同于“客户满意度”的表达)和规范经济理论,如 揭示对各种事务状态或对象的偏好 ,按其对用户的效用排序。
现代数据科学家保留了行为主义的大部分方法,同时更新了他们的理论词汇,以包括不可观察的潜在心理状态。但这样做的原因是务实的,而不是认识论的。定位不可观察的潜在偏好允许更好、更准确地预测用户行为,并且似乎口头上尊重消费者作为一个独特的思维、感觉和自我意识的人,其主观体验不同于海鞘。然而,在实践中,同样的效用理论形式适用于海鞘和人类平台用户。
正如哲学家如阿玛蒂亚·森、伊莉莎白·安德森和查尔斯·泰勒很久以前指出的,效用是经济学的一元通用货币。所有有价值的问题都归结为效用。它现在在数据科学中也是一个上升的概念,尽管它受到严重的理论和哲学问题的困扰。然而,总的来说,工程师和数据科学家似乎乐于依赖效用的概念。想想有多少https://www.dssgfellowship.org/有益于社会的数据科学计划是围绕着 社会福利最大化 的功利主义观念制定的。
效用至少融合了价值这个词的三种含义:经济价值、道德价值和数字价值。很容易看出这一举措对算法驱动的数字平台的吸引力。道德价值是模糊的东西,不容易理解,而且经常引起争议。将道德价值简化为一个也可以用金钱来表达的数字,使得决策变得简单,更重要的是,在计算上更容易处理。它允许对科学计算进行自然主义的伦理学还原。例如,如果道德价值可以归结为快乐(即“兴趣”),快乐可以归结为行为现象(即停留时间),行为现象可以归结为神经元活动,那么关于“不可通约的价值”或“商品的多样性”的问题可以礼貌地回避。
数据科学中使用的效用理论的规范方面尤其危险,因为它夹杂了各种关于人性和认知的不合理假设。显示偏好理论建立在理性选择理论的基础上:观察到的行为被认为是理想化合理化过程的结果,其中效用和概率以最佳方式结合,如贝叶斯法则所述。
如果揭示的偏好被规范地看待——作为具有完全信息、无限时间和计算资源的理想化贝叶斯代理的结果——那么我们也为消费者主权的意识形态找到了正当理由。当消费者的选择是可证明的最佳数学程序的输出时,我们有什么资格去批评他们呢?现代经济理论的教父保罗·萨缪尔森在行为主义主导学术心理学的时候发展了显露偏好理论,这并不是巧合。
数字营销漏斗和老鼠迷宫
1938 年,爱德华·托尔曼(Edward Tolman)写道,老鼠迷宫作为一种研究动物学习过程的工具,具有强大的力量,这预示着数字营销漏斗的现代理念。
现在,让我以最后的信仰告白来结束。我相信,心理学上的一切重要事情……都可以通过继续的实验 的理论分析 的决定因素 在 选择点 在 迷宫 中进行本质上的探究。
考虑到经济需要,RL 将越来越多地被用作针对企业目标的人类行为修正的自动化手段。对于数字营销来说,RL 可以用来系统地影响用户在选择选择点的行为,以达到产品购买(转化)的目的。漏斗的各个部分可以被视为用户状态和营销干预(例如,通知/展示/推荐商品 x)的动作。最佳营销策略选择给定用户状态下的最佳行动。更好的用户监视和数据捕获意味着更细粒度的状态表示。来源:可行性。****
如果比较不清楚,平台的用户就像迷宫里的老鼠。这个平台是公司的实验者,他希望你跑到迷宫的尽头,购买一些产品或点击一些广告。因为数据平台可以以类似 全景视觉 - 的方式全面监控和记录用户行为,所以 RL 算法现在可以用来塑造和引导它朝着平台的业务目标发展。事实上,通过指定奖励函数,可以同时实现几个优化目标。例如,奖励可能是点击行为(控制浏览行为)和购买(确保 RL 代理选择最终有助于购买的行为,而不是简单的大量点击)的函数。
你可以想象一个 RL 代理可能如何选择一个最优策略(即,一系列干预行动)来推动用户购买更多的产品,为某些政治候选人投票,或者——举一些行为矫正的非邪恶应用的例子——减肥或戒烟。数字营销和计算广告现在是行为修正科学与 RL 相遇的地方。结合的生成性对抗网络 (GANs)和创建适应性强的“个性化”音频、视频和基于图像的内容的能力,可能性是无限的。数十亿美元将被创造,而目前在这个领域几乎没有监管。
想象一下在中国这样的社会中这是多么的巨大。RL-agents 可以在淘宝、微信、美团外卖、 JD 、滴滴出行出行等平台上每天与数十亿用户互动。一个巨大的多智能体 RL 系统可以使用由中国***拥有和运营的中央数据存储器“重放缓冲器】来构建,其中无数专门的 RL 智能体的个体交互通过汇集状态-行动-回报历史来共享和改进行为政策。虽然有些牵强,但这并非不可能:斯坦福大学的 2021 年人工智能指数报告显示,中国在人工智能期刊引用方面已经超过美国。**
Joshua Hoehne 在 Unsplash 上拍摄的照片
私人利益中的数据科学&制造怀疑
将企业需求与自动化行为修正技术混合在一起是一个社会灾难的处方。举个例子,华尔街日报最近发表了一篇文章,披露了脸书如何在 2017-2018 年左右对其新闻推送算法进行修改,以抵消用户参与度下降的影响。这些变化旨在鼓励更多的个人联系和改善心理健康,但它们适得其反。相反,该算法实际上成为了一台愤怒和错误信息的传播机器,企业利润需求是扎克伯格和其他人没有采取任何行动来对抗随之而来的社会外部性的主要原因。**
然而,脸书的研究负责人对《华尔街日报》的说法进行了官方反驳。但是这有点像期望菲利普莫里斯给你关于吸烟影响的公正信息。鉴于企业利润的必要性,很难知道该相信什么。不幸的是,如果学术人才继续以目前的速度流失,前景似乎并不乐观。斯坦福大学的人工智能指数报告指出,现在北美 65%的人工智能博士毕业后进入行业,而 2010 年只有 44%。
因此,我们能做些什么来对抗不可避免地使用基于 RL 的技术作为以牺牲我们的精神健康、政治和社会稳定为代价来获取更大公司利润的手段吗?在他的书《私人利益中的科学》中, 谢尔登克里姆斯基详细描述了在烟草、产品安全、环境污染、工作场所有毒物质以及药物对成人和儿童的疗效和副作用等领域研究“被忽视的人类需求和不公正”的自由思想科学家“稀疏队伍”背后的历史。
像内奥米·奥雷斯克斯和克林姆斯基这样的学者揭示了协调一致的企业战略制造怀疑,以便在诸如吸烟和气候变化等具有集体重要性的问题上故意混淆和误导公众。这一战略的前提是有害后果的不确定性有利于现状。极不可能发生的危险,即使很大,也不需要采取预防措施。为什么平台不能使用类似的策略来“搅浑”青少年福祉、心理健康和社交媒体使用的研究水呢?我们已经看到类似的事情被用来回应脸书的告密者 Frances Haugen。****
企业数据平台掌握着回答具有重要社会意义的类似问题的关键。他们收集和控制数十亿用户的行为数据,从广告中获得大量现金,并可以随意干预数百万用户的在线体验,以测试关于情感传染等事情的因果假设。资金紧张、渴望发表论文的数据科学学者很难与之竞争。
为了公众利益走向数据科学
克林姆斯基有力地指出,我们必须捍卫美国研究机构的完整性,尤其是研究型大学。为什么?因为
大学不仅仅是智慧的源泉……大学是一个舞台,通过这个舞台,有奉献精神的男男女女可以为了社会的进步而向权力说真话。
我们可能需要政府监管机构和机构的帮助,以使公共利益数据科学研究成为现实。但立法者需要认识到,有意义的平台研究不仅需要访问行为数据,还需要访问推荐服务系统本身。好的科学旨在揭示现象的不可观察的原因;它必须超越简单地描述以前由平台管理的数据集中可观察到的相关性。最后,公共利益而非私人利益的学术数据科学研究遵守国际人类受试者研究伦理协议,我们可能还需要更新这些协议,以反映对社会负责的数据科学研究的新范式。
因此,这是为了培养新一代愿意向当权者说真话的学术数据科学家。
纠正波士顿住房市场数据集
原文:https://towardsdatascience.com/correcting-the-boston-housing-market-dataset-aa8cfabfa085?source=collection_archive---------45-----------------------
使用谷歌的地理编码器 API 修正纬度和经度坐标
图片来自 Sam Clarke 在 Unsplash ( 来源)
TL;博士
波士顿住房市场数据集的纬度和经度不正确。校正后的数据集可以在这里找到。
波士顿住房市场数据集无处不在。尽管如此,纬度和经度值是错误的。这篇文章相当短,旨在:a)引起人们对问题的注意,b)提供校正数据集的链接,以及 c)描述用于校正数据集的方法。
数据集有问题
如图 1 所示,住宅的快速绘图显示了纬度和经度的问题。
图 1:校正前的住宅图
我们首先注意到大量的城镇实际上出现在水中,如图 2 所示。
图 2:放大的图片显示许多城镇出现在水中
此外,我们可以通过检查谷歌地图上的各个城镇来确认纬度和经度是不正确的。图 3 显示了一个在 Nahant 的住宅的例子。
图 3:(左)出现在谷歌地图上的 Nahant 和(右)使用数据集坐标的 Nahant
这个数据集的很多在线分析都没有考虑这个问题(比如这里的)。尽管他们进行了出色的分析,但住宅的绘制是错误的。
修复方法
为了固定数据集,做了一个关键的假设。这就是纬度和经度的误差实际上是它们都移动了一个常量。在这个公式中,我们猜测误差是系统性的,而不是随机的。
我们假设每个住宅到其各自城镇中心的距离是一致且正确的。我们猜测这个误差实际上来自于城镇中心的转移。然后我们定义:
其中 x_i 是我们数据集中一个住宅 i 的坐标(纬度或经度), x_bar_j 是住宅 i 所在城镇 j (即城镇中心)的平均坐标, D_i 是住宅 i 到城镇中心 x_bar_j 的坐标距离
基于我们对误差性质的假设,这意味着如果我们用修正的 x_bar_j* 替换**x _ bar _ j ***,保持 D_i 不变,我们可以找到每个住所的修正位置。
为了找到正确的城镇中心 x_bar_j* ,我们使用了谷歌的地理编码器 API。这方面的代码如下所示:
完整的实现可以在这里找到。
结果
下面的图 4 并排显示了校正和未校正的坐标。
图 4:(左)未修正的城镇坐标和(右)修正的城镇坐标
值得注意的是,坐标比校正前更有意义,因为:
- 水上没有住宅
- 住宅成群出现(这是有道理的,因为它们应该来自同一个城镇)
可在处找到校正数据集的链接。
我希望这篇文章对希望对波士顿住房市场数据集进行分析的数据科学初学者(或专家)有所帮助。
除非另有说明,所有图片均由作者制作。
蒙特卡罗模拟中的相关变量
原文:https://towardsdatascience.com/correlated-variables-in-monte-carlo-simulations-19266fb1cf29?source=collection_archive---------6-----------------------
入门
香草冰淇淋的销量能超过巧克力吗?
图片由尼基👉请保持安全👈来自 Pixabay
目录:
- 介绍
- 问题陈述
- 数据准备
- 错误方法 1-独立模拟(参数化)
- 错误方法 2-独立模拟(非参数)
- 方法 1 —多元分布
- 方法 2-具有边缘分布的连接函数
- 方法 3——模拟销售增长的历史组合
- 方法 4——使用 PCA 消除商店销售增长的相关性
介绍
蒙特卡洛模拟是销售、资产回报、项目投资回报率等的一个很好的预测工具。
在之前的文章中,我提供了如何在商业环境中使用蒙特卡罗模拟来预测一系列可能的商业结果及其相关概率的实用介绍。
在本文中,我们将解决蒙特卡洛模拟中相关变量的挑战。我们将研究 4 种处理相关性的适当方法。
问题陈述
在我们的样本数据集中,20 年前,巧克力冰淇淋的年销售额为 500 万美元,香草冰淇淋的年销售额为 400 万美元。巧克力冰淇淋的需求量比香草冰淇淋多 25%。
在过去的 20 年里,对巧克力和香草的需求都在增长,但是巧克力和香草之间的销售差距已经缩小。去年,巧克力冰淇淋销售额为 1260 万美元,香草冰淇淋销售额为 1190 万美元。现在对巧克力的需求仅比香草多 6%。
注 —巧克力和香草冰淇淋的销量正相关,即巧克力冰淇淋和香草冰淇淋的销量往往同增同减。
问题:明年会是香草冰淇淋销量超过巧克力冰淇淋销量的一年吗?
巧克力和香草冰淇淋销售之间相互关系的图解(图片由作者提供)
解决方案:我们可以运行蒙特卡洛模拟来回答我们的问题。
独立模拟巧克力和香草冰淇淋的销售是错误的。
数据准备
我们首先配置巧克力和香草冰淇淋销售的样本起始销售数字。选定的数字分别为 500 万美元和 400 万美元。我们假设大多数人都有点偏爱巧克力冰淇淋。
START_CHOC = 5
START_VAN = 4
然后,我们想要绘制 20 个随机的年销售增长率,假设香草和巧克力冰淇淋的销售增长率遵循多元正态分布。这是正态分布的扩展,我们假设两种冰淇淋口味的销售增长率都遵循正态分布,但两个正态分布之间存在关系。
我们假设两种口味的平均增长率为 5%,标准偏差为 10%,两种口味的增长率之间的相关性为 0.9。
# Config for multivariate normal distribution
CORR = 0.9
MU = 1.05
SIGMA = 0.1
下面是生成增长率和年销售额的代码。
# Generate sales and growth rates for 20 periods
# using a multivariate normal distribution
cov_matrix = [[(SIGMA**2), CORR*(SIGMA**2)],
[CORR*(SIGMA**2), (SIGMA**2)]]distribution = ss.multivariate_normal(
mean=[MU, MU], cov=cov_matrix)sample_data = distribution.rvs(20, random_state=5)chocolate_growth = sample_data[:, 0]
vanilla_growth = sample_data[:, 1]chocolate_sales = np.cumprod([START_CHOC] + list(chocolate_growth))
vanilla_sales = np.cumprod([START_VAN] + list(vanilla_growth))# Prepare dataframes
growth_df = pd.DataFrame(data={
"Growth Rate - Chocolate": chocolate_growth,
"Growth Rate - Vanilla": vanilla_growth})sales_df = pd.DataFrame(data={
"Sales Chocolate (USD mln)": chocolate_sales,
"Sales Vanilla (USD mln)": vanilla_sales})df = pd.concat([growth_df, sales_df], axis=1)
df
冰淇淋销量和增长率(图片由作者提供)
错误方法 1-独立模拟(参数化)
首先,我们将运行一个蒙特卡洛模拟,我们将研究香草和巧克力销售的统计分布,但是将这两种分布都视为独立变量。这是一个错误的方法,因为香草和巧克力冰淇淋的销售是相互关联的。
我们知道分布的参数,因为我们已经创建了数据集,假设巧克力和香草的销售增长率遵循均值为 1.05(平均增长 5%)和标准差为 0.1 (10%)的正态分布。参见上一节。
然而,让我们假设我们不知道这些参数,以便复制我们在现实生活中会面临的挑战。我们必须使用历史数据来估计参数。
# Estimate means
mean_choc = np.mean(df["Growth Rate - Chocolate"])
print(f"Mean (Chocolate): {mean_choc}")mean_van = np.mean(df["Growth Rate - Vanilla"])
print(f"Mean (Vanilla): {mean_van}")# Estimate standard deviations
std_choc = np.std(df["Growth Rate - Chocolate"],
ddof=1)
print(f"StDev (Chocolate): {std_choc}")std_van = np.std(df["Growth Rate - Vanilla"],
ddof=1)
print(f"StDev (Vanilla): {std_van}")# Define normal distributions
distribution_choc = ss.norm(mean_choc, std_choc)distribution_van = ss.norm(mean_van, std_van)
来自 20 年样本的平均值和标准偏差(图片由作者提供)
接下来,我们模拟巧克力和香草冰淇淋销售的 1000 个样本增长率。
growth_vanilla = distribution_choc.rvs(1000,
random_state=1)growth_chocolate = distribution_van.rvs(1000,
random_state=2)
现在让我们准备一个函数,我们可以用它来检查香草的销售额是否会超过巧克力的销售额。
def exceed_check(growth_vanilla, growth_chocolate):
'''This function takes sample growth rates for
vanilla and chocolate ice cream sales and checks
if vanilla ice cream sales would exceed chocolate
given the combination of growth rates.
Args:
growth_vanilla (list): growth rates for vanilla sales
growth_chocolate (list): growth rates for chocolate sales
Returns:
flags_list (list): A list of True/False flags indicating
whether vanilla sales exceeds chocolate sales for the
given combination of growth rates
mean_pass_rate: Mean value of flags_list indicating the
probability vanilla sales exceeds chocolates given the
combination of growth rates
'''
# Last year's chocolate and vanilla ice cream sales
# set as constants to improve performance
FINAL_CHOCOLATE = 12.59
FINAL_VANILLA = 11.94
flags_list = [v*FINAL_VANILLA > c*FINAL_CHOCOLATE
for v,c in zip(growth_vanilla, growth_chocolate)]
mean_pass_rate = np.mean(flags_list)
return flags_list, mean_pass_rate
最后,我们来查一下香草销量超过巧克力的概率…
exceed_check(growth_vanilla, growth_chocolate)[1]
概率: 34.1%
错误方法 2-独立模拟(非参数)
在第二个错误的方法中,我们独立地模拟了巧克力和香草的销售增长率,但是我们没有假设任何统计分布。我们从历史中得出样本增长率。
growth_vanilla = df["Growth Rate - Vanilla"].dropna(
).sample(1000, replace=True, random_state=1)growth_chocolate = df["Growth Rate - Chocolate"].dropna(
).sample(1000, replace=True, random_state=2)
现在我们检查香草销售额超过巧克力的可能性…
exceed_check(growth_vanilla, growth_chocolate)[1]
概率: 35.9%
到目前为止,我们分别对待巧克力和香草销售的两种错误方法给了我们 34%到 36%之间的可能性…毕竟明年很有可能是香草冰淇淋爱好者之年…
图片来自 Pixabay 的 Clker-Free-Vector-Images
方法 1-多元分布
我们将用来检查香草销售额是否可能超过巧克力销售额的第一个适当方法是估计代表数据的多元分布,并从该样本中得出潜在增长率。多元分布模拟多元变量的组合分布。相关性被捕获。
请记住,我们实际上是从多元正态分布中生成的数据,巧克力和香草的平均值为 1.05,标准偏差为 0.1,相关性为 0.9。不过,这里我们将假设我们不知道参数,我们将使用历史数据来估计分布参数,就像我们在独立参数模拟中所做的那样(“错误方法 1”一节)。
我们已经估算了前面提到的平均值和标准偏差,但是我们仍然需要估算巧克力和香草冰淇淋销售之间的相关性。
corr = df.corr().iloc[0, 1]
corr
估计的相关性与我们用来生成数据的实际值 0.9 相差不远(图片由作者提供)
我们现在可以从多元正态分布中得出 1000 个样本的增长率…
# We need to recalculate the covariance matrix
# using the estimated paramaters
cov_matrix = [[std_choc**2, corr*std_choc*std_van],
[corr*std_choc*std_van, std_van**2]]growth_rates = ss.multivariate_normal(
mean=[mean_choc, mean_van],
cov=cov_matrix).rvs(1000, random_state=1)growth_chocolate = growth_rates[:, 0]
growth_vanilla = growth_rates[:, 1]
最后,我们计算香草销售额超过巧克力的概率…
exceed_check(growth_vanilla, growth_chocolate)[1]
概率: 11.3%!请注意,在我们考虑了巧克力和香草冰淇淋销售之间的相关性后,这种可能性现在低了很多。
看起来巧克力可能仍然是主要的口味…
图片来自请不要出售我的作品,因为是来自 Pixabay 的
方法 2-具有边缘分布的连接函数
在上一节中,我们看了多元正态分布。巧克力和香草冰淇淋的销量都服从正态分布,它们是相关的。这使得用多元正态分布来表示它们变得很容易。
有时,我们可能有两个或更多来自不同统计分布的变量,并且没有已知的多元分布可以解释它们的组合分布。如果我们确实知道变量 + 的个体(边际)分布,我们知道它们之间的相关性,那么连接函数可以有所帮助。
对系词的详细解释超出了范围,但简单地说…
假设一个变量可能的最低值是 0,最高值是 1。Copulas 生成该范围内的值的组合,从而保持变量之间的相关性所暗示的关系。由于我们的变量是巧克力和香草冰淇淋销售额,并且它们正相关,当香草冰淇淋也具有高价值时,copulas 将绘制更接近 1(最高值)的巧克力冰淇淋销售额增长值,反之亦然。
有一些现有的库可以安装来利用 copula,但下面我们将使用 hack 从头构建一个 copula(高斯函数),这可能有助于更好地理解这个过程。
首先,我们需要重新计算巧克力和香草销售增长这两个变量之间的相关性,因为 copulas 是基于等级相关性的。在上一节中,我们计算了皮尔逊相关系数,但现在我们将使用 Kendall 的 Tau 来衡量等级相关性。等级相关性是基于计算值的等级之间的相关性,而不是值本身。
corr = ss.kendalltau(
df.dropna().iloc[:, 0], df.dropna().iloc[:, 1])[0]corr
0.74 的等级相关性低于我们之前计算的 0.93 的相关性(图片由作者提供)
现在我们可以构建我们的系词…
# We set variances to 1 because the covariance matrix we
# are constructing will be used with a multivariate normal
# distribution of means 0 and std 1 to derive a copula
cov_matrix = [[1, corr],
[corr, 1]]# We will draw 1000 combinations from the distribution
random_vals = ss.multivariate_normal(cov=cov).rvs(
1000, random_state=1)# Finally a cumulative density function for a distribution
# ranges between 0 to 1 so it will be used to convert the
# drawn samples to the values we need for our copula
copula = ss.norm.cdf(random_vals)
print(copula.shape)
copula
作者图片
我们可以看到 copula 有 1000 个跨 2 个变量的相关条目,它们的范围从 0 到 1。
下面是我们两个变量的相关 copula 值的散点图。
sns.scatterplot(x=copula[:, 0], y=copula[:, 1])
作者图片
介于 0 和 1 之间的 copula 值捕获了变量之间的相关性,因此现在我们只需将 0–1 值转换为我们希望用于巧克力和香草冰淇淋销售增长率的实际值。
我们使用百分点函数来表示每个变量在转换中的分布。我们已经在独立参数模拟部分估计了分布(“错误方法 1”)。不同之处在于,我们现在不只是从每个分布中随机抽取值,而是使用 copula 值和百分点函数从每个分布中抽取相关随机值。
# distribution_choc and distribution_van area already
# calculated in previous sections
growth_chocolate = distribution_choc.ppf(copula[:, 0])
growth_vanilla = distribution_van.ppf(copula[:, 1])
最后,让我们将这些增长率传递给我们的函数,以检查香草销售额超过巧克力销售额的可能性…
exceed_check(growth_vanilla, growth_chocolate)[1]
概率: 11.1%
11%的概率与上一节中的概率相似,证实了我们在最初应用的 2 个错误方法中严重高估了概率。
这种方法有几个步骤,可能需要对不同的概念进行更彻底的解释。不过需要记住的一点是,我们使用 copula 生成的介于 0 和 1 之间的值可以用于任何统计分布的组合。
我们的例子很简单,因为两个变量的分布都是正态的,所以上一节的方法(多元正态分布)是足够的,实际上应该产生与本节相同的结果。但是想象一个不同的场景,其中变量 A 是正态分布,变量 B 是二项式分布等等。在这种情况下,将需要系词。
一个假设的场景是预测电影票销售和爆米花销售,其中我们将电影院游客的数量建模为泊松分布,然后我们使用二项式分布来建模爆米花销售,其中每个买票的电影院游客都有一定的概率购买爆米花。
方法 3——模拟销售增长的历史组合
这是一种类似于独立非参数模拟的简单方法(第 2 节“错误方法”),其中我们不估计任何统计分布,而是直接从历史中抽取样本。
我们应用的修正是,我们不独立地从不同的历史点获取巧克力和香草销售的历史增长率。相反,我们随机选取历史上的一个点,从历史上的同一点中选取两个增长率。然后,我们在历史中绘制另一个点,并做同样的事情,直到我们达到我们想要运行的模拟轮数。
例如,我们回放历史,并在第一轮模拟中从第 5 年开始计算两种口味的增长率,然后在第二轮模拟中从第 11 年开始计算,依此类推。
在“错误方法 2”一节中的独立方法中,例如,我们可以在同一轮模拟中采用第 5 年香草的增长率,以及第 11 年巧克力的增长率。我们在重演巧克力和香草冰淇淋的销售历史,两者相互独立。
resampled_history = df[["Growth Rate - Chocolate",
"Growth Rate - Vanilla"]].dropna(
).sample(1000, replace=True, random_state=1)growth_chocolate = resampled_history["Growth Rate - Chocolate"]
growth_vanilla = resampled_history["Growth Rate - Vanilla"]exceed_check(growth_vanilla, growth_chocolate)[1]
概率: 21% 这一概率高于从最后两种适当方法得出的预期的约 11%,但低于错误模拟方法暗示的约 35%。
这种方法依赖于有足够的历史记录,通常更适合于财务数据,例如,我们有许多历史数据点。
在我们的示例中,我们只有 20 年的数据,代表巧克力和香草冰淇淋销售的 20 种历史增长率组合。这是一个很小的数字,我们会对过去发生的一些事情给予过多的重视。
方法 4——使用 PCA 消除商店销售增长的相关性
在前一种方法中,我们的方法面临的挑战是,我们只从 20 个数据点进行重新采样,因为我们有 20 个香草和巧克力冰淇淋历史销售增长的组合。
在独立的非参数模拟中(“错误方法 2”部分),该方法是错误的,因为我们将香草和巧克力的销售增长率视为独立的。这使得我们有 400 (20 x 20)个历史数据点进行重新采样,因为我们可以将巧克力的 20 个历史销售增长率中的任何一个与香草的 20 个历史增长率中的任何一个结合起来。我们能够将第一年巧克力的增长率与第二年香草的增长率结合起来…在方法 3 中,我们做不到。
在这最后一种方法中,我们遵循一个非常相似的方法,即我们不估计任何统计分布,我们重放历史增长率。
这个方法的核心是我们首先去关联两种口味的冰淇淋销售增长率。这种方法将允许我们将某一年的巧克力的历史增长率与另一年的香草的历史增长率结合起来,因为我们消除了我们必须控制的相关性。我们最终会有更多的数据点需要重新采样。
步骤 1 是使用去相关方法。我们在这个例子中使用主成分分析,我想你应该很熟悉。Choletsky 分解也是金融中一种流行的替代方法。
请注意,PCA 通常用于数据科学中的降维,但我们真正感兴趣的是这样一个事实,即 PCA 组件是去相关的。在我们的例子中,我们不希望减少维度,所以我们将传递两个变量(巧克力和香草的销售增长率),我们将获得两个去相关的组件。由于这些主要成分是去相关的,我们可以混合和匹配历史上不同时间点的成分,并得到巧克力和香草销售增长率的 400 种组合,我们可以从中重新取样。
pca = PCA(n_components=2)# Normalize chocolate and vanilla growth rates to apply PCA
normalized_chocolate = (
df["Growth Rate - Chocolate"].dropna() - mean_choc
) / std_chocnormalized_vanilla = (
df["Growth Rate - Vanilla"].dropna() - mean_van
) / std_van# Apply PCA transformation on normalized values
components = pca.fit_transform(
np.array([normalized_chocolate,
normalized_vanilla]).T)components
代表 20 年数据的 20 x 2 阵列和 2 个 PCA 组件(图片由作者提供)
接下来,我们运行 1000 次模拟,从元件阵列中取样。
np.random.seed(1)sampled_components = [[x[0], x[1]] for x in zip(
# Sampling 1000 entries from first PCA component
np.random.choice(components[:, 0], 1000),
# 2nd PCA component
np.random.choice(components[:, 1], 1000))]
下一步是通过反转我们已经完成的转换(标准化和主成分分析)将采样成分值转换为增长率。
inverse_pca = pca.inverse_transform(sampled_components)# Denormalizing
growth_chocolate = [(x * std_choc) + mean_choc
for x in inverse_pca[:, 0]]
growth_vanilla = [(x * std_van) + mean_van
for x in inverse_pca[:, 1]]
最后…
exceed_check(growth_vanilla, growth_chocolate)[1]
概率: 17.1% 更接近我们基于方法 1 和方法 2 预期的 11%。
结论
下面是我们预测的香草冰淇淋销量超过巧克力的可能性。我们使用了 2 个错误的方法和 4 个合适的方法。
作者图片
两个错误的方法,运行蒙特卡罗模拟,假设香草和巧克力冰淇淋的销售是独立的,大大高估了香草的销售可能在明年超过巧克力的概率。
因为两种口味的销售被认为是独立的,所以有一个不切实际的高概率被认为香草的销售将会比正常的增长率高得多,而巧克力的销售将会比正常的增长率低得多。现实表明,这两种口味的销售彼此正相关,因此在大多数情况下,这两种口味的增长都很高,或者都很低,表现略有不同。
方法 1 和 2 是最准确的,这意味着香草有 11%的可能性超过巧克力。这是因为实际数据来自多元正态分布。然而,最佳方法的选择取决于手头的数据集。
方法 1 和 2 要求基本的统计分布能够被相当精确地估计。方法 3 和 4 依赖于拥有足够大的数据集。
最重要的一点是不要忽略蒙特卡罗模拟中的相关性。
相关性和因果性——“啤酒和尿布”的故事?
原文:https://towardsdatascience.com/correlation-and-causality-a-beer-and-diaper-story-27a064f4f995?source=collection_archive---------32-----------------------
用图解和例子理解相关性和因果关系
图片由 SparrowsHome 来自 Pixabay
我猜想你正在为一家在线零售商设计推荐引擎。你做的一切都是对的(至少你是这么认为的……)。在结果中,你发现当啤酒被男性购买时,你的算法正在推荐尿布。牵强的想象?还是你的算法推荐错了还是对了?啤酒和纸尿裤有关联吗?或者他们有因果关系——可笑吧?
了解不同自变量和因变量之间的关系是探索性数据分析或机器学习模型构建的关键步骤之一。相关性、共线性、协方差和因果关系是理解这种关系的一些选项。在本文中,我们将讨论相关性和因果关系。
让我们更好地理解这些术语。相关性的正式定义是,在统计学中,相关性或依赖性是两个随机变量或二元数据之间的任何统计关系,无论是否是因果关系。(来源: 维基百科 )
并且,因果关系(也称为因果关系,或原因和结果)被定义为— 是一个事件、过程、状态或对象(原因)对另一个事件、过程、状态或对象(结果)的产生产生影响,其中原因部分地对结果负责,结果部分地依赖于原因。(来源: 维基百科 )
唷…令人费解,对吧?这是大多数统计术语的问题。所以让我们来分解一下—
- 有什么关联?
- 什么是因果关系,即原因和结果?
- 如何确定因果关系
有什么关联?
简而言之,相关性是两个变量之间的关联或变化的度量。这两个变量之间的关系用强度和方向来解释。如果一个变量的增加导致第二个变量的增加,那么这两个变量是正相关的。如果一个变量的增加导致另一个变量的减少,那么两个变量是负相关的。同样,如果一个变量的变化导致另一个变量的显著变化,那么两个变量是强相关的,否则是弱相关的。
当讨论相关性时,最常见的是线性相关性(例如,身体的重量与身体的质量线性相关,即 W = mg,其中 m 是质量,g =重力或重力加速度)。然而,两个变量也可以具有非线性关系(例如,圆的体积和半径具有非线性关系)
相关系数
相关系数提供了幅度和方向的信息。基于不同类型数据(正态与非正态数据、连续与离散或分类数据、有序数据等),有不同的方法来计算相关系数。)-
皮尔逊积差相关系数 :又称皮尔逊相关系数或简称皮尔逊系数,是一种衡量两个变量之间相关性的统计方法。该系数提供了线性关联强度的度量。皮尔逊相关系数从-1 到 1 不等。正负符号表示关系的方向,数值表示关系的强度。
图片由萨加尔·加瓦利拍摄
让我们看看皮尔逊系数的例子:
- 模拟数据(图 1、2 和 3)及其相关系数,以了解如何解释皮尔逊系数。
图片由萨加尔·加瓦利
2.使用“来自 scikit-learn 库的 Iris 数据集”的皮尔逊系数
图片由萨加尔·加瓦利
然而,为了有效地使用人员系数,应满足以下假设:
- 两个变量都是连续的,并且是联合正态分布的。如果 aX +bY 具有正态分布,则两个变量 X 和 Y 被认为是联合正态分布的。
- 数据中没有异常值。极端异常值对系数值有不适当的影响。(地块 7 和地块 8)
图片由萨加尔·加瓦利
与皮尔逊相关系数类似,还有其他类型的相关系数,如斯皮尔曼相关系数,用于非正态分布的连续数据、有序数据或具有有效异常值的数据。其他类型的相关系数包括 Kendall、Phik 和 Cramér 的 V 相关系数等。
什么是因果关系,即原因和结果?
两个变量之间的因果关系可以用因果关系来定义。如果一个行为或事件(原因)导致了一个现象(结果),那么这个行为或事件和这个现象(另一个行为或事件,观察,结果)就有因果关系。
理解两个变量是否具有因果关系(即两个变量之间的因果关系)对于机器学习模型的建立是至关重要的。然而,在对相关的两个变量之间的关系进行分类时,必须小心谨慎;相关性并不意味着因果关系。
如何确定因果关系?
现在,要确定两个变量是否有因果关系,需要满足一定的条件。
- 逻辑表明原因和事件应该是连续的事件,即一个接一个。这就形成了确定因果关系的第一个条件——时间顺序。例如,为了通过营销努力增加销售额,营销必须在 delta 增加销售额之前进行。
- 关联:两个变量要有因果关系,首先要有关联。如果两个变量之间没有关系,就不可能有因果关系。通常使用相关系数来识别关联性。
- 所有其他的因果解释都应该被排除。例如,变量 A 和 B 之间的关系可能是以下任何情况的结果:
- 事件 A 和事件 B 可能是事件 c 的结果。例如,空调销售量的增加不可能是冰淇淋销售量增加的原因,但两者都是夏季温度升高的结果。
- 事件 A 是事件 B 的必要条件,但不是事件 B 的原因。例如,燃烧需要氧气,但不是燃烧的原因。
- 事件 A 会导致事件 C,而事件 C 又会导致事件 D,最终导致事件 b。
确定因果关系的主要方法之一是进行实验(如假设检验、A/B 检验或对照组研究)并检验结果。在设计实验时,必须小心避免偏见,并检验上述标准的有效性。
然而,对于大多数数据科学家来说,这在大多数情况下也是不切实际的——在大多数情况下,数据已经被收集并提供给你了。在这种情况下,必须依赖前两个标准(时间排序和关联),而对于第三个标准,则依赖业务用户。执行分析,完成建模并测试问题的结果。如果是有效的和想要的,一切都准备好了,如果不是,就必须回到绘图板,重新评估因果关系。
你遇到过这样有趣的关系吗?请在下面的评论中告诉我——谢谢。
附言:
- 这里举的啤酒和尿布的例子是为了增加读者的兴趣。然而,啤酒和尿布似乎在零售行业的设置中没有任何关联。在这里阅读关于它的起源和争论的详细故事。
- 绘制散点图和计算皮尔逊系数的代码(图 1-6):
代码由萨加尔·加瓦利
直观解释相关性
原文:https://towardsdatascience.com/correlation-explained-visually-4875448e8e56?source=collection_archive---------11-----------------------
皮尔逊相关的几何方法有助于深入理解它,并更准确地解释其结果。
[图片由作者提供]
不时会有人过来说“我终于找到了皮尔逊相关的替代品”。事实是——尽管有缺点——皮尔逊相关系数(又称 T0 系数)因其简单、稳健和可靠而难以替代。
但是,冷硬公式可能有点难以把握。因此,我试图找到皮尔森的 r 的视觉解读,我希望它能帮助你(就像它帮助我一样)深入理解它。
从公式开始
你可能已经见过这个公式成千上万次了:
皮尔逊相关系数公式。[图片由作者提供]
如果你对代码比对数学更熟悉,那么你会更喜欢这个 Python 片段:
import numpy as npx = np.array([1,2,3,4])
y = np.array([7,6,8,9])codev_xy = np.sum((x — np.mean(x)) * (y — np.mean(y)))
ssd_x = np.sum((x — np.mean(x)) ** 2)
ssd_y = np.sum((y — np.mean(y)) ** 2)corr_xy = codev_xy / np.sqrt(ssd_x * ssd_y)
但是公式 是什么意思 ?
该公式可以分解为三个具有一些著名名称的构造块:
皮尔逊相关的三个组成部分。[图片由作者提供]
最有趣的部分是分子:。其实分母只是一个归一化因子,绑定了-1 和 1 之间的相关系数(数学证明见此处)。实际上,在其他条件相同的情况下,相关性越大,相关系数越大。
这个配方可能看起来有点模糊,但是再看一眼,就很清楚它只由两种成分组成:
皮尔逊相关系数是由“距离”构成的。[图片由作者提供]
而且,因为我们只处理二维( x 和 y ),所以在一个图中表示它们很容易。
所以,让我们借助一些数据点,将相关性带入生活吧!
一些数据点。[图片由作者提供]
从几何学上来说,共生现象很容易被发现。它只是每个数据点和质心之间的所有“矩形”的面积之和(即以 x 的平均值作为其自身的 x 以及以 y 的平均值作为其自身的 y 的点)。
相互依存的图形解释。[图片由作者提供]
真正起作用的是每个矩形的“符号”!事实上,
- 右上和左下象限(图中绿色)中的矩形有正号,因此它们被添加到 codeviance 中。当 x 和 y 都高于(或都低于)平均值时,就会出现这种情况。换句话说,它们是一致的。
- 左上和右下象限(图像中的红色)中的矩形有负号,因此它们被从余度中减去。当 x 高于(低于)平均值,而 y 低于(高于)平均值时,就会出现这种情况
因此,当大多数数据点相对于 x 和 y 一致时,我们可以近似地说相关性(以及相关性)为正。反之,大部分点不和谐时为负。想想也很有道理:codeviance 试图表达 x 和 y 如何“一起改变”。
为了完整起见,我们也可以将分母的构件形象化:
离差平方和的几何解释。[图片由作者提供]
最后的结局是:
分子和分母的最终结果。[图片由作者提供]
在大多数值得注意的情况下,现在很容易弄清楚为什么相关系数是现在这个样子。例如,让我们看看其中的两个:
- 辛普森悖论;
- 对称关系。
1.辛普森悖论
辛普森悖论是数据科学面试中反复出现的话题。这让很多人感到困惑。但是希望,多亏了这种图形化的方法,你再也不会感到困惑了!
我们举个例子,灵感来自 ResearchGate 。
你有两个群体:男性和女性。你对两组都进行了一些医学治疗(而且,由于男性更高更重,他们接受了更高的剂量)。你计算剂量和恢复之间的相关性,它是强正的:0.68。很好,这意味着药物是有效的,对吗?
嗯,等一下。你看一下两组的曲线图,你会注意到下面的情况:
一些数据点说明了辛普森悖论。[图片由作者提供]
虽然在每组中剂量和恢复之间存在反比关系(这应该与负相关相关),但是您的皮尔逊r是强正的。这是为什么呢?
通过我们的几何解释,我们可以立即了解正在发生的事情:
辛普森悖论:计算偏差。[图片由作者提供]
实际上,与剂量平均值和恢复平均值相比,所有男性都在右上象限,而所有女性都在左下象限。因此,即使在每个单独的组中,这种关系是负的,但是这种相关性在很大程度上是正的。因此,正相关。
将所有东西放在一起:
辛普森悖论的几何解释。[图片由作者提供]
2.对称关系
当两个变量具有“对称”关系时,它们的相关性将(接近)为零。
为了理解为什么会发生这种情况,让我们取一条关于 y 对称的抛物线(但对于 x 也是一样)。
现在,很明显为什么分子是零。事实上,左侧的所有数据点都与右侧的数据点“抵消”(即,它们具有相反的符号)。
我们来直观的证明一下:
抛物线皮尔逊相关的几何解释。[图片由作者提供]
感谢您的阅读!我希望这篇文章对你有用。
如果你对我在剧情中使用的 Python 函数感兴趣,你可以在Github 项目中找到它。
我感谢反馈和建设性的批评。如果你想谈论这篇文章或其他相关话题,你可以发短信给我我的 Linkedin 联系人。
同量异位标记蛋白质组学中的相关性
原文:https://towardsdatascience.com/correlation-in-isobaric-labeling-proteomics-926045214f96?source=collection_archive---------44-----------------------
在基于同位素标记质谱的蛋白质组学中,基本统计量是如何表现的?
作者图片
皮尔逊相关系数用得很多。介绍完毕。我们利用它作为各种数据集中线性相关的量度,今天我想讨论一下这种无处不在的统计指标在蛋白质组学中的应用。我将重点介绍基于质谱(MS)的同量异位标记蛋白质组学,这是一种在生物学和临床研究中测量相对蛋白质丰度的流行技术。如果你想了解更多关于这项技术的信息,可以看看我之前的文章或者 Rauniyar 和 Yates 的开放访问 T2 评论。
假设和数据结构
同量异位标记蛋白质组学可以应用于不同种类的实验,但是典型的设计具有以下共同点:
- 研究中的样本彼此相似,它们属于相同的生物物种和相同的类型,例如,都是血浆样本。与此相关,我们预计在不同的条件下,大多数蛋白质的丰度保持相当稳定。
- 从每个样品中取出等量的蛋白质材料,例如,通过具有分光光度检测的生化蛋白质分析来测量。例如,均衡蛋白质含量通常是可行的,而精确估计活检组织的干重可能是困难的。
但是固定蛋白质总量意味着我们可以有效地利用相对量。这反过来意味着同量异位标记蛋白质组数据是 组成的 ,对组成数据应用相关性分析应该谨慎,正如在许多出版物中所讨论的,例如,在 Lovell 和合著者【2】的论文中,作者清楚地说明了解释组成基因表达数据相关性的危险。
此外,同量异位标记质谱数据由于其获取方式而具有内在的组成性,正如 O'Brien 等人【3】在 2018 年的一篇论文中所讨论的。简而言之,标记批次中所有样品的定量信号在相同的光谱中获得,并且信号的总丰度通常受到限制,这取决于环境和某些获取设置。这意味着一批中的肽信号强度不是相互独立的:
同时测量整个标记批次的同量异位报道分子强度,并且通常不是相互独立的。作者图片
然而,尽管数据具有多种成分的性质,但对于相关性分析来说,事情并不都是令人沮丧的。由于样本之间很大程度上彼此相似,我们预计只有参与有趣生物过程的某些蛋白质会(有希望)在样本之间发生急剧变化,而可能不是最丰富的蛋白质。任何特定蛋白质对总丰度的影响都可以忽略不计。然而,从鸟瞰图来看,每个样本中上升和下降的蛋白质应该相加。那么,同量异位素标记数据集的关联情况是怎样的呢?
为了说明真实数据的相关性,我将使用由十个大肠杆菌样本组成的研究。MS 数据可从 PRIDE archive 网站获得,我已经重新处理了文件,并将蛋白质丰度表和所有相关代码放入 GitHub 储存库。在加载、过滤和对数转换报道分子强度值后,我们得到列中有 10 个样品、行中有 1836 个蛋白质的表,其中 Uniprot 成员作为索引:
数据集包括 5 种不同的遗传/刺激条件,每种条件在 2 个生物重复中平行制备。重复对(1/2、3/4、5/6、7/8、9/10)中的样品非常相似,而条件之间存在显著差异。正如你在上面看到的,除了 P25665,对数转换的报告强度值在每一个显示的蛋白质行中都是稳定的,这符合我们对样品相似性的假设。这些值的分布并不完全像钟形曲线,但是它们是对称的、单峰的,并且具有非常接近的中间值:
作者图片
事实上,这些值非常集中,因为它们已经被总肽强度标准化。由于我们提取了等量的蛋白质,我们预计每个样品的总信号强度大致相等。如果不是后者,我们可以假设出现了问题,例如蛋白质浓度测量或样品制备过程中的异常,可以通过调整总丰度或中值丰度进行纠正。在这种情况下,在处理 LC-MS 文件的过程中,每个样品的总强度都被提取出来,然后进行均衡。蛋白质表中的列和确实非常相似:
dfLog.sum()S01 5407.358507
S02 5415.529107
S03 5421.951839
S04 5413.545848
S05 5420.977531
S06 5410.352606
S07 5424.180405
S08 5425.054158
S09 5399.895850
S10 5405.012957
dtype: float64
总和略有不同,可能是因为平衡发生在工作流程的中间,一些肽和蛋白质在最终报告前被过滤掉。是的,这种规范化强化了数据的组合性质!但我认为这是合理的,因为这是根据基于实际相等蛋白质含量的实验设计完成的。它不创造组合性,而仅仅反映实验性设计。
样本-样本相关性
让我们来看看样本间对数 10 转换的同量异位素报告子丰度的成对相关性。计算的一个原因是评估样本之间的相似程度。然而,查看散点图,我们注意到所有的相关性都非常好,无论是在生物重复之间还是在不同条件之间:
作者图片
皮尔逊相关系数都很高,在 1.0 左右:
很容易看出它们如此相似的原因:定量光谱中的总强度取决于绝对肽量和其他因素,并且对于批次中的所有样品,它同步变化。由于大多数蛋白质在样品间保持相对恒定,对于大多数数据行,所有样品的绝对信号强度将非常相似,产生高相关系数。
不过,我们不需要查看绝对信号强度。该分析针对的是相对蛋白质丰度,那么我们为什么不缩放数据呢?将每行中的值除以该行中的平均强度,并对缩放后的值进行对数变换后,我们得到了结构非常不同的数据集。大多数值现在集中在 0 附近,分布看起来比以前更像钟形:
作者图片
缩放后的数据集具有完全不同的相关性前景:
作者图片
作者图片
现在有了正相关和负相关,这是意料之中的,因为我们已经将每个蛋白质的值的总和限制为一个常数。我们有效地增加了另一个层次的组合性!但是我们能从这个多成分数据集中的相关性推断出有用的信息吗?我们有成对的 1/2、3/4 等生物学重复,它们之间的相关性确实很好,而生物学上不同的样品之间的相关系数的绝对值较低,符号为正或负。所以在某种程度上,这些相关性确实揭示了样本之间的相似关系。
缩放同量异位素数据的另一个实用方法是使用其中一个样本作为分母。例如,该样本是疾病研究中的健康对照,或者是可用于数据集之间可比性的参考样本。假设样品 S01 是我们数据集的分母:
作者图片
所有的相关性都变成了正号!我们还没有引入蛋白质值的限制,就像我们对蛋白质平均值进行缩放时一样,所以我们不希望正相关和负相关处于某种平衡状态。同时,我们仍然看到生物复制之间的相关性更高。
样本间的相关性可能不是比较重复的完美方法,因为相关性的前景是由分母的选择决定的。如果我们除以对照,与对照非常不同的样品可能表现出高相关系数,而对照样样品可能具有低的成对相关性,这仅仅是因为经对数变换的相对强度在 0 附近,并且受噪声的影响大于强相对变化。
蛋白质-蛋白质相关性
蛋白质丰度的成对相关性可用于构建在全球范围内表征蛋白质/基因之间关系的相关性网络。我们可以计算所有蛋白质之间的相关性,将行为相似的蛋白质分组,找到各组之间的关系等等,这非常酷[5]!这是我们的大肠杆菌数据集的蛋白质-蛋白质相关矩阵,根据对数强度计算得出:
作者图片
看起来很迷人!正负符号相关性或多或少处于平衡状态,鉴于数据集的组成性质,这是可以预料的:随着一些蛋白质的相对强度下降,其他蛋白质也下降。较低的绝对值是普遍的,如果我们取相关矩阵,提取上面的三角形而不取对角线,展平阵列并构造直方图,这就变得很清楚了:
作者图片
我们预计蛋白质-蛋白质相关性不会受到重新缩放的影响。事实上,如果我们采用均值标度表并计算相关系数,分布结果是相同的:
作者图片
我们的原始数据矩阵包含 5 个不同的条件,每个条件 2 个重复。虽然观察组内重复的再现性很重要,但我们可以对重复值进行平均,并获得每个条件下每个蛋白质的单个值,用于进一步的生物学解释。从图片中移除生物可变性使得关联图更加清晰:
作者图片
正如我们之前讨论的,根据实验设计,数据集已被归一化为每个样本中相等的总丰度。如果没有执行标准化会发生什么?让我们模拟蛋白质丰度的系统偏差,假设 S02 的浓度测量值错误,我们采集了多余的材料,而 S04 和 S08 的平均强度较低,假设过滤单元在样品制备过程中悄悄泄漏:
作者图片
不规则是明显的,但也没那么糟糕吧?相比之下,相关矩阵的变化是剧烈的:
作者图片
作者图片
蛋白质在全球范围内变得高度相关!回到假设,我们让大多数蛋白质保持在几乎恒定的水平,当我们引入高于背景噪声水平的偏移时,它对受影响样品中的强度的影响最大。我认为这加强了在 LC-MS 数据处理过程中标准化的重要性:如果我们研究相似的样品并计算相同的蛋白质含量,我们最好确保样品平均值/中位数在结果数据集中没有偏差,因为我们的假设表明分布应该集中。
结论
我们已经查看了同量异位标记基于 MS 的蛋白质组数据中的样本-样本和蛋白质-蛋白质相关性,蛋白质表和 Python 代码可在 GitHub 上获得。我们已经讨论了数据的组成性质,这意味着在解释相关性时应该谨慎。样品间的相关系数受我们测量蛋白质值的方式影响很大,无论样品的性质如何,未经测量的报道强度的相关系数都非常高。蛋白质-蛋白质相关系数受到总样品丰度标准化的强烈影响。
参考
[1] N .劳尼亚尔和 J. R .耶茨,三。鸟枪法蛋白质组学中基于同量异位标记的相对定量 (2014),蛋白质组学研究杂志,13,12,5293–5309。开放访问。
[2] D .洛弗尔等人。比例性:相对数据相关性的有效替代 (2015),PLOS 计算生物学 11(3): e1004075。开放访问。
[3] J.J .奥布莱恩等人。组成蛋白质组学:空间限制对利用同量异位标签进行蛋白质定量的影响 (2018),J. Proteome Res. 17,1,590–599。根据 CC-BY license 开放访问。
[4]j . jerlstrm Hultqvist等 一种噬菌体酶诱导细菌代谢扰动,赋予一种新的混杂功能 (2018),Nat Ecol Evol 2,1321–1330
[5]朗菲尔德和霍瓦特。 WGCNA:用于加权相关网络分析的 R 包 (2008),BMC 生物信息学 9,559。开放访问。
相关性与因果性
原文:https://towardsdatascience.com/correlation-vs-causation-3e3481c71fef?source=collection_archive---------37-----------------------
比较相关性和因果性
Benjamin Behre 在 Unsplash 上的照片
相关性也称为关联。它指的是两个不同实体或数据点之间的关系。当一个事物上升时,另一个事物下降,反之亦然,这意味着它们一起变化。
让我们以一家跨国公司为例,该公司正在研究其过去 10 年的销售数据,这些数据包含每年以美元计算的销售额和不同的特征,如通过电视、广播和报纸投放的广告金额。
为了理解这些数据,我们创建了散点图,并发现所有这些特征都与销售额呈线性正相关。如果我们增加在这些广告上的花费,销售额也会增加,反之亦然。
来源(作者)
正如你在这里看到的,我们无法明确说明是销售导致了广告的增加,还是广告导致了销售的增加,或者是否有第三个因素导致了销售和广告的增加。这是因果关系的问题,因为在这里我们不能决定什么导致什么。
为了理解什么是因果关系,让我们举个例子。但在此之前,我们应该知道,因果关系是指由于某种原因导致的事情,如德里因 covid 病例增加而实行封锁。在这种情况下,我们可以说增加的 covid 案例导致了锁定。
让我们举一个例子,我们正在研究德里由于不同原因造成的事故数量,在这个数据集中,我们发现大多数事故发生在司机打电话的时候。那么,这是否意味着如果你在德里打电话,你会遇到事故?
答案是否定的。因为事故背后的主要原因可能是粗心大意或打电话时没有注意交通状况。我们需要明白,相关性是一个量化两个不同事物之间关系强度的数字量。而因果关系可以被认为是一个结论,它表明某事物引起了某事物。
因此,在预测特征和目标变量之间的因果关系和相关性之间的差异时,理解这一点非常重要。我希望读完这篇文章后,你能清楚地理解因果关系和相互关系。
本文是与 Piyush Ingale 合作的。
在你走之前
感谢 的阅读!如果你想与我取得联系,请随时通过 hmix13@gmail.com 联系我或我的 LinkedIn 个人资料 。可以查看我的Github*简介针对不同的数据科学项目和包教程。还有,随意探索* 我的简介 ,阅读我写过的与数据科学相关的不同文章。
余弦相似直觉及其 Python 实现
原文:https://towardsdatascience.com/cosine-similarity-intuition-with-implementation-in-python-51eade2674f6?source=collection_archive---------13-----------------------
包括使用余弦相似性公式的实际计算
图片由来自皮克斯拜的皮特·林福思拍摄
机器学习中经常会出现这种情况,你需要比较数据,分析它们有多相似。
例如,在自动文本摘要中,在训练期间,您需要识别原始文档中的哪些句子与参考摘要中的句子相似。评估摘要的质量也需要这样做。
或者你可能需要将一份文件分类,比如说,科学、育儿或技术。
一种用于计算两个文本之间相似度的技术叫做余弦相似度。
考虑下面的基本文本和其他三个文本。我想测量文本 1、文本 2 和文本 3 与基本文本的相似程度。
**Base text** Quantum computers encode information in 0s and 1s at the same time, until you "measure" it**Text1**
A qubit stores "0 and 1 at the same time" in the same way how a car travelling north-west travels north and west at the same time**Text2**
Considering how quickly the brain reorganizes, it’s suggested that dreams are a defence mechanism**Text3**
Computers will come with more processing power due to more advanced processors
你是怎么做到的?
文本变成了载体
这个案例很简单,可以帮助你清楚地想象它是如何工作的。
首先,你需要选择——在什么方面相似?!比如同样字数的两个文本相似吗?
这里有两个属性,或称为特征,我用来衡量相似性。
- 字数统计(无介词或冠词)
- 基础文本中的单词
图一。作为向量表示的文本。按作者。
这两个属性可以被认为是向量的元素,如图 1 所示。如您所见,X 轴和 Y 轴代表了这些特征。
这两个矢量之差形成一个角度。这个角度告诉你它们有多相似或不同。
0 度角=它们是一样的。
90 度角=它们彼此相反。
余弦相似性
虽然知道角度会告诉你文本有多相似,但最好是 0 到 1 之间的值。1 表示文本相同。
这就是余弦相似性出现的原因。这是计算它的公式。
图二。来源:https://en.wikipedia.org/wiki/Cosine_similarity
这里有一些数学让你玩得开心。
a 和 B 是两个文本的向量表示。分子 A . B 表示两个向量的点积。||A 或 B||表示矢量的大小。
让我们来计算其中一对——基础文本和文本 1。
Let A be the Base text vector = 11, 11
Let B be text1 vector = 4, 17**Dot product of A and B** = 11 * 4 + 11 * 17 (A first element times B first element + A second element times B second element)
= 44 + 187
= 231The magnitude is taken by squaring each element and adding them up, then taking the square root.||A|| = **√**11**² +** 11²
||B|| = **√**4**² +** 17²||A|| = 15.5563
||B|| = 17.4642||A||*||B|| = 15.5563 * 17.4642
= 271.6783Cos sim = 231 / 271.6783
**= 0.85 (85% similar!)**
Python 代码
代码很简单,特别是因为我使用了一个内置函数来计算余弦相似度。
Python 代码。来源: codebasics 。
结果如下:
结论
正如您在结果中看到的,文本 2 与基础文本不太相似。Text2 是关于梦的,和关于量子计算机的基础文字没有任何共同之处。
但是,你有没有注意到,有 70%的相似!?这不可能。
那是因为我选的功能不太对。单词特别重要。除非这是我真正想要的——字数相似的文本是相似的,主题无关紧要……这是对文本比较的一种奇怪的理解。
在以后的文章中,我将更多地探索现实世界中用于特性选择的技术。
感谢阅读。
延伸阅读:
https://medium.com/programming-for-beginners/the-other-approach-to-solve-linear-regression-90be71778b58 https://medium.com/programming-for-beginners/unsupervised-versus-supervised-machine-learning-1e55aeb3d2df
使用 Elastic Horovod 和 Amazon EC2 Spot 实例进行经济高效的分布式培训
原文:https://towardsdatascience.com/cost-efficient-distributed-training-with-elastic-horovod-and-amazon-ec2-spot-instances-599ea35c0700?source=collection_archive---------39-----------------------
理解大数据
根据员工系统的可用性动态调整您的培训课程
梁杰森在 Unsplash 上的照片
Horovod是一个流行的框架,用于在多个 GPU 工作人员和多个主机上运行分布式培训。在这篇文章中,我将解释如何使用 Elastic Horovod 来降低分布式培训环境中的成本,并演示在Amazon Elastic Compute Cloud(Amazon EC2)spot 实例上运行它所需的配置步骤。
本文包括四个部分。在第 1 部分中,我们首先描述如何使用 spot 实例来降低培训成本。在第 2 部分中,我们将讨论数据分布式训练,并介绍在多个 spot 实例上进行训练的挑战。在第 3 部分中,我们描述了 Elastic Horovod 解决这一挑战的方式,并阐述了解决方案的一些方面。在第 4 部分中,我们在 Amazon EC2 spot 实例上演示了一个弹性 Horovod 的例子。
我要讲的故事和我要分享的例子是基于 Gloo 0 . 21 . 2 版本的 Horovod、PyTorch 1.4 版本的 py torch 和 tensor flow 2.3 版本的。这些框架继续快速发展,一些 API 定义、使用流程和功能行为可能会发生变化。请务必重新评估我们将针对未来版本做出的任何假设和结论。
免责声明 1: 这篇文章的目的是引起人们对这个有趣而重要的新特性的注意。不一定推荐使用它。是否集成弹性 Horovod 应由多种考虑因素决定,其中一些我们将在下面讨论。
免责声明 2: 本帖绝不是为了取代弹性 Horovod 文档。我们将多次参考文档,详细阐述一些微妙之处,扩展其中一个示例,并演示一个端到端的示例。但是,对于您自己的任何实现,官方文档都应该是您的参考来源。
第 1 部分:使用 Spot 实例降低培训成本
现代 DNN 培训项目的主要挑战之一是管理培训成本。训练模型所需的硬件是昂贵的,考虑到我们经常需要运行多个训练实验,有时在多个设备上,不难看出成本会很快成为一个问题。
在云中进行培训时,降低成本的一个令人信服的方法是使用剩余云服务容量中的折扣计算引擎。在 AWS 中这些被称为 Amazon EC2 Spot 实例 ,在 Google Cloud 中它们被称为 可抢占 VM 实例 ,在微软 Azure 中它们被称为 低优先级 VM。这些产品的具体细节往往会有所不同,但共同点是它们都为未使用的计算引擎提供了显著的折扣。
代价是,与按需或保留实例相反,这些机器可能不可用(例如在高峰使用期间),即使成功获得,它们也可以在任何时候被抢占。因此,spot 实例可能不是时间关键型训练任务的好选择。但对于其他任务,它们可能会节省大量资金。
当然,需要考虑培训工作提前终止的可能性。没有人愿意花几个小时训练一个模型,只是为了在他们即将完成的时候让他们的训练机器被抢占。正如我在上一篇文章中描述的,我们可以通过在我们的训练应用中开发 容错 来防止这种情况。具体来说,通过定期存储模型检查点,我们可以确保终止的训练会话可以从最后存储的检查点恢复,而不是从头开始训练。存储检查点的频率应该通过权衡存储检查点的计算开销和在终止的情况下必须从最后存储的检查点重新运行训练的开销来确定。以高频率存储检查点将减少终止后恢复的开销,但是将增加存储模型权重的开销。以低频率存储检查点减少了捕获模型权重所花费的时间,但是在过早终止的情况下增加了更长时间重新训练的风险。
第 2 部分:通过数据分发加速训练
加速 DNN 开发的常用方法是执行数据分布式训练。在数据分布式训练中,我们在多个工作器(GPU)上并行训练我们的模型。多个工作者可以在单个设备上(具有多个 GPU),或者在多个设备上。在每个训练步骤中,每个工人训练不同批次的样本,然后与所有其他工人分享其结果梯度。用 N 表示工人的数量,分布式培训的效果是,我们在每个培训步骤结束 N 批培训。如果配置正确,这可以将模型收敛所需的步骤数减少 n 倍。
越来越多的趋势是在越来越多的(GPU)工作人员和越来越多的设备上分布模型(尤其是大型模型)的训练。自然,多台昂贵机器的使用放大了在低成本现场实例上培训的潜在节省。然而,在这种情况下,我们现在需要考虑多个训练设备中的任何一个上的现场中断的可能性。(一个有趣的问题是,使用超过 1/N 训练步数的 N 个设备是否会增加我们对现场中断的整体脆弱性。另一个有趣的问题是,一个实例的局部中断是否会增加其他实例的局部中断的可能性。虽然很难预测现场中断或计算其可能性,但您可以采用一些策略来减少对多个现场中断的脆弱性。有关该主题的更多信息,请参见此处的。)
在许多分布式训练框架中,包括 Horovod,在单个设备的现场终止的情况下,整个训练会话将失败。因为在 N 个工作线程的情况下,点中断的开销要高得多,所以增加捕获检查点的频率是有意义的(如上所述)。但是捕获每个检查点的开销也要高得多,因为现在有 N 个工作线程在捕获检查点期间暂停。
有人可能想知道,在多个训练设备的情况下,当只有一个设备被中断时,我们为什么需要终止整个训练会话。为什么训练不能简单地在剩余的设备上继续?这就是弹性 Horovod** 的用武之地。**
**https://horovod.readthedocs.io/en/stable/elastic_include.html
第 3 部分:弹性卵形线
在 Horovod 版本 0.20 中引入的 Elastic Horovod 支持动态增减工作人员的数量,而不会中断培训过程。特别是,如果您正在运行多个 spot 实例,并且其中一个实例被中断,您将无需(从最新的检查点)重新启动培训会话,从而节省大量时间(和成本)开销。当同一个 spot 实例恢复活动时(如果它被配置为“持久”),或者引入一个新的 spot 实例时,这也适用。在接下来的小节中,我们将讨论这个特性的一些方面。
有 Gloo 的 Horovod
弹性 Horovod 需要 Gloo 控制器来协调 Horovod 进程之间的工作。这与更常见的不支持弹性 Horovod 的 MPI 控制器相反。关于 Gloo 的更多细节,参见 Horovod 安装指南。
发现主机
为了支持动态伸缩,Elastic Horovod 需要一种发现主机设备的机制。这是通过用户定义的“主机发现脚本”提供的,该脚本被传递给 horovodrun 命令行。该脚本必须定义为输出可用主机的名称列表。更多详情见此处。下面是一个非常简单的主机发现 bash 脚本的示例,它遍历一个预定义的 IP 地址列表,并只打印从其中接收到成功 ping 响应的地址:
#!/bin/bash
hostArray=(
"10.0.1.20"
"10.0.1.21"
"10.0.1.22"
)
for host in ${hostArray[*]}; do
if ping -c 1 $host &> /dev/null
then
echo $host
fi
done
在实际场景中,主机发现脚本可能要复杂得多,并且将取决于您分配工作机的机制以及您如何为它们分配 IP 地址或主机名。
PyTorch 示例
下面是一个如何使用 PyTorch 和 Elastic Horovod 创建一个简单的训练脚本的例子。该脚本基于这里提出的模板,添加了缺失的功能。我们突出显示了与弹性 Horovod 相关的代码部分。
import torch
import horovod.torch as hvd
import torchvision.models as models
import torch.nn as nn
import torch.optim as optimhvd.init()
torch.cuda.set_device(hvd.local_rank())
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
lr = 0.001
model = models.resnet50(pretrained=True)
model.to(device)
loss_optim = nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr * hvd.size())
optimizer = hvd.DistributedOptimizer(optimizer)def get_random_batch():
batch_size = 2
data_in = torch.rand(batch_size, 3, 64, 64).to(device)
target = torch.zeros(batch_size).long().to(device)
return data_in, target# training loop must be wrapped by [@hvd](http://twitter.com/hvd).elastic.run
[**@hvd**](http://twitter.com/hvd)**.elastic.run** def train(**state**):
for **state.epoch** in range(state.epoch, 100):
print("Epoch", state.epoch)
for **state.batch** in range(state.batch, 100):
data, target = get_random_batch()
optimizer.zero_grad()
output = model(data)
loss = loss_optim(output, target)
loss.backward()
optimizer.step()
# commit the state at the end of each epoch
# see documentation for how to choose frequency of 'commit'
**state.commit()**
**state.batch = 0****def on_state_reset():
# adjust learning rate on reset
for param_group in optimizer.param_groups:
param_group['lr'] = lr * hvd.size()**# state object tracks and synchronizes state among the workers **state = hvd.elastic.TorchState(model, optimizer, batch=0, epoch=0)
state.register_reset_callbacks([on_state_reset])** train(state)
下面是如何使用 disover_host.sh bash 脚本运行 Elastic Horovod 的示例,每个主机设备包含 4 个 GPU(插槽),以及上面的 Python 脚本(我们将其命名为 train.py):
horovodrun -np **8** \
--min-np **4** \
--max-np **12** \
--host-discovery-script **discover_hosts.sh** \
--slots **4** \
python **train.py**
在本例中,一旦有 8 名工人可用,培训就会开始,只要有 4 名工人可用,培训就会继续,并且在任何给定时间,培训的工人都不会超过 12 名。
弹性态物体
培训工人之间的同步由弹性状态对象管理。该对象封装了需要在工作线程之间同步的所有变量,包括模型权重、优化器变量、epoch 和批号。
状态对象包括用于备份训练状态的提交功能。这是一个自动防故障装置,旨在防止由于某个工作线程意外崩溃而导致状态损坏的可能性。类似于上面讨论的关于选择检查点捕获频率的难题,决定提交训练状态对象的频率是在减少失败情况下从最后一次备份重新训练的开销和提交动作的开销之间的权衡。我们的目标应该是配置我们的环境,使意外崩溃的可能性极小,并将提交减少到最低限度。例如,我们可以依靠 AWS 现场中断通知来确保发现脚本以优雅的方式处理现场中断,并避免意外的连接故障。
关于弹性 Horovod Keras API 的重要提示:使用 TensorFlow Keras 训练时,弹性状态承诺通过hvd . Elastic . commitstatecallback回调进行管理。注意这个回调的默认行为(如 elastic keras 示例所示)是在每批之后提交。这将大大降低你的训练速度。为了避免这种情况,在回调构造函数中指定一个 batches_per_commit 值。
重置回调函数
重置回调函数负责根据培训人员的添加或删除对模型配置进行更改。需要特别注意训练可能依赖于全局批处理大小的超参数,尤其是优化器参数。许多流行的优化器(如 Adam )的性能取决于全局批处理大小的值。如果在训练期间全局批处理大小发生变化,而没有对优化器设置进行适当的调整,则训练收敛可能会受到负面影响。 Elastic Horovod 文档建议根据活动工作者的数量来调整学习率(如上面的 PyTorch 示例),或者使用对工作者数量变化不太敏感的优化器(如 Adasum)。另一个选项是修改每个工作线程的本地批处理大小,以便不改变全局批处理大小(假设 GPU 内存允许这样做,并且不会导致 GPU 资源利用不足)。但是不能保证这些技术就足够了。在调整弹性训练之前,您应该验证您的训练算法能够处理工人数量的变化,而不会损害收敛。
数据划分
执行多员工数据分布式培训时,需要做出的一个决定是如何在不同员工之间分配培训数据。在弹性训练场景中,这个决定有些复杂。如果您选择对数据进行分割,使每个工作人员在独立的数据子集上进行训练,那么您可能希望在每次工作人员数量发生变化时对数据进行重新分区,以确保每个数据样本都受到相同的关注。
通过定义每个工作者在整个数据集的随机洗牌上进行训练,可以避免随着拓扑的每次变化而更新数据集的需要。虽然这种策略中的数据采样结果可能与分片的情况有很大不同(例如,在训练过程中给定样本的外观不一定像分片的情况那样均匀分布),但在许多情况下,它不会影响训练的收敛能力,尽管您可能希望在自己的模型上验证这一点。
主机排除策略
弹性 Horovod 包括一项相对严格的政策,将变得不响应的员工排除在外。(在撰写本文时,Horovod 源代码将此功能称为“黑名单”。)这可能会对训练环境造成限制,在训练环境中,主机可能会被中断,但稍后会以相同的 IP 地址或主机名恢复。在撰写本文时,有一个开放拉取请求旨在放松这一政策,这将有望进入即将到来的版本。在任何情况下,您都可能需要通过覆盖默认行为来自定义排除策略。
调度员的脆弱性
弹性 Horovod 将使您能够从任何主机系统的故障中恢复,除了使用 horovodrun 命令运行培训会话的主机。如果这台主机出现故障,整个培训课程将会终止。
为了增加系统的容错能力,你可以在一个不可抢占的设备上运行 horovodrun 命令,比如一个按需 AWS EC2 实例。为了降低成本,您可以将该设备指定为专用调度程序,而不需要其自身的任何 GPU 工作程序。然而,这种方法有一个潜在的问题。当前 Horovod 代码中内置了一个假设,即所有设备的网络接口名称都是相同的。虽然在相同的 GPU 工作设备上确实经常是这种情况,但在非 GPU 设备上可能不是这样。我们将在下一节中看到这样的例子,我们将在 EC2 实例上演示弹性 Horovod。
有一个开放的特性请求来解决这个问题,所以希望这个问题会在未来的版本中得到解决。与此同时,您可以尝试重命名网络接口,或者尝试以下简单的解决方法(hack):打开 launch_gloo_elastic 函数中的horovod/runner/gloo _ run . py .创建一个 dispatcher_nics 列表以及现有的 nics 列表,并将此列表传递给后续的 network.get_driver_ip 调用,而不是如中所示的 nics
nics = get_common_interfaces(driver)
**dispatcher_nics=['ens5']**
server_ip = network.get_driver_ip(**dispatcher_nics**)
另一个要考虑的选项是将 GPU 设备的子集配置为按需实例。虽然这种解决方案可能成本更高,但它具有额外的优势,即使在零现场实例可用性的情况下也能确保持续培训。
弹性射线
Ray 是一个构建分布式应用的流行框架,支持启动云集群和自动集群扩展。Elastic Horovod 包括与 Ray 的集成,可以用来简化环境设置。参见文档了解如何轻松扩展您的脚本以使用 Ray 功能。
第 4 部分:Amazon EC2 Spot 实例上的弹性 Horovod
在本节中,我们将在 Amazon EC2 集群上演示一个端到端的弹性 Horovod 示例。特别感谢我的同事 Max Rabin 对这一部分的帮助。
有许多不同的方式来配置和启动云集群,包括高级 API(比如 Ray )。我们选择使用 boto3 Python API 来演示实例创建,但是该示例可以很容易地适用于其他方法。
步骤 1:创建 EC2 Spot 实例
我们从启动三个 p2.xlarge spot 实例主机设备和一个 c5.xlarge 按需实例开始,它将充当我们的调度程序。我们选择了单个 GPU 设备(即插槽=1),但在现实世界中,与主机数量更多、每个主机的插槽数量更少的情况相比,主机数量更少、每个主机的插槽数量更多(例如 p2.8xlarge)的情况下,您通常会获得更好的性能。
在下面的代码块中,您可以找到如何创建三个 GPU spot 实例的示例。要创建 dispatcher 实例,只需将 count 设置减少到 1,将实例类型更改为 c5.xlarge,,并删除 InstanceMarketOptions 设置。记下创建调用返回的实例 id,因为这些 id 可用于从命令行管理实例。
import boto3
ec2 = boto3.resource('ec2', region_name="us-east-1")
instances = ec2.create_instances(
MaxCount=3, MinCount=3,
ImageId='ami-072519eedc1730252',#replace with ML AMI of choice
InstanceType='p2.xlarge',
SubnetId='<subnet id>', # <-- fill this in
IamInstanceProfile={'Arn':'<InstanceProfile>'}, <-- fill this in
SecurityGroupIds=['<SecurityGroupIds>'], <-- fill this in
InstanceMarketOptions={
'MarketType': 'spot',
'SpotOptions': {
"SpotInstanceType": "persistent",
"InstanceInterruptionBehavior": "stop"
}
}
)
print(instances)
对于我们的图片 ID,我们选择了最新的 Ubuntu 18.04 AWS 机器学习图片。下面是提取最新图像的命令行代码片段。
aws ec2 describe-images --owners amazon \
--query 'Images[?Name!=`null`]|[?starts_with(Name,`Deep Learning AMI (Ubuntu 18.04)`) == `true`].[ImageId,Name,CreationDate]' \
--output text | sort -k2 | tail
第二步:SSH 设置
Horovod 依赖于调度员和所有工人之间的无密码 SSH 通信。要设置这个,使用一个记载的机制连接到 EC2 实例。在 dispatcher 上创建无密码的 SSH 密钥,并将公钥复制到每台主机设备上。有关详细信息,请参考下面的链接。
https://linuxize.com/post/how-to-setup-passwordless-ssh-login/
在真实的场景中,这一步应该是自动化的。
第三步:作为 Ubuntu 用户,激活虚拟环境并安装 Horovod
需要在所有实例上执行此步骤。
source activate pytorch_p36
pip install --upgrade pip
HOROVOD_WITH_GLOO=1 pip install --no-cache-dir horovod
在 dispatcher 上运行 ifconfig 以查看网络接口的名称,并按照上一节所述更新horovodrun/runner/gloo _ run . py文件。
步骤 4:配置 discover_hosts.sh 脚本
将我们在上面创建的 discover_hosts.sh 复制到 dispatcher 实例上,并用三个主机实例的 IP 修改 hostArray。
确保该脚本是可执行的,并且其目录在$PATH 环境变量中。
步骤 5:使用 horovodrun 进行 PyTorch 训练
将上面的 PyTorch 脚本复制到每个主机设备,并运行以下测试:
测试 1 —主机添加 : 停止三台主机中的一台。这可以通过 Amazon EC2 仪表板或使用 AWS CLI 来完成:
aws ec2 stop-instances --instance-ids i-<id1>
在有两个活动主机的调度程序上运行horovudrun:
horovodrun -np **2** --min-np **1** --max-np **3** --host-discovery-script **discover_hosts.sh** --slots **1** python **train.py**
在培训运行时,启动第三个 EC2 实例(从仪表板或 CLI),验证培训会话是否识别了添加内容,并将第三个实例添加为培训主机。
aws ec2 start-instances --instance-ids i-<id1>
测试 2 —主机移除:由于我们无法确定现场终止的时间,我们将通过简单地停止其中一台主机来模拟。像以前一样,开始对所有三台主机进行训练,经过几个训练步骤后,停止其中一台主机。验证是否已识别出移除操作,以及培训会话是否能够仅使用剩余的两台主机继续进行。
请注意,我们刚刚执行的主机移除会被视为不合适的,并且会导致故障主机被添加到排除列表中。(如果您使用相同的 IP 重新启动同一台机器,它将不会被重新添加到相同的培训课程中。)在真实的场景中,应该增强主机发现机制,以确保优雅地处理现场中断。
测试 3——将运行时间与非弹性 Horovod 进行比较:您可能有理由希望验证增加的功能不会带来任何额外成本。为此,将运行时与非弹性运行进行比较:
*horovodrun --gloo \
-np 3 \
-H server1:1,server2:1,server3:1 \
python train.py*
测试 4 —测量提交频率的影响:使用弹性状态提交的频率来测量对训练运行时的影响。
第六步:清理
不要忘记在工作结束时删除所有 EC2 实例。
这可以通过 EC2 仪表板或使用 AWS CLI 来完成:
*aws ec2 terminate-instances --instance-ids i-<id1> i-<id2> ...*
摘要
Elastic Horovod 是 Horovod 的一个引人注目的新特性,它支持在可抢占实例集群上进行训练,而没有在设备中断时必须从检查点重新开始训练的潜在开销。这种解决方案可以在对培训进度影响最小的情况下,显著降低培训成本。然而,Elastic Horovod 可能不是每个团队和每个项目的最佳解决方案。时间关键型任务通常最好在完全可靠的按需实例上运行,即使对于非关键型培训任务,您也应该验证收敛性不受动态变化的工作人员数量的影响。祝你好运!**
人工智能会有情感吗?
原文:https://towardsdatascience.com/could-an-ai-ever-feel-emotions-797a5719e5a4?source=collection_archive---------36-----------------------
人工智能概论系列的第 4 部分
情绪、感觉和 AGI。资料来源:Tengyart via Unsplash 。
随着意识程度的每一次增加,绝望的强度也成比例地增加:意识越多,绝望越强烈。
-索伦·克尔凯郭尔
欢迎来到探索人工智能系列的第 4 部分(AGI)!如果你错过了前三部,在这里看看,从第一部开始。本周我们将着眼于一个情绪和感觉的模型,并试图解开和分离一些非常复杂和误用的术语。
具体来说,本周我们来看看并解决这些问题:
- 什么是情绪和感情?
- 在 AGI 语境中,动机、驱力、情感和感觉之间有什么区别?
- AGI 人能像我们一样体验事物或感受事物吗?
下周我们将关注意识本身:我们认为它是什么,它与情绪和感觉有什么关系,以及人工智能和 AGI 将如何迫使人类进行一些严肃的反思,到底对人类意味着什么…
在这个系列中,每周/每隔一周会有一个新的帖子出现(我希望如此),如果有问题、评论或澄清,可以随时给(mferg@mit.edu 发电子邮件。尽情享受吧!
免责声明:毫无疑问,有些人更有资格对我将涉及的问题和主题进行深入的讨论,从情感到神经形态计算。对于这些人来说,这个系列只是对这些主题的介绍,因此,如果为了简洁而省略或浓缩了一些内容,请见谅。我真的只是想要这个系列,以及激发它的课程,作为一个相关 AGI 主题的调查,这些主题通常在学习人工智能或人工智能时不会被教授。还要注意:这个系列与麻省理工学院或其品牌没有任何关系——我只是喜欢写一些我感兴趣的东西,麻省理工学院并不正式认可这里陈述的观点。
第一部分:什么是情绪和感受?
它们是一样的吗?不一样?有点相同又有点不同?
“我们的每一次呼吸,我们的每一步,都充满了和平、快乐和宁静。”
―一行禅师
正如与本系列中的大部分概念一样,情绪和感受的定义也有很多,很多时候是可以互换使用的,甚至在研究论文中也是如此。理解所指的到底是什么经常令人困惑,因为在用词上也没有固定的一致。我在阅读论文时经常遇到这种困惑,即使这样,仍然很难确切知道作者在想什么。然而,这并没有阻止我们,所以现在也不会。让我们试着解开一些术语。
来自麻省理工学院认知科学百科全书[1],一种 情感 是:
在目标管理中起作用的心理状态或过程。
就这样?这听起来与本课程第 1 部分中人工智能研究人员如何看待智能本身的定义惊人地相似,我们将很快重新审视这种联系。本质上,情绪的核心是准备好以某种方式行动;这是一种紧迫感,或者说是一种将一些目标和计划优先于其他目标和计划的方式。情感和意识的主要研究者安东尼奥·达马西奥说:
情绪是复杂的,很大程度上是由进化炮制的自动化行动程序。这些行动是由一个认知程序来补充的,这个认知程序包含了某些想法和认知模式……[2]
让我们再深入一点。查尔斯·达尔文对情绪的用途有一些想法,并认为情绪表达是退化器官如阑尾的行为等价物[1]。因此,根据达尔文的解释,情感是我们过去进化的残余,现在已经没有任何用处了。然而,现代心理学之父威廉·詹姆斯认为情绪是身体对事件的生理反应的感知(根据现代研究,我们会看到他倒过来理解,但非常接近)。
心理学家西尔万·汤姆金斯认为,情绪实际上是有目的的,它们是特定动机系统的放大器。情感也可以被视为人类在无限的问题空间中做出决定的一种方式。这不是一个无关紧要的问题,这应该会引起任何人工智能研究人员的兴趣——情绪作为一种选择的方式,或者更好的是,最显著的刺激;它们是区分优先次序的一种方式。他们根据目标来促进某些选择;生活中完全理性的选择很少。[1]更一般地说, 情绪引导行为 。这也被称为体细胞标记假说(稍后会有更多内容),由达马西奥提出。
假设你是几千年前非洲大草原上的原始人。你有多种刺激争夺你的注意力,从你原眉上烦人的虱子到河对岸有吸引力的伴侣,再到近在咫尺的装满蜂蜜的蜂巢。你关注哪个?在这种情况下,以上都不是,因为相反你很快看到一只老虎向你扑来,而恐惧成为你情绪中最突出的部分(不是欲望、饥饿或原眉平衡)——它帮助你的大脑优先考虑最重要的生存方面。如果你死了,你就不能吃蜂蜜或交配,所以情绪是一种管理你所关注的,甚至是记忆的方式。
情绪是一种筛选生存所需刺激的方式。来源:Ian Keefe Via Unsplash
所以,在很大程度上,情绪为了这个系列可以被认为是对刺激的自动反应。它们是伴随着想法和特定思维模式的行动。把情绪想象成大脑和身体对某些刺激的反应,比如皮质醇增加,杏仁核处理增加等。像恐惧这样的情绪。[2]我们拥有它们的最大原因之一是作为决策的启发。[1]例如,当你不得不在一大群观众面前演讲时(如果你不喜欢公开演讲),你的情绪反应会是皮质醇增多、出汗、肾上腺素增加、视野狭窄、血压和心率加快等。因此,基于[1]和[2],如果你听到情绪这个词,那么思考对刺激的生理反应。
感情呢?它们是什么?根据达马西奥[2]:
“感觉主要是对我们的身体在情绪激动时所做的事情的感知,以及对我们在那段时间的精神状态的感知。”
因此,感觉可以被认为是身体的头脑/大脑在表达情感时的感知。害怕公开演讲 感觉 像什么?它可能因人而异,但在大多数情况下,大的,高层次的感觉是相同的。他还指出,在没有思维过程的生命中,情感可以存在并且很好,但是情感感觉可能不存在。他还指出,对人类来说,感情[2]:
…发布“认知资源的状态和某些心理脚本的部署”
这基本上意味着当你“有情绪”时,你会以不同的眼光看待这个世界,期待不同的事情。如果我开了几个小时的车,感到烦躁/疲劳,与我无处可去/无事可做相比,我对交通堵塞的体验是完全不同的。我们对他人的看法,我们喜欢什么,容忍什么,不喜欢什么,讨厌什么等等。所有的变化都基于我们的心情——也就是我们的感觉。
因此,在很大程度上,感觉可以被认为是一系列随着时间推移而展开的情绪感知,其中它们改变了人的精神状态并导致 体验一种情绪 像悲伤,像我们体验悲伤时的感觉(疲劳、分散等)。).把这看作是一种“更多精神”的成分,而不是“更多物质”的情感。情绪是生理反应,而感觉是你对它们的感知,它们让你有怎样的感觉。**
这里有一个例子,我希望它能使这种区别更加清楚。让我们看看每个人都希望经历的事情:爱。爱是一种情绪还是感觉?在这种情况下,我要说它是一种感觉,因为你知道体验爱的物理成分是什么样的:唤起(血流、眼睛眯着、体温升高)、舒适(皮质醇减少、血清素增加)、平静(血清素增加、催产素)、结合(催产素)等..所以在这种情况下,体验情绪的感觉就是感觉本身。
爱:一种感觉还是一种情感?来源:维多利亚罗马 via Unsplash 。
还记得那句话“ ”是什么感觉……”。我们回头再来看,我们会看到在过去的几个世纪里,这句话引发了多少场辩论。好了,根据达马西奥的观点,我们有了一个区分感觉和情绪的起点,以及它们各自是什么。请注意,显然还有其他关于情绪的理论,只是在细节上有所不同,但它们的目的和区别的高层次结论大体上是相同的。查看丽莎·费尔德曼-巴雷特和约瑟夫·勒杜的作品,深入了解更多。
第二部分:合成情绪和合成感觉
在人工智能/AGI 中实现情感/感觉
“我可以给你四万个理由来证明那个太阳不是真实的。我知道它是因为发射器的瑞利效应与其建议的大小不成比例。我知道它是因为它的恒星周期比真正的恒星更对称。尽管如此,我永远也不会知道它看起来是不是真的……感觉是不是真的。”
Cortana,光晕 4
现在,我们有了一个情感和感觉的坚实的起始模型,你如何在一个合成智能系统中编程/实现它们(无论是人工智能还是 AGI)。首先,情感在机器中会是什么样子?嗯,我们可以看看一些系统,他们已经实现了决策启发式,我们会的,但首先,一些更多的信息。
回到 1967 年,认知心理学家/人工智能先驱希尔伯特·西蒙(他将在 8 年后获得图灵奖,以及 1978 年的诺贝尔经济学奖,谈谈他的简历吧!)认为,因为资源是有限的,所以在任何复杂环境中运行的任何计算系统都需要一些能够中断正在进行的过程的系统来管理规划[2]。再一次,考虑到我们刚刚讨论的内容,这肯定会敲响警钟。对于你们这些铁杆计算机科学家来说,这或许可以被认为类似于操作系统中的内核,因为它负责管理文件和进程、访问、异常、虚拟内存和分页等…
人工情感会是什么样子?嗯,你必须有一些管理过程、资源和目标的方法,以及对它们进行优先排序的方法。这些已经在像 LIDA 这样的认知架构中实现了(我们将在几周后再次讨论),但是在没有身体的头脑中更难实现。许多认知架构都有一个模块专门用于目标优先化、,许多架构还有一个模块专门用于“躯体”记忆的形成、提取和重建。然而,很难说这些是否应该被认为是真实的情绪,因为,从技术上来说不是身体反应(因为没有身体——令人毛骨悚然,对吧?),然而(但是如果该架构是在一个实体介质上实现的,则可能有一个)。最后,在需要学习和发展的情况下,人工情感将被证明是最有价值的动机工具。
LIDA 的赛拉托尔·斯坦·福兰克林展示了它[3]:
“对 LIDA 体系结构的这个案例研究似乎表明,人工感觉和情感可以预期在软件代理或机器人中最有用,其中在线学习对象、类别、关系、事件、事实和/或技能是最重要的。如果这个要求存在,那么通过人为的感觉和情绪来实现主要动机也是有意义的。”
人造的“情绪”已经存在于一些软件中。来源:Arseny Togulev viaUnsplash
他说的“主要动机”是什么意思?这里有一个很好的分类:
- ****动机可以被认为是促使一个代理做事情的原动力,比如口渴、饥饿、疲劳和他们的主要行动。
- ****驱力是主要的动机,通常被认为是“最终目标”,比如“繁衍后代”,或者“活下去”。
- ****值是长期动机,通常被实现为损失函数,并且独立于环境或内部状态。
- ****情绪,也是感觉,可以认为是对价值成就/忽视/否定的一种反应。
这有很多术语(听起来都一样),但这里最重要的一点是,合成智能可能会优先考虑/追求不同层次的概念,情绪和感觉在其中扮演(或可能扮演)关键角色。我们绝对会探讨一致性问题(如何让一个合成智能做你想让它做的事情)和目标问题,但这并不像说“AGI 只会做它想做的事情”或“AGI 只会做我们告诉它的事情”那样明确…
第三部分:AGI 人能经历事情吗?
这种“感觉”是什么意思?
“创造一个讨厌你的东西,是不是很奇怪?”
―艾娃,不包括玛奇纳
感情和主观体验的问题,曾经是计算机科学、认知科学和哲学的眼中钉,现在它也将成为你的眼中钉!不客气
我想重温一下之前的那个“是什么样子的”短语。这在哲学上有个名字:感受性。来自麻省理工学院[2]:
"感受性最常用于描述精神状态的定性的、经验的或感觉的特性."
简而言之,感受性是离散的“感觉”时刻。感受性的一些例子包括:
- 放下车窗快速驾驶汽车的感觉
- 你的狗舔你的胳膊
- 晚上把小腿撞在咖啡桌上
- 对日落的感知
- 甜甜圈的味道
- 书店的味道
- 在棒球场的泥土上玩耍
- 上课无聊透顶
啊,甜甜圈。生命中最伟大的礼物之一。来源:杆长 via Unsplash 。
基本上,有无限多的感受性,可能我的感受性和你的略有不同——我喜欢芫荽叶和咖啡冰淇淋(不是一起),但你可能不像我一样喜欢它们,或者可能讨厌它。因此,我们的感受性可以相似,但极有可能不同。
然而,你可以否认感受性的存在,许多哲学家也是这样做的,因为它们只不过是复杂神经网络的神经化学反应。如果你接受感受性的存在,那么你就是在说 知道一切 知道精神状态(知道所有关于神经元和它如何产生主观性)和 体验 某事之间是有区别的。强调这一点的经典论点/例子是玛丽的房间思想实验(我们下周会看,但如果你感兴趣,这里有概述)。如果你拒绝感受性的存在,那么你就是在说[2]:
"除了可以通过功能或偶然的特征来解释的内容之外,我们的定性概念没有确定的、连贯的内容。
丹尼尔·丹尼特(1991 年)
这到底是什么意思?他的意思是,如果你知道所有关于大脑的事情,那么你就会知道经历某事是什么感觉,因为你知道大脑是如何引起它的。也就是说,在大脑过程之外没有什么额外的东西——感受性不是大脑的一些深奥或神秘的额外组成部分——相反,它们只是大脑的产物。下周我们将更深入地探究感受性,因为它与意识密切相关。
为什么或艾人关心感受性?qualia 是否存在可能意味着简单地关掉超级笔记本电脑和真正的谋杀之间的区别——消除一个能够忍受痛苦和经历的心灵。
没有人会在意你是否摧毁了一些没有意识的东西,比如石头,但是社会倾向于看不起那些摧毁有意识意识的人。这就引出了这个系列最重要的一个概念:主观体验以及一台机器是否能拥有它们。我们将在下周讨论这个问题,从下周开始,当我们讨论意识的时候。
更一般地说,这就是人们通常提到“有意识的机器”或“有感觉的机器”时的意思——一个拥有感受性并且能够感觉到的 AGI。于是,抛回之前的话题,感情=情绪+感受性。这是一个简单的等式,但在很大程度上是成立的:)****
TL;速度三角形定位法(dead reckoning)
情绪和感受是不一样的。情绪可以被认为是对刺激的生理反应,而感觉是你对这些情绪的感知。情绪可以被认为是一种启发,用来判断一个头脑应该做什么,有一些系统已经实现了这种“情绪启发”来帮助解决问题。最后,感受性和感觉密切相关,因为感受性通常被定义为“它是什么样的”下周,当我们试图解决意识问题时,会有更多的内容。
二元划分。来源:约书亚·富勒通过 Unsplash 。
“造物主,我从我的泥土里请求过你吗
塑造我的人,我恳求你吗
从黑暗中提拔我?"
——玛丽·雪莱,《弗兰肯斯坦》,引用弥尔顿的《失乐园》
其他需要考虑的问题:
- 你认为我们应该试着把感情编程成一个 AGI 吗?****
- 你认为 AGI 人必须有感情才能生存吗?
- 你觉得一个有感情的 AGI会想要什么?**
关于作者
Mike Ferguson 是麻省理工学院 DiCarlo 实验室的计算研究开发人员。他将致力于大脑评分,这是一种测量人工神经网络有多像大脑的工具。他将于 2021 年春天从弗吉尼亚大学毕业,获得计算机科学和应用数学学士学位,以及认知科学和哲学学士学位。他是《一周挑战》一书的参与者,在两年内阅读了超过 138 本关于人工智能、哲学以及对人类意味着什么的书籍。他和他的伯恩山犬“博伊·温斯顿”以及收养的边境牧羊犬“影子”住在弗吉尼亚州的夏洛茨维尔。
参考资料:
- 罗伯特·威尔逊和弗兰克·凯尔。麻省理工学院认知科学百科全书。麻省理工学院出版社,1999 年。
- 安东尼奥·达马西奥。自我浮现在脑海中:构建有意识的大脑。万神殿图书公司,2010 年。
- 富兰克林,斯坦和乌玛·拉马姆西。"动机、价值观和情感:一枚硬币的三面."第六届表观遗传机器人国际研讨会会议录,法国巴黎,2006 年 9 月,隆德大学认知研究。№128.2006.
Kubernetes 豆荚会被废弃吗?
原文:https://towardsdatascience.com/could-kubernetes-pods-ever-become-deprecated-e8ee6b4b8066?source=collection_archive---------21-----------------------
Pods、服务或部署等资源会被弃用并从 Kubernetes 中删除吗?这将如何发生?
照片由 Gary Chan 在 Unsplash 上拍摄
在任何软件项目中,随着时间的推移,会添加新的特性和 API,有时它们中的一些也会被弃用并最终被删除。即使是像 Kubernetes 这样的大型项目也不例外,但是当考虑弃用和最终移除时,并没有真正想到其 API 的核心部分。因此,问题是 Kubernetes 中的核心对象或 API,如 Pod、部署或服务,是否可以删除?如果可以,如何删除?
长话短说
如果这个问题的答案是“否”,那么这篇文章就没有存在的理由了,长话短说— “是”—GA 中的任何核心 API 对象,例如来自v1
API 组的某些东西都绝对会被弃用。
这个简单的一般答案并没有告诉我们太多。当谈到弃用时,Kubernetes 区分了几种类型的对象,例如 REST APIs、CLI 或特性门。它们中的每一个都有自己的一组不同成熟度的对象,如 alpha、beta 或 GA。所有这些都决定了某个对象——甚至像 Pod 这样的东西——在多长时间内以及在什么条件下会被弃用。所以,让我们更仔细地看看每一个,以及一些过去的例子和一些假设的未来可能发生的例子。
说来话长
不同的规则适用于不同的对象/功能,因此在我们讨论弃用规则和时间表之前,让我们先看一下所有不同的对象组:
- REST 对象——我们最感兴趣的部分——REST 对象或 REST APIs 涵盖了我们最经常交互的所有东西,即——顶层对象,如 Pods 或 Deployment,它们的模式字段,如
containers
、volumes
或env
,以及用于imagePullPolicy
的常量,如Always
、IfNotPresent
和Never
。 - 标志或 CLI—第二个最相关的组涵盖所有 CLI。这里最明显的是
kubectl
,但它也包括像kubelet
、kube-apiserver
或kube-scheduler
以及它们所有的子命令和标志。 - 特性/行为 —并不是所有的东西都可以用 API 准确标记或者成为 CLI 的一部分。还有整个系统的行为以及不同成熟度的实验特征。这些也需要(并且有)自己的弃用流程和时间表。
- 指标 —最后,Kubernetes 还公开了许多关于各种服务的
/metrics
端点的指标。考虑到它们中的许多被用于例如监控,它们也不能随时被改变或删除,所以它们有自己的一套规则。
剩余对象
对于 REST APIs 或对象,一般规则是在宣布弃用后,API 版本必须至少支持:
- GA: 12 个月或 3 个版本(以较长者为准)
- 测试版:9 个月或 3 个版本(以较长者为准)
- Alpha: 0 版本
这听起来很简单,但是还有许多其他的(不太容易理解的)规则适用于这里,所以让我们直接看一个例子,这样应该就清楚了。让我们假设一个名为 Task 的 API 对象(有趣的事实——这实际上是 Pods 的原名——参见 Kubernetes 的 first commit)。这个任务在 API 版本v1
中是 GA,并且决定它应该被弃用,那么真正会发生什么呢?
从上表中可以看出,如果在 API 版本v2alpha1
中任务对象被弃用,那么它还需要 9 个版本才能从 Kubernetes 中真正消失。让我也提醒你,以目前每年 3 个版本的发布节奏,整个弃用过程将需要 3 年以上!
然而,你应该考虑所有不是 GA 的对象,然而我们都在使用它们,就好像它们是 GA 一样。一个这样的例子是 Ingress,它在 1.19 才成为 GA,或者最近在 1.21 成为 CronJob。在这种 beta 甚至 alpha 特性的情况下,折旧时间表就不会这么慷慨了。如果您想检查某些资源属于哪个类别,您可以运行例如kubectl api-resources | grep beta
获取集群中所有测试 API 的列表。
几乎相同的规则适用于整个 REST API 对象及其字段、常量值或对象结构。这意味着我们都用来表示imagePullPolicy
的Always
、IfNotPresent
和Never
等常数不会凭空消失或随机变化,同样,字段也不会从一个部分移动到另一个部分。
至于一些现实世界的例子— PodSecurityPolicy 可能是最近历史上最大的一个。该 API 对象将从 v1beta1 升级到 EOL,从 1.21 版开始已被弃用,并将在 1.25 版中被移除。有关详细信息,请查看 KEP-2579 。
另一个重要的最近/正在进行的弃用是移除selfLink
字段。这是 KEP-1164 的一部分,在这个 GitHub 问题中也对这一变化进行了跟踪。
如果你想知道还有哪些反对意见,他们的理由是什么,或者他们的整个删除过程,那么你可以搜索kubernetes/enhancements repository中提到的“反对”,你会找到所有相关的 KEPs。
标志或 CLI
类似于 REST 对象,kubectl
或kubelet
子命令或它们的标志也可以被弃用,因此有自己的策略。
这比前一种情况简单得多。这里,对于面向用户的组件,例如kubectl
,策略是:
- GA: 12 个月或 2 个版本(以较长者为准)
- 测试版:3 个月或 1 个版本(以较长者为准)
- Alpha: 0 版本
对于面向管理的组件,如kubelet
、kube-apiserver
或kube-scheduler
,它是:
- GA: 6 个月或 1 次发布(以较长者为准)
- 测试版:3 个月或 1 个版本(以较长者为准)
- Alpha: 0 版本
这方面最近一个大的例子是dockershim
,它是kubelet
的一部分。以下章节概述了其弃用和移除,其中包括移除计划的整个章节,该计划将版本 1.20 列为弃用目标,版本 1.24 列为移除目标。
这方面的另一个显著变化是seccomp
配置文件将正式发布,在本 KEP 中概述。seccomp
配置文件实际上不是对标志或任何 CLI 的直接更改,但是将它们正式发布需要弃用kubelet
标志--seccomp-profile-root
,此处标注为
因此,本节的底线是 CLIs 的弃用时间表也相当宽松,但是如果您使用一些kubectl alpha ...
命令来实现自动化,那么您最好在升级您的集群甚至 CLI 二进制文件/工具之前检查弃用情况。
特征门
在任何时间点上,Kubernetes 都包含了许多实验性的特性。这些功能由所谓的功能门控制,这些功能门是我们可以用来打开或关闭它们的键/值对。
考虑到特性门用于实验特性,它们的弃用策略不同于其他 Kubernetes 对象。此外,随着特性经历成熟阶段,其门的行为也会发生变化。对于 alpha 特征,默认情况下门是禁用的;对于测试版功能,默认情况下是启用的;并且当特征达到 GA 状态时,门不再需要,并且变得废弃和不可操作。
至于弃用和移除这些功能所需的时间——alpha 功能可以随时消失,beta 功能在 1 次发布后(如果它们被移除)或 2 次发布后(如果它们进入正式版状态)就会消失。
如需具体示例,您可以点击查看功能门的完整列表。例如,您可以看到AffinityInAnnotations
功能从 alpha 版本升级到了弃用版本,对于一直升级到 GA 版本的功能,我们可以列出BlockVolume
、DryRun
或EndpointSlice
。至于功能在测试阶段后被弃用的情况,我找不到任何证据。
如果您决定打开其中的任何一个,请确保在升级集群之前检查它们的状态变化,尤其是在集群升级之后可能会消失的 alpha。
韵律学
列表中的最后一种对象是指标,在弃用时也需要保留相当长的时间,因为它们中的许多都是由监控工具消耗和聚集的。与前几节不同,指标只分为两类。在这里,我们只有稳定和 alpha 指标,其中稳定指标可能会在宣布弃用 3 个版本后被删除,而 alpha 指标可以随时被删除。
关于已弃用和已删除指标的示例,您可以看看这个删除了rest_client_request_latency_seconds
指标的提交。您还可以在 1.17 版本的发行说明中找到它,以及其他一些变更/废弃的指标。
如果您想了解关于指标生命周期及其组成部分的更多信息,您可以查看此文档页面。
结论
如今,似乎许多项目更多地采用了一种“快速移动和打破常规”的方法来弃用,同时频繁地进行大量更改,因此很高兴看到像 Kubernetes 这样的大项目具有经过深思熟虑的弃用过程,这为用户从计划要删除的 API 和功能中迁移出来留出了大量时间。
那么,这篇文章的要点是什么呢?—有什么东西会被废弃吗?— 是。你应该担心吗?——明明没有。由于一些折旧时间表很长,没有真正的理由担心东西突然被拿走。也就是说,你可能应该查看发行说明,留意所有你可能会用到的 alpha 特性,就好像它们是正式版一样。你也可以查看废弃的 API 迁移指南,它列出了所有将在未来某个时候被移除的 API。最后要注意的是——这些都不一定适用于 CRD——对于外部供应商开发的 CRD,您必须检查他们自己的策略,因为他们可以对其应用程序/集成/解决方案为所欲为。
本文最初发布于martinheinz . dev
https://itnext.io/hardening-docker-and-kubernetes-with-seccomp-a88b1b4e2111
机器学习有可能预测到 GameStop 的疯狂吗?
原文:https://towardsdatascience.com/could-machine-learning-have-predicted-gamestop-madness-aae8d9f7f77e?source=collection_archive---------18-----------------------
因为数据也有话要说…
马克西姆·霍普曼在 Unsplash 上的照片
我非常怀疑到今天为止你仍然不知道过去几天 GameStop 发生了什么。但是,假设你不知道。那没问题,除了一些头条,我也没有。像任何其他被误导的人一样,我决定阅读一些文章来了解正在发生的事情。经过进一步的调查,我被这个现象的名字震惊了。出现了一个新名词:“模因股票”。
我不想详细描述发生了什么,因为有很多信息,你会从其他伟大的、更有见识的作家那里找到更好的解释。但是,嘿,一个简短的概述不会伤害任何人。
GameStop 是一家中型零售商,没有什么特别之处。上周它的股票从 20 美元涨到了 400 多美元。最令人印象深刻的是,没有任何关于他们新的创新战略的消息,也没有关于他们销售的令人难以置信的报告,也没有他们聘请了 500 名数据科学家在他们的业务中使用人工智能。没什么。
股价上涨仅仅是因为 Reddit 中的协调小组决定投资它。
如果你想知道更多的原因,请在此之后再做,我会为你重新定向一些很棒的资源。如果你从这里开始,你可以和我一起试着用股市数据来理解这一点。
作为一个有一定金融知识的数据科学家,我会全程指导我的思考过程。我们将深入研究这个问题,像任何其他问题一样,思考是否可以使用机器学习来预测发生的。
股票市场数据
谈到股票市场,这有点令人生畏:市场上有数万亿种策略和指标,只有少数几个“定量分析师”可以声称知道所有这些。如果你不是其中之一,那你来对地方了!。我不认为你在这里需要任何这方面的知识。我将通过一些关于市场提供的最相关信息的直观解释来指导你,这对你理解将要发生的事情应该绰绰有余。
在我们继续之前,有必要介绍两个术语:数量和价格。在它们上面你会找到预测股票市场所需的大部分信息。 成交量 是指在特定时间范围内买入或卖出的资产数量。 价格 反映了——不出所料——交易的平均价格。
像任何其他数据科学问题一样,我们应该从查看数据开始,以便更好地理解上下文。感谢 yfinance ,我们可以收集数据,使用 mplfinance 我们可以顺利地将价格和交易量结合在一个可视化界面中。在下图中,你会发现 GameStop 的股票。
图片作者。这里的代码。
这里我想让你注意两件事。首先,价格非常稳定,并且在缓慢下降。第二, 成交量一直没有很高,直到现在 。这一点非常重要,因为我希望大家关注音量。让我们把上个月的情况放大一点。
图片作者。这里的代码为。
1 月 13 日成交量大幅增加。该股当天收盘时,价格几乎翻了一倍。在接下来的日子里,交易量逐渐减少,在 1 月 22 日达到最大值。
如果我们看到这一点,我可能会认为,在接下来的几天里,成交量一次又一次地推高了价格。但你可能会说,“不是数量,而是人”。
数据科学家实际上做的是检查数据是否反映了一些潜在的现实。
在这里,数量增加的原因是集体的、协调的努力,而不是数量本身。但一旦成交量实际增加,数据揭示出“有事”正在发生的信息。
不可否认的事实是,其他人用成交量来投资。正是在那里, 你已经失去了真正原因 的每一条线索。你无法知道这只股票因为 Reddit 的影响涨了多少,又因为不寻常的成交量涨了多少。对我们来说幸运的是,交易量还在,它还在给我们关于价格的有价值的信息。
仅仅看一个案例可能是不够的。读得多一点,我意识到这种事以前也发生过。对于赫兹:
图片作者。这里的代码是。
柯达。
图片作者。这里的代码是。
诺基亚。
图片作者。这里的代号。
还有 AMC。
图片作者。此处代码。
图案与 相同。前所未见的交易量和难以想象的价格。
为了让您看到典型图表的样子,我将显示亚马逊的股价和成交量。
图片作者。这里的代码是。
差异令人震惊。一只普通的股票会振荡,但是成交量在一个很小的区间内。不寻常的库存达到最低值的 50 多倍。
在没有将问题框架化为机器学习问题的情况下,我永远不会假设体积是决定性的预测变量。上面的想法只是指出可能有用的信息。
预言;预测;预告
那么,我们想预测什么呢?如果我们想仅用市场信息来预测一次反弹, 我们可以做得更好,因为价格和交易量都反映了 原因。预测下一个“迷因股票”这样不可预测的事情是不可能的。但是,更有意义的是在它一发生就预测它。一个“早期发现”就足够了。因此,我们需要检索的数据应该是低间隔的。
那么,使用什么类型的机器学习类型呢?后者非常重要,因为尝试对超低发生率事件使用监督学习可能不是最佳方法。尽管如此,无监督学习也有自己的分支 异常检测 。发现异常现象并不一定意味着股票会上涨,但肯定会告诉我们是否有什么奇怪的事情正在发生。
为此,我们将使用过去两个月的 5 分钟间隔数据(由于 API 限制)。我们将用前 40 天来训练模型,以检查模型是否能检测出奇怪的行为。这是为了 模拟 我们在 1 月 12 日将我们的模型投入生产。
直接使用价格和数量作为特征是很有诱惑力的。但一只股票可以上涨很多,这不一定是异常现象。出于这个原因,使用连续观测值之间的差值更安全。我们将使用不同的特征,包括成交量、价格和一些交易者常用的指标,每一个都与有所区别。 ta 包创造指标太棒了。**
K-means 是一种迭代定义质心的算法,试图最小化每个数据点与定义的质心之间的距离。您最终得到一些质心,聚类被定义为最接近特定质心的一组数据点。
对于这种情况,想法是观察训练数据中数据点和聚类之间的距离。然后,使用 25 个最大距离的平均值作为参考,如果来自预训练聚类的距离比参考大三倍,则我们将其宣布为异常。重要的是,我们将使用三个聚类来训练模型,只考虑最小的距离。
我们为每一只想要分析的股票训练一个模型。让我们先从 TSLA 开始,让你明白这个想法。第一种颜色表示训练数据,第二种颜色表示测试数据。异常的形状将是菱形。
****注:在下面,你会找到特斯拉股票的代码。你只需要改变其他情况下的参数。此外,可视化要求您在运行之前使用正确的参数运行以下代码。
图片作者。这里的代码是。
下面是另一个使用谷歌股票的例子。
图片作者。这里的代码是。
无论是特斯拉还是谷歌,我们都没有发现任何异常。这很有趣,因为这些股票的行为相当活跃。在这里,我们可以推断该模型能够理解有规律的运动,因为新的数据点从未离开预训练的质心太远。
GME 的故事
好了,现在是时候记住我们最初的问题了。这是可以预测的吗?。让我们从 1 月 11 日 GME 的最后一次训练数据开始模拟。想象一下,你负责这个模型,你看到如下。
图片作者。这里的代码为。
1 月 12 日没什么奇怪的。但是在 1 月 13 日和 14 日,你会得到大量的异常,与其他数据点的质心的距离看起来比正常的一天要远。看到这里,你开始想,我应该采取行动吗?。下周再说吧。
图片作者。这里的代码是。
19 日,出现了一些异常,你会有点担心,但仍然没有决定性的东西。的确,在那之后,你会在 20 日和 21 日有两天没有异常。也许一切又恢复正常了,你可以暂时放松一下。但是在 22 日下午,一切都变得疯狂了。几乎你收到的每一个新数据点都是异常的。记住,在每个数据点之间,你有 5 分钟的时间。想象你自己一遍又一遍地接收这个信息超过 2 个小时。
距离几乎达到了我们定义的阈值的三倍。显然,“有事”正在发生。但是是时候看看一切都失控的那一周了。
图片作者。此处代码。
视觉效果会自己说话。上周只有异常。
最后,整个画面。
图片作者。这里的代号。
机器学习可能预测到 GameStop 的疯狂吗?
给定最后的信息,是时候回答我们最初的问题了。我想围绕机器学习算法的可能性展开讨论。在上一节中,我们看到,甚至在股票达到最高价的两周前就发现了异常。
这是否意味着我们可以预测到这一点? 绝对不是 。
我们发现了一些异常,在我们观察它们的同时,价格也在上涨,但这并不一定能告诉我们,股票在未来肯定会上涨或下跌。我们必须非常小心异常现象代表了什么。
股票价格由复杂的交易算法甚至更复杂的人类行为所控制。上周,有一件事情变得很清楚,那就是试图预测社会现象是最具挑战性的任务之一,因为它取决于许多因素,其中大多数甚至不可能作为数据检索。
使用的方法证明了股票正在经历一些不寻常的情况,仅此而已。我们需要的不仅仅是机器学习算法来预测上周发生的事情。也许一个拥有这些信息以及更多信息的金融专家可能已经预料到了这一点。但是,机器学习模型本身完全依赖于它们所接受的应用程序。
最后的想法
使用异常检测方法,我们发现这个事件在成为现实之前揭示了一些线索。需要进一步的调查来确定这是否真的可以在其他场景中工作。
比技术讨论更重要的是,我认为我们应该分析股票市场的缺陷。人们一直拥有这种力量,但它从未以这种方式使用过。监管机构目前正在谴责这种行为,但现在是时候真正深入研究大型对冲基金的做法了。您刚刚看到了使用公开信息(如价格、交易量和一些指标)来检测异常是多么容易。想象一下监管者的可能性,因为他们有更多的详细信息。
我确信 机器学习将成为监管者 的最佳盟友之一。现在他们的工作是迈出第一步。
再见
我真的希望这个博客能让你感兴趣。如果你喜欢就跟着我!很快会有更多内容!。
我也在 Linkedin 和 Twitter 上。我很乐意与你交谈!如果你想多读一点,看看我最近的一些帖子:
**
承诺的文章
https://marker.medium.com/gamestop-proves-were-in-a-meme-stock-bubble-b3f39163a77f https://www.denofgeek.com/games/gamestop-gme-nokia-amc-hedge-fund-stock-market-wall-street-memes/ **
海王星真的能取代木星吗?
原文:https://towardsdatascience.com/could-neptune-really-replace-jupyter-9a90d6432325?source=collection_archive---------11-----------------------
非交互式笔记本的 Neptune 包概述
https://pixabay.com/images/id-2947880/
介绍
去年 10 月,我看了一个名为 Pluto.jl 的 Julia 包。Pluto.jl 是一个用于 Julia 编程语言的笔记本服务器,它有许多独特的功能,使它在竞争中脱颖而出。由于我主要是一个 IJulia 用户,我当然会将这个解决方案与 Jupyter 笔记本进行比较。从很多方面来说,我相信笔记本之间是互相打击的。然而,我在 Pluto.jl 和它背后的想法上遇到了一些根本性的问题,这使得我个人的笔记本比 Jupyter 上的更不实用。如果你想看那篇文章,你可以在这里看:
我发现在我使用 Pluto.jl 的经历中,它比我使用过的任何其他解决方案都要乏味得多。我要再次指出,这是我的选择,不是一揽子计划的错。然而,我发现笔记本的反应性质经常会妨碍任何代码单元的执行。这很难处理,因为在理论上,Pluto.jl 听起来很神奇。笔记本是反应式的,因此不存在会降低笔记本可复制性的状态问题。这种担忧是我从我最喜欢的机器学习爱好者之一 Joel Grus 那里继承来的,他也是我最喜欢的一本来自 O'Reilly 的书的作者。直接引用 Grus 的话,
"我们可以通过简单地改变这些单元格的执行顺序来完全误导我们的输出."
当然,这样的概念对于科学这样的东西来说是非常可怕的,尤其是在创造可重复的研究方面。Pluto.jl 试图通过添加反应特性来解决这个问题,但在我看来,它没有足够有效地跟上你正在做的事情,因此有点不足。此外,必须开始和结束任何多行单元也是相当乏味和烦人的。尽管反应功能在这方面失败了,但我认为冥王星笔记本还有很多其他可取之处。这就是 Neptune.jl 拿蛋糕给我赢的地方。
海王星
Neptune.jl 是冥王星笔记本的一个新的修改,它的主要目的是成为冥王星而没有反应功能。这意味着在 pure Julia 中使用笔记本单元的能力现在是可能的,而不必处理 Pluto 在您和您的代码之间的反应。这对我来说是可取的,因为我们可以有效地切断 Python 作为 Julia 语言和内核之间的桥梁,而完全使用纯 Julia。
更令人兴奋的是海王星和冥王星笔记本如何保存文件。Neptune 文件不存储在包含一堆 JSON 数据的 IPython 笔记本中,这些数据告诉 Jupyter 如何解码所有的细胞。相反,Neptune 文件被安全可靠地存储,嵌套在一个. JL 文件中,markdown 单元格被制成多行字符串。对我来说,这是一个相当大的卖点,利用像海王星或冥王星比 Jupyter 笔记本电脑。此外,这可能是一个巨大的进步,因为现在我们可以将应用程序和笔记本放在同一个文件中。不仅如此,我们的应用程序可以立即被很好地记录,因为我们所有的注释现在都保留在其中。JL 文件!我们总是可以通过用 Julia 调用它来运行这个文件。我们甚至可以包括它,这是一个朱莉娅文件!在这方面,Julia 文件将比笔记本文件更加多样化。
我对此唯一的担心是从不同的应用程序查看这款笔记本电脑。有几次我在 Github 里面查看一个笔记本的源码。这对于海王星或冥王星来说是不可能的。然而,我认为在大多数情况下查看 Julia 代码实际上是合适的,而且只要不使用 show()方法来显示 HTML 或图像,这甚至可能是 Github 的首选。
Neptune 还做了一些其他的改变,但是为了检验这些改变,我们需要添加带有 Pkg 的包。有一段时间,这个包在 Julia General registry 中不可用,但现在它已经注册了,我们可以通过 Pkg REPL 添加它。
julia > ]
pkg > add Neptune
现在我们将导入 Neptune 并使用 Neptune.run()方法来启动一个新的笔记本服务器。
using Neptune; Neptune.run()
(图片由作者提供)
如果您曾经使用过 Pluto.jl,您可能会认出这个主屏幕,因为除了中间的文本之外,它完全相同。在这里,我们也能很好地描述海王星到底是什么。Neptune 是一个笔记本服务器,它遵循 Jupyter 提出的思想,这是该软件包的灵感来源,但该服务器也由 Pluto.jl 的一个分支提供动力。
创建一个新的笔记本,我们很快看到来自 Pluto.jl 的反应无处可见——对我个人来说,这是一个非常令人愉快的景象。然而,我仍然感到沮丧的一个问题是无法使用 shift+enter 热键来创建新的单元格。很容易理解为什么不是这样,我认为在执行之前测量这样一个单元格的输入来检查热键输入可能会导致比它实际价值更多的麻烦。也就是说,我确实相信大多数数据科学家都非常频繁地使用这个热键,所以我认为这肯定是一个令人沮丧的事情。在我看来,每次我想添加更多代码的时候,都要把手伸向我的鼠标,这是令人难以置信的乏味。
将输出置于输入之上的风格选择也是我有意见的。我觉得这很荒谬。输出是输入的直接结果,并且总是在输入之后,我们不从下到上阅读页面,所以输出在单元格之上没有多大意义。我一直认为细胞没有运行,而实际上它们运行了,输出只是在细胞的上面而不是下面。当然,这是对 Pluto.jl 的抱怨,不是对 Neptune.jl 的抱怨,而是 Neptune.jl 是 Pluto.jl 的分叉,意味着它也继承了它的问题。然而,我要说的关于海王星的一件消极的事情是,这个图标真的很丑。对于这样的东西,这听起来可能是一个糟糕的批评,确实如此,但我更希望没有这样的评论,而不是有一张后面有白色背景的图片,它的长宽比是错误的。
幸运的是,有一个东西已经从 Neptune.jl 中删除了,它在 Pluto.jl 中。这个删除的特性是我在 Pluto.jl 中所鄙视的,它无法创建没有开始和结束的多行代码单元格。很容易理解为什么会这样,我想这可能是由于 Pluto.jl 保存文件的方式。然而,我发现每当我想写一行新的代码时,都需要写 begin 和 end,这很烦人。有趣的是,实际上我可能是建议这种改变的人,所以我非常高兴看到它在海王星如此完美地度过。
结论
本着开源的精神,我们收到了一个 Pluto fork,我相信它对原来的笔记本进行了很多戏剧性的改进。虽然 Pluto.jl 中的许多概念都很酷,但我认为它们中的许多也妨碍了 Julia 编程。在很多情况下,我对将反应作为笔记本的一部分感到非常恼火。我认为,反应实际上仍然是一个伟大的想法,但可能仍然需要一些肘油脂和智能编程投入其中,以真正显着。
那么问题来了,这真的能代替 Jupyter 笔记本和 IJulia 用于 Julian 数据科学吗?现在,我不得不说我的答案是否定的。我这么说的主要原因是因为 Neptune.jl 仍然有一些从冥王星遗留下来的输出错误。有时,输出就是不出现——当然,这可能会令人沮丧。我认为. jl 文件中的笔记本的概念确实很吸引人,我确信有一天我能看到像这样的笔记本解决方案很好地工作。然而,不幸的是,今天可能不是那一天。写这篇文章实际上让我想创建我自己的笔记本服务器,以便创建我想要的样子。那肯定会是一个有趣的项目!
虽然我认为海王星对我个人来说是一个更好的解决方案,但我仍然会坚持使用 IJulia。不幸的是,我认为冥王星有一些缺陷会带到海王星,但这两个包肯定都有未来——这让我很兴奋!我认为只要稍作调整,这两款笔记本服务器都可以很好地替代 Jupyter。然而,我要说,我认为这在很大程度上取决于个人偏好。我只是碰巧更喜欢 Jupyter 而不是这两个软件包,其他人可能不会有同样的感觉,所以我鼓励读者尝试这两种笔记本电脑,并自己决定哪个更好!感谢你的阅读,我希望这篇文章能帮助你找到最好的笔记本来写 Julia!
如何计算 Python 中列表项的出现次数
原文:https://towardsdatascience.com/count-occurrences-of-python-list-item-e87782d8954c?source=collection_archive---------21-----------------------
了解如何在 Python 中计算特定列表元素的出现次数
斯蒂夫·约翰森在 Unsplash 上的照片
介绍
统计列表元素在 Python 中出现的次数绝对是一项相当常见的任务。在今天的简短指南中,我们将探索几种不同的方法来计算列表项目。更具体地说,我们将探索如何
- 统计单个列表项出现的次数
- 对多个列表项的出现次数进行计数
我们将展示如何使用特定的列表方法或借助collections
模块来实现这两者。
首先,让我们创建一个示例列表,我们将在本指南中引用它来演示一些概念。
>>> my_lst = [1, 1, 2, 3, 1, 5, 6, 2, 3, 3]
>>> my_lst
[1, 1, 2, 3, 1, 5, 6, 2, 3, 3]
计算单个列表项出现的次数
当计算一个特定元素在列表中出现的次数时,你的第一个选择是[list.count()](https://docs.python.org/3/tutorial/datastructures.html#more-on-lists)
方法。例如,为了计算1
在列表my_lst
中出现的次数,您只需运行以下命令
**>>> my_lst.count(1)**
3
或者,你甚至可以使用collections
模块附带的Counter
类。collections.Counter
class 是dict
的子类,用于统计可散列对象。本质上,它是一个集合,用于观察计数的元素是否存储为字典键,以及它们对应的计数是否存储为字典值。
>>> from collections import Counter
>>>
**>>> Counter(my_lst)[1]**
3
计算多个列表项出现的次数
现在,如果你想计算多个条目在一个给定列表中出现的次数,你有两个选择。
第一种选择是在 for 循环中调用list.count()
。假设您想要计算列表元素1
、3
和5
在我们的列表中出现的次数。您可以这样做,如下所示:
>>> lookup = [1, 3, 5]
>>> **[my_lst.count(e) for e in lookup]**
[3, 3, 1]
或者,您可以使用collections.Counter
类,在我看来,它更适合计算多个项目的出现次数。
如果您想要计算列表中每个元素出现的次数 ,那么您可以简单地创建一个Counter
的实例。
>>> from collections import Counter
>>>
**>>> Counter(my_lst)
Counter({1: 3, 2: 2, 3: 3, 5: 1, 6: 1})**
如果您想要统计 元素子集在列表中出现的次数,那么下面的命令将会完成这个任务:
>>> from collections import Counter
>>>
**>>> lookup = [1, 3, 5]
>>> all_counts = Counter(my_lst)
>>> counts = {k: all_counts[k] for k in lookup}**
>>> counts
{1: 3, 3: 3, 5: 1}
最后的想法
在今天的简短指南中,我们探索了几种不同的方法来计算 Python 中列表项的出现次数。我们展示了如何使用列表方法count()
或collections.Counter
类来计算一个或多个列表项的出现次数。
成为会员 阅读介质上的每一个故事。你的会员费直接支持我和你看的其他作家。你也可以在媒体上看到所有的故事。
https://gmyrianthous.medium.com/membership
你可能也会喜欢
https://medium.com/geekculture/use-performance-visualization-to-monitor-your-python-code-f6470592a1cb </16-must-know-bash-commands-for-data-scientists-d8263e990e0e> </4-amazingly-useful-additions-in-python-3-9-732115c59c9d> [## Python 3.9 中 4 个非常有用的新增功能
towardsdatascience.com](/4-amazingly-useful-additions-in-python-3-9-732115c59c9d)
机器学习模型的反事实评估策略
原文:https://towardsdatascience.com/counterfactual-evaluation-policy-for-machine-learning-models-f58acba19647?source=collection_archive---------24-----------------------
如何监控其行为阻止我们观察地面真相的模型?
监控任何系统的目标都是跟踪其健康状况。在机器学习的背景下,跟踪我们在生产中服务的模型的性能是至关重要的。当我们的模型不再新鲜,需要重新训练模型时,它可以帮助我们通知。它还可以帮助我们在欺诈检测等案件中检测滥用行为,在这些案件中,可能有敌对行为者试图损害模型。
卢克·切瑟在 Unsplash 上的照片
缺乏基本事实标签
为了监控模型的性能,我们需要将它们的预测与真实标签进行比较。然而,一个模特的行为往往会阻止我们观察地面的真相。
要了解原因,请考虑信用卡欺诈检测模型的示例。我们将使用它作为本文的运行示例。它预测每一笔交易要么是欺诈,要么不是欺诈。应用程序代码现在通过阻止预测的欺诈交易来对这些预测进行操作。一旦事务被阻塞,我们就无法观察如果让它通过会发生什么。这意味着我们无法知道被阻止的交易实际上是否是欺诈性的。我们只能观察和标记我们允许通过的交易。换句话说,我们只能观察到非阻塞事务的偏态分布。
问题
我们模型预测的一部分缺乏基础事实标签,这引入了两个主要问题:
- 如何在生产中持续监控模型的健康——也就是说,检查模型的精度和召回率等指标?
- 如何才能做好模型的后续再训练?在部署模型的第一个版本之前,我们有一个代表真实世界分布的数据集。然而,在未来,有可能只训练那些被允许的例子,因为那些例子有一个基本的事实标签。这意味着我们只能在一个偏斜的分布上训练,这个分布不同于每次再训练的真实分布。随着时间的推移,这可能会导致模型的性能逐渐下降。
为了评估和重新训练我们的模型,我们希望在没有我们干预的情况下,样本和它们的标签有一个近似的分布。
目标
让我们定义我们的目标—我们需要一项政策,让我们:
- 评估模型在生产中的性能
- 为将来的再培训生成公正的培训数据
反事实评估政策
为了实现我们的两个目标,我们让一小部分本来会被阻塞的事务通过审查。我们姑且称这个分数为P(allow)
。
回到我们的欺诈检测示例,这意味着允许一小部分预测的欺诈交易通过。这些允许的交易可能有实际成本,但这是在生产中拥有健康模型所要付出的代价,并且这种做法在行业中被广泛采用。
在缺乏反事实评估策略的情况下,我们的模型逻辑可能如下所示。当模型得分大于阈值时,模型预测该交易是欺诈,我们决定阻止它。
**if modelScore > 0.5:
block()
else:
allow()**
这是用P(allow) = 0.1
修改后的逻辑。我们允许 10%的交易,否则我们会阻止。对于这 10%的交易,我们能够观察到真实的标签。
**if modelScore > 0.5:
if random.random() < 0.1:
allow()
else:
block()
else:
allow()**
获得无偏估计
让我们举一个例子,看看我们如何计算精度和召回率。这里P(allow) = 0.1
。在 1000 个例子中,该模型预测 100 个例子是欺诈。因为我们的反事实评估政策,我们还是让 10 个通过了。通过观察这些交易上的真实标签,其中 8 个被证明是真正的欺诈。
一个示例场景。图片作者。
精确
使用这种方法,只需使用 review 事务就可以直接计算精度。精度只是我们的审查交易中实际上是欺诈的一部分。
精度 =审查欺诈/审查交易= 8 / 10 = 80%
回忆
要计算召回率,首先需要估计欺诈交易的总量,包括模型捕获的交易量和交易总量。被模型捕获的欺诈交易可以通过用因子 10(即1/P(allow)
)对审查交易进行加权来估计。这样做是因为每个被阻塞的事务(但被随机选择不阻塞)在某种意义上代表了 10 个事务。
模型捕获的预计欺诈交易 =审查欺诈* 1/P(允许)= 8*(1/0.1) = 80
估计的总体欺诈交易量 =模型捕获的估计欺诈交易量+其他欺诈= 80 + 40 = 120
回忆 =模型捕获的预计欺诈交易/预计总体欺诈交易= 80/120 = 66.67%
培养
可以在 910 允许的交易上进行训练,这是我们知道基本事实的交易。对 900 个预测非欺诈交易使用权重 1,对 10 个审核交易使用权重 10(即1/P(allow)
)。这为训练数据创建了无偏的数据分布。
使用自定义倾向函数
我们可以为P(allow)
定制一个倾向函数,而不是一个常量。背后的逻辑是,我们可以将更多的审查预算用于不太“明显”的欺诈交易。
如果分类器对一项交易给出 1 分,则可以相当确定该交易是欺诈。另一方面,如果分数是,比如说,0.49 或 0.50 或 0.51,则不太确定,我们处于决策边界。有了上面的策略,不管分数如何,都允许以相同的比率审查交易,但在某种意义上,分数越大,就越有信心。为了优化有限的审查预算,明智的做法是在结果不太确定的地方,即在决策界限内,花费更多的预算。
为了做到这一点,可以使用P(allow)
的倾向函数来代替之前的统一阈值。P(allow)
将与分数成反比,这样它允许更多的交易接近边界,更少的交易接近 1。同样,这里为了训练和召回估计,我们将为我们决定允许的事务添加一个权重1/P(allow)
。
优势
这可以更有效地利用有限的审查预算,减少总体欺诈事件的发生。更不确定的交易是那些被审查更多的交易。我们试图在探索和利用范例之间找到一个理想的平衡。这有很强的理论背景。
不足之处
一个高权重的交易被错误分类将会极大地改变我们的估计。这可能会导致估计值出现很大差异,并使它们变得不可靠。在实践中,这可能是一个巨大的问题。
最后的想法
如果您正在开发一个可能会影响观察到的基本事实值的新模型,那么在生产中首次部署之前,必须考虑一个反事实评估策略。这将使您能够监控您的模型,并为再培训提供无偏见的数据分布。从倾向函数的简单统一阈值开始,只有在情况需要额外的复杂性时才超越它。
强化学习的反事实 I:“如果……会怎样?”
原文:https://towardsdatascience.com/counterfactuals-for-reinforcement-learning-i-what-if-d70188fb83c2?source=collection_archive---------9-----------------------
思想和理论
POMDP 框架和反事实简介
在哲学中,一个反事实思维实验问:“如果发生的是 A 而不是 B,会发生什么?”。从这种假设的考虑中获得对现实世界的洞察力是人类智慧的一个重要方面。
这个由两部分组成的系列将探索如何在强化学习框架内模拟反事实思维,以及这如何有助于创造更安全的代理。在这第一部分,我将奠定数学基础,在下一部分,我将解释如何将反事实应用于奖励函数学习的设置。这个系列是独立的,唯一的要求是理解强化学习,特别是马尔可夫决策过程。如果你想了解更多关于反事实研究的动机,你可以看看我以前的文章,关于强化学习的学习奖励函数的问题。
部分可观测马尔可夫决策过程
我们知道,马尔可夫决策过程(MDP)包括
- 状态的集合
- 答:动作的集合
- t:在给定一个状态和一个动作的情况下,确定下一个状态的概率的转移函数
- r:奖励函数,给状态和动作的历史分配一个分数
MDPs 中的时间通常以离散的时间步长来度量,代理在时间步长 t 的动作 a(t)跟随在同一时间步长的观察状态 s(t)之后。使用 R,一个代理因状态和动作序列 o(1)a(1)o(2)a(2)…而得到奖励,目标通常是使奖励最大化。为此,我们寻找一个策略,它是一个从状态到行为分布的函数,并决定代理的行为。
MDP 是一个多功能模型,是强化学习的核心。然而,有时使用更精细的模型是方便的。例如,一个代理的传感器可能无法明确区分某些状态。你可以将此建模为 MDP,其中状态对应于对真实状态的信念。这就是计算机程序的实现方式。但在数学上,用所谓的部分可观测马尔可夫决策过程(POMDP)来表达这种不确定性更容易。给定一个 MDP (S,A,T,R),POMP 增加了两个额外的元素:
- ω:可能的观察值的集合
- o:状态观测函数,给出给定环境状态下的观测值的概率分布。
在 POMDP 中,代理看不到真实的状态。相反,代理的输入是一个使用 o 从状态中概率确定的观察值。
为了稍后讨论反事实,我还需要定义历史:POMDP 上的历史 h 是观察和动作的序列 h = o(1)a(1)o(2)a(2)…其中 o(n)和 a(n)代表 POMDP 的时间步长 n 上的观察和动作。因为我所说的 POMDP 总是很清楚的,所以我将使用类似 P(h)的符号来表示在给定的 POMDP 中看到历史 h 的概率。P(s(n) = s)将用于谈论时间步长 n 处的状态是特定状态 s 的概率。相反,P(a(n) = a)是代理在时间步长 n 处采取行动的概率。
让我们考虑一个如何将问题建模为 MDP 的例子。在我们的场景中,代理参加一个游戏节目,并在两扇门中选择一扇门来赢得奖品。其中一扇门后是现金奖励,但如果代理人选择错误,他们就不得不空手而归。这个模型的基础环境很简单:有两个潜在的初始状态,表示为 s(l)和 s(r ),分别对应于奖品在左门或右门后面。可用的操作是打开任一扇门:a(l)代表左侧,a(r)代表右侧。根据我们的初始状态,在选择一个动作后,代理将转换到赢得现金奖励 s(\()的最终状态,或者什么都没有 s(N)。让问题变得棘手的是,代理人不知道他从哪个初始状态开始。两个初始状态对应于相同的观测值 o⁰,而最终状态导致 s(\))的不同观测值 o 和 s(N)的不同观测值 o。
gameshow 问题的 POMDP。图片由作者提供,灵感来自【2】
在这个 POMDP 上有四个可能的历史:o⁰a(r)o、o⁰a(r)o、o⁰a(l)o 和 o⁰a(l)o。为了最大化他们获胜的机会,代理人想要一个策略,最大化创建以观察值 o 结束的历史的概率。由于第一个观察值总是 o⁰,唯一的变量是代理人在第一个时间步中采取的行动 a,所以我们在寻找概率 P(o⁰ao)。但是,挑门会导致中奖的概率是由第一态 s(1)的真性情的概率决定的:p(o⁰a(r)o)= p(s(1)= s(r))p(a(1)= a(r))p(o⁰a(l)o)= p(s(1)= s(l))p(a(1)= a(l))。用不太数学的术语来说,当选择正确的门时获胜的概率与奖品在右边并且代理打开右边的门的概率相同,对于左边的门也是一样。如果我们假设获胜的门是由 gameshow 跑步者随机选择的,那么 P(s(1) = s(r)) = P(s(1) = s(l)) = 0.5,代理不能通过选择 a(1)的概率比随机做得更好。
这个难题就是反事实发挥作用的地方。如果我们假设选择左边的门会导致失败,那么推断状态 s(1)的真实性质是微不足道的,我们需要选择右边的门才能获胜。我们如何用数学方法对此进行编码?
POMDPs 上的反事实概率
为了正确解释 POMDPs 上的反事实,我首先需要解释一些潜在的假设。通俗地说,反事实推理可以用这样的陈述来表达,“如果是 X 的情况,那么我们可以推断 Y”——在我们的例子中,这变成了“如果是选择左边的门什么也没有导致,那么我们可以推断选择右边的门导致奖励”。就 POMDs 而言,X 和 Y 是关于历史的陈述:“如果反事实历史 h '已经发生,那么我们可以推断历史 h 具有这种可能性”。然而,在没有进一步假设的情况下,不可能从 h '推断出 h。在我们的例子中,反事实的历史将是 h' = o⁰a(l)o。通过使用“常识”,知道 h '将如何进行让我们推断出 P(o⁰a(r)o ) = P(a(r)),因此代理人应该设置 P(a(r)) = 1。然而,在数学上,时间步长 1 处的观测 o⁰可以指示 s(1) = s(r)或 s(1) = s(l),因此最终 P(o⁰a(r)o 归结为 s(1)的概率分布。
数学结果与我们的“常识”预期不同,因为我们还没有对潜在的假设进行编码,即除了我们改变的行为之外,世界上所有其他事实都保持不变。具体来说,这包括我们改变事物时的世界状态。因此,我们需要假设 h 和 h '仅在时间步长 t 之后才发散,因此到那时为止,它们的观察和动作是相同的。我们将使用 h(t)来表示由 h 和 h’共享的直到步骤 t 的历史。此外,我们需要假设“世界的真实状态”在 t 之前对两者都是相同的。换句话说,如果 s(n)是在 h 中产生第 n 个观察值的状态,类似地,对于 s'(n)和 h ',那么对于 n ≤ t,s(n) = s'(n)
在给定的 POMDP 上,我们现在可以推理 P(h | h ',t):给定在 t 处偏离 h 的反事实历史 h ',看到 h 的概率。首先,当我们看到反事实的历史:P(s(t) = s | h ')时,真实状态在分歧点 s。进一步,我们需要概率化,当时间步长 t 的真实状态为 s 时,在看到历史 h(t)之后,我们最终会看到历史 h: P(h | h(t),s(t) = s)。这三个概率之间的关系如下:
给定在 t 处偏离的反事实历史 h '的概率公式。
对于每个可能的状态 s,如果 s 在收敛点 t 是真实状态,则获得历史 h 的概率乘以如果我们假设反事实,则 s 是真实状态的概率。
用这个公式,很容易获得关于 P(o⁰a(r)o 的“常识”结果)。在这种情况下,t=1,因为只有第一次观察对 h '和 h 是相同的。
第二行中左边的项是代理打开右边门的概率,因为当真正的初始状态是 s(r)时,那么门的选择将确定性地导致 0 或 0。右边的项简化为 1,因为给定选择左边门导致没有赢得任何东西的历史,初始状态一定是 s(r)。在第三行中,两个术语都简化为 0,因为它们描述了矛盾事件的概率:当在初始状态下,钱在左边的门后面,那么打开右边的门不会导致获胜的观察结果 o。相反,在初始状态下,当打开左边的门导致失败时,奖励不可能在左边。
结论和应用
我们已经看到了反事实历史 h '的概念如何帮助我们对期望历史 h 的概率做出推断。这反过来可以帮助我们决定代理人的政策。然而,我们只考虑了一个平凡的例子,其中最佳政策可以通过检查推断。在奖励学习领域【1】【3】可以找到反事实在 POMPDs 上的真实应用。虽然它受到了本文中给出的数学的启发,但它改变了细节并添加了一些新元素。因此,你应该继续关注本系列的第二部分,在这一部分中,我将探索反事实在奖励学习中的应用!
[1] Armstrong 等人,在线学习奖励函数的陷阱,Arxiv,2020 年 4 月 28 日,https://arxiv.org/abs/2004.13654
[2]阿姆斯特朗·斯图尔特,POMDP 上的反事实,AlignmentForum,2017 年 6 月 2 日,https://www . alignment forum . org/posts/5bd 75 cc 58225 BF 06703752 a 9/counter factuals-on-POMDP
[3] Everitt 等,强化学习中的奖励篡改问题及解决方案:因果影响图视角,Arxiv,2021 年 3 月 29 日,https://arxiv.org/abs/1908.04734
5 种语言的 COUNTIF(VBA/SQL/PYTHON/M query/DAX power bi)
原文:https://towardsdatascience.com/countif-in-5-languages-vba-sql-python-m-query-dax-powerbi-639d3d7c6c7f?source=collection_archive---------20-----------------------
如何用另一种分析语言制作自己喜欢的 Excel 功能(VBA/SQL/PYTHON/M query/DAX power bi)
莎伦·麦卡琴在 Unsplash 上的照片
Excel 是大多数从事数据分析工作的人使用的功能强大的电子表格。数据量的增加和开发用户友好的工具是通过将它们与另一种工具或语言混合来改进 Excel 报表的机会。
在一家财务报告部门工作时,我面临着改进报告工具的需求。开始使用一门新语言的一个简单方法是用另一种语言翻译我们在 excel 中使用的内容。“我该如何旋转它?”“我怎么能找到它?”。
在这篇文章中,我将与你分享如何用 5 种不同的语言制作 COUNTIF:VBA,python,SQL,DAX (Power BI),M (Power query)。这将是简单的提示,但如果你想获得更详细的文章,别忘了关注我!
Excel 中的 COUNTIF
COUNTIF 是 Excel 的统计函数之一,用于计算符合条件的单元格的数量。
最简单的使用方法如下:
=COUNTIF(Where do you want to look?, What do you want to look for?)
但是在“你想找什么?”您可以放置一个条件标准(对于部分条件,它可以是逻辑运算符(、<>、=)和通配符(*、$)。
在这篇文章中,我将使用一个与我写的另一篇文章相似的例子,用 5 种语言介绍 SUMIF:
这将是一个标签与项目的列表在单元格 C2,我们可以把一个 COUNTIF 公式与参数:范围=A2:A8,标准=单元格(A2)。所以基本上我们计算列表中“Item1”的数量。
作者图片
=COUNTIF(A1:A8,A2)
VBA 的 COUNTIF
Visual Basic for Application (VBA)是集成到 Microsoft Office 应用程序中的 Microsoft Visual Basic 的实现。
在代码中,可以使用语句“WorksheetFunction.sumif”设置一个变量来存储 COUNTIF 结果的结果。它的工作方式与函数本身完全一样。然后,您可以将结果直接存储到 C2 单元格中。
Range(“C2”) = WorksheetFunction.COUNTIF(Range(“A2:A8”), Range(“A2”))
现在让我们通过声明变量来正确地做这件事:
Sub sumif()Dim wb As Workbook
Dim wsD As Worksheet
Dim Arg1 As Range
Dim Arg2 As Range
Dim Arg3 As RangeSet wb = ThisWorkbook
Set wsD = wb.Worksheets("Sheet1")Set Arg1 = wsD.Range("A2:A8") 'where to find
Set Arg2 = wsD.Range("A2") 'what to find
Range(“C2”)= Application.WorksheetFunction.SUMIF(Arg1, Arg2)
End Sub
SQL 中的 COUNTIF
SQL ( 结构化查询语言)或 sequel,是一种在数据库中存储、操作和检索数据的标准语言。这是面临 Excel 局限性的公司常用的升级方式之一。通常,第一反应是协商一些预算,以便将数据存储到数据库中,并使用 SQL 与该数据库“对话”,组织和操作数据。这种语言也非常值得赞赏。接近自然语言,在输入简单的 SQL 请求时不会有编码的感觉。
让我们从创建一个包含项目的表开始:
CREATE TABLE table1 (
Item varchar(255)
);
INSERT INTO table1
VALUES ('Item1');
INSERT INTO table1
VALUES ('Item2');
INSERT INTO table1
VALUES ('Item1');
INSERT INTO table1
VALUES ('Item3');
INSERT INTO table1
VALUES ('Item1');
INSERT INTO table1
VALUES ('Item4');
INSERT INTO table1
VALUES ('Item4');
SELECT*FROM TABLE1;
结果如下:
作者图片
请记住,在 SQL 中,当您想要获取信息时,通常会使用表达式 SELECT。基本上,在 SQL 中,你处理数据、表格和关系。因此,你必须很好地理解“我如何才能获得这些信息”,以便进行选择:
从“我必须如何应用”中选择“我将如何获得我想要的”。
因此,在我们的例子中,我们将选择“Item”列的项目等于“Item1”的情况的计数。让我们写出公式,然后分析它:
SELECT COUNT(CASE WHEN Item = 'Item1' THEN 1 END) FROM table1;
因此,当(SQL 中的 CASE 是一种“IF”函数)Item='Item1 '时,我们选择 CASE 的计数,然后(如果是这种情况)我们计数 1。这适用于表 1。
结果:
作者图片
Python 中的 COUNTIF
Python 是一种具有通用目的的解释型高级语言。它有广泛的应用,包括数据分析。我们可以通过说“对于所有的应用程序,它的库”来介绍 python。对于数据,不出意外,我们将使用著名的熊猫。
python 中 COUNTIF 有几种方法。我们可以玩数据框,列,分组等等。但是这里我将简单地创建一个包含所有条目的列表,然后循环进入这个列表,每次循环遇到“条目 1”时就加 1。所有这些都存储在一个变量结果中:
items =['Item1','Item2','Item1','Item3','Item1','Item4','Item4']
res = sum(1 for i in items if i == 'Item1')
结果如下:
作者图片
M 中的 COUNTIF
m 是工具 power query 背后的强大语言。即使您正在使用查询编辑器,每一步都将使用 M 编写,M 代表数据混搭或数据建模。我强烈推荐看看这种语言,我们可以做的不仅仅是使用图形界面。
关于 COUNTIF,图形界面非常流畅,我们可以直接使用。您只需将表格导入图形界面,然后使用列项中的过滤器:
作者图片
然后选择列“Items ”,并在字段 Transform 上进行计数:
作者图片
按结果显示图像
你得到了计数。另一种方法是使用左边的分组按钮,但在我们的例子中,它会增加更多的步骤,我们可以通过直接过滤和计数来跳过。我将介绍另一个更有用的特性(数据透视表)。
DAX 中的 COUNTIF:
DAX 代表数据分析表达式。不仅仅是一种语言,它还是一个函数和运算符库,可用于在 Power BI 和 Power Pivot 中构建公式。
COUNTIF 是一个介绍 CALCULATE 函数的好机会。它是 Power BI 中最著名的函数之一,在应用过滤规则后对表达式求值。它更接近于 COUNTIFS,因为您可以应用几个过滤器参数。
CALCULATE(<expression>[, <filter1> [, <filter2> [, …]]])
Expression:要计算的表达式。
Filter1,2,…:可以是一个布尔表达式,一个表过滤器,甚至是另一个函数。
在我们的例子中,通过在列“Items”=“item 1”中应用一个过滤表,要计算的表达式是 Table1 项的计数
countif = CALCULATE(COUNTA(Table1[Items]),Table1[Items] = 'Item1')
结论
这篇文章是一系列文章的一部分,在这些文章中,我分享了用其他语言实现 Excel 特性的方法。当然,当你决定从 Excel 转向编程时,你的数据分析方法将会完全改变,你将会发现有很多方法可以找到你的解决方案。如果你有其他的方式来做这件事,或者甚至知道如何用其他语言来做这件事,请在评论中分享它们,或者在我的社交网络中联系我!我将很高兴阅读你的想法!
使用 HyperLogLog 在 Google BigQuery 中更快地计算唯一元素
原文:https://towardsdatascience.com/counting-unique-elements-faster-in-google-bigquery-with-hyperloglog-bfbcac73495e?source=collection_archive---------55-----------------------
使用超对数算法,我们牺牲一些准确性来更快地完成工作。但是速度有多快,以什么样的准确度为代价呢?
克里斯·贾维斯在 Unsplash 上的照片
超对数(HLL)是一种估计数据集包含多少独特元素的算法。Google BigQuery 利用这种算法对拥有 10 亿行及以上的超大型数据集的进行了近似唯一元素计数。
在本文中,我们将讨论两点。
- HLL 是什么?
- HLL 与其他方法相比如何?
HLL 是什么?
超对数算法可以估计远超过 10⁹的基数,相对精度(标准误差)为 2%,同时仅使用 1.5kb 的内存。
-hyperlog log:Philippe Flajolet 等人对接近最优的基数估计算法的分析
HLL 是许多基数估计算法中的一种,这些算法都是为了解决一个问题而发明的:如何尽可能快速准确地计算唯一元素的数量。正如您可能已经猜到的,基数意味着数据集中具有重复条目的唯一元素的数量。
当您有一个非常大的数据集时,这些算法是非常有用的,这个数据集太大了,以至于无法在几秒钟内对多少个唯一条目进行排序和计数。下面是一些真实的使用案例。
- 通过计算在不同时间段传输的数据包的唯一报头对来检测网络攻击(例如拒绝服务)
- 估计 Redis、AWS Redshift 和 Druid 数据集中唯一记录的数量
- 统计一段时间内不同用户的数量,以获得移动应用的实时活动报告
HLL 是由 Philippe Flajolet 和 G. Nigel Martin 在 1984 年提出的 Flajolet-Martin 算法的各种改进的产物。从那以后,Google 采用并改进了它,使之成为 HyperLogLog++函数。除了 Google,许多其他技术平台也基于 HLL 实现了自己的数据结构。然而,它们都有相同的基本规则。
如果集合中的所有数字都以二进制表示,并且 n 是所有数字中前导 0 的最大数量,则 2^n 是数字的估计唯一计数。
简而言之,有了 HLL,我们牺牲了一些准确性来更快地完成工作。但是速度有多快,以什么样的准确度为代价呢?让我们在 Google BigQuery 中运行一些实验。
HLL 与其他方法相比如何?
让我们从一个大数据集开始。我使用的是维基百科数据集,可以通过谷歌大查询公共数据集获得。为了只提取 2020 年的数据,我用下面的查询创建了一个永久表。
# Create a table containing all hourly views per Wikipedia page in 2020 CREATE OR REPLACE TABLE `bigquery-301504.wikipedia.view_2020` AS SELECT * FROM `bigquery-public-data.wikipedia.pageviews_2020`
WHERE DATE(datehour) < "2021-01-01" AND
DATE(datehour) > "2019-12-31";
这个大表(2.24TB,超过 50 亿行)包含了 2020 年每个维基百科页面标题每小时的浏览量。你可以看看下面的模式。
作者照片
假设我们想知道 2020 年每个月有多少独特的图书被浏览,这里是我们可以编写的最简单的 SQL 查询。
查询
# Count unique titles viewed per month with DISTINCT method
SELECT EXTRACT(MONTH FROM datehour) AS month,
COUNT(DISTINCT title) AS title_count
FROM `bigquery-301504.wikipedia.view_2020`
GROUP BY month
ORDER BY month;
结果
作者照片
当使用 DISTINCT 函数时,Google BigQuery 需要跟踪它见过的每个唯一的日期。因此,运行这个查询需要 4 分多钟。
幸运的是,如果我们愿意牺牲一些准确性,我们可以走得更快。有两种方法可以得出一个大概的数量。
选项#1 —近似计数不同
查询
# Count unique titles viewed per month with APPROX_COUNT_DISTINCT method
SELECT EXTRACT(MONTH FROM datehour) AS month, APPROX_COUNT_DISTINCT(title) AS title_count
FROM `bigquery-301504.wikipedia.view_2020`
GROUP BY month
ORDER BY month;
结果
作者照片
好多了,但是我们能不能再用力一点?是的,我们可以。
选项 2——HLL
让我们看看如何使用 HLL 来解决同样的挑战,即计算每月观看的唯一标题。
查询
# Count unique titles viewed per month with HLL method
WITH hll_count AS (
SELECT EXTRACT(MONTH FROM datehour) AS month,
HLL_COUNT.INIT(title) title_count
FROM `bigquery-301504.wikipedia.view_2020`
GROUP BY month) SELECT month, hll_count. MERGE (title_count)
FROM hll_count
GROUP BY month order by month;
结果
作者照片
当我们放弃甚至不到 1%的准确性时,我们将查询速度提高了 6 倍。当然,有些情况下需要准确性,如财务报告或科学研究计算。否则,如果性能比绝对精度更重要,APPROX_COUNT_DISTINCT 和 HLL 都将派上用场。
尽管对 APPROX_COUNT_DISTINCT 和 HLL 的查询看起来不同,但值得注意的是,两者都使用了相同的 HLL 算法。由于第二种方法更复杂,您可能希望使用 APPROX_COUNT_DISTINCT 来保持代码更干净、可读性更好。
离别的思绪
如果你有兴趣了解更多关于 HLL 的演变,请查阅以下文章(按时间顺序排列)。
数据库应用的概率计数算法
大基数的双对数计数
HyperLogLog:对一个接近最优的基数估计算法的分析
实践中的超级对数:一种最先进的基数估计算法的算法工程
这就是我今天的全部内容。感谢您的阅读,如果您有任何反馈,请告诉我。大家保重,注意安全!
原载于 2021 年 1 月 13 日【http://thedigitalskye.com】。
新冠肺炎——对方法论危机的剖析。这一切都始于数据收集
原文:https://towardsdatascience.com/covid-19-anatomy-of-a-methodology-crisis-it-all-starts-with-data-collection-e23fcbcba54a?source=collection_archive---------32-----------------------
患病率和严重程度调查是监控 COVID 并轻松透明地做出稳健决策的必要工具。
摘要: 如果没有可靠的流行率(病毒传播)和严重性(感染导致住院等严重形式的概率),就无法对病毒传播的中期影响进行稳健评估。对患病率和相关严重程度的随机调查将大大加强当前的研究工作,促进决策,并提高公共政策的透明度,每年的费用可能在 100 万欧元以下。
图 1:垃圾进,垃圾出。https://xkcd.com/1838/
作者 :
- 塞缪尔·j·森德 (CEO,squareyourdataEdhec 副教授)——想法和写作
- Mircea Sofonea(蒙彼利埃大学传染病流行病学和进化副教授)——蒙彼利埃和欧洲流行病学建模中数据的使用
- Pierre Sonigo(Sebia laboratories 首席科学官)——免疫学理论、敏感性和实验室测量的解释,如 PCR 测试和血清学调查
我们感谢 Jacques Cohen(免疫学家,Uni RCA 名誉教授)对部署廉价医疗检测包进行调查的可能性的见解,感谢 Yves fra dier(Kantar Public 大规模调查的负责人)以及法国统计研究所的联系人对实施我们推荐的调查的实际见解;Minh Trinh(Rodeo AI 的合伙人)和 Yann Coatanlem(Praxis 智库的主席)为进一步推广这一信息提出了建议和提议。
注:流行率是目前受感染人群的比例,可视为全人口的阳性率;发病率指新感染的人。
简介
认为不管数据质量如何都可以应用复杂模型的天真观点解释了为什么财力雄厚的机构忽视数据收集。
然而,数据质量和回答给定问题的相关性阻碍了建模者的最大努力。缺乏可靠的数据会导致模型输出不可靠,进而在实践中导致比预期更多的有争议的结论,甚至可能导致对公共行动的不信任。
金融集团、国际机构和政府的雄厚财力为开发复杂模型提供了动力,这些模型有可能使用各种数据源,但稳健性本身并不是模型的特征,而是利用手头的数据集和模型对问题得出明确结论的能力。虽然简约被认为是测试简单模型或假设的理想模型属性,但没有稳健数据的简约模型可能不会导致稳健的预测。尽管丰富的数据和现代复杂的模型带来了新的见解或信号,但复杂性并没有阻止金融集团的破产。事实上,不受控制的复杂性是 2008 年金融危机的原因之一(见 Greenspan,2013 和 IMF 的 2008 年全球金融稳定报告)。
在 COVID 流行病的情况下,对两个基本变量----流行率和感染严重程度----的测量不佳,导致对病毒传播的中期影响或任何与病毒传播有关的政策的预测不可靠。因此,似乎有必要通过可靠的数据收集来加强当前的研究工作。我们的建议包括对患病率的随机调查。
这样的调查将允许更精确地追踪病毒传播,并且比现在花费更少。事实上,我们认为它可以在每个国家或州实施,每年的成本低于 100 万欧元。这将首次允许以公正的方式监测流行率和严重程度。病毒传播和政府措施的影响将以透明和无争议的方式进行评估。反过来,这不仅有利于决策,也有利于公共政策的沟通和可读性。这将提高疫苗接种活动和非药物干预(如隔离)的透明度和信心。
这种方法可以在相关的行政或地理级别(地区、州或国家)复制。
I)问题始于一个问题和一个模型概述
监测需求
COVID 流行病的两个基本组成部分可以概括为病毒循环(新感染人数)及其对个人和公共卫生系统的健康影响。
一小部分新感染将导致住院。这一分数是衡量感染严重程度的一个可能指标,可能会有波动(可能以任何一种方式波动,见下文)。因此 必须 进行监控。
感染的严重程度随时间而变化,这对于呼吸道病毒来说尤其如此,因为其循环很难停止。
从理论中得到启示
对于人群而言,病毒感染的平均严重程度随时间而演变,可能随着病毒突变而增加或减少,并且总是随着先前病毒循环导致的免疫力的增加而减少。不能假定它是恒定的,因此必须对其进行监控。
关于免疫,必须区分上呼吸道(“鼻子”)的免疫和下呼吸道(肺以及其他内脏)的免疫。
- 免疫 下呼吸道(肺部及其他内脏),对重症有效,持续时间长,简称全身免疫。
- 阻止病毒循环所需的上呼吸道免疫能力很弱且很短暂,这主要是因为鼻子中的粘膜组织很容易暴露于空气传播的病毒,且缺乏保护。由此可以说,不存在持久的 粘膜停止或绝育免疫。
系统免疫力的提高并不能完全防止上呼吸道的再感染和进一步的病毒传播,但降低了严重感染(内脏器官)的可能性。因此,这意味着感染严重程度的下降比新病例的下降要大得多。
疫苗也出现了同样的现象,疫苗可以预防严重病例,但对病毒循环和再感染只有部分效果。《我们的世界》的数据显示,目前英国的新增病例远高于大多数疫苗接种较少的国家;在疫苗接种率高的智利人群和其邻国疫苗接种率低的巴西人群中,新病例相似。相对于疫苗接种较好的邻国(智利和英国),疫苗接种滞后的国家(巴西和法国)的住院、ICU 和确诊死亡要高得多。
然而,经验严重程度可能以任何一种方式变化,取决于固有毒株毒力、医院超负荷以及总体感染、暴露和疫苗接种的年龄结构(必须加以控制)。它往往会随着免疫力的增加而减少,免疫力是通过接触病毒或接种疫苗获得的。
II)数据收集:清晰的数据胜过复杂的分析
使用精心设计的调查和实验
模型对于不可观测的事物是必要的,比如未来。通常,描述当前情况所需的重要参数可以通过观察和测量直接估计。
图 2 好的数据可以得到简单明了的结果。插图:https://xkcd.com/2400/
强大的数据收集允许回答一些关于当前和过去情况的相关问题。
必须提前组织数据收集,以便进行极其清晰的评估。
传统的数据收集方法涉及重复调查,理想情况下是对相同的个人进行调查,这被称为纵向或面板数据,以了解个人和集体的变化。
事实上,调查和实验设计( Fisher,1935 )被广泛认为是收集信息和测试假设的必要条件。联合国官方统计基本原则规定“用于统计目的的数据可从各种来源获取,无论是统计调查还是行政记录”
政府定期进行调查,以监测其行动的受欢迎程度;每月进行数以千计的调查,以监测经济活动、消费品和工业品的价格,以及公众对各种问题的看法。但令人惊讶的是,没有定期对 CoViD 感染、感染的严重程度和人群中的免疫防御进行这样的调查。
调查的图解
简单、廉价而有效的分析主要需要一个相关的问题和通过调查收集大量的信息数据。
调查的原则:从作为一个整体的(目标)人群中收集信息。
要从(目标)总体中收集信息,关键是样本必须具有与总体相同的特征。当人们被随机选择时会发生这种情况,但当人们自我选择时不会发生这种情况(如 PCR 测试、社交媒体发布等)。
图 3 有症状的人倾向于测试更多。PCR 测试受参与偏倚的影响。来自 https://xkcd.com/2357/的插图
当人们自我选择时(如 PCR 测试、社交媒体发布等),这种情况不会发生。
事实上,根据自我报告的测试来估计病毒的传播类似于通过计算拜登或特朗普的推特粉丝而不是通过通常的人口调查来估计他们获胜的概率。这既不是标准的也不是可靠的统计方法。
数据收集不佳的通常原因是缺乏明确的(事先)目标或对数据将提供的分析的描述。Sars-CoV-2 的监测和建模需要可靠的数据收集。
III)正确喂养模型
评估测量的需要
对新感染和新住院的非常短期的预测依赖于:
- 衡量当前的感染情况
- 衡量其严重程度,最好有临床随访,但住院概率的成本最低
- (对于超过一个月的预测,还需要病毒繁殖的速度)
对政策有用的长期模型必须侧重于人口特征,特别是应衡量:
- 感染总数
- 免疫防御的进化和感染的严重程度。
感染是所有预测的关键输入,从统计协议和医疗措施中推断出来的结果必须仔细审查。向模型提供不准确的数据可能会导致不准确的预测,这可能是有偏差的(错误的)、有噪声的,甚至是没有信息的。
为了更好地理解感染测量中的偏差,让我们回顾两个主要的(部分)测量:
- 目前或新的感染通常用 PCR 来测量,最近,抗原测试在大多数国家自 2020 年 5 月以来一直在使用,并在 2020 年夏季后扩大规模。
- 血清学调查旨在测量 Sars-CoV-2 特异性抗体的积累,有时被用作抗 Sars-CoV-2 免疫的替代物(即病毒严重程度)。
然而,这两个度量是有偏差的,这自然使得建模工作更加复杂。
从理论角度来看,这两种方法都有偏差:
- PCR 检测是对流行率的有偏测量,因为检测是自愿的:根据定义,那些不检测的受感染个体不计入结果中(参见 Sender,2021 对偏倚的更详细回顾)。
- 血清学调查不是流行率的衡量标准,但在没有以前流行率衡量标准的情况下,已于 2021 年春季部署。它们旨在替代过去的累积暴露,但这种替代既不能及时(抗体随着时间的推移而积累)也不能准确:抗体只是对抗 SarS-COV-2 的可能反应之一,而且它们可能会随着时间的推移而消退。
还有一些反事实:
- 自愿 PCR 检测中无症状者的比例远小于随机 PCR 调查中无症状阳性者的比例(根据 Petersen 和 Phillips 2020 ,75%的感染者无症状)。这证明了 PCR 检测中的检测不足:因为检测是自愿的,无症状的感染者倾向于检测少于有症状的。
- 虽然血清学调查不允许追踪病毒循环(流行率),但它们同样不允许追踪免疫力。30 岁以下人群中严重住院率和死亡率极低,证明全身免疫可以在暴露前获得。
然而,设计合理的统计调查既没有用于估计新病例,也没有用于监测感染的严重程度。这两个流行病发展的基本指标是不可测量的,因此必须用不可靠的基于模型的估计或病毒感染严重性固定的假设来代替。
公共预测中不良数据收集的影响
预测住院和死亡需要估计病毒暴露和隐含的严重性——新感染的新死亡或新住院的比率。
监测 Sars-CoV-2 的传播及其严重性的演变将非常简单,只需对新的 CoViD 感染(称为发病率或暴露)进行定期和可靠的调查。
图 4 推断背后的假设必须仔细检验。https://xkcd.com/605/
因为流行病学模型的这个关键参数还没有被明确地测量,所以必须对其进行假设。
这使得模型没有它们应有的稳健性。虽然严格意义上的发病率的精确测量对于预测住院率来说是不必要的,但发病率和严重程度是决定关于病毒传播的最佳公共政策的关键。
缺乏对患病率和严重程度的可靠测量,以及在模型中对严重程度的假设的必要使用,可能有助于解释为什么世界各地的政府政策差异很大。
㈣呼吁更好地收集数据。
像对待其他人一样对待 COVID。
总体而言,随机调查和纵向研究是日常经济生活中的惯例;与管理数据(匿名)匹配,它们提供了丰富的信息。我们推荐的抽样患病率调查可以自动与住院数据匹配,也可以与工资匹配,以评估 COVID 污染的经济影响。对有组织的数据收集的需求是惊人的明显。
对于 COVID,我们建议明确评估两个最重要的感染驱动因素,即病毒循环(新感染)及其严重程度,可评估如下:
- 监测新病例只需要定期的 PCR 调查。
- 总体人群的严重程度可以通过新住院病例与新病例的比率来估计
- 可以通过收集与感染相关的症状的严重程度以及在测试中测量的病毒浓度来完善和补充这种测量。毕竟,无症状感染的比例也代表了系统免疫力的提高(根据定义,被感染但没有任何疾病的人具有免疫防御)
- 当然,所有检查的信息也应与患者特征(年龄和健康状况)以及住院数据正式关联。
- 在这种随机的、较小的人口调查中,严重性必须理想地在三个或四个年龄组中进行测量;根据成本是否需要最小化,在这方面可以考虑各种选择。
收集这些信息仍然很重要,特别是因为呼吸道病毒有环境因素。干净的数据产生透明的信息,允许对 Sars-CoV-2 的演变进行可靠的评估,这在经济生活的所有方面都是需要的,只要 Sars-CoV-2 被视为潜在威胁,也用于知情的政策辩论和决策。
快速有效实施的实用建议。
1)组织难度
实施这种调查的一个实际困难在于人们认为需要协调统计和医疗机构。
图 5 对于调查等简单程序,直接做还是协调?https://xkcd.com/1445/
统计机构拥有人口数据库,可以设计具有不同层次的代表性调查。
卫生机构拥有解释测试的医学专业知识,但不习惯于人口范围的调查。
2020 年春季进行的一些血清学调查以相对低效的方式涉及了这两个研究所:结果往往在数据收集后几个月才公布。
2)直接、高效行动的可能性
自动测试的可用性有助于由一个独特的机构实施调查。按照顺序或优先级,我们建议:
- 为了提高速度,人们可以依靠市场研究公司部署在线调查(可能辅以一次面对面的计算机辅助采访),每个被选中的回答者都将收到(或在任何实验室或药房取回)测试包,他将每周报告结果。检测试剂盒包括抗原检测或快速血清学检测。
- 从长远来看,可以设计一个有代表性的队列,定期进行血清学测试,在实验室检查血液样本。
3)世界上有代表性的调查
虽然全人口代表性调查通常用于经济生活的各个方面,但在世界各地很少用于 COVID。
人口范围代表性调查的最好例子是由国家统计局在英国进行的调查,即新冠肺炎感染调查数据(国家统计局,2020)。该调查允许 Petersen 和 Phillips (2020 )计算无症状 PCR 阳性者的人口百分比。即使在英国,流行率的主流估计(病例总数)如在政府仪表板中可见的是在所有实验室进行的阳性检测的数量,而不是国家统计局公众代表调查。
在美国,在 CDC CoViD 19 监测项目中对一些非常特殊的公众进行了调查,特别是脆弱人群(孕妇、退休人员),但没有针对患病率和发病率进行全人口范围的代表性调查。
4)成本审查
与已经部署的监控系统的成本相比,测试的成本可以忽略不计(参见以下小节了解一些技术细节)。
我们主要评论追踪病毒传播的成本。这一措施将允许在实际条件下及时跟踪严重程度的演变,这可能比血清学更能提供信息,因为血清学不能实时提供信息,因为抗体在几周后就会产生。
- 测量病毒传播每年花费不到€100 万英镑,也就是说,在病毒严重传播期间,€花费 50 万英镑
今天,衡量病毒传播的唯一标准是决定检测 CoViD 的人的比例。对整个人口中病毒传播的调查每年将花费 75 万欧元。
这 75 万英镑与 CoViD 追踪应用程序的开发和部署成本形成了 1000 万欧元的对比。
这项调查可以从 1000 人的样本中在线进行,抗原自动测试可从当地药店获得(自动测试的生产成本约为 10 欧元,可花 5 欧元购买)。
- 追踪一个群体中的病毒传播每年将花费€100 万到€150 万英镑,也就是说,在密集传播期间不到€100 万英镑
群组调查将更加丰富,例如可以追踪人群中再感染的发生。反过来,这允许例如评估疫苗对再感染和病毒循环的保护作用——这在今天是不可能的,因为没有测量未接种疫苗的人的再感染概率。
然而,由于通常的流失率,队列调查稍微有点问题。
可以通过面对面的面谈、分发自动测试工具包、激励性演讲以及通常需要的程序解释来降低流失风险。额外费用:€20 万
两个外部设备也可以降低磨损风险。首先,政府和公共卫生官员可以强调承诺的重要性(以便能够及时监测卫生动态);其次,准货币激励(购物券)。额外费用:€20 万到€60 万
5)调查成本构成,快速回顾
下面提供的成本是采购成本。生产成本,尤其是测试成本,要小一个数量级。因此,实际的实施成本估计可以通过大规模采购和协作来降低。
标准采购成本可分解如下:
- 检测包:一个抗原检测包的价格为€5 到€10 欧元;PCR 测试被认为是更可靠的,可以很容易地部署为自我测试(与洗鼻技术);或者,可以采用基因组测试(目前还没有这种方法)。
- 在线调查部署成本非常低廉,实施和分析成本基本固定,几乎没有人均成本。
- 管理费用有助于减少流失率。
- 初步的一小时面对面面试,€每 1000 人需要 20 万英镑,€每 10000 人需要 100 万英镑。确实有固定成本(组织、培训)。
必要的样本大小取决于所需的精度。方差的公式是 *p (1-p) / N,,它随着样本大小 N 而减小,但随着真实比例 p 接近 50%而增大。
可以通过公式*N = p _ cent (1-p _ cent)/V _ target得到期望的样本量,其中 p_cent 为最中心先验概率, V_target 为目标方差(目标标准差的平方)。
为了以 1%的标准偏差衡量当前的感染情况,鉴于流行率不可能超过 10%,900 人就足够了;4 倍的人可以达到 0.5%的标准偏差(这里的精度可以说是正负 1%),因此 10 k 人就足够了。
这些基本计算对总体(或调查的类别)有效。不同年龄组和地区的详细结果自然需要更多的数据。然而,六个区域需要的数据不到六倍,因为这些区域是相互关联的,所以一个区域给出了其他区域的信息。
结论:行动中的简单胜过复杂
大规模调查允许收集跨空间(如州、地区、城市)的详细信息、经济和社会特征(年龄、经济活动),但重要的是,还可以确定互动的质量。
这种大规模的调查不仅成本高昂,而且由于涉及文化上不同的机构,在组织上也可能具有挑战性。
从短期来看,要求对 Sars-CoV-2 在人群中的传播进行至少一次精确测量似乎并不过分。
因为 Sars-CoV-2 仍然被认为是一种重要的风险,所以必须在高强度循环期之前实施病毒循环的相关监测。在北半球,呼吸道感染往往在 10 月份上升,在 4 月份消退——目前的情况可以说(仍然)需要在今年剩下的时间里进行监测。
从 10 月 1 日到 4 月 30 日监测病毒传播将花费 50 万欧元,并保证更好地监测病毒感染,确保健全、合理和易于沟通的公共政策反应。
衡量接种疫苗者和未接种疫苗者再次感染概率的群组调查将在传染期花费 100 万至 200 万欧元。
资料来源:Unsplash / Solen Feyissa
编者按: 《走向数据科学》是一份以研究数据科学和机器学习为主的中型刊物。我们不是健康专家或流行病学家,本文的观点不应被解释为专业建议。详见我们的 读者术语 。想了解更多关于疫情冠状病毒的信息,可以点击 这里 。
新冠肺炎和巴西:数据探索
原文:https://towardsdatascience.com/covid-19-and-brazil-a-tragedy-of-5570-cities-in-maps-and-graphs-84886c2154c6?source=collection_archive---------32-----------------------
Andre A. Xavier 在 Unsplash 上拍摄的照片
地图和图表中 5570 个城市的悲剧
上周五,2021 年 2 月 26 日,标志着巴西首例新冠肺炎病例记录一周年。在这一时期,病例和死亡的累积统计数字令人恐惧。根据世卫组织统计,该国死于这种疾病的总人数排名第二,病例总数排名第三。如果仔细观察,这些数字可能会更加可怕。
当我们观察巴西各城市时,我们意识到其中几个城市的新冠肺炎死亡人数已经接近 2014 年至 2018 年在这些地方观察到的平均死亡人数。然而,悲剧不是一夜之间发生的。有许多线索表明它会发展到我们今天的位置。震撼了 5000 多个巴西城市中数千个家庭的轨迹是逐步建立起来的。基于 COVID 的死亡人数与巴西各城市总死亡人数的最新平均值的比较,我将在以下段落中更详细地讲述这个痛苦和损失的故事。
五年来巴西死亡人数的变化
巴西的死亡数据需要两年时间才能被正确确定并以公开的形式发布。现有的最新数据是 2018 年的。下图显示了 2014 年至 2018 年间该国各种原因导致的死亡总数的变化。
2014-2018 年死亡人数的演变。作者图片
从图表中可以看出,死亡人数始终在 100 万以上,在过去两年略有增加后,过去三年保持稳定。在第一例新冠肺炎病毒感染一周年的当天,巴西有 249,691 人死于该疾病。这在图中由穿过竖线的水平线表示。
调查数据显示,图表中显示的平均值约为 128.2 万人死亡。当我们将 2021 年 2 月 26 日 COVID 累积的死亡人数与该统计数据进行比较时,我们得出结论,该疾病相当于过去五年可用数据计算的所有死亡平均中观察到的死亡人数的 19.5%。这一比率在各市之间差别很大。在本文的其余部分,当阅读各市的死亡百分比时,该数字应被理解为这些地点的死亡人数与 2014 年至 2018 年期间统计的总死亡人数的各自平均值的比较。
新冠肺炎在巴西各城市的死亡百分比分布
下图显示了相对于我们在本文中关注的平均值,新冠肺炎造成的死亡百分比在巴西所有城市的分布情况。
死亡百分比。作者图片
该图显示,绝大多数城市的数值低于 25%,但很容易看出有超过 50%的数值,在一些城市,COVID 相当于平均值的 75%以上,在一个特定的城市,该数值已经达到 99%。没错,2021 年 2 月 26 日,巴西一个自治市记录的 COVID 死亡总人数几乎与五年平均所有可能原因的死亡总人数相同。
以 COVID 的死亡百分比作为参考,我们可以看到,在整个巴西,数百个城市已经超过了平均死亡总数的 19.5%。下图显示了这些城市在巴西各州的分布情况。
死亡率高于全国的城市数量统计排名。作者图片
拥有第二大城市的圣保罗在图表中表现突出。然而,你接下来看到的并不是你所期望的。像马托格罗索州、亚马孙州、帕拉州和托坎廷斯州这样的州几乎没有直辖市。我们将在后面看到,这些州也出现在死亡百分比高于平均死亡人数 19.5%的 10 个城市的名单中。
地图和图形中悲剧的演变
在以下段落中,我展示了巴西各城市在四个特定日期与 COVID 的死亡百分比相关的分布情况。这个想法是为了表明,这些数字朝着我们今天看到的画面一直在进化。我选择了与疾病传播的第一波和第二波高峰时刻相关的三个日期。第四次约会是 2021 年 2 月 26 日。见下图。
COVID 每日死亡人数的时间序列。作者图片
这些分析是根据巴西的地图完成的。在这里,我们以这样的方式绘制地图,较冷的颜色,接近蓝色的阴影,指的是低于全国 19.5%的城市死亡率。这个数字越低,颜色越冷。接近红色的暖色表示百分比高于参考值的城市。这个数字越高,颜色越暖。
为了得到一个初步的想法,请看下面的 2020 年 3 月 17 日的地图,这是我们作为本文参考使用的数据库中第一个登记死亡的日期。
2020 年 3 月 17 日基线图。作者图片
不出所料,整个巴西都被涂成蓝色,毕竟疫情才刚刚开始。
不到三个月,情况就开始发生变化,我们已经可以看到 COVID 统计的死亡百分比超过平均水平的 30%。参见 2020 年 6 月 4 日的地图。
2020 年 6 月 4 日的地图。作者图片
从图中可以看出,在 6 月初,尤其是亚马逊和帕拉市将要发生的事情的第一章已经开始被书写,在地图上代表它们的颜色已经开始呈现暖色调。
下图显示了与平均死亡总数相比,COVID 死亡率最高的 10 个城市。
2020 年 6 月 4 日死亡人数(%)的城市排名。作者图片
如上所述,在十个城市中,七个位于亚马孙,三个位于帕拉。在这一天,托南廷斯是巴西唯一一个 COVID 死亡率高于 2014 年至 2018 年平均总死亡率 30%的城市。
从下图可以看出,到 2020 年 8 月 6 日,地图已经明显变暖。
2020 年 8 月 6 日的地图。作者图片
之前占主导地位的强烈蓝色调已经从地图上消失了。该量表显示,已经有一些城市的新冠肺炎死亡率超过了 50%。可以看到,北部地区和中西部部分地区开始以暖色调为主,或者至少是不太冷的色调。
下图显示了死亡率最高的十个城市的最新情况。
2020 年 8 月 6 日死亡人数(%)的城市排名。作者图片
如果在 2020 年 6 月初,只有一个城市的比率超过 30%,两个月后我们可以看到,所有 10 个城市都远远超过了这一标志,帕拉恰马已经超过了 50%。
2020 年 08 月 06 日的里程碑与第一波 COVID 死亡人数下降轨迹的开始相吻合。不幸的是,休战并没有持续多久,到 2021 年 7 月 1 日,巴西已经出现了单日死亡人数的新纪录。请看下面那天地图的样子。
2021 年 7 月 1 日的地图。作者图片
从上面的图像中,你可以看到弱冷色调在整个巴西东部盛行,而暖色调在中西部不太明显,强暖色调在北部占主导地位。色标已经显示有超过 60%的城市。
请参见下图了解排名的更新情况。
2021 年 1 月 7 日死亡人数(%)的城市排名。作者图片
上图中的十个城市都超过了 50%,其中七个已经超过了 60%。
最后,我们指出了在巴西第一例新冠肺炎病例一周年纪念日的感受。见下图。
2021 年 2 月 26 日的地图。作者图片
巴西东部的冷色调和弱色调与暖色调和弱色调存在争议。在中西部,我们已经看到更强烈的暖色调获得了更大的空间,而在北部,尤其是在亚马逊州,悲剧正在上演。色标已经显示 75%的比率已经危险地超过,非常接近 100%。
看看下面这些城市的排名。
2021 年 2 月 26 日死亡人数(%)的城市排名。作者图片
图中可见亚马逊(AM)和帕拉(PA)在图中盛行。也可以看出,8 个直辖市超过死亡人数的 75%;更可怕的是,在 Pará的 Faro 市,据核实,COVID 在一年内杀害的人数相当于该市登记的所有死亡人数的年平均数。对于这个巴西北部的小自治市来说,这似乎是对悲剧最好的定义。
2021 年作为 2020 年的重演?
超过 25 万人死亡后,情况似乎不会很快好转。免疫接种运动出现延误,公共权力机构几乎没有努力颁布更严格的措施,迫使社会疏远,人们对紧急援助的持续性表示怀疑,这种援助可能成为减少疫情影响甚至减少流动性的工具,甚至部分人口似乎更相信误导性措施,而不是科学和集体意识,这些措施往往是由那些应该保护人们免受疾病的人传播的。
现在看来,2020 年及其可怕的统计数据将在 2021 年重演悲剧。
代码和数据
这些数据可以从两个致力于提高巴西开放数据质量和可用性的组织下载。【2014 年至 2018 年间巴西的死亡人数数据由 Base dos Dados 提供。另一方面,COVID 的死亡人数来自数据初创公司 Brasil.io 的努力。
数据处理和分析的代码可在我的 Github 上获得。
COVID 19:优化新冠肺炎的锁定策略
原文:https://towardsdatascience.com/covid-19-optimizing-lockdown-policies-for-covid-19-c7d501938549?source=collection_archive---------28-----------------------
如何以及何时实施锁定政策
在像素上的照片
尽管在过去的几个月里,我们终于开始接种新冠肺炎疫苗,但过去一年里,通常被称为“拉平感染曲线”的主要方法是社交距离。然而,全球各国政府行政部门之间显然缺乏共识,有可能用一整套条款来阐述每个国家实施的多种措施。
T4 没有描述这些措施,也没有评估最佳措施,我们决定将何时以及如何实施封锁的问题留给一个能够优化封锁政策的模型,以期减缓疾病的传播。特别是,我们从封锁位置(多久一次、何时以及这些时间段应该有多长)的角度来解决封锁策略管理的问题,以便最大限度地减少特定人群中的感染高峰。
本文简要介绍了我们的方法和发现。然而,如果你想阅读更多关于这个主题的内容,我们鼓励你阅读全文及其参考资料。
下面是这篇文章的结构:
- 介绍我们最近对锁定优化的研究
- 最常用的流行病学模型的简要描述
- 介绍最受欢迎的优化,以尽量减少疫情的传播
- 我们的研究和结果
来自《走向数据科学》编辑的注释: 虽然我们允许独立作者根据我们的 规则和指南 发表文章,但我们并不认可每个作者的贡献。你不应该在没有寻求专业建议的情况下依赖一个作者的作品。详见我们的 读者术语 。
介绍
在阅读了许多关于新冠肺炎锁定优化的论文后,我们发现最近的文献涵盖了两种主要类型的干预。一方面是持续的封锁,人口被限制几个星期,就像疫情开始时在中国或欧洲实施的那样。另一方面是所谓的动态锁定,这是严格和放松限制期的交替间隔。这些干预措施的效果经常相互比较或与较软的缓解措施进行比较。
总的来说,比较不同干预方式的论文倾向于指出动态策略是最小化活跃病例峰值的最佳策略。然而,这些研究只比较了预先确定的锁定期和固定的时间框架。如果我们把锁定位置和长度分配的任务留给我们的算法来决定,结果会与以前的发现一致吗?
目前用于研究锁定位置的技术包括使用流行病学模型对感染曲线进行建模,并应用数学优化方法来降低感染曲线的峰值。有趣的是,在最近的文献中很少有实例使用数学优化方法来比较不同的干预措施。
模型
为了优化感染者的曲线,首先需要对病毒的传播进行建模。在目前的文献中,在疫情水平上模拟病毒疾病有两种主要的模型选择:基于方程的模型(EBM)和基于主体的模型(ABM)。前者(EBM)定义了一组微分方程,并专注于有效地捕捉全局相互作用,忽略了局部现象,如人口统计特征、运动模式或不同受试者暴露水平的差异。后者(ABM)将疾病建模为称为代理的自主决策实体的集合。虽然在研究大规模行为时,基于主体的模型可以提供关于特定主体交互作用的有趣见解,但它们可能会受到复杂性快速增加的影响。由于系统固有的随机性,小参数的任何增加或改变都可能彻底改变模拟的整体行为,增加计算成本并使优化器的任务复杂化。因此,我们决定使用 EBM 模型,因为它是确定性的,导致更稳定的解决方案,简化了后验分析,并且比 ABM 模型计算成本更低。
图 1 显示了易感-暴露-感染-康复(SEIR)房室模型的图表,其中 S 定义了人群中易感个体的比例, E 表示暴露个体的比例, I 表示感染个体的比例, R 表示康复个体的比例。
在用于描述该模型的所有参数中,特别感兴趣的是传染率(β),其定义为每个易感-感染个体的潜在传染次数,这是因为其难以表征,但在该模型的适用性中很重要。
SEIR 比较模型
【计算机】优化程序
为了找到最优的锁定时间,该问题可以被公式化为以最小化感染曲线的峰值为目标的任务调度问题。在文献中找到的在新冠肺炎环境中解决这种资源优化问题的一些主要方法是强化学习(RL)和进化算法。因为目的是找到给定情况下的最佳锁定策略,而不是找到通用的自适应锁定策略,所以可以避免使用强化学习来避免这样的问题。与 RL 相比,进化算法更容易实现,因为损失函数更容易建模,并且算法易于并行训练。尽管遗传算法(GA)是最常见的进化方法,但我们观察到它们具有由局部最优引起的高度发散。因此,为了获得更可靠的解决方案,我们决定将优化器改为进化策略(ES) 。与遗传算法相似,专家系统使用一个由适应度函数评估并受变异干扰的个体群体。
我们的研究和结果
我们把我们的工作目标定义为双重的。一方面,我们旨在通过试验基于 SEIR 方程的模型和基于进化策略(es)的新型优化器的组合来扩展锁定优化策略的当前洞察力。另一方面,我们旨在探索传输速率参数(β)对优化器提出的结果策略的影响。
第二项研究背后的动机在于从工作中的数据集中报告的数据中选择“正确的”恒定传输速率的困难。虽然大多数基于 SEIR 的作品基于以前的文献选择恒定的速率,但是图 2 和图 3 显示了非恒定行为的证据。由 Olivier 等人(2020) 引入的基于指数衰减的(β)建模启发了我们研究锁定内外的常量和变量函数组合的 4 种场景(开-关、衰减-关、开-衰减、衰减-衰减)。此外,我们设置了四个不同的锁定期长度和数量的场景,每个场景的锁定期最长为 60 天(12 个 5 天期,6 个 10 天期,4 个 15 天期,2 个 30 天期)。此外,为了避免我们的结果对特定国家有偏见,我们对来自意大利和日本的数据评估了所有提到的条件,这两个国家具有非常不同的 COVID 传播模式。
图二。意大利的传染率。绿色和红色竖线表示强制隔离的开始和结束。
图 3。一段时间内日本的传播率。绿色和红色竖线表示紧急状态的开始和结束。
结果表明,无论何时将指数衰减函数应用于锁定之外的传输速率,优化器都会在更短的锁定时间内显示更好的性能,遵循动态策略并支持文献中的结果。但是,当传输速率的衰减在锁定范围内时(on-decay 和 decay-decay 的情况),优化器倾向于对两个国家进行更长时间的锁定。
图 6 显示了在实验阶段进行的 32 次运行中的一次,在这种特殊情况下,数据来自意大利。
意大利 10 天的四种进展率情景。
尽管由于模型的简单性,这些结果对实际案例的适用性并不明确,但这项研究为研究动态和连续锁定时传输衰减率的影响提供了很好的见解,表明应在其他优化器(基于代理)和模型(SEIRSHUD)的进一步研究中进一步考虑。
如果你喜欢这个帖子,请考虑 订阅 。你将获得我所有的内容+所有其他来自牛逼创作者的文章!
基于神经网络的新冠肺炎保单多分类
原文:https://towardsdatascience.com/covid-19-policies-multi-classification-with-neural-network-d85cbc0f90c0?source=collection_archive---------25-----------------------
记录我调整 ML 模型的学习曲线,该模型可以分类 20 个类(将来甚至更多)
奥比·奥尼耶多尔在 Unsplash 上的照片
小介绍~
在进入工作的细节之前,我想留出一些空间来分享这个项目和这篇文章背后的动机的总结。
我在 Coronanet.org 度过了一段美好的时光,这是一个了不起的跨国团队,有 500 多名研究助理在一起工作,收集全球新冠肺炎政策的数据。我们的最终目标是以最有用的形式发布尽可能多的政策数据集,然后这些数据集可以用于不同类型的研究/新闻工作。我们组织收集的数据的许多方法之一是手动通读并将其分类为 20 种不同的策略类型(社交距离、锁定等,随便你怎么说)和其他子类型。事实上,许多保单看起来并不清楚它们属于任何特定的保单类型,而且每天都有大量的传入数据,这证明很难仔细检查每一份保单的标签准确性。这就是我们开始用不同的 ML 模型进行实验的地方,以寻找一种可以识别错误编码并比人工工作更有效地清除这些错误的算法。
随着对最佳模式的探索的继续,已经并将会有许多变化。因此,我想记录一些我个人取得的进步、成功和局限性,因为我在不断学习和寻找更好的模型,希望我能为团队的共同目标做出有意义的贡献,无论大小!所以…
让我们开始吧
数据收集
我是从我们机构的公开回购上刮来的数据,可以在这里找到。我使用 s elenium 只从一些选定的国家收集数据集(这些国家有许多已公布的政策记录)。[注:如果您也使用 Chrome,您需要先将Chrome driver下载到您的电脑上,以便运行并打开浏览器。
**from selenium import webdriverdriver=webdriver.Chrome('/Users/irenechang/Downloads/chromedriver')
driver.get('[https://github.com/CoronaNetDataScience/corona_tscs/tree/master/data/CoronaNet/data_country/coronanet_release'](https://github.com/CoronaNetDataScience/corona_tscs/tree/master/data/CoronaNet/data_country/coronanet_release'))**
由于数据集文件名具有相同的格式,我将为所有我想要抓取并解析成这种格式的国家名称制作一个列表。
***#showing only a few countries*
country_names = ['Germany', 'United States of America', 'Spain', 'Australia', 'India']
countries_to_scrape = []*#parse string together*
for country in country_names:
countries_to_scrape.append("coronanet_release_" + country + ".csv")**
selenium 的魅力来了,当你站在浏览器自己移动到页面的地方时,它使所有的刮擦都变得愉快。我们会的
(1)为每个链接创建 xpath
(2)进入每个链接→导航到下载按钮→点击它,
以下代码片段实现了全部自动化:
***# get the link for each data file*
urls = []
for country in countries_to_scrape:
xPath = "//a[[@title](http://twitter.com/title)='"+ country + "']"
print(xPath)
link = driver.find_element_by_xpath(xPath).get_attribute("href")
urls.append(link)**
[注意:如果您以前没有使用过,XPath 是一种查询语言,就像 SQL 一样,但用于 XML 文档,也就是可以在“开发人员工具”中查看的 web“结构”。这里,我们想要提取这些国家的 csv 的链接(也称为 href 属性),这些链接可以在< a >标签中找到,这些标签碰巧具有与所示文本相同的标题(标题属性)
突出显示的部分是我们要导航到的地方
**//a[@title='coronanet_release_Germany.csv']
//a[@title='coronanet_release_United States of America.csv']
//a[@title='coronanet_release_Spain.csv']
//a[@title='coronanet_release_Australia.csv']
//a[@title='coronanet_release_India.csv']**
☝️是来自 print() 的结果,这些是我们的XPath。接下来,按照类似的过程,我们进入第二阶段,获取原始 csv 文件,并连接所有这些数据帧。
**from parsel import Selector
csv_urls = []
for url in urls:
driver.get(url)
sel = Selector(text=driver.page_source)
raw_csv = driver.find_element_by_id('raw-url').get_attribute("href")
csv_urls.append(raw_csv)dfs = []
for csv in csv_urls:
# read each csv into a separate dataframe
dfs.append(pd.read_csv(csv))big_frame = pd.concat(dfs, ignore_index=True)**
数据预处理
从 big_frame 开始,我只对 2 列感兴趣,“描述”和“类型”。
对于其余的预处理步骤,我密切关注 Miguel 的笔记本,可以在这里找到。他每一步的讲解都非常清晰,非常有帮助,尤其是对于我这样刚开始处理文本数据的人。一般来说,核对表应该是:
- 特殊字符和标点符号
- 下放箱子
- 删除号码
- 词干化和词汇化
- 停用字词(国家名称、地区名称以及在正式文件和政策中使用的字词)
- 标签编码
- 列车-测试分离
下面是我的步骤 5 的一个片段:
**#stopwords
nltk.download('stopwords')
stop_words = list(stopwords.words('english'))# include country names in stopwords
country_text = []
for text in df["description_1"].tolist():
for c in pycountry.countries:
if c.name.lower() in text:
text = re.sub(c.name.lower(), '', text)
country_text.append(text)df["description_2"] = country_textfor stop_word in stop_words:
regex_stopword = r"\b" + stop_word + r"\b" df['description_2'] = df['description_2'].str.replace(regex_stopword, '')**
符合模型
首先,由于数据是不平衡的,所以我们将计算类权重,以备以后在神经网络中使用:
**from sklearn.utils import class_weightclass_weights = list(class_weight.compute_class_weight('balanced', np.unique(df2['type']), f2['type']))class_weights.sort()
class_weights*# assign labels to these weights*
weights = {}
for index, weight in enumerate(class_weights) :
weights[index] = weight
weights**
Out:
{0: 0.3085932721712538,
1:0.481440839694655,
2:0.491285285,29698,149953,
3:0.682745,50609,
4:0.66。5566646
接下来,我们将我们训练和测试集转换成可用的对象形式,并打印出来以供查看:
**dataset_train = tf.data.Dataset.from_tensor_slices((X_train.values, y_train.values))
dataset_test = tf.data.Dataset.from_tensor_slices((X_test.values, y_test.values))for text, target in dataset_train.take(5):
print('Desc: {}, label: {}'.format(text, target))**
以下是贴有标签的前 5 个描述的结果:
**Desc: b' us embassy montevideo consular section closed routine consular services notice emergency situations considered time ', label: b'Restriction and Regulation of Government Services'Desc: b' pennsylvania governor signed senate bill waives requirement schools session least days provides continuity education plans ensures school employees paid closure provides secretary education authority waive student teacher standardized assessments march ', label: b'Closure and Regulation of Schools'Desc: b"dumka district n state jharkhand defined government services would remain operational lockdown follows law order agencies - function without restrictions officers attendance - compulsory grade '' 'b' officers reduced % grade 'c' district administration treasury officials - function restricted staff wildlife forest officers - function taking necessary precautions ", label: b'Restriction and Regulation of Government Services'Desc: b'texas reopening non-essential businesses starting may per executive order ga- hair salons barber shops nail salons tanning salons must maintain mandatory ft distance patrons swimming pools operate % capacity may jail time removed enforcement mechanism update may gov abbott removed jail time penalty failing follow covid- restrictions ', label: b'Restriction and Regulation of Businesses'Desc: b' public safety curfew imposed mobile alabama effective pm april remain effect april persons shall remain places residence shall public places ', label: b'Lockdown'**
我们的下一个任务是一次性编码 20 个标签。为此,我创建了一个散列表,以便按类别代码方便地查找值:
**table = tf.lookup.StaticHashTable(
initializer=tf.lookup.KeyValueTensorInitializer(
keys=tf.constant(list(category_codes.keys())),
values = tf.constant(list(category_codes.values()))
),
default_value=tf.constant(-1),
name="target_encoding"
)[@tf](http://twitter.com/tf).function
def target(x):
return table.lookup(x)**
使用这些函数,我们可以将训练集和测试集中的标签编码成数字数组。用 next() 打印出结果
**def fetch(text, labels):
return text, tf.one_hot(target(labels), 19)train_data_fetch = dataset_train.map(fetch)
test_data_fetch = dataset_test.map(fetch)next(iter(train_data_fetch))**
输出(第一个 tf。张量是我们的训练数据,第二个是我们转换的训练标签):
**(<tf.Tensor: shape=(), dtype=string, numpy=b' april mha writes states ensure smooth harvesting sowing operations maintaining social distancing -day lockdown fight covid- - union ministry home affairs mha sent advisory states regarding granting exception agricultural operations lockdown restrictions fight covid- keeping mind harvesting sowing season - advisory exceptions allowed farming operations farmers farm workers procurement agricultural productions operation mandis movement harvesting sowing related machinery etc '>,
<tf.Tensor: shape=(19,), dtype=float32, numpy=
array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 0., 0., 0.,
0., 0.], dtype=float32)>)**
开始创建模型
首先,我们需要在将文本数据输入模型之前对其进行标记。我使用了谷歌已经实现的模型,它将为我们创建一个嵌入层。简而言之,它是这样工作的:
谷歌开发了一个嵌入模型, nnlm -en- dim128 ,这是一个基于令牌的文本嵌入训练模型,在英文谷歌新闻 200B 语料库上使用了一个三隐层前馈神经网络语言模型。这个模型将文本的任何主体映射到 128 维的嵌入中
要使用它,只需传入该型号的链接,该链接可以在这个网站上找到【注意:您可能需要检查以确保您正在使用的版本是最新的,否则它会给你错误】:
**embedding = "[https://tfhub.dev/google/nnlm-en-dim128/2](https://tfhub.dev/google/nnlm-en-dim128/2)"
hub_layer = hub.KerasLayer(embedding, output_shape=[128],input_shape=[], dtype=tf.string,
trainable=True)
hub_layer(train_data[:1])**
潜入这一层给了我们什么:
**<tf.Tensor: shape=(1, 128), dtype=float32, numpy=
array([[ 1.85923278e-01, 3.82673025e-01, 8.69123638e-02,
-2.36745372e-01, -1.19763926e-01, -5.65516986e-02,
2.45870352e-01, 5.02816178e-02, -2.10541233e-01,
-4.42932360e-02, 1.28366366e-01, 1.47269592e-01,
1.41175740e-04, 4.45434526e-02, 2.13784329e-03,
1.61750317e-01, -2.32903764e-01, -2.10702419e-01,
-2.09106982e-01, 1.55449033e-01, 4.53584678e-02,
4.31233309e-02, 1.48296393e-02, -1.68935359e-01,
1.12579502e-01, -1.03304483e-01, 1.61703452e-01,
2.13061482e-01, -4.74388264e-02, 1.27027377e-01,
-3.04564610e-02, -1.92816645e-01, -3.22420187e-02, ... ]])**
神经网络模型的陷阱是过度拟合,一如既往,因此我们通常必须使用脱落层来正则化它。Dropout layer 是一种正则化神经网络的工具,其中许多层的随机输出被忽略,因此稀疏网络将不得不适应纠正来自先前层的错误(阅读更多此处)。
在不知道我的模型是否会出现这种情况的情况下,我训练了两个模型,一个有脱落层,另一个没有,并比较了它们的结果。对于这些模型,不要忘记使用早期停止。
***#build the basic model without dropout*
model_wo_dropout = tf.keras.Sequential()
model_wo_dropout.add(hub_layer)
for units in [128, 128, 64, 32]:
model_wo_dropout.add(tf.keras.layers.Dense(units, activation='relu'))
model_wo_dropout.add(tf.keras.layers.Dense(19, activation='softmax'))model_wo_dropout.summary()*#compile the model*
model_wo_dropout.compile(optimizer='adam',loss=tf.keras.losses.CategoricalCrossentropy(from_logits=**True**), metrics=['accuracy'])train_data_fetch = train_data_fetch.shuffle(70000).batch(512)
test_data_fetch = test_data_fetch.batch(512)*#fit the model*
from keras import callbacks
earlystopping = callbacks.EarlyStopping(monitor="val_loss", mode="min", patience=5, restore_best_weights=**True**, verbose=1)
text_classifier_wo_dropout = model_wo_dropout.fit(train_data_fetch, epochs=25, validation_data = test_data_fetch,
verbose=1, class_weight=weights, callbacks =[earlystopping])**
对我们的测试和训练集的评估~
***#training errors*
y_train_pred = model_wo_dropout.predict(train_data)
print(classification_report(train_labels.numpy().argmax(axis=1), y_train_pred.argmax(axis=1)))*# test errors*
test_data, test_labels = next(iter(dataset_test.map(fetch).batch(test_length)))
y_pred = model_wo_dropout.predict(test_data)
print(classification_report(test_labels.numpy().argmax(axis=1), y_pred.argmax(axis=1)))**
培训结果
测试结果
结果,与我在建立这个神经网络之前尝试作为基线模型的逻辑回归模型相比,提高了 10%,这是一个非常好的景象。我将在完成对漏失层模型的实现后进一步讨论这些结果。
带有脱层的模型,用于确认过度拟合
正如我之前所说,为了确认我们的模型是否过度拟合数据,我训练了一个具有几个丢弃层的二级神经网络,并比较了结果。我们可以在 0.1-1.0 的范围内网格搜索最佳压差参数。这里,我用 0.3 作为参数。
我们必须重建训练和测试设备。这种模型的唯一区别在于图层构建过程。从这一点开始,所有的一切都与没有脱落层的模型相同。重要的是要注意,我们不应该在输出层(也就是最后一层)之前有脱落层,因为输出层不能再纠正前面层的错误,所以添加另一个脱落层最终会损害模型的性能(我就是这种情况)。
***# re-create train, test data for fitting the model*
train_data_fetch_dropout = dataset_train.map(fetch)
test_data_fetch_dropout = dataset_test.map(fetch)*# build a similar model but with the dropout layers*
model = tf.keras.Sequential()
model.add(hub_layer)
**for** units **in** [128, 128, 64]:
model.add(tf.keras.layers.Dense(units, activation='relu'))
model.add(tf.keras.layers.Dropout(0.3))
model.add(tf.keras.layers.Dense(32, activation='relu'))
model.add(tf.keras.layers.Dense(19, activation='softmax'))
model.summary()**
结果如下:
培训结果
测试结果
~讨论和扩展问题:
- 有和没有脱落层的模型的性能基本相同。即使使用了脱落层,训练和测试误差之间的差异也没有改善。事实上,与没有 dropout 层的模型相比,使用 dropout 层的模型无法预测更多类别的标签(许多类别的准确率为 0%)。然而,在检查了大数据集和正则化没有显著改善模型的事实之后,我不认为过度拟合在这个模型中是个大问题。进一步的分析可能涉及在不同的辍学率值上拟合模型,以确认性能没有提高是因为我们没有选择一个好的辍学率,还是因为数据集本身。
- 逻辑回归以及其他 ML 模型在训练和测试误差之间没有那么大的差距。可以说,这些最大似然模型不像神经网络模型那样遭受过度拟合,然而,假定我们已经使用了最佳参数,这些模型很难进一步改进。与此同时,神经网络有很好的机会超越这一点。由于我们的兴趣在于获得更准确的预测,我们将使用神经网络。
- 据观察,在我添加了更多的数据点(更多的国家)后,两个模型的总体准确性都提高了。这让我想知道获得所有可用的数据是否会进一步提高准确性。
- 在不同的拟合尝试中,精度显示出轻微的波动(由于神经网络模型可能落入“局部最大/最小”陷阱的事实),但平均而言,结果在范围[0.66-0.71]内,这比我拟合的机器学习模型的平均结果(约 59-60%)增加了约 5-10%。查看混淆矩阵,每个类别中的指标也有所改善。
- 另一个可能影响模型预测能力的来源是,许多类别(以健康资源、健康监控和健康测试为例)共享许多共同的词,因此接下来的步骤之一是识别和开发在不同类别中出现很多的停用词的集合,以减少这些类别之间的相似性,并查看这是否会进一步提高性能。
总之,这个神经网络模型非常简单,肯定有改进的空间,重点是数据预处理过程(更多停用词、过采样/欠采样),以及进一步的交叉验证以达到平均精度。话虽如此,这对我来说是一次非常充实的学习经历,也是第一次接触神经网络!如果你已经走了这么远,非常感谢你!我期待着更新你更多关于我的这个模型的未来版本。
这个笔记本的完整版本可以在这个 Github repo 中找到:
**https://github.com/irenechang1510/Topic-classification-NN/blob/main/Topic classification with Neural Network.ipynb
请随时通过我的 LinkedIn 联系我,如果您有任何问题,我很乐意与您联系!
参考资料:
[1] Dipanjan (DJ) Sarkar,面向自然语言处理的深度迁移学习—具有通用嵌入的文本分类 (2018),面向数据科学
[2] Miguel Fernández Zafra,Python 中的文本分类 (2019),towardsdatascience**
通过数据故事分析新冠肺炎疫苗接种进展
原文:https://towardsdatascience.com/covid-19-vaccination-progress-analysis-around-the-world-736d7e57f198?source=collection_archive---------12-----------------------
全球不同国家新冠肺炎疫苗接种项目的详细数据分析和以结果为导向的故事讲述。
设计者: Nevil Sutaria
在过去的一年里,新冠肺炎疫情是世界上最严重的健康灾难。预测新冠肺炎疫苗接种趋势已成为一个具有挑战性的问题。许多卫生专业人员、统计学家、研究人员和程序员一直在使用各种方法跟踪病毒在世界不同地区的传播。天才科学家开发的各种疫苗的增加激发了对正在进行的疫苗项目的更多了解的好奇心,以及从数据中找到有意义的见解的浓厚兴趣,驱使我致力于这一特殊的努力。
在查阅了多个网站后,我在 Kaggle 上找到了合适的数据集。我特别使用了 Jovian 来完成这个项目,因为它易于使用和理解。此外,完整的代码可在 GitHub 上获得。
该项目旨在通过使用从互联网收集的数据中发现的推论,传达对全球不同正在进行的疫苗接种计划的分析。探索性数据分析中使用的 python 库包括 NumPy、Pandas、Matplotlib、Seaborn 和 Plotly 。以下项目的目标包括:
- 哪个国家首先开始为其公民接种疫苗?
- 哪个国家拥有最高的接种人群?
- 提供哪些不同类别的疫苗?
- 各国使用哪种疫苗?
数据准备和清理
我们读取数据文件,并聚合几个字段的数据(国家、iso_code 和疫苗——特定国家使用的疫苗接种方案)。数据清理是成功的数据分析项目中最关键的一步。在大多数情况下,数据集只有很少的“NaN”(非数字)值、一些空行(值为 0)以及冗余列,可以使用和配置 drop function 并根据需要将 NaN 值更改为 0 或删除整行来删除这些值。
“数据科学家花 60%的时间清理和组织数据。~根据福布斯的一项调查
探索性数据分析和可视化
我们将初始化 Python 包,我们将使用这些包进行数据摄取和可视化。我们将通过设置字体大小、图形大小、面部颜色等来配置环境。此外,我们通常会使用 seaborn 进行可视化。
现在,我们可以通过处理目标来开始处理数据。
1。哪个国家的公民接种疫苗最快?
为了绘图,我们需要一组以特定方式排列的数据值。可以通过使用 groupby()、max()、sort_values()等方法来实现。此外,我们将比较前 10 个国家的简洁可视化。排列好之后,我们可以使用 seaborn 内置函数绘制它们,如下所示。
从下面的图像中可以清楚地看到,以色列在人均剂量方面领先世界,每 100 个人就有超过 80 个剂量。
2。哪个国家接种疫苗的人数最多?
让我们找出接种疫苗人数最多的国家。为了便于可视化,我们将考虑排名前 10 位的国家。在这里,我们使用 matplotlib 绘制了数据,并使用了总接种量系列。
从下面的图像中可以清楚地看到,美国大约有 6000 万人接种了疫苗。
3。提供哪些不同类别的疫苗?
为了找到不同的类别并了解哪种疫苗被广泛使用,我将代码整理如下:
辉瑞在世界上最常用的新冠肺炎疫苗名单中名列榜首,其次是 Mordema 和牛津-阿斯利康。
4。不同国家使用的疫苗有哪些不同?
在这个特定的目标中,我们将使用 Plotly 库来绘制一个二维世界地图。这里我们使用 iso_code 来获取特定地区/国家的位置。此外,hover_name 属性用于创建动态图表,以便当我们将鼠标悬停在某个特定国家时,它会显示疫苗的详细信息。
要看动态图,请点击这里。
推论和结论
从上面的分析和可视化,我们可以得出结论:
- 在 以色列,给病人接种疫苗的比率最高。
猜想:是因为它的面积小(就面积和人口而言),人口相对年轻,2020 年 12 月天气相对温暖,中央集权的国家政府制度,以及对大规模国家突发事件实施迅速反应的发达基础设施。
2.*美国接种疫苗的人数最多,约占其总人口的 6000 万 其次是 中国 和 英国 。*
推测:由于这些都是发达国家,疫苗对公众来说更容易获得。
3。 Moderna、辉瑞/BioNTech 是世界范围内最受欢迎的疫苗,因为它几乎没有副作用(迄今已知)。此外,印度使用 Covaxin,Covishield 为其公民接种疫苗。
4.不同的国家使用不同的疫苗,即、* 印度 — Covaxin、牛津/阿斯利康、 美国 — Moderna、辉瑞/BioNTech、**以色列 — Moderna、辉瑞/BioNTech、 英国 —牛津/阿斯利康、辉瑞/*
从推论和推测中,可以得出这样的结论:来自世界各地的人们都在自我教育,并愿意在政府的免费疫苗接种计划下接种疫苗。此外,这些疫苗已被证明对新冠肺炎有效(到目前为止)。如果接种疫苗的人数继续增长,那么所有国家都可以在今年年底前为其人民接种疫苗。
参考资料和未来工作
我们可以通过比较接种疫苗前和接种疫苗后的死亡人数来扩展该数据集的用途,以检查每个国家每种疫苗的有效性。
资源:
- 数据集
- 数据分析课程
- 新冠肺炎疫苗接种
- 日期时间库文档
- Matplotlib 文档
- 辅导点
- Seaborn 文档
- 熊猫文档
- Plotly 文档
- W3schools
设计者: Nevil Sutaria
新冠肺炎疫苗接种:对印度有什么好处?
原文:https://towardsdatascience.com/covid-19-vaccination-what-does-it-hold-for-india-992550aeb217?source=collection_archive---------27-----------------------
使用 R 可视化当前疫苗接种数据,并估计在印度 5 个邦接种疫苗所需的时间
丹尼尔·施鲁迪在 Unsplash 上拍摄的照片
简介
新冠肺炎疫情已经影响到世界各国,印度对此并不陌生。从旅行禁令开始,到防护设备、病床、氧气瓶甚至医生的严重短缺,该国人民经历了许多苦难。然而,随着疫苗接种运动的开始,似乎有了一个更美好的未来。
我对疫苗接种运动的效果很好奇,所以我决定把这个问题分成几个小问题
- 我们应该选择哪 5 个州来可视化疫苗接种曲线?
- 疫苗的施用在性别、疫苗类型或年龄组方面有什么不同吗?
- 给定上述信息,我们能否估计在某一特定州给所有人接种疫苗需要多少天?
为了探索这一点,我收集了印度 5 个邦的疫苗接种数据——德里、西孟加拉邦、马哈拉施特拉邦、卡纳塔克邦和北方邦,并使用 R 来可视化基于不同类别的数据。利用这些数据和每个州的人口普查数据,我试图准确地估计出该州所有人接种疫苗所需的时间。然而,值得注意的是,该模型完全基于疫苗接种数据。如果与每个州的感染和死亡率的额外数据相结合,它将更加敏感,从而产生更准确的估计。
通过这篇文章,我将分享我的思考过程、发现和分析。
第一部分:为什么选择这 5 个州?
我选择的五个邦是德里、西孟加拉邦、马哈拉施特拉邦、卡纳塔克邦和北方邦。选择它们最重要的原因是因为这五个州都是印度感染人数最多的前 10 个州(1)。此外,考虑到 UP 的人口是德里的 7.7 倍,我认为比较德里和北方邦之间的疫苗接种率会很有趣。
第二部分:使用 R 可视化疫苗接种数据
下一步是可视化使用 R 收集的数据,并观察数据中的模式。除了绘制接种疫苗的总人数随时间变化的图表之外,我认为根据 3 个类别比较 5 个州会很有趣:性别、疫苗类型和年龄。让我们看看每个类别中的州是如何比较的。
A .总体接种曲线——接种总人数与时间
5 个州中每个州的“随时间接种疫苗的总人数”图表
在所有 5 种状态中,我们观察到一条 S 形曲线。这种模式是人口曲线的特征,因此毫不奇怪我们在疫苗接种曲线中也看到了这种模式。疫苗接种率起初滞后,但在大约第 50 天(或 2021 年 3 月 7 日)后呈指数增长。总的来说,很高兴看到五条疫苗接种曲线都呈指数增长!
B .比较关于性别的曲线
5 个州中每一个州的“接种疫苗的个体与时间和性别的关系”图表
现有数据只包括三种性别——男性、女性和变性人。虽然很高兴看到所有五个州的男性和女性的曲线都相似,但同样重要的是要注意到两性之间的差距随着时间的推移而增加。这种模式的唯一例外是卡纳塔克邦。除了是唯一一个女性疫苗接种曲线比男性更陡的州,它也是唯一一个两性之间的差距不会随着时间的推移而增加的州。
尽管跨性别个体已经被纳入数据集的一部分,但他们的疫苗接种曲线在所有五个州似乎都是接近零的直线。其原因可能是,与那些认为自己是男性和女性的人相比,认为自己是变性人的人数非常少。
C .比较关于疫苗类型的曲线
5 个州中每一个州的“接种疫苗的个人与疫苗类型的时间关系”图表
在印度,目前有三种疫苗获得批准——CoviShield/Astrazeneca-Oxford 疫苗、Covaxin 和 Sputnik V。
在所有五个状态中,我们看到 CoviShield 和 Covaxin 曲线之间的巨大差异。可能是人们在有意选择 CoviShield 而不是 Covaxin 或许 CoviShield 更容易获得,能够满足所有州的供应要求。
在所有五个状态中,我们观察到史泼尼克五号的曲线是一条接近零的直线。这表明接受 Sputnik V 疫苗的人数远远少于接受 Covaxin 或 CoviShield 疫苗的人数。这是意料之中的,因为 Sputnik V 最近刚刚获得印度政府的批准,并于 5 月 17 日至 23 日在市场上出售。因此,看到曲线还没有呈指数增长并不奇怪。
D .比较关于年龄的曲线
五个州中每一个州的“接种疫苗的个体年龄分布图”
CoWIN 疫苗接种门户网站将人群分为三个不同的年龄组——18-45 岁、45-60 岁和 60 岁以上。
一般来说,我们看到 45-60 岁和 60 岁以上的年龄组有相似的疫苗接种曲线。然而,德里的情况并非如此,因为 45-60 岁年龄组的疫苗接种曲线远比 60 岁以上年龄组的疫苗接种曲线陡峭。此外,我们还看到,在德里,60 岁以上年龄类别的曲线在第 80 天左右(或 2021 年 4 月 6 日)开始变平。这背后的原因尚不清楚。
在所有 5 个州,18-45 岁年龄组的疫苗接种曲线起初滞后,但在大约第 105 天(或 2021 年 5 月 1 日)后出现大规模指数增长。这是有意义的,因为 CoWIN 疫苗接种门户网站只允许 18 岁以上的个人在 2021 年 5 月 1 日之后注册接种疫苗。
第三部分:估算特定州所有人接种疫苗所需的天数
现在,我已经将所有这些数据可视化并观察到某些趋势,一个想法浮现在脑海中——有没有一种方法可以预测为某个特定州的所有人接种疫苗需要多少天?
为了回答这个问题,我采用了一种简单的数学方法。使用 R,我开发了一个线性回归模型,并获得了五个州中每个州接种疫苗的总人数随时间变化的趋势线。然后,利用这个等式和印度的人口普查数据(3,4),我通过逆向工作计算了该邦所有人接种疫苗所需的预计天数。下表总结了我的发现。
总结调查结果的表格
注:上述卡纳塔克邦人口的最后一次记录是在 2020 年,即 2021 年的数字尚未更新。对于所有其他国家,人口是基于目前的数字。
上面的数字挺有意思的。我的观察总结如下:
- 德里的人口是所有邦中最少的,我们预计为所有人接种疫苗需要 345 天。
- 尽管卡纳塔克邦的人口是德里的 2.3 倍,但预计为所有公民接种疫苗需要 342 天(比德里少 3 天)。这表明卡纳塔克邦在疫苗接种方面做得很好。
- 马哈拉施特拉邦的人口是德里的 4.2 倍,卡纳塔克邦的 1.8 倍,但它预计只有 355 天的时间为所有人接种疫苗。这仅仅比德里的预测天数多 10 天,考虑到它的人口,这是值得称赞的。
- 最后,我们有西孟加拉邦和北方邦。西孟加拉邦的人口是德里的 3.3 倍,而北方邦的人口是德里的 7.7 倍。尽管存在如此巨大的差异,西孟加拉邦所有人接种疫苗的预计天数为 549 天(仅为德里预计时间的 1.6 倍),澳大利亚首都地区为 585 天(仅为德里预计时间的 1.7 倍)。这是非常值得称赞的,表明考虑到他们庞大的人口,西孟加拉邦和北方邦的疫苗接种工作是有效的。
总之,30、180 和 360 天后接种疫苗的人口的估计百分比显示在下面的柱状图中。
柱状图显示了分别在 30、180 和 360 天后各州接种疫苗人口的估计百分比
假设目前的疫苗接种率——预计德里、马哈拉施特拉邦和卡纳塔克邦将在未来 1 年多内为所有人接种疫苗,而北方邦和西孟加拉邦也需要一段时间才能做到。
最终想法
拥有 13.9 亿人口的印度是世界上疫苗接种规模最大的国家之一。专家表示,70-85%的人口需要接种疫苗以获得群体免疫,这意味着至少有 9.73 亿人(5)。虽然该分析仅考虑了有限时间内的 5 种状态和数据,但一旦有更多数据可用,观察疫苗接种曲线如何变化将是有趣的。
该模型考虑了纯粹从疫苗接种活动中获得的数据。如果结合更多关于每个州的感染率和死亡率的信息,将有助于我们将疫苗接种活动与感染率联系起来。这将是政府和卫生官员手中的一个非常重要的政策工具,以帮助印度实现无 COVID。
参考和链接:
- https://www . business insider . in/India/news/新冠肺炎-印度各州案例/slidelist/81984395.cms
- https://www . livemint . com/news/India/Sputnik-v-vaccine-has-reach-the-India-to-be-available-by-next-week-gov-official-11620904330559 . html
- https://www . India online pages . com/population/state-wise-population-of-India . html
- https://www.macrotrends.net/cities/21228/delhi/population
- https://health . Cleveland clinic . org/在疫情战争结束之前,有多少人需要接种疫苗/
- http://www . sth da . com/English/wiki/be-awesome-in-gg plot 2-a-practical-guide-to-be-high-effective-r-software-and-data-visualization
从 Kaggle 链接到数据集:
https://www.kaggle.com/sudalairajkumar/covid19-in-india?select = covid _ vaccine _ state wise . CSV
链接到 GitHub 上的代码:
https://github.com/dikshasen24/COVID-19-Vaccination-Article
基于线性规划的新冠肺炎疫苗预约分配
原文:https://towardsdatascience.com/covid-19-vaccine-appointment-allocation-using-linear-programming-a5e20119090?source=collection_archive---------33-----------------------
分享我在马来西亚国家新冠肺炎免疫计划(PICK)中的数据科学经验
照片由 Pexels 的 Nataliya Vaitkevich 拍摄
国家新冠肺炎免疫接种计划,通常被称为 PICK ,是马来西亚政府目前正在实施的一项全国疫苗接种运动,旨在通过成功实现居住在马来西亚的公民和非公民的群体免疫,遏制新冠肺炎病毒的传播,并在马来西亚结束新冠肺炎疫情。【1】
作为马来西亚卫生部动员计划的一部分,我被分配到protect Health Corporation Sdn Bhd(protect Health)协助过去 3 个月的 PICK 计划。ProtectHealth 是一个由卫生部指定的法人实体,旨在将私人医生转变为新冠肺炎疫苗接种计划中的疫苗接种员。
在 ProtectHealth 下,我加入了处理私人全科医生(GP)和私人医院的团队。我们的任务是促进他们与州卫生部和我的 Sejahtera 团队之间的疫苗接种计划。在本文中,我将以全科医生为例,因为仅私人全科医生就贡献了总疫苗接种量的 5% 。
每周,我们将与相关方沟通,根据 GP 预先商定的剂量模型分配疫苗预约。
疫苗接种者预约分配是指在未来某个日期给予 GP 的新doe one预约的数量,对于 GP,我们的目标是每周一次。MySejahtera 团队将根据分配情况推送已注册的受种者。
例如,GP A 同意每周 300 剂的模型(第一剂和第二剂),我们将需要用下周的新号码填充空白的第一剂疫苗接种槽。请参考下图以获得更好的说明:
过程的图解。作者图片
产生疫苗预约的困难。
当你只需要为一个全科医生或一个小区域分配预约时,这听起来很容易,但当你处理全国所有的全科医生时,事情就会变得混乱,每周大约有1000-2000 人,,而时间是你唯一没有的东西。
我们面临的情况如下:
- 推出辉瑞疫苗,该疫苗需要将特定州或地区的受种者四舍五入到最接近的 6 位。
- 由于各种原因,如 EMCO 或物流问题,在某个地区突然停止提供疫苗注射
- 新给药方案的分配
- GPs 的各种运行时间/天数
- 以及更多需要临时决定的情况😢。
问题的说明——每周要安排多少次约会(第一剂)。作者图片
这些情况的后果,我们决定我们需要一个健壮的系统,能够:
- 一键重新生成疫苗接种预约,即快速
- 能够为州和地区添加新的排除或包含规则
- 能够添加新的剂量方案
- 根据现有的第二次剂量预约优化我们的分配,以优化全科医生的能力
- 能够四舍五入到最接近的六位,以防止疫苗接种者的浪费
- 不要过量给全科医生增加负担
线性规划来拯救
线性规划或 LP,一种数学建模技术,其中线性函数在受到各种约束时被最大化或最小化。【2】
在下面的例子中,我们有一个变量 X 和 Y,其中 X + Y 必须小于 5,只有 X 必须小于或等于 2。X 和 Y 可以是什么?线性规划将从可行域中找出最大(最优)点(2,3)。
最佳点的简单说明,作者提供的图像
在接种者预约分配中应用 LP:
使用上述概念,我们将总剂量方案的约束公式化为:
**Mon + Tue + Wed + Thurs + Fri + Sat + Sun < Total Dose**
如果我们想在一周的某一天停止,我们可以根据状态动态添加规则:
If state == "Johor", then let Fri == 0
如果我们想把总剂量减少到 6
If drug == "Pfizer" then round_down(Daily dose of M/Tu/W/Th/F/Sa/Su)
LP 模型为我们的疫苗预约生成提供了灵活性,因为我们能够使用该模型根据多个州和机构的请求添加多个条件。我们使用的 python 包是 PuLP,更多关于 PuLP 的信息,可以访问这里。
应用 LP 的结果:
在我们的分配模型中应用 LP 之后,我们可以在每周不到 5 分钟的时间内重新生成我们的每周约会。任何特别的变化都可以立即在我们的主数据库中进行。这些变化将反映在重新生成的每周约会中,因为我们已经自动化了整个数据 ETL(提取、转换、加载)过程。
然而,值得一提的是, LP 并没有解决我们所有的问题,我们仍然需要手动添加一些特殊情况或非常非常特别的情况,但它解决了我们在生成每周疫苗预约分配中几乎 95%的问题。
最终想法:
将书中的内容应用到现实生活中的问题需要你调整参数并有一点点创造力,但是通过对基本概念的深刻理解,你可以将理论应用到实践中。有些人可能会说 LP 可能不是问题的最佳解决方案,但它确实解决了我们在疫情期间的痛苦。
最后,在我看来,LP 是数据科学从业者必须学习的重要技术,尤其是当您需要优化生产力和避免设施浪费时。
如果你对 LP 感兴趣,可以看下面另一篇文章:
https://medium.datadriveninvestor.com/an-introduction-to-modern-portfolio-theory-mpt-in-portfolio-optimization-d19cd8b16b34
如果你想成为中等会员,可以考虑通过这个链接支持我
致谢:
感谢博士的团队成员。和你们一起工作是我的荣幸。感谢你们在整个疫苗接种项目中几乎每天都在工作。
在我的硕士学习期间,我选修了一门叫做商业智能和决策分析的课程,老师是的黄·李沛博士。我很感激他耐心地教我这个技巧。这是一种奇妙的技术!
新冠肺炎疫苗——公众情绪如何?
原文:https://towardsdatascience.com/covid-19-vaccine-whats-the-public-sentiment-7149c9b42b99?source=collection_archive---------36-----------------------
使用 NLP (Stanza、NLTK Vader 和 TextBlob)对新冠肺炎疫苗推文进行逐步情感分析
疾控中心在 Unsplash 拍摄的照片
新冠肺炎疫情自称是最严重的全球威胁之一,并且仍然是一个持续的威胁。同样,我们正处于人类历史上最大的疫苗接种运动中。据彭博报道,到目前为止(截至 2020 年 1 月 26 日),已经在 56 个国家注射了令人震惊的 6810 万剂疫苗。
虽然疫苗为抗击新冠肺炎带来了新的希望,但它也引发了激进的反疫苗运动。因此,用最近推特数据上的情绪分析(Python 语言)来衡量公众对新冠肺炎疫苗的看法将会很有趣。
泰勒:博士
- TextBlob 和 NLTK Vader 有相似的情绪比例趋势(正面 > 中性 > 负面),而 Stanza 的情绪趋势与此相反(负面 > 中性 > 正面)
- 从集合方法的结果来看,总体情绪是****混合,只是稍微偏向正面,基于正面 ( 40.0% )和负面 ( 38.4% )情绪的比例****
- 链接到 GitHub repo
内容
1。Twitter API2 的设置。提取并预处理推文3 .感情分析用 NLTK 维德4。用 text blob5 进行情感分析。感情分析同节6。感悟来自感悟7。用集成方法合成情感
1.Twitter API 的设置
要使用 Twitter API,我们首先需要一个 Twitter 开发人员帐户:
- 步骤 1 :前往 Twitter 开发者应用页面创建一个开发者账户
- 第二步**:申请被批准后(这可能需要一天时间,但我的申请马上就被批准了),前往开发者仪表板。点击侧边栏上的'项目&应用 ' > ' 概述,进入概述部分。点击“新建项目按钮创建一个新项目。
作者推特截图
- 第三步:返回概述并点击钥匙图标以访问新创建项目的钥匙和令牌。
作者推特截图
- 第四步:生成(或重新生成)这 4 个代码:(1) API Key、
(2) API Secret、 (3) 访问令牌、 (4) 访问令牌 Secret 。记住保存这 4 个代码,因为我们以后会用到它们。
点击“生成”或“重新生成”时弹出显示访问代码的窗口
2.提取和预处理推文
Twitter API 认证
我们将使用tweepy包来访问 Twitter API。您可以使用以下命令安装该软件包:pip install tweepy
****
使用之前保存的访问凭证(4 个代码),我们可以设置 Twitter API 认证。
推文提取
以下是 tweet 提取代码的主要考虑事项:
- 每 15 分钟有 900 个 API 调用的速率限制,所以我们需要在代码中加入一个
time.sleep(15 * 60)
步骤 - 我提取了最近 7 天的每一天,因为 Twitter API 只允许提取 7 天前的推文
- 为了获得与新冠肺炎疫苗相关的推文,使用的搜索词是‘covid 19 covid 疫苗’
- 排除被转发或非英语的推文
对于这个项目,检索了以下属性:用户名、位置、推文文本、标签和推文日期。使用我编写的提取代码,我能够在不到 2 小时的时间内提取大约 13,000 条推文。**
摘录的推文示例
文本预处理
正如你所料,推文文本会变得非常混乱。幸运的是,我们可以使用tweet-preprocessor包来高效地执行预处理。可以安装pip install tweet-preprocessor
默认情况下, tweet-preprocessor 会删除 URL、标签、表情符号、保留字(如 RT)和提及等项目。如果你想定制推文的预处理方式,请查看他们的文档。我使用了默认设置,代码如下所示:
其他预处理步骤包括:
- 从原始 标签 栏的字典中提取单个标签
- 只保留带有包含字符串' vacc '的文本或标签的推文
- 删除带有重复 tweet 文本的行
我们的 Twitter 数据集现在已经准备好进行情感分析,我们将使用 3 个独立的包来进行分析。我们开始吧!
让我们看看我们能从新冠肺炎疫苗相关的推特数据中得到什么启示|图片由 Joshua Hoehne 在 Unsplash 上发布
3.用 NLTK Vader 进行情感分析
介绍
自然学习工具包( NLTK )是一个 Python 包,提供了支持自然语言处理(NLP)的程序,并附带了预先训练好的模型。
特别是,我们将使用价感知词典和情感推理机(【VADER】)模型,这是一个词典和基于规则的情感分析工具,旨在对社交媒体文本进行情感分析。它使用一个带有简单启发的单词包方法(例如,在出现某些单词如“very”时增加情感强度)。
设置和分析
使用pip install nltk
安装 NLTK 后,我们可以使用 Vader 模型运行情感分析:
Vader 返回复合分数,这是给定文本的单一一维情感测量。得分范围从-1(最负面)到+1(最正面),中性情绪得分在 - 0.05 到 0.05 之间任意设定。
4.使用 TextBlob 进行情感分析
介绍
TextBlob 是一个流行的 Python 库,用于处理文本数据和执行一系列 NLP 任务,包括情感分析。与 NLTK Vader 类似,TextBlob 情感分类器是基于单词包方法的。事实上,TextBlob 是建立在 NLTK 和模式库之上的。
设置和分析
这是安装 TextBlob 的命令:pip install textblob
,下面是运行 TextBlob 情感分析的方法:
TextBlob 情感分析器返回两个分数,即极性和主观性。我们看极性得分,就像维达一样,是一个在-1 和 1 范围内的浮点数,其中-1 表示最负,+1 表示最正。同样,对于维达,中性情绪被任意定义为介于 - 0.05 和 0.05 之间的分数。
5.用 Stanza 进行情感分析
介绍
Stanza 是 Stanford NLP 组的官方 Python NLP 库,取代了基于 Java 的 CoreNLP 。这些模块建立在 PyTorch 的基础上,其预建的情绪分析器基于 CNN 分类器,该分类器在数据集上进行训练,包括斯坦福情绪树树和航空公司推特情绪。
设置和分析
使用命令pip install stanza
安装节库。然后,我们下载 Stanza 的英语包,并运行情感分析:
Stanza 返回一个从 0 到 2 的情感分数,映射: 0: 阴性, 1: 中性, 2: 阳性。由于每条推文可能包含许多句子,我们对每条推文的句子取平均分。
6.来自情感分析的见解
在使用三种不同的分析器生成情感之后,是时候使用seaborn
库来可视化和解释结果了。
NLTK Vader 和 TextBlob 的情绪比例相对相似,正面情绪最高,负面情绪最低。 TextBlob 是迄今为止最积极的,对积极情绪的回复为 48.5% 。另一方面,第节产生的情绪是最负面的,负面情绪的比例最高( 42.6% )。
总体而言,TextBlob 和 NLTK Vader 情感评分比 Stanza 的高 ( 即更积极)。这一发现证实了另一项分析对 TextBlob 和 Stanza 情感分析的比较。
虽然 TextBlob 是最受欢迎的 Twitter 数据情感分析器,但 Stanza 当然值得探索,因为它部分是在 Twitter 数据集上训练的。这里的结果是一个很好的例子,说明了在不同数据集和方法上训练的不同分析器如何导致不同的结果。
在手动查看了 100 条推文的样本后,我发现最具代表性的观点位于 TextBlob(有点过于积极)和 Stanza(有点过于消极)之间。让我们试着得到介于两者之间的情感结果。
7.用集成方法合成情感
我运用了一些创造性的方法,从三个情感分数的平均值中创建了一个综合分数。所有 3 个分数都已经在[-1,1]的范围内,并且在计算平均值时给予相同的权重。
与前面的步骤一样,分数 ≥ 0.05 被定义为正,分数 ≤- 0.05 被定义为负,两者之间的任何值被设置为中性。通过综合评分和分类系统,我们得到了以下结果:****
积极情绪( 40.0% )的比例略大于消极情绪( 38.4% )的比例,但这两个比例被认为相似。这表明,在分析点上,对新冠肺炎疫苗的总体情绪往往是混合的,只是稍微倾向于正面的情绪。****
结论
在这篇文章中,我写了通过 Twitter API 提取与新冠肺炎疫苗相关的推文,并实现了 3 个不同的情感分析器(NLTK Vader、TextBlob、Stanza)来评估这些推文。
展望未来,仍有很大的探索空间。
- 基于推文日期的观点趋势
- 评估不同地区(如国家)的观点
- 为中性情绪尝试不同的分数阈值
- 评估 TextBlob 返回的主观性组件
期待您加入我的数据科学学习之旅!请随时关注此媒体页面以了解更多数据科学内容,或者在 LinkedIn 上联系我。
CovidSimNet:介绍一种确定“相似”COVID 状态的方法
原文:https://towardsdatascience.com/covidsimnet-introducing-a-method-to-determine-similar-covid-cities-6d6701aad03b?source=collection_archive---------37-----------------------
使用数据来确定 COVID 状态相似性矩阵,以估计政策对相似状态和“高风险”状态的影响
在分析和证明假设的过程中,数据一直扮演着不可或缺的角色。随着高度优化且易于使用的框架的出现,几乎每秒钟都在收集数据。世界上最有价值的资源不再是石油,而是数据(《经济学家》)。据估计,到 2025 年,每天将产生约 463 艾字节(1 艾字节可存储 5 万年的 DVD 质量视频)的数据。
约翰·斯诺,英国医生,现代流行病学的创始人之一,在 19 世纪发现霍乱的源头是被污染的公共水泵。他通过在地图上绘制霍乱病例发现了这一点,并调查了大多数病例都是靠近水泵的人。
照片由米卡·鲍梅斯特在 Unsplash 上拍摄
介绍
在本文的中,我们提出了一种看似合理的方法,通过创建一个逐状态相似性矩阵,该方法可用于识别相似的 COVID-hit 状态。该矩阵可进一步用于同时估计许多州的政策效果,也可用于确定高风险州。
数据
我们将使用美国每个州的 COVID 数据,包括每个州的确诊病例、死亡人数和人口。我们从约翰霍普金斯大学 系统科学与工程中心(CSSE)的 新冠肺炎数据仓库中检索数据集。
对于每个州和日期,我们都有确诊病例(死亡病例也是如此)(图片由作者提供)
为了从这些熊猫数据框架中提取相关信息,我们首先汇总每个日期的确认数量和死亡数量,然后将其与每个州的人口数合并。在执行所有预处理和聚合后,我们检索最终的数据帧。
我们最终的数据框架(图片由作者提供)
N 现在,我们通过在 0 和 1 之间缩放值来导出给定列的标准化数量。我们使用下面的公式和附带的代码来计算所需的值
作者图片
final[‘death_normalized’] = (final[‘total_deaths’] — final[‘total_deaths’].min()) / (final[‘total_deaths’].max() — final[‘total_deaths’].min())final[‘confirmed_normalized’] = (final[‘total_confirmed’] — final[‘total_confirmed’].min()) / (final[‘total_confirmed’].max() — final[‘total_confirmed’].min())final[‘population_normalized’] = (final[‘Population’] — final[‘Population’].min()) / (final[‘Population’].max() — final[‘Population’].min())
标准化的数据框架(图片由作者提供)
注:为了使用死亡项和确认项,我们将两个量相加,从而得到一个对两列的信息进行量化的项。这是一个主观决定,可以根据目标的设定来决定。
我们进一步得到 1 和总数之间的最小值,将最大值限制为 1(图片由作者提供)
def get_min(row): return min(1, row['total'])
计算数据框架(图片由作者提供)
度量标准的制定
我们将该指标定义为 1 和每个总体的标准化列之和之间的最小值。对于每个州,我们将标准化列的相加除以总体。对于一个州来说,“风险因素”表示该州的“风险”有多大。我们使用下面的代码和公式来计算指标。
风险系数公式(图片由作者提供)
final[‘risk_factor’]=final[‘combined’]/final[‘population_normalized]
final = final.replace(np.inf, 0)
final[‘risk_factor_softmax’] = softmax(final[‘risk_factor’])
注意:这是一个主观指标,可以根据目标进行调整。替代方法包括获得总人口或使用最大人口。
Softmax 简介
在计算“风险系数”时,我们可以看到这些值不是在 0 或 1 之间。我们希望这是概率,这样我们可以为每个状态建立一个表示相似性的共现矩阵。
风险因子值不在 0 和 1 之间(图片由作者提供)
soft max 函数将给定向量归一化为概率分布,使得每个分量在 0 和 1 之间,并且这些分量相加为 1,因此它们可以被解释为概率,较大的输入分量对应于较大的概率。
Softmax 函数(图片由作者提供)
N 为了将我们的值转换为概率并最终创建状态的共生矩阵,我们将 softmax 应用于向量。
已应用 Softmax(图片由作者提供)
最终数据帧(图片由作者提供)
定义“高风险区域”
高风险区域被定义为超过容许系数的状态。如果一个状态等于或大于“耐受因子”,我们将该状态归类为“高风险区域”。对于我们当前的任务,我们将“容差系数”设置为 0.02,但这个值可以变化。
注意:容差是基于值的,可能会因不同的数据而变化(例如,如果我们分析的是印度的 COVID 数据,而不是美国的数据)。
确定高风险区域的详细算法表达式(图片由作者提供)
tolerance_factor = 0.02def is_risk_area(row): if row['risk_factor_softmax'] >= tolerance_factor: return True else: return Falsefinal['is_risk'] = final.apply(is_risk_area, axis=1)
代表“高风险”区域计数的图(图片由作者提供)
由转换后的列组成的数据帧(图片由作者提供)
构建共现矩阵,也称为相似矩阵
为了计算两个状态在“风险因子”方面有多相似,我们定义了一个术语,称为“差异因子”。差异因子表示被认为相似的状态所需的最小差异。对于我们当前的任务,差异因子被设置为 0.01。
注意:差异系数是基于值的,可能会因不同的数据而变化(例如,如果我们分析的是印度的 COVID 数据,而不是美国的数据)。定义的指标是主观的,可以根据不同的偏好进行调整。
确定相似性的详细算法表达式(图片由作者提供)
提示:为了提取一个更彻底的相似性分数,我们可以返回概率的补数,这样我们就有介于 0 和 1 之间的值来表示两个状态之间的强度。我们也可以包括其他因素。
计算数据框架(图片由作者提供)
推导共生矩阵
为了从上述数据帧中导出共生矩阵,我们使用 scipy.sparse 模块创建了一个 coo_matrix。这个函数将创建一个维数(状态数,状态数)的矩阵,在我们的例子中就是(58,58)。对于每一个州,我们都有对应于另一个州的分数。
from scipy import sparse
user_items = sparse.coo_matrix((cmat.score.astype(float),(cmat.state1.astype('category').cat.codes,
cmat.state2.astype('category').cat.codes)))
最终数据帧的样本(图片由作者提供)
根据确诊人数和死亡人数显示每个州与另一个州相似程度的热图(图片由作者提供)
我们如何判断两个状态是否相似的例子(图片由作者提供)
两个相似状态的演示输出(基于风险因素)(图片由作者提供)
结论和进一步的应用
我们展示了一种合理的方法来确定“高风险”州,并建立一个类似州的地图。定义的指标是主观的,可以根据客观情况进行调整。该方法的应用是无限的,因为它可以应用于:
- 估计政策对各州的影响。(例如,确定周末关闭餐馆对一个州的影响,并使用同现相似性矩阵近似计算对另一个州的影响)
- 检测高风险州或城市
还有很多……
破解数据科学访谈:2021 年的高级 SQL 技能
原文:https://towardsdatascience.com/crack-data-science-interviews-advanced-sql-skills-in-2021-322fef819c6c?source=collection_archive---------5-----------------------
破解数据科学面试
数据科学家和软件工程师的高级读物
由费尔·南多在 Unsplash 拍摄的照片
结构化查询语言 SQL 是检索和管理数据的首选编程语言。从关系数据库中有效地提取数据是任何数据专业人员的必备技能。在过去的几个月里,我一直与数据科学的领导者保持密切联系,经常出现的一个建议是编写更多更好的 SQL 查询。
为了跟踪谁是活跃用户,我们使用 SQL。
为了计算业务指标,我们使用 SQL。
为了执行任何与数据检索和管理相关的操作,我们使用 SQL。
…
在之前的两篇帖子中,我介绍了数据科学访谈中问到的几个基本 SQL 技能,这对初学者读者来说是一个很好的开始:
</4-tricky-sql-questions-for-data-scientists-in-2021-88ff6e456c77>
在今天的帖子中,我对 FAANG 公司提出的 5 个真实的面试问题进行了现场编码和思考。这些问题都是 LeetCode 上的中级题,第一次试用解决不了的请放心。
#问题 1:苹果、亚马逊和脸书的排名分数
- https://leetcode.com/problems/rank-scores/
编写一个 SQL 查询来对分数进行排名。如果两个分数相同,两者的排名应该相同。请注意,在平局之后,下一个排名数字应该是下一个连续的整数值。换句话说,级别之间不应该有“漏洞”。
+----+-------+
| Id | Score |
+----+-------+
| 1 | 3.50 |
| 2 | 3.65 |
| 3 | 4.00 |
| 4 | 3.85 |
| 5 | 4.00 |
| 6 | 3.65 |
+----+-------+
例如,给定上面的 *Scores*
表,您的查询应该生成以下报告(按最高分排序):
+-------+---------+
| score | Rank |
+-------+---------+
| 4.00 | 1 |
| 4.00 | 1 |
| 3.85 | 2 |
| 3.65 | 3 |
| 3.65 | 3 |
| 3.50 | 4 |
+-------+---------+
重要提示: 对于 MySQL 解决方案,要转义用作列名的保留字,可以在关键字前后使用撇号。例如【等级】。
穿过我的思维
苹果、亚马逊和脸书在他们的数据科学采访中提出了这个问题。这是一个简单的问题,要求等级之间没有“漏洞”或“跳跃”。
在 SQL 中,有两种处理秩的方式: rank() 和 dense_rank() 。区别在于 dense_rank()命令不会跳过等级,而 rank()命令会在出现平局时跳过等级。
问题语句明确地告诉我们,在平局之后,等级之间不应该有“洞”,这使得 dense_rank()成为一个明显的选择。如果另一个问题没有提供这样一个友好的暗示,记得让你的面试官澄清如何打领带。如果他们有意排除如此重要的信息,他们希望你提出问题。
解决办法
*# Write your MySQL query statement below
SELECT score, DENSE_RANK() OVER(ORDER BY Score DESC) AS `Rank`
FROM Scores*
有两点需要注意:
- DESC 。如果问题要求按得分降序排列,记得用 DESC。
Rank
。Rank 是 SQL 中的保留关键字,您应该在它的前后包含一对撇号,例如Rank
。
#问题 2:数苹果和橘子
- https://leetcode.com/problems/count-apples-and-oranges/
表:Boxes
*+--------------+------+
| Column Name | Type |
+--------------+------+
| box_id | int |
| chest_id | int |
| apple_count | int |
| orange_count | int |
+--------------+------+
box_id is the primary key for this table.
chest_id is a foreign key of the chests table.
This table contains information about the boxes and the number of oranges and apples they contain. Each box may contain a chest, which also can contain oranges and apples.*
表:Chests
*+--------------+------+
| Column Name | Type |
+--------------+------+
| chest_id | int |
| apple_count | int |
| orange_count | int |
+--------------+------+
chest_id is the primary key for this table.
This table contains information about the chests we have, and the corresponding number if oranges and apples they contain.*
编写一个 SQL 查询来计算所有盒子中苹果和橘子的数量。如果一个盒子里有一个箱子,你还应该包括里面苹果和橘子的数量。
返回结果表中 任意顺序 。
查询结果格式如下:
*Boxes table:
+--------+----------+-------------+--------------+
| box_id | chest_id | apple_count | orange_count |
+--------+----------+-------------+--------------+
| 2 | null | 6 | 15 |
| 18 | 14 | 4 | 15 |
| 19 | 3 | 8 | 4 |
| 12 | 2 | 19 | 20 |
| 20 | 6 | 12 | 9 |
| 8 | 6 | 9 | 9 |
| 3 | 14 | 16 | 7 |
+--------+----------+-------------+--------------+
Chests table:
+----------+-------------+--------------+
| chest_id | apple_count | orange_count |
+----------+-------------+--------------+
| 6 | 5 | 6 |
| 14 | 20 | 10 |
| 2 | 8 | 8 |
| 3 | 19 | 4 |
| 16 | 19 | 19 |
+----------+-------------+--------------+
Result table:
+-------------+--------------+
| apple_count | orange_count |
+-------------+--------------+
| 151 | 123 |
+-------------+--------------+*
穿过我的思维
这是一个很好的 SQL 问题,因为它测试了候选人的分析技巧和分解问题的能力。让大多数候选人感到困惑的棘手部分是存在两个表,您应该将这两个表结合起来以获得有效值。
例如,box_id = 18 有来自箱子表的附加苹果和桔子计数,但是 box_id = 2 没有附加计数。
这两种情况下如何计算计数?
答案是 IFNULL()命令。我们指定如果箱子表中没有值该怎么办,如果有值该怎么办。如果没有 IFNULL()语句,我们就会遇到错误。
解决办法
*# Write your MySQL query statement below
SELECT SUM(b.apple_count+IFNULL(c.apple_count,0)) AS apple_count, SUM(b.orange_count+IFNULL(c.orange_count,0)) AS orange_count
FROM Boxes b
LEFT JOIN Chests c
USING(chest_id)*
有两点需要注意:
- 左加入。我们应该使用左连接,而不是内连接,因为我们希望在 box 表中保留甚至没有 chest_id 的记录。
- IFNULL(c.apple_count,0) 。如果 apple_count 中有 Null,我们应该指定值。
#问题 3:项目雇员 I,脸书
- https://leetcode.com/problems/project-employees-i/
表:Project
*+-------------+---------+
| Column Name | Type |
+-------------+---------+
| project_id | int |
| employee_id | int |
+-------------+---------+
(project_id, employee_id) is the primary key of this table.
employee_id is a foreign key to Employee table.*
表:Employee
*+------------------+---------+
| Column Name | Type |
+------------------+---------+
| employee_id | int |
| name | varchar |
| experience_years | int |
+------------------+---------+
employee_id is the primary key of this table.*
编写一个 SQL 查询,报告每个项目所有员工的平均工作年限,四舍五入到两位数 。**
查询结果格式如下:
**Project table:
+-------------+-------------+
| project_id | employee_id |
+-------------+-------------+
| 1 | 1 |
| 1 | 2 |
| 1 | 3 |
| 2 | 1 |
| 2 | 4 |
+-------------+-------------+Employee table:
+-------------+--------+------------------+
| employee_id | name | experience_years |
+-------------+--------+------------------+
| 1 | Khaled | 3 |
| 2 | Ali | 2 |
| 3 | John | 1 |
| 4 | Doe | 2 |
+-------------+--------+------------------+Result table:
+-------------+---------------+
| project_id | average_years |
+-------------+---------------+
| 1 | 2.00 |
| 2 | 2.50 |
+-------------+---------------+
The average experience years for the first project is (3 + 2 + 1) / 3 = 2.00 and for the second project is (3 + 2) / 2 = 2.50**
穿过我的思维
脸书包括这个问题。在写任何查询之前,我总是问自己:
“你真的明白这个问题问的是什么吗?”
上面写着每个项目的平均经验年数。有两条关键信息。首先,平均值被定义为经验年数的总和除以员工人数。第二,结果应该按项目分组。
剩下的就不言自明了。
解决办法
**# Write your MySQL query statement below
SELECT project_id, ROUND(SUM(experience_years)/COUNT(employee_id),2) AS average_years
FROM Project
JOIN Employee
USING(employee_id)
GROUP BY project_id**
一个警告,记住将结果四舍五入到 2 位数,如果问题没有说明什么,就要求澄清。
#问题 4:两个人之间的通话次数,亚马逊
- https://leet code . com/problems/number-of-calls-between-two-person/
表:Calls
**+-------------+---------+
| Column Name | Type |
+-------------+---------+
| from_id | int |
| to_id | int |
| duration | int |
+-------------+---------+
This table does not have a primary key, it may contain duplicates.
This table contains the duration of a phone call between from_id and to_id.
from_id != to_id**
编写一个 SQL 查询来报告每对不同的人 *(person1, person2)*
之间的通话次数和总通话时长,其中 *person1 < person2*
。
以任意顺序返回结果表。
查询结果格式如下:
**Calls table:
+---------+-------+----------+
| from_id | to_id | duration |
+---------+-------+----------+
| 1 | 2 | 59 |
| 2 | 1 | 11 |
| 1 | 3 | 20 |
| 3 | 4 | 100 |
| 3 | 4 | 200 |
| 3 | 4 | 200 |
| 4 | 3 | 499 |
+---------+-------+----------+Result table:
+---------+---------+------------+----------------+
| person1 | person2 | call_count | total_duration |
+---------+---------+------------+----------------+
| 1 | 2 | 2 | 70 |
| 1 | 3 | 1 | 20 |
| 3 | 4 | 4 | 999 |
+---------+---------+------------+----------------+**
穿过我的思维
亚马逊问这个问题。分析问题后,我们发现一对不同的人可能是人 1 →人 2 或人 2 →人 1。我们必须把它们加在一起,得到总持续时间。****
- 我们如何做到这一点?
- 从 from_id 和 to_id 中选取值时的用例。
由于问题有一个额外条件 person1 < person2 ,我们可以使用 CASE WHEN 语句从 from_id 和 to_id 中选择较小(较大)的值。具体来说,我们选择较小的值作为人员 1,较大的值作为人员 2。
**SELECT CASE WHEN from_id< to_id THEN from_id ELSE to_id END AS person1**
然后,我们按照相同的过程为 person2 选择较大的值,并计算数量/持续时间。
参见下面的代码。
解决办法
**# Write your MySQL query statement below
SELECT CASE WHEN from_id< to_id THEN from_id ELSE to_id END AS person1,
CASE WHEN from_id <to_id THEN to_id ELSE from_id END AS person2,
COUNT(*) AS call_count,SUM(duration) AS total_durationFROM Calls
GROUP BY person1, person2**
问题 5:销售分析 II,亚马逊
- https://leetcode.com/problems/sales-analysis-ii/
表:Product
**+--------------+---------+
| Column Name | Type |
+--------------+---------+
| product_id | int |
| product_name | varchar |
| unit_price | int |
+--------------+---------+
product_id is the primary key of this table.**
表:Sales
**+-------------+---------+
| Column Name | Type |
+-------------+---------+
| seller_id | int |
| product_id | int |
| buyer_id | int |
| sale_date | date |
| quantity | int |
| price | int |
+------ ------+---------+
This table has no primary key, it can have repeated rows.
product_id is a foreign key to Product table.**
编写一个 SQL 查询,报告 购买者 购买了 S8,但没有购买 iPhone 和 G4。请注意,S8、iPhone 和 G4 是出现在 *Product*
表中的产品。
查询结果格式如下:
**Product table:
+------------+--------------+------------+
| product_id | product_name | unit_price |
+------------+--------------+------------+
| 1 | S8 | 1000 |
| 2 | G4 | 800 |
| 3 | iPhone | 1400 |
+------------+--------------+------------+Sales table:
+-----------+------------+----------+------------+----------+-------
| seller_id | product_id | buyer_id | sale_date | quantity | price
+-----------+------------+----------+------------+----------+-------
| 1 | 1 | 1 | 2019-01-21 | 2 | 2000 |
| 1 | 2 | 2 | 2019-02-17 | 1 | 800 |
| 2 | 1 | 3 | 2019-06-02 | 1 | 800 |
| 3 | 3 | 3 | 2019-05-13 | 2 | 2800 |
+-----------+------------+----------+------------+----------+-------Result table:
+-------------+
| buyer_id |
+-------------+
| 1 |
+-------------+
The buyer with id 1 bought an S8 but didn't buy an iPhone. The buyer with id 3 bought both.**
穿过我的思维
亚马逊问这个问题。要选择购买了 S8 但没有购买 iPhone (G4)的用户,我们可以使用 product_name = 'S8' 和 product_name!= 'iPhone' 如果是 Python 问题,则过滤出案例。不幸的是,它在 SQL 中变得更加棘手,我们不能使用!=符号。
那么,如何才能筛选出病例呢?
SUM(以防万一)化险为夷!
回想一下我们可以用 CASE WHEN 语句来赋值条件。此外,我们可以将它与 SUM()子句结合起来,计算每种情况的总值,将其相加,并选择满足条件的案例。
解决方案
**# Write your MySQL query statement belowSELECT DISTINCT buyer_id
FROM Sales
INNER JOIN Product
USING(product_id)
GROUP BY buyer_id
HAVING SUM(CASE WHEN product_name = ‘S8’ THEN 1 ELSE 0 END) > 0
AND SUM(CASE WHEN product_name = ‘iPhone’ THEN 1 ELSE 0 END) = 0
AND SUM(CASE WHEN product_name = ‘G4’ THEN 1 ELSE 0 END) = 0**
外卖食品
- 在提出解决方案之前,充分理解问题。
- 如果缺少关键信息,询问澄清问题。
- 在下一次数据科学面试之前,练习这些高级主题。
Medium 最近进化出了自己的 作家伙伴计划 ,支持像我这样的普通作家。如果你还不是订户,通过下面的链接注册,我会收到一部分会员费。
**https://leihua-ye.medium.com/membership **
我的数据科学面试序列
** </5-python-coding-questions-asked-at-faang-59e6cf5ba2a0>
喜欢读这本书吗?
请在 LinkedIn 和 Youtube 上找到我。
还有,看看我其他关于人工智能和机器学习的帖子。**
破解数据科学访谈:基本的机器学习概念
原文:https://towardsdatascience.com/crack-data-science-interviews-essential-machine-learning-concepts-afd6a0a6d1aa?source=collection_archive---------21-----------------------
破解数据科学面试
赢在 2021 年:数据科学家/工程师的必读之作,第 1 部分
美国宇航局在 Unsplash 拍摄的照片
介绍
数据科学面试涵盖了广泛的主题:测试候选人总体统计流畅性的统计部分,关于候选人各种 ML 算法和权衡的机器学习部分,以及锻炼我们现场编码技能的编程部分。
更不用说每个面试官最喜欢的“向我介绍你的解决方案”和几十次后续互动了。更重要的是,在 DS 社区中有一个新发现的趋势,即转向像数据结构和算法这样的计算机科学基础(查看的精彩文章 Emma Ding @Airbnb)。
综合来看,它们似乎太令人生畏而难以处理。
如果我们把大块分成小块,每一块都变得更“可咀嚼”和易于管理。
就像算法“各个击破”
一语双关!
这是关于基本概念的两篇文章的第一章。在第一章中,我将重点放在机器学习部分,并解释 DS 面试中的这些常见问题。在第二章中,我转换话题,详细阐述统计方面的内容。这是:
概念 1:偏差和方差
1.1 什么是偏见?
偏差是对估计值与其真实值之间的差异的估计。用简单的语言来说,它衡量我们的模型与实际数据点有多“接近”。
其数学公式表示如下:
维基百科
偏差与特征选择和模型复杂性直接相关,过于简化的模型往往具有较高的偏差。
1.2 什么是方差?
方差是指由于模型过于复杂和训练数据的选取而导致的建模误差。它衡量的是模型对噪声的拟合程度,而不是数据中的模式。使用不同训练集训练的模型具有不同的方差。与数据的选择直接相关。具有高方差的模型在训练数据中表现良好,但在新数据集中表现不佳。
其数学形式表示如下:
维基百科
总的来说,灵活的(复杂的)模型倾向于具有低偏差但高方差,aka。过度适应训练集中的噪声,并且刚性(简单)模型具有高偏差但低方差,aka。欠拟合真实数据模式。
顺便提一下,任何机器学习算法都有三种误差来源:偏差、方差和不可约误差,如下所示。
总误差=偏倚+方差+不可约误差
照片由奥斯丁·迪斯特尔在 Unsplash 上拍摄
概念 2: L1 和 L2 正规化
2.1。什么是正规化?
正则化是一种回归形式,它通过将系数估计值约束或缩小到零来产生简约的模型。它通过向成本函数添加惩罚来实现这个目标。在机器学习算法中,如果我们包括太多可能的特征,我们会使模型过度适应训练数据中的噪声。过度拟合会降低未来数据(测试集)的模型精度。正规化解决了这个问题。
2.2 什么是拉索回归(L1 正则化)?L1 是如何导致稀疏的?
什么
LASSO 回归(L1 正则化)包括一个超参数α乘以系数绝对值之和,作为其成本函数中的惩罚项,如下所示(用红色标记):
截图 1:来自数据科学家实用统计
一方面,如果我们不应用任何惩罚(设置α =0),上述公式变成常规的 OLS 回归,这可能会过度拟合。
另一方面,如果我们应用一个非常大的惩罚(或者,一个大的α值),模型可能会欠拟合,因为我们错误地惩罚了所有的系数(包括最重要的系数)。
如何
L1 被称为稀疏正则化。如果我们运行梯度下降来计算权重,L1 正则化迫使任何权重更接近于 0,而不管其大小。在每次迭代中,L1 从权重中减去一个小值,一些系数最终收敛到 0。因此,L1 通过将不太重要的特征的系数缩小到 0 来导致模型稀疏。
(关于 L1 如何导致稀疏的原因,特别归功于索纳·耶尔德勒姆的邮报。
2.3。什么是山脊(L2)?L2 是如何工作的?
岭回归采用系数乘以λ的“平方值”作为罚项,如下所示。
截图 2:来自数据科学家实用统计
如果 lambda λ为 0,则公式变为常规 OLS 回归。成本函数的惩罚项(用红色标出)增加了模型的偏差,并使对训练数据的拟合更差。
为了简单起见,L2 被称为正则化。随着速率趋向于 0,L2 正则化速度减慢,而不是收缩到 0。在每次迭代中,L2 移除一小部分权重,因此永远不会收敛到 0。
2.4。L1 和 L2 的异同
相似之处
这两种方法都用于避免过度拟合。L1 正则化处理特征的数量,L2 正则化处理特征的权重。
差异
L1 正则化最小化残差平方的和(回归部分:屏幕截图 1 的左边部分)和超参数乘以斜率的绝对值。
L2 正则化最小化残差平方和(回归部分:屏幕截图 2 的左边部分)和λ乘以斜率平方(在红框中标出)。
L1 更稳健,有多种解决方案,而 L2 不那么稳健,只有一种解决方案。
2.5。如何选择 L1 和 L2?
套索回归(L1)可以处理变量选择和参数收缩。因此,当很少有变量具有相当大的实质性影响时,我们更喜欢套索回归。
岭回归(L2)很好地处理了参数收缩,但保留了模型中的所有系数。当存在许多具有小/中等实质性影响的变量时,这是优选的(【ISLR】)作者:Hastie & Tibshirani,2013)。
此外,当存在共线要素时,L2 是首选。一个简单的例子是女性和怀孕。由于这两个特征共线,系数方差往往很大,这进一步损害了估计的稳定性(Terence Parr 教授的帖子)。
Adomas Aleno 在 Unsplash 上拍摄的照片
概念 3:机器学习算法和距离度量
3.1 什么是欧氏距离?你为什么选择它去 KNN?
定义:为了让 KNN 工作,我们需要根据一些度量来确定两个记录之间的相似性。欧几里德距离是距离度量之一。为了计算欧几里得距离,我们取两个向量之差的平方根,如下所示:
截图 3:来自数据科学家实用统计
我们选择欧氏距离有两个原因。
- 欧几里德距离在计算上是高效的。KNN 涉及 K*n 两两比较(K:特征的数量;n:行数)。对于大型数据集,计算量可能相当大。
- 输入变量在类型和规模上是相似的(例如,宽度、高度)。换句话说,我们假设一个向量中一个单位的增加(减少)与另一个向量中一个单位的增加(减少)相同。(这个超级重要。我被一个 FAANG 问过这个问题)。
3.2 维度的诅咒
维数灾难是指当输入变量/特征过多时,很难找到最优解。
每个特征提供了一个维度来聚类数据点,并且当有太多维度(例如,特征、输入变量)时,使得每个观察彼此等距变得困难。
3.3 决策树和随机森林有哪些权衡?
决策树是一种基于树的模型,它根据不同的特征做出预测决策。它易于应用,快速,可解释,但往往适得其反。
随机森林是一种集成学习算法,它通过自举样本在每个节点组合多个决策树。RF 有一个集体决策过程,并采用每个 DT 做出的所有预测的大多数类别。
因此,RF 具有更高的精度。但是相对于 DT 来说计算量很大,我们也不知道它是如何工作的(像黑盒一样)。
3.4 什么是决策树的基尼杂质?
基尼系数是衡量每一部分数据的同质性或杂质的一种方法。测量杂质以分割每个分区中的数据,并最终计算加权平均值:选择导致最低加权平均值的分区。
3.5 I 型和 II 型误差、阿尔法和贝塔水平
第一类错误是指当零假设(H0)为真时,我们错误地拒绝了它。这是一个假阳性。例如,电子邮件过滤算法错误地声称一封电子邮件是垃圾邮件,但实际上它不是。我们使用α水平来表示当 H0 为真时错误拒绝它的概率,也就是 I 型错误。
第二类错误是指当替代假设(Ha)正确时,我们未能拒绝零假设的情况。这是一个假阴性。例如,电子邮件过滤算法无法检测垃圾邮件。我们使用β水平来表示类型 II 错误,即当它为真时拒绝 Ha。
外卖食品
有人要求我解释一些概念,但我无法对所有的概念给出满意的答案。像任何其他数据科学实践者一样,我过于关注 ML 算法的应用/生产方面,而忘记了最基本的概念,这对于面试来说并不理想。
唯一的出路就是分解算法,理解每一块是如何工作的,就像为什么选择欧几里德距离而不是其他度量一样。
Medium 最近进化出了自己的 作家伙伴计划 ,支持像我这样的普通作家。如果你还不是订户,通过下面的链接注册,我会收到一部分会员费。
https://leihua-ye.medium.com/membership
我的数据科学面试顺序:
</4-tricky-sql-questions-for-data-scientists-in-2021-88ff6e456c77>
喜欢读这本书吗?
请在 LinkedIn 和 Youtube 上找到我。
还有,看看我其他关于人工智能和机器学习的帖子。
破解数据科学访谈:基本统计概念
原文:https://towardsdatascience.com/crack-data-science-interviews-essential-statistics-concepts-d4491d85219e?source=collection_archive---------9-----------------------
破解数据科学面试
赢在 2021 年:数据科学家/工程师的必读之作,第 2 部分
照片由 Adomas Aleno 在 Unsplash 上拍摄
介绍
数据科学面试涵盖广泛的主题,面试官经常要求我们解释最基本的概念。它更可能会问这样的问题,比如你为什么选择 L1 而不是 L2,而不是从头开始建立一个机器学习算法。
我的数据科学专业网络反复告诉我,他们不期望求职者知道每一种算法。相反,他们期望对基本面有很高的熟悉度。完全说得通。在打下坚实的基础后,你可以很快学会一种新的算法。
统计学和机器学习是密不可分的双胞胎,在这两个领域中有许多概念可以互换使用。在另一章中,我阐述了机器学习中最基本的概念。如果你还没有机会,这里是:
在今天的帖子中,让我们转向统计学,解决数据科学访谈中最常见的 10 个概念。
概念 1:缺失数据
关于缺失数据的面试问题看起来很容易,但很有挑战性。你必须根据数据类型和上下文来定制你的答案。我们中的许多人,包括我在内,未能认识到缺失数据的本质,并相应地调整他们的回应。
我对这个话题做了深入的研究,想出了应对策略。
面试问题:缺失数据有多少种?每种类型的解决方案如何?
总的来说,有三种类型的缺失数据,我们应该针对每种情况分别处理。
第一种:完全随机缺失(MCAR)。
- 缺失数据和其他变量之间没有关系。换句话说,一些数据丢失是没有原因的。它的发生完全是由于随机性。
- 解决方案:我们可以删除缺失值,只关注完整的观察值。然而,MCAR 假设在现实生活中很少是正确的,删除缺失值可能会给参数估计带来偏差。
类型 2:随机缺失(MAR)
- 缺失值不是随机的。它取决于其他变量,但不取决于丢失的数据本身。听起来很困惑?别担心,我需要一段时间来理解要点。
- 这里有一个有用的例子。有两个变量:学生的 GPA 和学生的专业(STEM 和非 STEM)。STEM 学生的绩点有缺失,但非 STEM 学生没有。这里,缺失值(GPA)与另一个变量(major)有关,但与自身无关。
- MAR 是唯一的,不同于第三种类型的缺失值(稍后讨论)。
- 解决方案:由于其他变量会导致缺失值,我们可以使用高级插补方法(如 KNN、线性回归、平均值、众数、中位数)来插补缺失值。然而,代价是我们可以减少数据差异。
第三类:非随机缺失(MNAR)
- 由于变量本身的原因,数据丢失。
- 上例中有两个变量:学生的 GPA 和专业(STEM 和非 STEM)。在这个时间里,绩点高的同学不存在价值观缺失,绩点低的其他同学存在价值观缺失,无论专业如何。
- 变量本身不可观察的特性导致了值的丢失!换句话说,有有效输入和没有有效输入的人是根本不同的。
- 解 : MNAR 引入了一个非常微妙的情况。简单的插补不起作用,因为其他变量不会导致缺失值。完全删除会导致模型偏差。我们应该分析数据丢失的原因,并尽可能收集更多的数据。
缺失数据是一个宽泛的问题,答案可能很长,也可能因上下文而异。请解释丢失的数据有不同的类型,并且您希望在提出解决方案之前了解更多有关业务问题的信息,并从那里着手。
参考
https://www.displayr.com/different-types-of-missing-data/ https://github.com/zhiqiangzhongddu/Data-Science-Interview-Questions-and-Answers-General-
概念 2:装袋和增压
制袋材料
面试问题:什么是装袋?它是如何工作的?赞成?缺点?
Bagging, Bootstrap Aggregating ,是一种集成学习算法,通过替换随机生成新的训练数据,适合多个模型。由于 bootstrap 过程,每个模型都是相互独立的。
对于回归问题,bagging 采用所有模型的平均值。对于分类问题,它采用模型的大多数类。
优点
- Bagging 结合了几个弱学习器,提高了模型性能。
- 它减少了方差并避免了过度拟合。
- 装袋可以并行进行。
缺点
- Bagging 将高偏差引入到具有高偏差的数据集的聚合中。
- 它是不可解释的,并且计算量很大。
助推
面试问题:什么是助推?它是如何工作的?赞成?缺点?
Boosting 是一种集成学习算法,它使用原始数据的子集来生成弱模型。然后,boosting 将它们依次组合成一个更强的模型。为了创建子集数据,boosting 会评估以前模型的性能,并为以前模型中的错误分类事例增加更多权重。
赞成的意见
- 当数据有偏差时,提升效果很好。
- 它照顾到了以前模型的重量。
骗局
- 如果数据具有很高的方差,它的性能会很差。
- 计算开销很大。
参考
**</20-machine-learning-related-questions-to-prepare-for-interviews-93bcba72f911> https://en.wikipedia.org/wiki/Bootstrap_aggregating https://stats.stackexchange.com/questions/18891/bagging-boosting-and-stacking-in-machine-learning
概念三:什么是 Bootstrap?
Bootstrap 是一种从原始数据集中重复抽取随机样本的重采样方法。Bootstrap 允许我们甚至用一个样本来对总体参数进行统计推断。在机器学习中,bootstrap 广泛用于集成学习算法,如随机森林。
参考
概念 4:多重共线性
面试问题:什么是多重共线性?怎么检测出来的?解决方案?
当回归模型中的独立变量相互关联时,就会发生多重共线性。它会产生有偏见的估计。
检测多重共线性有两种方法。首先,我们可以画一个相关矩阵,检查两个或两个以上的变量是否高度相关。
第二,我们可以使用方差膨胀因子。VIF 测量回归模型中多重共线性的数量。数学上是模型总方差和只包含单个自变量的方差之比。高 VIF 表示高度共线性。
解决方案
- 丢弃相关变量,保留最重要的变量。
- 转换数据以避免变量相关性。
- 利用主成分分析进行降维。
参考
https://www.investopedia.com/terms/v/variance-inflation-factor.asp
概念 5:维度的诅咒
每个变量都为聚类数据提供了一个维度。太多的变量提供了太多的维度,使得数据稀疏地分布在这些维度上。稀疏分布使数据点距离相等,并使依赖于距离度量的机器学习算法无效,例如,欧几里德距离 ( 统计学习介绍)。
例如,K 最近邻算法采用欧几里德距离作为度量,并且在高维空间中表现不佳,因为它不能找到局部邻居。
参考
https://www.amazon.com/Introduction-Statistical-Learning-Applications-Statistics/dp/1461471370
概念 6:第一类和第二类错误
第一类错误,也称为假阳性,是当零假设(H0)为真时拒绝它。简单地说,第一类错误是指声称某事已经发生,但实际上它并没有发生。
第二类错误,又称假阴性,是指当替代假设(Ha)为真时,拒绝零假设的失败。简而言之,第二类错误是指声称什么都没发生,但实际上却是这样。
以下示例最能说明这两种类型的错误:
效果大小常见问题 作者保罗·埃利斯
毫无疑问,这是我见过的最生动的例子。
概念 7:统计能力
它是当替代假设为真时,检验拒绝零假设的概率。用通俗的语言来说,如果真实的效果存在,我们就不会错过一个效果。
(统计功效是实验研究的一个关键概念,我将结合统计模拟和统计功效再写一篇帖子。敬请期待!)
概念 8:辛普森悖论
它描述了存在于子组中的一种趋势,当这些组聚集在一起时,这种趋势消失或逆转。辛普森悖论可能错误地导致统计推断中误导性的因果主张。
它是由混杂变量引起的,我们必须在分析中包括缺失的变量。
参考
</22-statistics-questions-to-prepare-for-data-science-interviews-d5651a8b3c56> https://medium.com/the-innovation/the-so-called-simpsons-paradox-6d0efdca6fdc https://en.wikipedia.org/wiki/Simpson's_paradox
概念 9:大数定律
在概率论中,LLN 描述了大量重复试验 的结果随着试验次数的增加而接近 的真实期望值。
在英语中,这意味着我们将获得总体参数的真实值(例如,平均值、标准差等)。)经过大量的试验。
一个简单的例子。如果你掷一枚公平硬币 10,000 次,你得到的正面总数大约是 5,000 次,或者大约 50%的概率。然而,如果你只抛 6 次硬币,出现的正面总数可能是 6 或 0,而不是 50-50。
概念 10:中心极限理论
即使总体分布不是正态分布,重复样本的形状也接近正态分布。中心极限理论在统计学和机器学习中有着广泛的应用,特别是在假设检验和统计推断中。
外卖食品
- 技术面试要求彻底理解最基本的概念。我们可以把最复杂的问题分解成这些基本组成部分。
- 在 FAANG 的一次面试中,我被要求从一个样本中构建一个置信区间。读完这篇文章后,你会知道你可以引导样本来创建额外的数据,并使用中心极限理论来进行假设检验。
- 在另一次旅游采访中,有人问我如何处理缺失数据的解决方案。读完这篇文章后,你会知道你应该要求澄清,并决定丢失数据的性质。
Medium 最近进化出了它的 作家伙伴计划 ,支持像我这样的普通作家。如果你还不是订户,通过下面的链接注册,我会收到一部分会员费。
https://leihua-ye.medium.com/membership
我的数据科学面试顺序:
</5-python-coding-questions-asked-at-faang-59e6cf5ba2a0>
喜欢读这本书吗?
请在 LinkedIn 和 Youtube 上找到我。
还有,看看我其他关于人工智能和机器学习的帖子。**
破解数据科学访谈:数据科学家的五项 SQL 技能
原文:https://towardsdatascience.com/crack-data-science-interviews-five-sql-skills-for-data-scientists-cc6b32df1987?source=collection_archive---------3-----------------------
破解数据科学面试
Leetcode 助你获得高薪数据职位
泽通李在 Unsplash 上的照片
介绍
结构化查询语言 SQL 是数据从业者用来检索存储在关系数据库中的数据的首选编程语言。对于数据科学家来说,编写有效的查询请求不再被认为是一项不错的技能,而是一项基本技能。这种趋势可以通过在 DS 招聘信息和面试环节中具体包含 SQL 经验得到支持。
除了编程( Python )、机器学习、 A/B 测试和统计,数据科学家经常被要求定义和从多个来源提取数据,以构建感兴趣的指标。不幸的是,SQL 仍然是一项不受重视的技能,没有足够的数据科学家充分认识到它的多功能性和重要性。
在过去的几个月里,我一直与主要技术公司的高级数据科学家和招聘经理保持密切联系。我收到的评价最高的建议和推荐之一是掌握 SQL 技能,并知道如何有效地提取数据。
为此,我创建了一个三部曲帖子,专为初级程序员量身定制。它从简单到中等难度的问题逐步进行。如果你最近开始了你的 SQL 之旅,我建议在阅读这篇文章之前先看看这三篇文章:1。容易,2。容易/中等和 3。中等。
问题 1:不同性别的累计总数
https://leetcode.com/problems/running-total-for-different-genders/
编写一个 SQL 查询来查找每种性别每天的总分。
按性别和日期排序结果表
查询结果格式如下:
Scores table:
+-------------+--------+------------+--------------+
| player_name | gender | day | score_points |
+-------------+--------+------------+--------------+
| Aron | F | 2020-01-01 | 17 |
| Alice | F | 2020-01-07 | 23 |
| Bajrang | M | 2020-01-07 | 7 |
| Khali | M | 2019-12-25 | 11 |
| Slaman | M | 2019-12-30 | 13 |
| Joe | M | 2019-12-31 | 3 |
| Jose | M | 2019-12-18 | 2 |
| Priya | F | 2019-12-31 | 23 |
| Priyanka | F | 2019-12-30 | 17 |
+-------------+--------+------------+--------------+
Result table:
+--------+------------+-------+
| gender | day | total |
+--------+------------+-------+
| F | 2019-12-30 | 17 |
| F | 2019-12-31 | 40 |
| F | 2020-01-01 | 57 |
| F | 2020-01-07 | 80 |
| M | 2019-12-18 | 2 |
| M | 2019-12-25 | 13 |
| M | 2019-12-30 | 26 |
| M | 2019-12-31 | 29 |
| M | 2020-01-07 | 36 |
+--------+------------+-------+
穿过我的思维
这是那种你第一眼就能解决或者感觉完全迷失的问题。它很容易把你引入歧途。
原因如下。
问题要求“每个性别每天的总分,”我的第一反应是计算累计总和,然后按性别和天分组。所以,我错误地试图在 SQL 中找到一个不存在的计算累积和的语法。
经过一番努力之后,我意识到我们可以应用 SUM() OVER( PARTITION BY… )语句来计算按性别分组的累计总和。然后,按天排序结果。
解决办法
# Write your MySQL query statement below
SELECT gender, day, SUM(score_points) OVER(PARTITION BY gender ORDER BY day) AS total
FROM Scores
经验法则:
- 许多 SQL 命令遵循相同的语法,如 SUM() OVER()、ROW_NUMBER() OVER()、LEAD() OVER 等。理解了其中一个命令的用法,您就为其他命令做好了准备。
- 你一定要把你的测试结果分组吗?如果是这样,请使用 PARTITION BY。
- 成绩排名怎么样?如果是这样,请使用 ORDER BY。
问题 2:找出连续范围的起始数和结束数
https://leetcode.com/problems/find-the-start-and-end-number-of-continuous-ranges/
由于 *Logs*
中删除了部分 id。编写一个 SQL 查询来查找表 *Logs*
中连续范围的开始和结束编号。
按 *start_id*
顺序排列结果表。
查询结果格式如下:
Logs table:
+------------+
| log_id |
+------------+
| 1 |
| 2 |
| 3 |
| 7 |
| 8 |
| 10 |
+------------+Result table:
+------------+--------------+
| start_id | end_id |
+------------+--------------+
| 1 | 3 |
| 7 | 8 |
| 10 | 10 |
+------------+--------------+
穿过我的思维
亚马逊在面试过程中包括了这个问题。
此问题询问缺少数字的连续范围的开始和结束。识别连续范围的起点和终点相对容易,可以分别使用 MIN(log_id) 和 MAX(log_id) 找到。棘手的部分是识别两个范围之间的不连续性。例如,我们如何辨别这两个连续范围之间的不连续性:1–3 和 7–8?在这里,我们遗漏了 5、6 和 7。
解决方案在于我们如何对结果进行分组。如果存在不连续,我们将观察到 log_id 和每个观察的行排名之间的差距。对于连续范围,观测值应具有相同的范围;如果有任何差距,那么我们观察到组差异的跳跃。
Logs table:
+------------+
| log_id |
+------------+
| 1 |
| 2 |
| 3 |
| 7 |
| 8 |
| 10 |
+------------+
在 Logs 表中,数字 1、2、3 构成了一个连续的范围,log_id 与行排名之差在同一范围内是一致的,为 0(即 log_id —行排名,1–1 = 2–2 = 3–3 = 0)。同样的规则也适用于 7 和 8,两者相差 3(即 log _ id-row ranking = 7-4 = 8–5 = 3)。正如所看到的,当我们从第一范围移动到第二范围时,我们观察到差异的跳跃(不连续)(从 0 到 3)。
解决办法
# Write your MySQL query statement below
SELECT MIN(log_id) AS start_id, MAX(log_id) AS end_id
FROM (
SELECT log_id, ROW_NUMBER() OVER(ORDER BY log_id) AS row_id
FROM Logs
) sub
GROUP BY log_id — row_id
ORDER BY start_id
经验法则:
- 分析手头的问题,把它分解成不同的部分。如果需要,使用子查询来完成次要任务,并移至外部查询。
- ROW_NUMBER() OVER(ORDER BY …):获取每个单元的行号。
- GROUP BY:log _ id 和行号之间的差值,用于标识不连续性。
照片由法比安·金特罗在 Unsplash 拍摄
问题 3:部门最高工资
https://leetcode.com/problems/department-highest-salary/
*Employee*
表包含所有雇员。每个雇员都有一个 Id,一份薪水,还有一个部门 Id 列。**
*+----+-------+--------+--------------+
| Id | Name | Salary | DepartmentId |
+----+-------+--------+--------------+
| 1 | Joe | 70000 | 1 |
| 2 | Jim | 90000 | 1 |
| 3 | Henry | 80000 | 2 |
| 4 | Sam | 60000 | 2 |
| 5 | Max | 90000 | 1 |
+----+-------+--------+--------------+*
*Department*
表包含公司的所有部门。
**+----+----------+
| Id | Name |
+----+----------+
| 1 | IT |
| 2 | Sales |
+----+----------+**
编写一个 SQL 查询来查找每个部门中工资最高的雇员。对于上面的表,您的 SQL 查询应该返回下面的行(行的顺序无关紧要)。
**+------------+----------+--------+
| Department | Employee | Salary |
+------------+----------+--------+
| IT | Max | 90000 |
| IT | Jim | 90000 |
| Sales | Henry | 80000 |
+------------+----------+--------+**
穿过我的思维
亚马逊在面试过程中包括了这个问题。
在给出具体细节之前,让我浏览一下总体分析。问题问的是各部门工资最高的员工。因此,自然的问题是可能有多个工资最高的雇员,我们需要返回匹配的雇员。
下面是具体的细分。我将使用一个子查询来获取按部门 Id 分组的最高(最大)薪金,然后在匹配部门 ID 和薪金之前连接雇员和部门表。
解决办法
**# Write your MySQL query statement below
SELECT d.Name AS Department, e.Name AS Employee, Salary
FROM Employee e
JOIN Department d
ON d.Id = e.DepartmentIdWHERE (DepartmentId,Salary) IN (
SELECT DepartmentId, MAX(Salary)
FROM Employee
GROUP BY DepartmentId
)**
经验法则:
*Department*
表只包含两列,其唯一的功能是返回部门名称为部门 id。这应该会变成看问题提示时的第二本能。- 如果问题是返回每个组(如 department)的最大/最小值,典型的方法是应用子查询为每个组创建一对最大/最小值,然后将该对与外部查询进行匹配(如 WHERE 子句中所示)。
问题 4:第二高的薪水
**https://leetcode.com/problems/second-highest-salary/submissions/
编写一个 SQL 查询,从 *Employee*
表中获取第二高的薪水。
+----+--------+
| Id | Salary |
+----+--------+
| 1 | 100 |
| 2 | 200 |
| 3 | 300 |
+----+--------+
例如,给定上面的雇员表,查询应该返回 *200*
作为第二高的薪水。如果没有第二高的薪水,那么查询应该返回 *null*
。
+---------------------+
| SecondHighestSalary |
+---------------------+
| 200 |
+---------------------+
穿过我的思维
亚马逊和苹果在他们的采访循环中包含了这个问题。
我在另一篇博文中介绍了如何解决这个问题:
</4-tricky-sql-questions-for-data-scientists-in-2021-88ff6e456c77>
这是一个简单的问题,可以通过以下步骤解决:
1\. Rank Salary in a descending order2\. LIMIT result by 1 and OFFSET 1, which returns the second highest salary3\. Use DISTINCT to deal with duplicates 4\. Include the IFNULL statement in the outer query
查看其他帖子了解详细解释。包含它的唯一原因是为问题 5 提供基线分析,并允许我们比较和对比解决方案。
解决办法
SELECT IFNULL(
(SELECT DISTINCT Salary
FROM Employee
ORDER BY Salary DESC
LIMIT 1
OFFSET 1),
NULL) AS SecondHighestSalary
经验法则:
- 理解 OFFSET 和 IFNULL 是如何工作的。
问题 5:第 n 高工资
https://leetcode.com/problems/nth-highest-salary/
编写一个 SQL 查询,从 *Employee*
表中获取第 n 份最高工资。
+----+--------+
| Id | Salary |
+----+--------+
| 1 | 100 |
| 2 | 200 |
| 3 | 300 |
+----+--------+
例如,给定上面的员工表,其中 n = 2 的第 n 个最高工资是 *200*
。如果没有第 n 个最高工资,那么查询应该返回 *null*
。
+------------------------+
| getNthHighestSalary(2) |
+------------------------+
| 200 |
+------------------------+
穿过我的思维
这是一个普遍的问题,几乎所有的 FAANG 公司都希望求职者表现出色。
它要求第 n 个最高工资,如果没有这样的值,则返回*null*
。例如,如果我们输入 n=2,则返回第二高的值;n=3,第三高。
第一步,我们需要根据薪水值(降序)在子查询中创建一个排名索引。在采访中,我们需要澄清我们应该如何处理平局:我们应该跳过下一个指数还是返回一个连续的数字?
对于我们的例子,我们选择 DENSE_RANK 来确保连续的排名;说出排名排名 _ 薪资。
在外部查询中,我们选择 DISTINCT Salary 并在 WHERE 子句中设置 n = rankings_salary ,这将返回排名第 n(最高)的薪金。
解决办法
CREATE FUNCTION getNthHighestSalary(N INT) RETURNS INT
BEGIN
RETURN (
# Write your MySQL query statement below.
SELECT IFNULL((SELECT DISTINCT Salary
FROM (
SELECT Salary, DENSE_RANK() OVER(ORDER BY Salary DESC) AS rankings_salary
FROM Employee
) AS aaa
WHERE n = rankings_salary), NULL) AS getNthHighestSalary)
;
END
经验法则:
- 如果您必须编写嵌套查询请求,请不要惊慌。推荐的方法是首先编写子查询中最里面的部分,然后一层一层地移动到外部查询。
- 一个常见的错误是:忘记命名子查询。
- 不要忘记使用 DISTINCT 和 IFNULL。
外卖食品
熟能生巧。
当我开始用 SQL 编码时,我能执行的唯一查询是对表中的唯一值进行计数。快进到今天,我已经习惯了需要子查询、窗口函数和其他高级应用程序的更高级的编码任务。
我想与我的数据同事们分享的最大收获是从小处着手,从错误中学习,并相信增量学习的价值。做那种成长,变得比昨天好 1%的人。你最终会得到回报的。
感谢你的读者,祝一切顺利。
Medium 最近进化出了它的 作家伙伴计划 ,支持像我这样的普通作家。如果你还不是订户,通过下面的链接注册,我会收到一部分会员费。
https://leihua-ye.medium.com/membership
我的数据科学面试序列
喜欢读这本书吗?
请在 LinkedIn 和 Youtube 找到我。
还有,看看我其他关于人工智能和机器学习的帖子。**
如何赢得 A/B 测试数据科学面试(Doordash 案例示例)
原文:https://towardsdatascience.com/cracking-a-b-testing-data-science-interviews-bc66e399b109?source=collection_archive---------8-----------------------
逐步指导模拟面试
布鲁斯·马斯在 Unsplash 上的照片
介绍
A/B 测试是一项受欢迎的技能,经常在数据科学面试中进行测试。同时,帮助准备 A/B 测试面试的资源非常少。在我 15 年的职业生涯中,作为数据科学领域的招聘经理,我发现大多数候选人在这些面试中表现不佳。事实上,实验领域一直在发展,每年都有新的概念和方法变得更加相关。这意味着,即使是多年前做过 A/B 测试的经验丰富的数据科学家,也经常在面试中被难倒。
在本帖中,我们将进行一次模拟面试,这将有助于你理解面试官想要什么,以及如何应对这些面试。你可能会问,为什么要模拟面试?嗯,作为数据科学家,我们有时会在沟通方面遇到困难,在头脑中有一个模板会有很大的帮助。就我个人而言,我还发现,当我能够想象高风险的情况以及它可能如何发展时,它有助于我更好地做好心理准备,更好地处理压力,并在整体上表现得更好。
我们将使用一个来自的送餐公司 Doordash 的例子,该公司的移动应用程序目前在 iPhone 应用程序商店中排名第一。他们通过实验不断改进他们的应用程序,并在数据科学面试中寻找强大的实验技能,特别是对于产品数据科学或产品分析角色。
问题
采访者——door dash 正在扩展到其他领域,比如便利店送货。他们的通知在过去取得了很好的成功,他们正在考虑发送一个应用程序内通知来推广这个新推出的类别。
你将如何设计和分析一个实验来决定他们是否应该推出通知?
解决办法
第 1 部分——提出澄清性问题,以更好地理解业务目标和产品功能细节
面试官想要什么-
- 在深入实验细节之前,你是否先陈述了产品/业务目标?在不知道产品目标的情况下谈论实验是一个危险信号。
受访者——在我们开始实验细节之前,我想确保我对背景的理解是清楚的。像这样的功能可能有多个目标,例如增加新用户获取量、增加该类别的转化率、增加该类别的订单数量或增加总订单价值。你能帮我理解这里的目标是什么吗?
面试官——这是一个合理的问题。对于应用内通知,我们主要是试图提高新类别的转化率,即在所有登录应用的用户中,在新类别下订单的用户的百分比。
受访者——好的,这很有帮助。现在,我还想了解更多关于通知的信息——信息是什么,目标受众是谁?
面试官——目前我们不提供任何折扣。信息只是让他们知道我们有一个新的类别,他们可以开始订购。如果实验成功,我们打算向所有用户推出通知。
受访者——好的。谢谢你的背景介绍。我现在准备好深入研究实验细节了。
第 2 部分—陈述业务假设、零假设并定义要评估的指标
面试官想要什么-
- 您认为除了主要指标之外,还要考虑次要指标和护栏指标
受访者——为了陈述业务假设——我们预计,如果我们发送应用内通知,那么新类别的日订单数量将会增加。这意味着我们的零假设(Ho) 是转换率没有因通知而改变。
现在,让我说明我们希望在实验中包含的不同指标,因为通知的目标是提高新类别的转化率。这将是我们的主要指标。就次要指标而言,我们还应该观察平均订单值,看看有什么影响。转换率可能会增加,但平均订单价值会降低,从而导致整体收入下降。这是我们可能需要注意的事情。
我们还应该考虑护栏指标 —这些指标对业务至关重要,我们不希望通过实验影响它们,例如花在应用程序或应用程序卸载上的时间。在这种情况下,我们是否应该包括任何这样的指标?
面试官——我同意你对主要指标的选择,但在这个练习中,你可以忽略次要指标。就护栏指标而言,你是对的——door dash 希望对他们的应用程序的任何功能或版本做出明智的判断,因为我们知道安装了该应用程序的客户的 LTV 要高得多。我们要小心,以免驱使用户卸载应用程序。
受访者——好的——很高兴知道这一点。因此,我们将把卸载的百分比作为我们的护栏指标。
第 3 部分—选择显著性水平、功效、MDE,并计算试验所需的样本量和持续时间
面试官在寻找什么-
- 您对统计概念的了解以及样本量和持续时间的计算
- 您是否考虑了网络效应(常见于双边市场,如 Doordash、优步、Lyft、Airbnb 或社交网络,如 FB、LinkedIn)、星期效应、季节性或新奇性效应等因素,这些因素可能会影响测试的有效性,需要在进行实验设计时加以考虑
受访者——现在我想谈谈实验的设计。
让我们首先看看我们是否需要考虑网络效应——当控制的行为受到给予测试组的处理的影响时,就会出现这种情况。由于 Doordash 是一个双边市场,它更容易看到网络效应。在这种特殊情况下,如果对试验的处理增加了试验组的需求,可能会导致供应不足(即缓冲剂),进而影响对照组的表现。
为了考虑网络效应,我们将需要选择不同于我们通常所做的随机化单元。有许多方法可以做到这一点——我们可以进行基于地理的随机化或基于时间的随机化或网络集群随机化或网络自我中心随机化。您想让我详细介绍一下吗?
采访者——我很高兴你提到了网络效应,因为它实际上是我们在 Doordash 实验中仔细寻找的东西。为了节省时间,我们假设这里没有网络效应,然后继续。
受访者——因此,如果我们假设没有网络效应需要考虑,那么实验的随机化单元就是用户——也就是说,我们将随机选择用户,并将他们分配到治疗组和对照组。治疗将收到通知,而控制将不会收到任何通知。接下来,我想计算一下样本量和持续时间。为此,我需要一些投入。
- 基线转换——这是更改前质控品的现有转换
- 最小可检测差异或 MDE —这是我们感兴趣检测的转化率的最小变化。比这更小的更改对业务来说实际上并不重要—通常选择这样的更改,即预期结果的改进将证明实现和维护该功能的成本是合理的
- 统计功效——测试正确拒绝零假设的概率
- 显著性水平——当假设为真时,拒绝零假设的概率
通常选择 5%的显著性水平和 80%的功效,我将假设这些,除非你另有说明。我还假设对照组和治疗组各占一半。一旦我确定了这些输入,我将使用功效分析来计算样本大小。我会为此使用一种编程语言。例如,在 R 中,有一个名为“pwr”的包可用于此目的。
采访者——是的,假设根据分析,我们得到的样本量是每个变化需要 10,000 个用户。你将如何计算测试的持续时间?
受访者——当然,为此我们需要每天登录该应用程序的用户数量。
采访者—假设我们有 10,000 名用户每天登录该应用程序。
受访者——好吧,在这种情况下,我们至少需要 2 天时间来进行实验——我是通过将控制和治疗的总样本量除以每日用户数得出的。但是,在确定期限时,我们还需要考虑其他因素-
- 一周中的某一天效应— 周末的用户群可能与平日不同—因此,运行足够长的时间以捕捉每周周期是很重要的。
- 季节性— 有些时候用户的行为会有所不同,这一点很重要,比如节假日。
- 新奇效应——当你引入一个新功能,尤其是一个容易被注意到的功能时,最初它会吸引用户去尝试。一个测试组开始可能表现良好,但随着时间的推移,效果会迅速下降。
- 外部影响— 例如,假设市场表现非常好,更多人可能会忽略通知,期望获得高回报。这将导致我们从实验中得出虚假的结论
由于上述原因,我建议至少进行一周的实验。
面试官——好的,这很公平。你会如何分析测试结果?
第 4 部分—分析结果并得出有效的结论
面试官想要什么-
- 您对不同场景中使用的适当统计检验的了解(例如,样本均值的 t 检验和样本比例的 z 检验)
- 你检查随机化——这会给你一些印象分
- 你提供最终建议(或实现最终建议的框架)
受访者——当然。分析有两个关键部分-
- 检查随机化 —作为最佳实践,我们应该在分配试验和对照时检查随机化是否正确。为此,我们可以查看一些我们预计不会受到测试影响的基线指标,并对两组进行比较。我们可以通过比较两组之间这些指标的直方图或密度曲线来进行比较。如果没有差异,我们可以得出结论,随机化是正确的。
- 所有指标的显著性检验(包括主要指标和护栏指标)——我们的主要指标(转化率)和护栏指标(卸载率)都是比例。我们可以使用 z 检验来检验统计显著性。我们可以使用诸如 R 或 Python 这样的编程语言来做到这一点。
如果转换率有统计上的显著增加,并且卸载率没有受到负面影响,我会推荐实施这个测试。
如果转换率有统计上的显著增加,并且卸载率受到负面影响,我建议不要进行测试。
最后,如果转换率没有显著增加,我建议不要进行测试。
面试官——听起来不错。感谢您的回复。
结论
在 A/B 测试或实验性面试中表现出色,将为你在招聘过程中提供优势,让你从其他候选人中脱颖而出。所以我强烈建议花时间学习 A/B 测试中的关键概念,并为这些面试做好准备。我组织了一个 2.5 小时的课程,用真实世界的例子和作业深入地涵盖了这些概念。查看— 完成关于产品 A/B 测试的课程,并附上面试指南 ( 使用此链接获得折扣价)
学习和面试愉快!
如果您希望继续看到我关于数据科学和分析采访准备的内容,您可以关注我的Medium。
如果你在寻找数据科学职业相关的指导或者一对一的导师,可以联系我Linkedin。
破解数据科学家的商业案例访谈—第 2 部分
原文:https://towardsdatascience.com/cracking-business-case-interviews-for-data-scientists-part-2-c96d9b9a4292?source=collection_archive---------11-----------------------
图片由黄敏哈
如果您错过了上一篇文章,下面显示了本系列第 1 部分的链接。
破解数据科学家的商业案例访谈——第一部分
欢迎回到“数据科学家的商业案例访谈”的“第二部分”在这篇文章中,我将讨论解决问题方法的 7 个步骤的其余部分。本文将涵盖:
(1) 第四步:制定问题分析和工作计划——使用问题分析工作表和工作计划来“计划”行动
(2) 第五步:进行分析——简单案例的样本分析(一个玩具的例子)
(3) 第六步:综合发现——构建故事情节金字塔(“分组”结构与“论证”结构)
(4) 第 7 步:制定建议 —将故事金字塔转化为大纲和最终演示文稿
(5) 总结:关键要点
步骤 4:制定问题分析和工作计划
一旦我们对要分析的问题进行了优先排序,我们需要(1)设计详细的分析,( 2)进行适当的工作规划。解决问题方法的 7 个步骤中的第 4 步有助于计划行动。图 28 显示了问题分析和工作计划如何帮助准备行动。
图 28:黄敏哈拍摄的图像
图 29 显示了“工具#4A”:问题分析工作表。“这有助于我们思考您需要通过什么样的分析和活动来证明或否定在步骤 2 和 3 中生成并排列优先级的假设。此外,我们应该写下潜在的数据来源或数据提供者,以明确我们期望从哪里获得相关数据或信息。请注意,相关数据或信息可以是定量的(如 CRM 数据库中的交易数据表),也可以是定性的(如消费者焦点小组访谈、业务利益相关者访谈)。这个阶段的“分析和活动”的描述不必太详细。最好简短扼要。
图 29:黄敏哈拍摄的图像
图 30 显示了“工具#4B:工作计划工作表”这有助于我们指定最终产品(即关键交付成果)并为每个关键任务分配责任和期限。请注意,工作计划工作表(以及问题分析工作表)对于数据科学经理非常有用,可以确保最终交付成果的总和有助于团队找到他们想要找到的答案。此外,让负责任的所有者和截止日期在团队成员中明确期望。重要的是与团队成员共同开发这一工具,以建立和达成共识。最后,我要推荐 2 个实用的小技巧:(1)请避免共同承担责任。将一项关键任务分配给两个以上的人,不清楚谁对结果负责。如果您必须将一项关键分析或任务分配给两个以上的人,您仍然可以明确领导和支持角色。(2)对于时间线,请确保您已经包括了一些缓冲区。将会出现意外事件和数据问题,这可能会延迟整体时间表(例如,数据质量问题、基础设施问题、招聘问题、关键利益相关方的可用性等)。)在初始工作计划中包含缓冲区有助于您减少意外问题造成的潜在延迟。
图 30:黄敏哈拍摄的图像
图 31-图 33 显示了一个简单的“问题分析工作表”的例子以约翰章鱼为例。请注意,这一步有助于我们定义单独的工作流,并确定相关的数据和信息提供者。
图 31:由黄敏哈拍摄的图像
图 32:由黄敏哈拍摄的图像
图 33:黄敏哈拍摄的图像
步骤 5:进行分析
在步骤 4 中定义了关键的分析和活动之后,您终于可以进行实际的分析了。这是一部分,可能会因项目和问题而有很大不同。我将通过一个简单的案例来展示这个阶段是如何随着时间的推移而发展的。对于大多数商业问题,从基线(没有采取任何行动的状态)和目标开始是有帮助的。如果您同意度量这两种状态的标准,那就更好了。如果没有,您可能需要额外的工作来清楚地定义要使用的度量标准,并与相关的利益相关者建立共识。对于约翰章鱼的例子,我们可以从当前状态的评估开始。“瀑布图”非常有用,可以直观地显示基线和目标,以及要缩小的差距。图 34 显示了 John Octopus 示例的基线、差距和目标。为了购买一台售价 900 美元的 MacBook Pro 电脑,John Octopus 需要弥补 240 美元的缺口。
图 34:黄敏哈拍摄的图像
对减少开支的影响的第一次分析如图 35 所示。收集多个时间段的数据通常很重要,因为数据中可能存在季节性或趋势性。图 35 中的月支出数据表确实显示了支出随时间的波动。与单个月的估计相比,使用 3 个月的平均值(32 美元)将是对平均月支出更可靠的估计。图 36 中每月平均花费的细目证明了最初的假设是错误的。咖啡和漫画书是最大的两项支出,而不是视频游戏和 CD。让我强调一下,最初的假设不一定是正确的。这个阶段的数据和分析将证明或否定一个假设,这是一个有助于集中分析的工具。
图 35:由黄敏哈拍摄的图像
图 36:由黄敏哈拍摄的图像
找出哪些项目是支出最高的项目是一回事,但你还需要考虑减少支出的可行性。图 37 显示了定性开支削减可行性评估的示例。举个例子,章鱼哥约翰决定不削减咖啡开支,因为早上没有咖啡他无法正常工作。根据图 36 中项目的平均月支出(即对减少支出的影响)以及图 37 中削减支出的可行性(按高/中/低评估),我们可以在图 38 中创建一个“优先化”矩阵。这表明,电子游戏和光盘是约翰没有太多困难就能减少开支的物品。我们可以反映这一分析的结果,并评估我们缩小了多少差距。图 39 显示,在视频游戏和光盘上的支出削减可以在未来 6 个月贡献 80 美元,这将差距缩小到 160 美元。
图 37:黄敏哈拍摄的图像
图 38:由黄敏哈拍摄的图像
图 39:由黄敏哈拍摄的图像
作为第二项分析,约翰·章鱼评估了他可以通过出售不必要的资产(如二手漫画书)赚多少钱。图 40 总结了这一分析的结果,通过出售不必要的资产,确定了 50 美元的额外节约。图 41 回顾了增加额外节省后与目标的差距。由于增加了 50 美元,剩余的差额现在减少到 110 美元。请注意,量化每次分析的影响并将其与目标进行比较有助于您判断何时可以停止。如果整体影响大到足以实现你的目标,你可以早点停止,而不是做所有的活动或分析。
图 40:黄敏哈拍摄的图像
图 41:由黄敏哈拍摄的图像
图 42 和图 43 总结了分析# 3——朋友和邻居访谈的结果:约翰调换工作能增加多少收入。在仔细研究了他的发现后,约翰意识到他每小时只能挣 6-8 美元。图 44 总结了他的发现。通过换工作来增加他收入的假设似乎行不通。我们被困在这里了吗?我们如何缩小剩下的差距?
图 42:由黄敏哈拍摄的图像
图 43:由黄敏哈拍摄的图像
图 44:由黄敏哈拍摄的图像
这是多重迭代开始发生的地方。有时候,最初的假设可能不足以实现你的目标。我们需要考虑其他可能的想法。通常,到目前为止进行的数据和分析为新想法提供了基础。图 45 显示了该过程的输出示例。章鱼哥约翰意识到他可以同时遛多只狗。这可以让他的月收入增加 32 美元,而不需要投入更多的时间。在反映了他月收入的增加后,图 46 显示他现在可以买一台 982 美元的电脑,这超过了他 900 美元的目标。一个问题就解决了!
图 45:由黄敏哈拍摄的图像
图 46:黄敏哈拍摄的图像
图 47 总结了一些在“进行分析”步骤中有用的技巧让我再次强调多次迭代的重要性。与其试图以缓慢的速度达到完美,不如快速高效地多次迭代。快速失败是非常受鼓励的,你总是可以迭代多次来改进。
图 47:黄敏哈拍摄的图像
第六步:综合调查结果
一旦你完成了第 5 步的分析,第 6 步就是交流的重要开始:“综合发现”。请注意,合成不同于总结。图 48 对比了基于相同基本事实的综合与汇总的不同之处。合成倾向于更关注“那又怎样?”
图 48:黄敏哈拍摄的图像
金字塔原理(芭芭拉·明托)有助于综合潜在的事实。图 49 显示了合成过程与交流的不同之处。合成通常是自下而上的。从潜在的事实、数据和分析出发,分组有助于找到一种模式或相似性。通过问“那又怎样”,你最终可以将这些综合成统治思想。相比之下,沟通通常是以自上而下的方式进行的。
图 49:由黄敏哈拍摄的图像
图 50 介绍了“工具#5:故事情节金字塔”你可以有一个“分组”结构,其中一个主导思想由独立但连贯的想法支持。另一个替代方案是“论证”结构,在这种结构中,主导思想由一系列想法支持。图 51 和图 52 提供了这两种逻辑结构的更多细节和优缺点。
图 50:由黄敏哈拍摄的图像
图 51:黄敏哈拍摄的图像
图 52:由黄敏哈拍摄的图像
为了使这些更具体,图 53 和图 54 提供了一个“分组”结构的例子。“分组”结构对注重行动的观众来说很有效。另一个主要好处是,如果一个点被拒绝,其余的点仍然有效。然而,对于某些观众来说,这可能被认为是太强有力了。
图 53:由黄敏哈拍摄的图像
图 54:黄敏哈拍摄的图像
图 55 提供了一个“参数”结构的例子。这对抗拒的观众可能是有效的。但是,如果听众不同意这种情况或评论,论点可能无法说服。
图 55:黄敏哈拍摄的图像
图 56 提供了一些有用的综合技巧。组织和结构是建立一个坚实的故事情节的关键。保持信息的重点是值得的。即使你的分析中有有趣的事实,如果这些事实与关键问题无关,也应该避免离题。
图 56:黄敏哈拍摄的图像
步骤 7:提出建议
一旦你在第 6 步制定了一个“故事情节”,7 步解决问题方法的最后一步就是“制定建议”我来强调一下这个阶段最后沟通的重要性。有时,由于缺乏令人信服的沟通,非常畅销的分析和令人信服的数据无法产生业务影响。在某些情况下,有效的沟通者甚至可以用不那么令人信服的数据和分析成功地说服听众。图 57 显示了你在步骤 6 中开发的故事情节金字塔如何转化为最终报告或演示的大纲。
图 57:黄敏哈拍摄的图像
讲述故事的一种流行方式是 SCR:情境、复杂、解决。这种方法非常有效,尤其是在观众比较抗拒的情况下。此外,东方文化的观众往往喜欢这种讲故事的方式(即建立)。相比之下,西方文化的观众通常更喜欢“自上而下”的讲故事方式。更多高层领导受众倾向于“自上而下”的讲故事方式。然而,这些在很大程度上取决于具体的受众和情况。图 58(6 号工具)显示了 SCR 的细节。
图 58:由黄敏哈拍摄的图像
图 59 提供了一家资产管理公司基于情景、复杂性和解决方案讲述故事的示例。对情境和复杂性的认同对于受众接受决议中的建议至关重要。
图 59:由黄敏哈拍摄的图像
总结:关键要点
我介绍了一个 7 步解决问题的方法,它可以用于业务问题和数据科学问题(尤其是决策科学问题或更面向应用的数据科学问题。)希望您发现这种结构化的问题解决方法有助于(1)为数据科学家的业务案例面试做准备,以及(2)作为数据科学家处理日常活动和任务。在图 60 中,总结了 7 步解决问题方法中每一步的要点。
图 60:黄敏哈拍摄的图像
*本文中的约翰·章鱼例子改编自渡边谦的《解决问题 101:给聪明人的一本简单的书》。
免责声明:我并不代表麦肯锡建议的解决问题的方法,这里有所描述。我只是分享我的观点。
参考
- 金字塔原理:写作和思考中的逻辑,ISBN-13:978–0273710516,芭芭拉·明托
- 解决问题 101:一本给聪明人的简单的书,ISBN-13:978–1591842422,渡边谦
原载于 2021 年 12 月 11 日【http://bigdataco.blogspot.com】。
破解数据科学家的商业案例访谈:第 1 部分
原文:https://towardsdatascience.com/cracking-business-case-interviews-for-data-scientists-step-1-define-a-problem-6a63f86b9a38?source=collection_archive---------18-----------------------
问题定义、结构化和优先级排序
图片由黄敏镐
商业案例研究面试问题往往是面试过程中最难的部分,尤其是对于没有工作经验的早期数据科学家。即使在得到一份工作后,从其他团队和利益相关者那里获得一种结构化的方式来制定和解决业务问题也是有益的。
基于我作为前麦肯锡顾问和数据科学家超过 10 年的学习,我分享一个“解决问题的 7 个步骤”的方法。这种结构化的业务案例/问题解决流程以及相关的框架和模板将帮助您更轻松地处理和解决新的业务问题。
在本文中,我将讨论:
(1) 问题解决方法的 7 步概述
(2) 第一步:定义一个问题——如何通过解决一个恰当的问题来避免第三类错误
(3) 第二步:构建问题——如何将问题分解成可管理的子问题
(4) 第三步:确定问题的优先级— 如何确定要解决的子问题的优先级
下面显示了其余步骤的“第 2 部分”的链接。
破解数据科学家的商业案例访谈—第二部分| Minha Hwang |迈向数据科学
概述“解决问题的 7 个步骤”方法
解决业务问题本身就是一项艰巨的任务。然而,应用结构化的问题解决方法对于数据科学家来说非常有帮助,可以使这变得更加愉快。这个在大学或者研究生院还没有教好。像麦肯锡这样的顶级管理咨询公司已经开发了这种方法,这也是他们成功的秘诀之一。本着分享的精神,我将在这一系列的两篇文章中详细描述这种方法。本文将有助于(1)数据科学家准备业务案例面试,(2)数据科学家及其业务合作伙伴解决业务问题并产生业务影响,(MBAs 准备管理咨询公司的业务案例研究面试,以及(4)博士生和研究人员采用假设驱动的方法并提高研究效率。解决业务问题的 7 个关键步骤如下:
(1)定义一个问题
(2)构造一个问题
(3)优先处理问题
(4)制定问题分析和工作计划
(5)进行分析
(6)综合研究结果
(7)提出建议
这不是一个线性过程。因此,你需要重复几次来得到一个更好的解决方案,直到你确信进一步迭代的好处是有限的。定期修改和重新评估是非常重要的。这些步骤听起来非常直观和简单。在这一点上,你可能想知道这是否有帮助。魔鬼在细节中。现在,让我深入研究每一个步骤,展示它是如何工作的。我在图 1 中总结了“解决问题的 7 个步骤”。
图 1:图片由 黄敏哈 拍摄
第一步:定义问题
解决业务案例的最重要的步骤是“问题定义”,这一点经常被忽视如果机器学习工程师解决了错误的问题,那么用复杂的自然语言处理模型完美解决问题还有什么意义?信不信由你,这种“第三类错误”(解决一个错误的问题)在实践中经常发生。如果有一个合适的问题定义阶段,这是完全可以避免的。
在描述这个阶段的关键要素之前,我想指出一个可以解决的“定义明确的问题”与我们通常所说的“问题”有很大的不同在日常互动中,我们通常所说的“问题”是指认识到“有些事情不对劲”发生的事情和应该发生的事情(即目标)之间存在差距。)或者已经发生的和可能发生的有差距(即机会。承认“问题”是困难的,而且会产生焦虑。它往往非常“笼统”,可以只是“陈述事实”。这仅仅是对形势的认识,需要采取行动。
可以解决的“明确定义的问题”具有以下特性:
- 一个发人深省的问题,而不是一个事实
- 具体,不笼统
- 可测量
- 行动导向
- 相关(针对关键问题)
- 有时间限制的
此外,它是
- 有争议的(非事实陈述或无争议的主张)
- 关注决策者需要什么才能前进
定义明确的问题的这些性质通常可以用一个“聪明”原则来概括。这个原理如图 2 所示。
图 2:图片由 黄敏哈 拍摄
为了使“明确定义的问题”更具体,让我用一个简单的玩具例子来对比“明确定义的问题”和我们通常所说的“问题”。下面总结了这个玩具例子的背景:约翰章鱼。
- 事情经过:约翰上周六和朋友去看了《Ready Player One》(虚拟现实上的电脑生成动画电影(即 CGI),他很喜欢。
- 目标:约翰看完电影后印象深刻。因此,他想成为好莱坞 CGI 电影导演。
- 需要采取行动的情况(典型意义上的问题):
- 约翰对如何制作电脑动画电影毫无头绪。
- 他甚至没有电脑。
- 首先,他需要弄清楚如何买一台电脑,以便开始工作。
我们有足够的信息来正确定义这个问题吗?不,还没有!我已经在图 3 中总结了我们目前所拥有的信息。
图 3:图片由 黄敏哈 拍摄
让我介绍第一个问题定义工具,来阐明我们需要哪些额外的信息来“正确地定义”问题。“问题定义工作表”是一份很好的清单,可以确保我们拥有正确定义问题所需的所有信息。关键要素是:
(1)问题定义:请强迫自己把这个当成一个“问题”。
(2)背景:了解问题的历史和组织背景很重要。
(3)关键利益相关者:谁是关键决策者?谁会受到这个决定的影响?
(4)成功的标准:没有这个,你怎么知道自己是否成功解决了业务问题?请确保在解决问题之前正确定义“成功指标”。你解决不了问题,这是无法衡量的。
(5)约束:把甚至不应该考虑的写下来也是有帮助的。
(6)解决方案空间的范围:通常,对于问题的地理或业务线焦点有明确的要求。检查时间要求也很好(即 4 周、3 个月、1 年后的答案?).有时候,80/20 方向性的答案是渴望的。其他时候需要非常精准的回答(网站流量增加 1%或者网站流量增加 1.1%)。明确所需的准确性有助于正确衡量提议的方法或解决方案是否合适。
为了便于将来使用,第一个工具“问题定义工作表”如图 4 所示。
图 4:图片由 黄敏哈 拍摄
现在,让我们为 John Octopus 玩具示例收集更多信息。这些是:
- 时机:John 希望在暑假期间从 8 月份开始获得一些设计实践,而暑假只有 6 个月的时间。
- 计算机的类型和价格范围:
- 约翰发现 MacBook Pro 很适合 CGI 使用。
- 二手 MacBook Pro 售价约 900 美元
- 其他上下文:
- 约翰不想借或租电脑。
- 约翰有 140 美元的存款。他的父母每月给他 100 美元的零花钱,他每周帮邻居遛狗一次,每小时挣 15 美元,相当于每月 60 美元。
- 约翰平均每月花费 80 美元。
- 如果约翰想在 10 个月内拥有一台电脑,他可以通过存钱来买。
有了额外的必需信息,我们可以正确地定义 John Octopus 的问题,如图 5 所示。
图 5:图片由 黄敏哈 拍摄
看到问题定义的坏例子通常是有帮助的。图 6 显示了同一个 John Octopus 例子中有缺陷的问题定义的三个例子。
图 6 图像由 黄敏哈 组成
作为最后一个练习,我们可以再考虑一个例子,这个例子不太基于个人经验,但更多地来自商业案例。
图 7 显示了洋葱银行有缺陷的问题定义的更多例子。
图 7:图片由 黄敏哈 拍摄
相比之下,图 8 显示了洋葱银行的一个明确定义的问题的例子。
图 8:图片由 黄敏哈 拍摄
希望本文能帮助您理解定义良好的业务问题的关键要素。一个好的问题定义是 60%以上的解决问题的努力。请确保您在数据科学家访谈或作为数据科学家的日常任务中正确定义了问题。
第二步:构建问题
一旦你恰当地定义了一个问题,下一步就是“构建一个问题”通常,已定义的问题太大,即使在问题定义之后也无法有效解决。将一个问题分解成子问题(即问题)的更小和可管理的组成部分非常有助于使问题解决可行和有效。这允许将工作划分并分配给不同的团队成员,并进行适当的责任分配。此外,这一步是确定问题优先级的后续步骤的基础,在这一步中,将根据解决问题的重点来确定优先级。“逻辑树”(2 号工具)在问题结构化的过程中非常有用。图 9 介绍了一个逻辑树。
图 9:图片由 黄敏哈 拍摄
一个“逻辑树”(2 号工具)帮助我们确保待维护问题的完整性。通过检查离散的组块(即子问题)是互斥的,并且是集体穷举的(即“MECE”),我们可以确保解决问题的部分最终将真正解决问题。由于这些部分没有重叠,我们可以避免重复工作。事实上,没有差距(集体详尽)确保我们没有遗漏任何重要的东西。这也有助于作为一个通信设备。在团队中创建逻辑树有助于建立共识,这也可以在团队之外以结构化的方式共享。最后,这有助于集中使用框架和理论。验证提出的框架和理论通常会揭示逻辑上的差距或尚未考虑的方面。
有两种不同类型的逻辑树。在解决问题的初始阶段,一个"问题树 " ( 什么/如何树)更有助于思考整个解决方案空间。一旦你对问题有了足够的了解(例如,经过几次反复的探索性分析、最初的二手数据研究,或者访谈和会议),一个“假设驱动树”(为什么树)就变得更加相关了。该树更适合基于假设集中解决问题的努力,并作为确定优先级的基础。数据科学领导者成功的秘诀是尽早建立良好的假设并正确安排工作的优先级。图 10 总结了两种类型的逻辑树。
图 10:图片由 黄敏哈 拍摄
为了使“逻辑树”的使用更加具体,让我们通过使用 John Octopus 的一个简单案例来开始一个练习。图 11 是一个样例“问题树”,您可以创建它来为 John Octopus 解决问题。请注意,我们正在询问“如何”开发该树的问题。图 11 显示了最高的两个级别。由于我们的目标是在 6 个月内拿出 900 美元购买一台二手 MacBook Pro 电脑,我们可以开始将问题分为增加收入和减少储蓄。为了开发下面的分支,我们必须考虑一下约翰·章鱼哥是如何获得收入的,他的大部分钱都花在了哪里。
图 11:图片由 黄敏哈 拍摄
一旦我们开发了顶层,我们就可以进一步开发上层和下层分支的问题树。如果你想练习,我会建议你不要看下面的解决方案。在实践之后,你可能会意识到开发一个“MECE”树需要大量的思考,即使是像这样一个简单的问题。图 12 和图 13 分别显示了上分支和下分支的潜在问题树。
图 12:图像由 黄敏哈 拍摄
图 13:图片由 黄敏哈 拍摄
什么会被认为是不好的“问题树”?看到不好的例子有助于理解好的解决方案需要什么。图 14 显示了 John Octopus 问题的有缺陷的问题树示例。你可以看到,通过混合不同的水平,这是不一致的——增加收入与许多支出类别细分处于同一水平。此外,这不是“MECE”,因为咖啡和糖果等重要的消费类别没有显示出来。
图 14:图片由 黄敏哈 拍摄
到目前为止,我们已经看到了 John Octopus 问题的“问题树”(如何/什么树)的例子。如果您创建一个“假设驱动树”(为什么树),它与您创建的问题树有什么不同?图 15 显示了 John Octopus 问题的“假设驱动树”示例。请注意,这可以通过问一系列“为什么”的问题来展开。
图 15:图像由 黄敏哈 拍摄
现在,让我们通过使用一个更加面向业务的示例来做另一个创建“问题树”的练习。假设你被可口可乐公司聘为管理顾问,该公司试图解决全球盈利能力下降的问题。有许多方法可以开发“问题树”。这些将帮助你考虑给定问题的不同维度和方面。图 16、图 17 和图 18 显示了针对给定问题开发问题树的三种不同方式:利润驱动、地理位置和业务线。
图 16:图片由 黄敏哈 拍摄
图 17:图片由 黄敏哈 拍摄
图 18:图像由 黄敏哈
最后再考虑一个例子,是 A/B 测试的数据科学问题。我们试图解决的问题是“如何提高 A/B 测试的灵敏度。”对于许多大型科技/互联网公司来说,这是一个重要的问题,这些公司使用基于 A/B 测试的数据驱动决策来做出产品功能发布决策。通过提高指标敏感度,公司可以用更少的数据进行精确的推断(即,更短的实验持续时间或更小的实验样本量)。)典型的 A/B 检验依赖于一个独立的 2 样本 t 检验作为检验统计量。对 A/B 测试中驱动测试统计量的因素有一个直观的理解,将有助于您开发一个问题树,并集思广益以提高度量敏感度。提醒一下,A/B 测试的测试统计如下所示。从更直观的角度来看这个公式,你可以意识到 3 件事很重要:效果大小(即你的治疗组和对照组之间的均值差异)、方差(即噪音水平)和样本大小。请注意,我在顶部简化了一个更通用的公式,假设治疗组和对照组之间的方差相同(即混合方差),治疗组和对照组之间的样本量相同,以方便直观。
图 20:图片由 黄敏哈 拍摄
图 20 显示了增加 A/B 测试灵敏度问题的潜在“问题树”。
图 20:图片由 黄敏哈 拍摄
希望你已经对如何应用逻辑树将问题分解成更易管理的块(即子问题)有了很好的理解。总之,好的逻辑树是(1)一致的,(2)相关的,(3)“MECE”。图 21 在一张图中更清楚地说明了这一点。
图 21:图片由 黄敏哈 拍摄
最后,我将通过提供一些关于“如何制作逻辑树”的提示来结束这一部分图 22 显示了技巧,以及基本原理(即为什么)。
图 22:图片由 黄敏哈 拍摄
第三步:区分子问题的优先级
一旦你把一个问题分解成子问题,下一步就是“优先化”。这实质上是砍掉问题树或假设驱动树的分支,把注意力集中在最重要的事情上。图 23 以图形的形式展示了这个过程。
图 23:图像由 黄敏哈
我们可以使用哪些潜在的标准来确定优先级?潜在(业务)影响、技术或执行可行性、风险通常是有用的标准。个人或公司的价值观也可以作为指导。在实践方面,参考高层管理议程以确保您的项目将从领导和高层管理获得所需的支持是一个不错的主意。检查 okr 在这方面会有帮助。图 24 总结了您可以考虑的潜在标准。
图 24:图片由 黄敏哈 拍摄
图 25 显示了“工具#3”,它对于解决问题的优先化步骤非常有用。优先级矩阵(2 x 2 矩阵),其中一个轴是潜在影响,另一个轴是可行性,是一个有用的可视化工具,可以对要关注的子问题进行优先级排序。在图 25 中,我使用了 John Octopus 问题来使它更加具体。
图 25:图片由 黄敏哈 拍摄
为了更熟悉解决问题的第三步:优先化,让我们再次使用约翰章鱼问题。在图 26 中,我展示了问题树的上层分支,以及如何应用优先级。类似地,在图 27 中,问题树的较低分支显示了类似的优先级排序练习。
图 26:图片由 黄敏哈 拍摄
图 27:图片由 黄敏哈 拍摄
到目前为止,结构化问题解决方法的前 3 个步骤:(1)定义问题,(2)构建问题,以及(3)区分问题的优先次序,都是通过例子来介绍的,使它们更加具体。
在后续文章(第 2 部分)中,我将详细描述解决问题过程的其余部分。下面显示了下一篇文章的链接。
数据科学家的商业案例访谈-第二部分
*本文中的 John Octopus 例子改编自《解决 101 个问题:聪明人的一本简单书》渡边谦的书。我会推荐那本书,尤其是给学生看的。
免责声明:我并不代表麦肯锡建议的解决问题的方法,这里有所描述。我只是分享我的观点。
原载于 2021 年 9 月 6 日 http://bigdataco.blogspot.comhttp://bigdataco.blogspot.com/2021/09/cracking-business-case-interviews-for.html。
破解微软 Power BI: DA-100 考试!
原文:https://towardsdatascience.com/cracking-microsoft-power-bi-da-100-exam-8df7d6bf53c7?source=collection_archive---------12-----------------------
最近,我通过了微软 Power BI: DA-100 考试的数据分析,并将微软数据分析师助理认证添加到我的技能桶中。
在 Unsplash 上由 Adeolu Eletu 拍摄的照片
在这篇文章中,我将分享我的个人经验,学习 BI 和清除 DA-100 考试。我希望这能帮助其他有志之士。我不会妥协的签署 NDA,因此没有问题将在这篇文章中披露。
Power BI 是最常用的商业智能和数据可视化工具之一。在这个数据驱动的世界中,该认证有助于展示您的数据分析技能。
关于考试 DA-100
微软现在正从基于工具的认证转向基于角色的认证,如数据分析师、数据工程师、数据科学家、开发人员等。
使用 Microsoft Power BI (DA-100)分析数据是 Microsoft 数据分析师助理认证的要求。考试费用是 165 美元。从 2021 年 6 月起,认证有效期缩短至 1 年。但是可以在微软学习网上免费续借。
该考试测试设计和构建可扩展数据模型、清理和转换数据以及启用高级分析功能(通过易于理解的数据可视化提供有意义的商业价值)的知识。
考试分为 5 个部分:
- 准备数据(20-25%)
- 对数据建模(25–30%)
- 可视化数据(20–25%)
- 分析数据(10-15%)
- 部署和维护可交付成果(10-15%)
点击此处查看详细技能概要。衡量的技能不断更新。因此,请务必查看考试页面。
这是一个 180 分钟的在线考试。考试由两部分组成:MCQs 和案例分析。第一部分大约有 45-50 个选择题,在 2-3 个案例研究中每个大约有 4-5 个问题。最高总分可能是 1000,及格分数是 700。考试刚结束,成绩就出来了。
目前,微软为受新冠肺炎影响的求职者和学生提供 15 美元的考试。
备考
谈到我使用 Power BI 的经验,我使用该工具完成了几个小型学术项目。除此之外,我在考前真的没有任何行业经验。所以我真的不得不振作起来通过考试。
我发现备考最好的就是微软提供的官方学习路径。学习路径包括每个主题的详细阅读材料和精心设计的练习概念的实验室。相信我,你不会厌倦阅读这些材料。为了更清晰起见,我还曾经在 Youtube 频道上回顾过一些概念,比如“立方体中的家伙”和“T2”。
此外,我参加了 Udemy 上的 MICROSOFT POWER BI DA-100 考试:高级 2021 模拟测试课程。它由不同主题的样题组成,解决它们可以让你了解真正的考试。此外,你可以谷歌转储不同网站上发布的问题集,它们值得练习。
其他一些重要的提示…
- 在开始考试之前,你必须上传周围的照片。做好准备。
- 提供的时间足够完成考试。所以,不要急着通读每个问题,不要错过任何一个微小的细节。
- 如果你在 DAX 上很弱,不要害怕,没有多少高级 DAX 被评估。
- 区段提交后无法重新访问。所以,在提交之前,重新核实一下答案。
最后,我想说,微软官方文档是关键!!如果你完成了学习材料,没有人能阻止你通过考试。我希望我的经历能帮助 DA-100 的有志之士。我最美好的祝愿伴随着每个备考的人:)
如有任何其他疑问,请随时评论。
疯狂简单的异常检测帮助客户取得成功
原文:https://towardsdatascience.com/crazy-simple-anomaly-detection-for-customer-success-458e94d4d516?source=collection_archive---------25-----------------------
如何检测使用情况的变化,及时做出反应并让您的客户满意
异常检测这个话题很吸引人。有大量的方法可以使用,从简单的统计到更复杂的无监督学习方法。此外,异常检测的影响是巨大的。当事情没有按计划进行时,检测的能力是一个奇妙的工具,并且具有拯救生命的潜力(例如在预防性维护中)。
在本文中,我们将探索一种极其简单的异常检测方法。有时候最简单的解决方案可能会产生最大的影响。在这种情况下,我们将使用中位数绝对偏差或 MAD 来检测企业交易的 WhatsApp 消息数量中可能的异常值。
介绍
在客户成功领域,特别是在 SaaS B2B 公司,衡量我们客户的产品使用是至关重要的。本质上,SaaS 企业希望了解他们的客户如何使用他们的产品,以及他们使用了多少。背后的原因是,如果客户不使用你的产品,很可能他们遇到了某种麻烦。这可能是因为他们不知道如何使用它,他们没有从中获得价值,或者他们遇到了某种产品缺陷。在任何情况下,使用率下降都会导致客户流失。除其他事项外,客户成功团队的角色是识别可能发生这种情况的案例,并帮助这些客户最终引领他们走向成功。
除了使用 MBR 或 QBRs(月度或季度业务回顾)进行定期检查之外,客户成功团队还可以通过了解客户何时较少使用他们的产品来采取积极的态度。这是一个实现异常检测的完美例子。这个想法是检测每个客户的使用数据中的异常,并让客户成功团队联系那些放弃使用的客户。
数据
要使用的数据类型因业务而异。如果你是 Shopify 这样的电子商务平台,你可能会对跟踪销售感兴趣,如果你是 MailChimp 这样的电子邮件营销平台,你会对发送的电子邮件感兴趣。当我在 Sirena 工作时,我会使用 WhatsApp messages 的使用数据,Sirena 是一款让企业通过 WhatsApp 与客户沟通的应用。在本文中,我将使用从一个非常简单的模拟中随机生成的 WhatsApp 消息数据。这个数据集在我的 Github 中公开:fake data/whatsapp messages
该数据集包含 4 个不同客户在 10 周内处理的邮件数量。为了简单起见,我们将只关注一个客户;顾客 3。
异常检测
疯了
中位数绝对偏差(MAD)是一个非常简单的样本变异度量。从这个意义上来说,它非常类似于衡量统计离差的标准偏差。MAD 被定义为每个观测值和中值之间的残差绝对值的中值:
然而,与标准偏差相比,MAD 的一个很大的优点是其对异常值的稳健性或不敏感性。平均值和标准偏差都受到异常值的严重影响,因此对异常检测极为不利。在他们的论文中,Leys 等人(2013)表明,许多研究人员仍然使用标准差来表示离差,并建议转向 MAD。在这篇文章中,我将向您展示如何在 Python 中使用它来检测异常或离群值。
实施
我们将从单个客户开始,在本例中为客户 3:
您可能会惊讶于它的实现是如此简单。事实上,计算 MAD 基本上只是 python 的一行代码:
这一行所做的是定义一个(lambda)函数,该函数接受一个 numpy 数组(x ),并计算每个 x 与 x 的中值之差的元素绝对值的中值,这正是 MAD 的定义。简单。
在计算 MAD 时,我们面临的唯一(非常微小的)复杂情况是,我们实际上想要计算滚动 MAD。但是使用 numpy 也很简单:
如你所见,首先我们计算滚动中值,然后我们加上滚动平均值。我们可以绘制出它与数据的关系,从而了解我们正在做的事情:
我们可以看到 MAD 是高度滞后的,这没关系。请记住,我们不是要一个非常复杂的异常检测器或预测模型。我们只需要了解对我们的客户来说什么是“正常的”使用变化。
很好,现在我们有了 MAD,我们需要定义标准来理解一个观察是否是一个实际的异常。为此,我们将添加一个阈值,并为我们的滚动 MAD 创建上限和下限:
太好了!现在,我们可以将这些边界添加到图表中,看看我们在处理什么:
看起来不错!现在我们有了 MAD 和一个边界,它可以帮助我们确定一个观察是否是异常。这意味着,对于每个时间点,如果观测值高于滚动 MAD 的上限或低于下限,我们就说这是一个异常。
在这种特定情况下,50%的阈值似乎有点太紧了。我们可以尝试改变这种情况,直到我们对假阳性的数量感到满意为止。我们可以用 70%试试。
使用这些数据,我们可以很容易地获得 MAD 实现检测到的所有异常的列表:
结果向我们显示了每天的使用情况(值)、我们期望看到的情况(MAD)和时间间隔(MAD 上限和下限)。
结论
在这篇文章中,我们探索了一种非常简单的方法,使用中值绝对偏差或 MAD 来实现使用数据的异常检测。当然,您可以做很多修改来适应您的特定用例,比如滚动窗口、阈值或者决定何时通知您的团队。我敢肯定,您可以想象当客户的一个帐户停止使用时,一个松散的集成会通知客户成功管理人员。但是,如果您的产品使用有相关的季节性,请考虑调整通知服务。例如,在我们的例子中,如果使用率下降发生在周末(使用率预计会在周末下降),通知 CSE 没有太大意义。另一种选择是有两个 MAD 界限,一个是周末的更宽松的界限,另一个是工作日的更严格的界限。可能性是无限的。
参考文献
莱斯大学、莱伊大学、克莱恩大学、伯纳德大学和利卡塔大学(2013 年)。检测异常值:不要使用平均值周围的标准偏差,使用中位数周围的绝对偏差。《实验社会心理学杂志》,49 期 (4),764–766 页。
使用 Wtfutil 在您的终端中创建一个漂亮的仪表板
原文:https://towardsdatascience.com/create-a-beautiful-dashboard-in-your-terminal-with-wtfutil-573424fe3684?source=collection_archive---------12-----------------------
现在你可以在你的终端上查看你的日程表,待办事项,系统信息,Docker,Git 等等。
动机
作为一名数据科学家或程序员,终端可能是您大部分工作的随身工具。如果你能像下面这样查看你的日程表、待办事项、系统信息、docker、git 和你最喜欢的博客的更新,那不是很好吗?
作者图片
这就是 WTF 派上用场的时候。
WTF 是什么?
WTF 允许您监控系统、服务和重要信息。以下是您可以使用 WTF 查看的一些内容:
- 谷歌日历
- 码头工人
- 饭桶
- 资源使用
- 系统
- 您最喜爱的网站的更新
还有更多!在本文中,我将向您展示如何使用 WTF 将这些信息添加到终端仪表板中。
装置
公司自产自用
您可以使用 Hombrew 安装 WTF
brew install wtfutil
wtfutil
二进制的
如果这个方法对你不起作用,从 GitHub 下载最新的二进制。如果您使用的是 Linux,您可以通过键入以下命令来检查您使用的是哪个 ARM 版本
dpkg --print-architecture
由于我的 ARM 版本是 amd64,所以在Downloads
下载了wtf _ 0 . 36 . 0 _ Linux _ amd64 . tar . gz,解压文件,然后将文件wtfutil
移动到 /usr/local/bin
:
mv ~/Downloads/wtf_0.36.0_darwin_amd64/wtfutil /usr/local/bin
然后设置执行文件的权限
chmod a+x /usr/local/bin/wtfutil
现在它应该工作了!
wtfutil
作者图片
如果这两种方法都不适合你,在这里查看其他方法。
自定义仪表板
现在我们的仪表板看起来有点无聊。让我们向仪表板添加一些有用的模块。要在终端中编辑配置文件,请键入
nano ~/.config/wtf/config.yml
或类型
gedit ~/.config/wtf/config.yml
使用代码编辑器编辑文件。
谷歌日历
如果你像我一样,使用谷歌日历来提醒自己即将到来的事件或约会,如果你不用打开谷歌日历就可以在终端上浏览一周,那不是很好吗?幸运的是,WTF 允许你这样做。
要将 Google Calendar 添加到您的仪表板,首先通过在步骤 1 中点击“启用 Google Calendar API”来启用 Google Calendar API。
作者图片
下载完credials.json
后,将其移动到本地机器的一个保存位置。例如,您可以将您的credentials.json
文件移动到~/.config/wtf/
:
sudo mv ~/Downloads/credentials.json ~/.config/wtf
然后将 Google 日历的凭证文件路径添加到~/.config/wtf/config.yml
删除或禁用~/.config/wtf/config.yml
中的textfile
部分,因为其位置与gcal
重叠
保存文件,然后键入wtfutil
,您应该会看到一个提示“转到您的浏览器中的以下链接,然后键入授权码”。单击链接并将代码复制到终端。
现在,您应该可以在终端上看到 Google 日历的事件和约会,如下所示!
作者图片
提要阅读器
如果你想获得你喜欢的网站如 Medium 的每日更新,只需将feedreader
添加到~/.config/wtf/config.yml
,然后在feedreader
下添加他们的 RSS 源。
您可以按照本说明或本说明在媒体上查找个人资料、出版物和主题的 RSS 源,或使用本说明查找任何其他网站的 RSS 源。
保存上面的配置后,您的仪表板应该如下所示:
作者图片
如果您想要选择特定的部分,请在该部分的顶部键入数字。由于数字 2 紧挨着提要阅读器标题,我们将键入2
来访问提要阅读器部分。
然后使用向上或向下箭头在不同的文章之间移动。键入o
在浏览器上打开文章。现在你可以在你的终端中获得你喜欢的网站的每日更新!
作者 GIF
CmdRunner
如果您想在仪表板上显示终端命令的输出,如nvidia-smi
,将cmdrunner
添加到您的~/.config/wtf/config.yml
:
cmd
:要运行的终端命令。在这种情况下,它是nvidia-smi
args
:添加命令的参数。由于nvidia-smi
没有任何参数,数组为空。
我禁用了clocks_a
和clocks_b
部分,为我的新部分留出了空间。如果您希望保留clocks_a
和clocks_b
部分,可以通过编辑position
中的参数随意改变nvidia-mi
的位置。
保存配置文件后,您的仪表板应该类似于下图。
作者图片
饭桶
了解您最近使用 git 更改或提交了哪些文件也很有用。要显示关于本地 git 存储库的信息,请将下面的代码添加到您的~/.config/wtf/config.yml
中:
您应该会看到如下所示的内容:
作者图片
码头工人
如果您正在使用 docker,了解 Docker 容器和映像的信息可能会很有用,比如卷、内存限制、磁盘使用等。
要将 Docker 的信息添加到您的终端仪表板,请将以下代码添加到您的~/.config/wtf/config.yml
:
保存配置文件后,您的仪表板应该如下所示:
作者图片
资源使用
要在仪表盘上显示关于 CPU 和内存使用情况的信息,请将resourceusage
添加到您的~/.config/wtf/config.yml
:
您应该能够在仪表板中看到您的 CPU 和内存使用情况!
作者图片
待办事项列表
您也可以通过将todo
添加到您的~/.config/wtf/config.yml
来将待办事项列表添加到您的终端:
您应该会看到如下所示的内容:
作者图片
您的待办事项列表中还没有任务。让我们通过键入4
来添加一个任务,然后键入n
来添加一个新任务。添加任务后,点击“保存”将任务添加到列表中。
作者图片
一个新项目被添加到您的列表中!
作者图片
要检查任务,请使用向上或向下键选择任务,然后键入 Space。若要取消选中该任务,请再次键入 Space。
作者图片
就是这样!现在,您有了一个有用且漂亮的仪表板,可以在您的终端中查看。您的仪表板现在应该如下所示:
作者图片
点击查看添加到终端的其他选项。
结论
恭喜你!您刚刚学习了如何使用 WTF 创建一个漂亮的终端仪表板!能够使用一个命令查看所有重要信息可以每周节省时间。希望这篇文章能给你建立自己的终端仪表盘的动力。
本文中显示的完整的~/.config/wtf/config.yml
文件可以在这里找到。
https://github.com/khuyentran1401/Data-science/blob/master/terminal/wtf/config.yml
我喜欢写一些基本的数据科学概念,并尝试不同的算法和数据科学工具。你可以在 LinkedIn 和 Twitter 上联系我。
如果你想查看我写的所有文章的代码,请点击这里。在 Medium 上关注我,了解我的最新数据科学文章,例如:
创建一个仪表板来跟踪任何与 Plotly 和 Dash
原文:https://towardsdatascience.com/create-a-dashboard-to-track-anything-with-plotly-and-dash-f9a5234d548b?source=collection_archive---------1-----------------------
或者“我如何停止使用第三方应用程序来跟踪我的投资”!自己的模板真的很容易上手。
剧透警告:这不是我的实际投资组合!
早期的探索
自从我开始投资我的血汗钱,我就痴迷于拥有某种仪表板或工具,让我能够快速了解事情的进展。
我对 Excel 并不陌生,我曾经有一个交易日志,很快就变得太无聊而无法填写…还有一些工作涉及到标准化来自我当时使用的两个经纪人的交易数据,这没有帮助。
所以在浪费了一些时间尝试定制一些有趣的仪表盘和在线模板后,我得出结论: Python 是我的最佳选择!
请注意:投资组合数据仅仅是一个例子,但是我们将创建的模板可以非常容易地适应其他数据— 我将向您展示如何实现。本文中的任何内容都不应被视为财务建议!
我已经知道我想要看到什么样的指标和图表,所以这帮助我在头脑中已经有了几个目标的情况下开始这个项目。从一开始,我就设想在我的仪表板上至少有两页纸。主页面会给我一个投资组合总价值的视图,而第二个页面会让我浏览每只股票的进出情况。
我能想到十几个这样的应用程序,但通常你必须付费才能使用这些很酷的功能…
那么,为什么不构建您自己的仪表盘并根据您的需求进行定制呢?我将帮助你开始布局和基本功能,我们将看看我们如何能发展它。在跳到仪表板之前,我们需要做一些预处理,但我保证这是值得的!
可以跟着笔记本里面的 资源库 一起看。我还录制了一个教程,在那里我可能会更详细地解释一些部分。
如果你想要一个更高级的仪表盘来分析你的投资组合,我推荐你参加 高级课程 !
如果你是 Python 和 Plotly 的新手,我有自己的 免费 Plotly 速成班 让你快速上手!
准备我们有史以来最好的仪表板
对于这个项目,我决定混合使用 Plotly、Dash 和一些引导主题。有了 Python 的一些基本概念,您应该能够很快理解并构建自己的仪表板!我现在将把重点放在主页上,因为已经做了很多工作。
以下是我们今天的目标:
- 准备交易和股票价格
- 我们全球投资组合价值随时间变化的图表
- 对比我们与 S&P500 的回报
- 多个 KPI,如 7D/15D/30D/YTD 绩效
- 我们投资组合中的顶级股票
- 用 Dash 和 Plotly 创建我们仪表板的第一个版本
为了获得所有这些信息,我们需要我们的交易历史和我们交易的股票的历史价格。
https://medium.com/@fneves/membership
交易—2.0 版
我们首先从我们的代理导出交易历史(希望您也能以 CSV 格式获得它)。然后,我们需要获取该表并计算一些额外的列。大多数情况下,您会看到常见的“日期、股票、买入/卖出、价格、价值”列,我会添加其他列,如股票的累计头寸和累计成本、交易损益等。
这些计算是一个独立项目的一部分,我有一个 python 脚本来完成它。代码有点难解释,但是我已经把它作为我准备的整个项目的课程的一部分。稍后会有更多信息。
尽管如此,我还是在 存储库 中包含了一个改进的事务历史的工作示例。您可以使用它来帮助您计算自己的增强数据集。
因此,从存储库中获取代码,首先确保您拥有所有必需的包并导入它们。
收集价格
第二部分相对简单,我将向您展示如何快速获得任何股票的价格历史。你甚至可以保存价格,以后再用,或者你可以进行一次强迫症的冒险,开始用 1 分钟蜡烛建立你自己的数据库!
这部分我准备用一个在其他文章里看到很多的知名包!它叫 yfinance ,真的很好用,还有熊猫 datareader 。在用下面的日期变量定义了我们分析的开始之后,我们可以创建并运行函数 get_prices ,如下所示。
我建议从一两年前开始,然后尝试从 1920 年开始每天都点蜡烛。你交易历史中的股票越多,提取它们的时间就越长,但通常很快。
完成后,您将获得一个名为 all_data 的变量,它本质上是一个数据框架,包含每个股票及其日线图的多索引。
我们会马上把它变成一本字典,使它更容易与我们的交易历史信息合并。
“团结”和征服
这是我们把头寸规模和股价放在一起的部分。这使我们能够获得全球投资组合价值和其他重要指标。
关于 Python 字典的一个很酷的事情是,你可以创建一个循环来给它们提供几个数据帧,这非常方便,因为你可以稍后只使用 mega_dict['AAPL']调用一个特定的 ticker。下面,我将遍历过滤后的报价器列表中的每一个报价器,并在没有交易的日子里填补空白。
看看那本词典中的任何一个关键词,看看有什么信息。每个列名都以 ticker 开头,所以我们以后可以使用它。
我们还需要包含“mktvalue”的每一列来计算我们投资组合的总价值。出于这个原因,我们还需要一个漂亮的数据框架,其中包含每个股票的所有列。你猜对了——它叫 mega_df !
有价值的专栏
为了获得代表每只股票在任何给定日期的市场价值的每一列,我们使用一个过滤器,然后对每行中的所有值求和。“portf_value”列现在是您的全球投资组合价值。
获取 S&P500 的价格也很简单,我们可以将它与之前的数据框架结合起来。我们已经可以计算一些有用的东西,比如每日百分比变化,以及价值差异。
我在下面添加了一些额外的指标,我计划稍后在我们的仪表板上使用,作为我们指标部分的一部分。
用 Plotly 绘制我们自己的图表
如果你有使用 matplotlib 的经验,Plotly 可能看起来很奇怪。对我来说是,当我开始的时候!但事实是,您可以创建交互式图表,然后将它们与 Dash 这样的框架结合起来,以生成真正强大的仪表板。
Dash 使用 Flask 做后端(在你的电脑上创建一个本地服务器,用 dashboard 本身托管一个“页面”),所以如果你已经了解 Flask,你肯定有优势。对 HTML 如何工作的一些基本理解可能也会派上用场。
但在我看来,这个项目最棒的部分是这个布局可以回收用于不同的项目。当我在做这个的时候,我实际上做了一些调整,以便能够跟踪我的加密组合。如果你感兴趣,请在评论中告诉我!
对于 Seaborn 的粉丝来说,Plotly 乍一看可能显得过于简单和局限。不要让他们网站上的 3 行示例欺骗了你…有很多你可以定制的。为了供您参考,我将留下一些我经常使用的设置,您应该有一个很好的起点来尝试这些设置。
投资组合价值
我喜欢让代码保持整洁,所以我将创建一个新的数据框架,我们可以参考这个特定的图表。我还将定义一个开始日期,以使图表更加清晰。
不要害怕评论和编辑这些参数。您可以简单地按照逻辑顺序分解更新。我留下了几行,在那里我改变了布局边距,或者布局高度,以及其他。
解决这个问题的一个好方法是记住每个图表都是以一个图形对象开始的。一旦你声明了那个变量,你就向它添加了元素,比如图表。您还可以添加新的行来添加更多的内容,包括对其格式的更改。完成定制后,运行“show()”方法来显示图表。
现在看起来有点“赤裸裸”,但我更喜欢以后将标题作为 HTML 元素添加进去。当我们开始冲刺时,我会告诉你怎么做。随意取消示例中标题更新的注释(第 30 行),看看它是如何显示的。使用这段代码,我们刚刚创建了第一个仪表板图表。检查如何交互式地选择图表的特定部分!
我希望代码中的注释容易理解,但是如果你迷路了,或者想尝试更高级的东西,一定要去他们的网站。他们有大量的例子供你探索!
对比我们与 S&P500 的增长
对于我们的第二个图表,我们将比较我们的月收益和 S & P500 收益。我打算在这里使用日线时间框架,但是如果你有超过几个月的交易,柱线会变得很小。因此,我不得不为这个图表设计一个新的列,并进行一些操作来为我们的下一个 Plotly 图表获得正确的格式。
一旦我们得到了新的数据框架,就很容易创建一个条形图。如果你花一些时间浏览代码,请注意我们正在做和以前一样的事情。首先,我们声明一个 Figure 对象变量。
然后我们给它添加两条迹线,这将是我们图表中的系列。然后,我们用一些额外的线条使图表看起来更好。不要忘记使用“barmode”作为组(第 27 行)。
在 X 轴上使用“时间周期”变量
KPI 卡
这部分将给你的仪表板一个非常漂亮的触感。我希望能够看到我的投资组合相对于标准普尔的表现。我将在下一个数字中添加四个元素。这些被称为指示器,如果你喜欢仪表和速度计,文档中也有一些。
请注意,底部的数字是“百分点”
这四个要素将包含我们投资组合在 7、15、30 和 200 天内的表现。
另外,我将为每个元素添加一个 delta 参数,参考标准普尔指数相同的时间框架表现。
如果您使用“数字+增量”模式,我们的指示器将显示我们的性能,并与我们的参考进行比较。
出于本文的目的,我将添加与 S&P 性能相同的四个元素,但是这里没有增量。这两列稍后将并排显示在我们的仪表板上!
我们投资组合中的顶级股票
这篇文章已经有点长了,但是我觉得我还需要给你看一样东西!根据你持有的股票数量,你可能想看看你持有的最多的股票是什么。这是我们主页的另一个很酷的功能,但是我们必须获得当前价格才能计算我们的当前头寸。
出于多样性的考虑,我将分享一种不同的获取股票信息的方法——这次是“常规市场价格”。这是一个简单的循环,使用了 yfinance 包,但这不是最有效的方法,因为它在返回我们需要的信息之前,为每个股票获取了大量信息。
尽管如此,请随意使用它进行试验,并获取更多的信息,如部门和行业信息,我将在下一篇文章中介绍。
如果你想让这个仪表板更上一层楼,我准备的课程可能会让你感兴趣。在此查看更多详情!
快速提示:如果你和我一样,只是不能忍受饼图,我决定给这个一个转折,把它变成一个甜甜圈。你可以用参数“孔”来达到这个效果。不客气!
用破折号组合所有元素
快到了!
现在,我们已经拥有了仪表板第一部分所需的所有图表,并准备将它们放入 Dash 应用程序中。
如果你是 Dash 的新手,就把它想象成一个在你的电脑上运行的服务器,它在那个服务器上托管一个网页,上面有你发送到那里的信息。您可以通过您最喜欢的浏览器访问它,运行方法""时它会提供链接。run_server() ”。
使该页面看起来像仪表板的最简单的方法是使用 Bootstrap 模板(带有许多样式选项的预建模板),并将 Plotly 图表添加到 Dash 应用程序中。您将能够像编写网页一样编写代码,向其中添加组件,采用块结构—就像 HTML 一样。
我在 视频 中回顾了一些技术方面的内容,但你需要记住的主要事情是,我们仪表盘上的所有组件都在一个容器内。
这个容器可以有行和列。每行和每列都可以包含多个组件(HTML、Dash 核心组件(dcc)、Dash 引导组件(dbc))。最后,一个组件可以是一个简单的文本段落,或者一个标题,一个图表(像 plotly 图表),一个下拉菜单,以及许多其他东西。
这将是我们的网格。绿色的三个主要行,以及第 2 行和第 3 行的一些列
Dash 甚至允许您使用回调函数,这将使仪表板对用户输入做出响应,如选择日期、切换、下拉菜单中的项目以及许多其他事情。这些特性将在下一篇文章中添加,因此用户可以更改日期,例如选择特定的股票进行分析。
再看一下我们正在创建的网格,然后看看下面的代码。你应该很容易找到这三行(第 5 行、第 7 行和第 31 行)。
这是告诉您行在列之前的最佳时机。如果你反过来做,你会得到一些错误!
如果这是你的第一个 Dash 教程,我知道这可能是一个令人生畏的代码片段!如果你不能理解每一句话,试着去读每一行甚至。如果你能把它和我放在上面的仪表盘或布局图并排比较,会有所帮助。
如果你喜欢黑暗模式,你可以很快改变主题。在第 1 行,我使用 Bootstrap 的内置 FLATLY 主题。这个网站有一个很酷的方式来查看所有可用的主题。你只需要把名字改成你想尝试的(比如 MINTY,SLATE 等。)—但为此您需要dash _ bootstrap _ components。
下一步是什么?
我们现在有了自己的仪表板,可以快速查看我们的全球投资组合。在下一篇文章中,我们将使这个页面与交互,并且添加一个侧边栏以便能够移动到我们的第二个页面。我提到我还想查看每只股票并获得一些关于其表现的指标,所以我们会处理好的。最后,我希望获得有关行业和部门的信息,以便能够分别绘制图表。
如果你想更多地了解 Dash,并学习如何基于这个项目建立一个仪表板, 留下你的电子邮件 ,我会让你知道我的新课程何时准备好。我正在录制视频和创建代码的痛苦过程中,但这将是一个有很多例子和我自己的预处理功能(如交易数据集的额外列)的完整项目。
我确信在发布之前我需要一些反馈,所以有机会我会请你们中的一些人来回顾一下!
如果一切按计划进行,我会添加如下功能:
- 为交互性添加日期选择器
- 该仪表板的新页面,我们可以在其中选择一只股票
- 关键指标,如 PnL、累计损益、真实值。/不真实。等等
- 烛台价格图表显示交易和我们的平均成本线
- 烛台模式识别和回溯测试——这太棒了!
我希望你喜欢这个教程,甚至可能在你自己的项目中使用这个模板。
如果你对这里的任何部分感到困惑,不要忘记观看视频教程!
感谢您的阅读!一如既往,我欢迎反馈和建设性的批评。如果你想取得联系,可以在这里联系我https://www.linkedin.com/in/fabioneves/推文或者回复下面的文章。**
创建快速自动记录、可维护且易于使用的 Python API——CRUD 路由和路由管理
原文:https://towardsdatascience.com/create-a-fast-auto-documented-maintainable-and-easy-to-use-python-api-crud-routes-and-routing-7e8f35ebda46?source=collection_archive---------28-----------------------
学习如何捕捉请求并获取它们所携带的信息
我们的 API 监听传入的请求(图片由唐纳德·詹纳蒂在 Unsplash 上提供)
在 上一篇文章 中,我们已经用 5 行代码建立了一个 API。我们已经安装了依赖项,并创建了一个工作 API,只有一个简单的路径。在本文中,我们将进一步构建,用多种不同的途径充实 API,向您展示使用 FastAPI 可以做的所有事情。然后,我们将关注如何以简洁明了的方式组织所有这些路线
安装
为了让这篇文章尽可能容易理解,我们将假设我们正在为我们的博客网站编写一个 API。目标是创建一些我们可以 CRUD(创建、读取、更新、删除)的公共路径:
- 添加新文章
- 从数据库中检索文章
- 更新文章以修复打字错误,例如
- 删除一篇文章
我们将专注于捕捉请求和提取信息。我们的 API 如何与我们的数据库通信是另一个主题,在本文的https://mikehuls.medium.com/dramatically-improve-your-database-inserts-with-a-simple-upgrade-6dfa672f1424中有很好的描述。也可以查看本文 中的 来创建一个版本控制的数据库结构。
由于我们的 API 将负责捕捉请求并获取它们携带的信息,所以让我们首先快速检查一下请求是如何工作的,以便我们可以准确地为我们的 API 创建端点来捕捉所有信息。
要求近距离拍摄(图片由 Jassine Khalfalli 在 Unsplash 上拍摄)
请求
让我们稍微简化一下,假设一个请求由一个URL
、一个HTTP method
和一个可选的body
组成。在我们的 API 中实现它们之前,我们将快速浏览每一个。
剖析 URL
我假设你对网址很熟悉,因为你在使用互联网时必须把它们输入浏览器。为了我们的 API,让我们把下面的 URL 分成与我们相关的 3 个部分。
https://www.github.com/mike-huls?tab=overview&郎=恩
- https://www.github.com
这部分指定网站托管的服务器的位置。 - /mike-huls
路径路径。这指定了我们想要在网站上访问的资源(文件)的确切位置。把它想象成你计算机上的一个文件系统;就像c:/users/mike/mystuff
一样。 - ?tab=overview&lang=en
问号是查询字符串分隔符。它将到特定资源的路由与将被传递给资源的查询参数分开。参数成对传递,用“&”分隔。
总之:我们向[https://www.github.com](https://www.github.com/mike-huls?tab=overview)
发送一个请求,在/mike-huls
的服务器上搜索我们的资源,然后给资源传递一些查询参数,即tab=overview
和lang=en
。我们将在以后创建路线时使用这些术语。
HTTP 方法
方法(也称为“动词”)用于在发送请求时区分不同的(HTTP)操作。虽然还有很多,但对于本文,我们将使用主要的 4:
- 获取—用于检索数据
- 发布-用于提交数据
- 上传—用于更新数据
- 删除—用于删除数据
我愿意把这些方法看作是区分你的目标的额外数据。
请求正文
主体是我们想要发送的实际数据。在我们的例子中,我们可以发布一篇新文章,这样我们的 API 就可以将它插入到数据库中。
在我们的 API 中路由不同类型的请求(图片由 Javier Allegue Barros 在 Unsplash 上提供)
创建我们的 API
记住,请求由一个 URL 和一个方法组成。为了捕捉这些,我们需要为不同类型的请求创建特定的路由。在路线中,我们需要指定(至少)两件事:
- 路径(捕捉 URL 的路径
- 一个方法(捕捉请求的 HTTP 方法)
让我们来看看创建、读取、更新和删除文章(CRUD)所需的所有操作。我们将从最简单的开始:检索文章。
简单阅读:检索所有文章的路径
最简单的途径是检索所有文章。看起来是这样的:
@app.get("/all_articles")
def get_all_articles():
return function_that_retrieves_all_articles()
两件事很重要。首先注意我们使用了 GET 方法(用@app.get
表示)。第二个是我们指定路径的地方:GET 方法中的articles
部分。这定义了到此路由的路径。对这个路由的 get 请求可能类似于:[www.ourbloggingwebsite.com/all_articles](http://mikehuls.medium.com/)
,它将从数据库中检索我们所有的文章。
使用查询参数读取:检索一篇文章的路线
检索所有文章对于获得我们所有文章的概览来说是非常好的,但是如果用户只想阅读一篇文章呢?让我们创建另一个只检索一篇文章的路径:
@app.get("/article")
def get_one_article(articleId:int):
return function_that_retrieves_article(articleId=articleId)
请注意,这条路线看起来与前一条非常相似。它仍然使用 get 方法,但是路径略有不同:函数现在需要一个参数;我们必须提供一个文章 Id。这称为查询参数。对该路由的 GET 请求如下所示:[www.ourbloggingwebsite.com/article?articleId=1](https://mike-huls.github.io/)
。这将只返回一篇文章,即 articleId =1 的文章。
我们可以在这条路线上增加一点这样的东西
@app.get("/article")
@app.get("/article/{articleId}")
def get_one_article(articleId:int):
return dbConnection.get_one_article(articleId=articleId)
请注意,我们在这里添加了第二行;它允许用户使用查询参数如/article?articleId=1
和路径如/article/1
检索文章。我们可以使用两条线或只用一条线。
删除:删除文章的途径
delete 语句的工作方式与带有查询参数的 GET 完全相同,它使用查询参数进行筛选。
@app.delete("/article")
def delete_one_article(articleId:int):
return dbConnection.delete_one_article(articleId=articleId)
如您所见,它与前面的方法非常相似,唯一的例外是我们在第一行中使用了 DELETE 方法。
创建:发布新文章的途径
让我们来看看现有的东西。插入新文章。路线看起来像这样:
@app.post("/article")
def post_article(body:dict):
return dbConnection.post_article(articleJson=body)
再次注意,我们使用的是发送到/article 路径的帖子。FastAPI 从请求中获取主体数据,并将其传递给负责将其插入数据库的函数。
更新:更新现有文章的途径
更新将来自 GET 的查询参数和来自 POST 请求的主体的查询参数组合在一起:
@app.put("/article")
@app.put("/article/{articleId}")
def update_article(articleId:int, body:dict):
return dbConnection.update_article(articleId=articleId, articleJson=body)
注意,它接收一个 articleId 和一个 body。我们可以用这些来替换数据库中的记录;我们使用 articleId 查找它,然后用 articleJson 中的数据替换它。轻松点。
组织路线
我们刚刚创建的所有路线都是为了一件事:修改文章。如果我们也有故事呢?有了所有这些途径,你可以想象你的项目会很快变得混乱。谢天谢地,组织这些路线很容易。
我们的路线整洁有序(图片由 Martin Lostak 在 Unsplash 上拍摄)
我们将创建一个名为article_routes.py
的文件,并添加以下代码:
from fastapi import APIRouter
router_articles = APIRouter()
添加完这段代码后,我们可以使用路由器来捕捉请求。我们只需将前一章中编写的所有代码片段粘贴到article_routes.py
中。
@router_articles.get("/article")
def get_one_article(articleId:int):
return function_that_retrieves_article(articleId=articleId)
那些对细节有敏锐眼光的人注意到了一件事:在前一部分,我们用@app.get(....)
修饰了函数。在上面的例子中,我们必须使用@router_articles
,因为这是我们的新路由器。点击 查看此文件 的最终版本。
最后一步是转到我们的main.py
文件,告诉它将某些请求重定向到我们的新文件。我们将所有与文章有关的请求重定向到我们的文章路由器,方法是导入它并告诉 FastAPI 重定向某些请求。我们的 main.py 文件现在简洁明了:
from fastapi import FastAPI
from routes.article_routes import router_articles
app = FastAPI()
app.include_router(router=router_articles, prefix='/articles')
当我们开始处理故事时,我们可以轻松地包括一个新的路由器,并在其中编写我们所需的所有代码!轻松又有条理。
结论/TL;速度三角形定位法(dead reckoning)
在这里 查看最终 api 的回购。
本文主要关注什么是请求,以及我们如何在路由中从这些请求中获取不同类型的信息。有了这些知识,你就可以创建一个非常好的 API 了。在下一篇文章中,我们将关注于为我们的路线定义模型。有了这些,我们就可以在将数据传递给数据库之前对其进行清理和检查。此外,我们将重点关注安全性;例如,只有经过认证的访问,或者您必须提供密码。订阅敬请关注!****
如果你有建议/澄清,请评论,以便我可以改进这篇文章。同时,查看我的其他关于各种编程相关主题的文章。
编码快乐!
—迈克
页(page 的缩写)学生:比如我正在做的事情?跟我来!
用 FastAPI(第 1 部分)用 5 行代码创建一个快速自动记录、可维护且易于使用的 Python API
原文:https://towardsdatascience.com/create-a-fast-auto-documented-maintainable-and-easy-to-use-python-api-in-5-lines-of-code-with-4e574c00f70e?source=collection_archive---------11-----------------------
非常适合只需要一个完整、有效、快速和安全的 API 的(没有经验的)开发人员
构建和使用我们的 API 就像使用这台自动售货机一样简单(图片由詹娜·哈姆拉在像素上拍摄)
你有一个很棒的 python 程序,你想把它公之于众。使用 FastAPI,您可以快速创建一个超快速的 API,让其他用户可以使用您的 Python 代码。
在这篇文章中,我们将用 5 行代码创建一个 API。什么?五行?!没错;FastAPI 不叫 FastAPI,因为它比 Django 或 Flask 之类的框架快很多倍;设置起来也超级简单快捷。
在我们创建了我们的初始 API 之后,我们将在下一部分扩展它,展示创建一个全功能、超快、生产就绪的 API 所需的所有必要知识。我们来编码吧!
FastAPI 简介
让我们先快速浏览一下我们的框架。FastAPI 是一个现代的、开源的、快速的、高性能的 Python web 框架,用于构建 Web APIs。在 uvicon 下运行的应用程序被列为最快的 Python 框架之一,仅次于 Starlette 和 uvicon 本身(由 FastAPI 内部使用)。听起来不错吧?让我们不再浪费时间,看看如何使用它。
装置
安装非常简单。我们将首先用 PIP 安装 FastAPI。然后我们还需要安装 Uvicorn。这是运行 FastAPI 的 web 服务器。
pip install fastapi uvicorn
建议在虚拟环境中安装 Python 依赖项。这样你就可以让你的项目不再混乱。查看本文 了解如何使用虚拟环境的简单说明。
创建我们的 API
所有必要的工具都已安装,让我们在根处创建一个 API,在 的五个 行中。我们将创建一个名为main.py
的文件:这个文件将是我们应用程序的主要入口点,并将定义我们的 API。插入下面的代码:
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def simple_route():
return {"Hello": "There"}
看到这有多简单了吗?我们正在导入fastapi
,创建一个新的实例,我们将把它存储在app
变量中。这是我们已经定义的 API!在最后三行中,我们定义了一条路线。API 已创建!
我们的 API 已经设置好,可以运行了。3, 2, 1..开始!(图片由 Andrea Piacquadio 在像素上拍摄)
启动我们的 API
是时候启动我们的 API 了。打开终端,导航到上一步中的main.py
文件所在的文件夹(如果您没有使用终端的经验,请查看本文https://mikehuls.medium.com/terminals-consoles-command-line-for-absolute-beginners-de7853c7f5e8)。执行以下命令:
uvicorn main:app --reload
这将调用 Uvicorn 并告诉它运行位于main.py
文件中的app
(上一步中定义的变量)。如果我们为了加速开发而保存更改,那么--reload
标志会重新加载;我们不必为了看到变化而手动停止和启动 API。
如果您使用虚拟环境,请确保首先激活它。另一种称呼乌维科恩的方式是python -m uvicorn main:app --reload
。这完全一样,只是你可以指定一个特定的 python.exe,例如:
c:/mike/myProj/venv/scripts/python.exe -m uvicorn main:app --reload
测试我们的路线
如果一切正常,您将看到“应用程序启动完成”。如果你没有另外指定,那么 uvicorn 运行在你的本地主机上,端口 8000。于是打开浏览器,对着localhost:8000
。您应该看到以下内容:
API 上/ route 的返回值(图片由作者提供)
自动文档
关于使用 FastAPI,我最喜欢的一个特性是,它会自动生成如何使用该 API 的说明和概述;有哪些路线,如何调用的例子,你甚至可以测试路线,看看返回值!在localhost:8000/docs
或localhost:8000/redoc
检查一下。这些是相同文档的不同样式。
那是一场又短又快的比赛!(图片由在像素上运行 4 个 FFWP
结论
在大约 5 分钟的时间里,我们已经完成了一个简单的 API,在根上只有一条路由。但是还没有太多的互动性。我们想连接我们的 API,这样它应该能够接收和发送一些消息!
在 的下一部分 中,我们将了解如何接收查询参数和主体。此外,我们将在 API 中创建更多的路由,并以智能的方式组织这些路由。稍后,我们将关注使用 Docker 的数据验证、安全性和部署。
如果你有建议/澄清,请评论,以便我可以改进这篇文章。同时,看看我的关于各种编程相关话题的其他文章。
编码快乐!
—迈克
页(page 的缩写)学生:比如我正在做的事情?跟我来!
用 Python 中的 Flask 创建一个成熟、专业的 API 第 1 部分
原文:https://towardsdatascience.com/create-a-fully-fledged-professional-api-with-flask-in-python-part-1-1c94f732e584?source=collection_archive---------20-----------------------
专业且安全地允许访问您的 Python 程序-通过 6 个简单的步骤设置基础
我们的 API 正在愉快地连接我们的服务(图片由 Steven Johnson 在 Pexels 上提供)
没有 API 的应用程序就像没有服务员的餐馆。在餐馆里,你不需要和厨房沟通,也不需要等着点菜来享用美食。同样的,一个网站不需要知道如何与你的数据库通信。像一个服务员一样,我们的 API 从我们的网站收到一个命令:“我想要一些带有元数据的用户统计数据”。API 随后检查订单(是否允许您拥有该数据?),说服我们的数据库(厨师)为他烹制一些美味的信息,等待数据库完成,最后将数据返回到网站。
为什么需要 API 呢?
API 允许两个(或更多)服务以一种分离的方式相互通信。最常见的例子是处理网站和数据库之间通信的 API。它提供访问、便利、安全和额外的功能。让我们来看一下每个要点的简短示例。
1.接近
假设您创建了一个名为 pixelcounter.py 的 Python 程序,它读取一个图像文件并计算像素数。当你把你的图像文件放在 USB 上的时候,走到装有 pixelcounter.py 的电脑前,把图像放在电脑上,然后把它加载到 pixelcounter.py 中,最后开始计数。
这行得通,唯一的问题是:我们是程序员。我们没有时间把东西放到 u 盘上,更不用说走到咖啡机以外的地方了!一个好的解决方案是将 API 和 pixelcounter.py 放在服务器上。这样,人们可以发送图像进行统计..轻松点。
2.便利
API 也提供了很多便利。为了发送电子邮件,只需将收件人、主题和消息发送到 API。如果您可以将数据发送给 API,那么您不需要理解和 SMTP 是如何工作的。
3.额外功能
使用 API 还可以提供额外的功能。例如,您可以计算哪个用户请求了哪些数据。这样你可以限制使用,检查人们最感兴趣的功能,哪些功能根本不会被使用,或者按请求向用户收费。
4.安全性
API 允许两个程序以安全的方式相互通信。像脸书这样的网站要检索你的朋友,需要从数据库中获取数据。你不希望另一个人得到你的个人资料。这就是 API 的用武之地;它检查是谁发出的请求,以及这个人是否被允许获取数据。
如何创建一个 API?
在这篇文章中,我们将开始创建一个 API,它将允许我们做上面描述的所有事情。在这一部分中,我们将着重于设置我们的项目,获得一些基本的功能和测试我们的路线。如果您看到任何您不熟悉的术语,请查看本页底部的词汇表。
让我们连接我们的服务!(图片由像素上的像素生成)
按照这些步骤创建一个包含所有必需依赖项的项目,然后我们将创建一个控制器来处理路由上的请求。
第一步。创建您的 python 项目
创建您的根文件夹:将包含项目的文件夹。在这个例子中,我们将使用c:/my_root_folder
步骤 1.1(可选)创建虚拟环境
创建虚拟环境可以帮助您将已安装的软件包保持在一个整洁的包中。本文 中 关于理解和创建 venvs 的更多信息。以下是本项目的操作方法:
导航到您的根文件夹并执行这段代码。
python -m venv c:/my_root_folder/venv
这将创建一个文件夹来存放你所有已安装的软件包。不要忘记:
- 通过导航到
c:/my_root_folder/venv/scripts
并执行activate
,在安装包之前激活您的环境。现在您处于您的环境中,可以在这里安装软件包了 - 通过调用
c:/my_root_folder/venv/Scripts/python.exe
来执行你的脚本。我们稍后会更深入地讨论它
第二步。安装依赖项
我们需要两个包,所以我们需要安装 Flask 和 flask-restful。pip install Flask flask-restful
第三步。构建您的项目
下一步:创建一些文件夹,我们可以把我们的 te API 的不同部分,即我们的配置,路线和控制器:
mkdir config routes controllers
第四步。创建 API
我们的项目已经建立,是时候构建我们的 API 了!在我们的根文件夹中创建一个名为 main.py 的文件,并赋予它以下内容
from flask import Flask
from flask_restful import Apiapp = Flask(__name__)
api = Api(app)if __name__ == "__main__":
# start up api
app.run(port=5000, debug=True)
这里发生了什么事?:
这个脚本导入所有需要的包,并实例化一个 app 和 api。然后,它在本地主机端口 5000 上运行应用程序。执行您的脚本:
`c:/my_root_folder/venv/Scripts/python.exe c:/my_root_folder/main.py``
您会注意到您的脚本正在运行,但没有停止。我们创建的服务器持续监听请求。让我们给它点东西听。
第五步。创建路线和控制器
我们希望转到 localhost:5000/test,并让 API 在我们导航到该页面或向该位置发布内容时执行一些操作。为了做到这一点,我们需要我们的 API 来监听一个路由,即 /test 。
from flask import Flask
from flask_restful import Api
from controllers.testController import TestControllerapp = Flask(__name__)
api = Api(app)
api.add_resource(TestController, '/test')if __name__ == "__main__":
# start up api
app.run(port=5000, debug=True)
上面的代码与第一段代码几乎相同。如你所见,听路线很容易。这发生在第 7 行:api.add_resource(TestController, ‘/test’)
它在 /test 监听请求,并将请求传递给我们的 TestController,这是我们在第 3 行导入的一个类。让我们创建这个控制器。用这个内容创建c:/my_root_folder/controllers/testController.py
:
from flask_restful import Resource, requestclass TestController(Resource):
def get(self):
return {
"message": "get: hello from the testcontroller"
}
从 API 请求数据有多种方式。您可以发送 GET 请求或 POST 请求。GET 用于检索数据,比如检索我的个人资料图片。POST 请求用于提交数据,如提交评论。还有更多的类型,我们将在下一部分讨论。首先让我们测试一个简单的 API。
上面的 TestController 实现了一个 get 方法,该方法处理传递给控制器的 get 请求。现在我们只返回一条简单的消息。
第六步。测试
打开浏览器并导航到 localhost:5000/test。如果一切顺利,您将看到我们在控制器中定义的消息。
假设这个服务员是我们的 API,为我们提供一些数据(图片由pix abayonPexels提供)
结论
祝贺你创建了你的第一个 API!我们的新 API 已经启动并运行,但是它很笨。在下一部分中,我们将实现更多的功能,比如不同类型的请求、使用 JSON web 令牌的安全性以及到数据库的连接。关注我敬请关注!
—迈克
词汇表
一些术语,解释
- API =应用编程接口。允许您连接两个程序
- 发送给 API 的命令。你在请求它做些什么
- 响应=API 返回的东西;数据、错误或状态
- 某网站上的一条路径。是【www.medium.com】/@ Mike huls****或test.com/this/is/a/path中的加粗部分
- 状态代码= 代表 api 状态的代码。大家都听说过 404:没找到!
使用 Python 在 Neo4j 中创建图形数据库
原文:https://towardsdatascience.com/create-a-graph-database-in-neo4j-using-python-4172d40f89c4?source=collection_archive---------0-----------------------
实践教程
从数据清理到图形填充
马丁·格兰让,CC BY-SA 4.0 ,通过维基共享
数据科学家第一次使用 Neo4j 研究图形时,最常问我的一个问题是如何将数据放入数据库。在之前的一篇文章中,我展示了如何使用通过 Docker 设置的 Neo4j 浏览器 UI 以几种不同的方式之一来实现这一点。在这篇文章中,我将展示如何使用 Python 生成的数据来填充数据库。我还将通过 Neo4j 沙箱向您展示如何使用不同的 Neo4j 数据库设置。
有这篇文章代码的 Google Colab 笔记本可以在这里找到。(笔记本上有如何将 Colab 连接到 Kaggle 以便更快下载数据的说明。)
必要的工具
- Neo4j Python 驱动(撰写本文时版本为 4.2)
- Jupyter 笔记本/实验室或 Google Colab 笔记本(可选)
- 熊猫
用 Python 清理数据
照片由奥利弗·黑尔在 Unsplash 拍摄
现在我们实际上可以开始用 Python 做一些数据管理了。为了这篇文章,我们将使用 Kaggle 上的 arXiv 数据集,它包含了超过 170 万篇学术 STEM 论文。(写这篇帖子的时候,是在 18 版。)您应该继续将数据下载到您本地机器上。
现在转到您的笔记本,我们可以开始考虑我们的数据。我已经通过以下方式加载了数据:
(你不必使用tqdm
,但我发现知道文件大小超过 1.79M 条目对检查我的进度很有帮助。)
您可以通过df.dtypes
看到我们的数据结构如下:
id object
submitter object
authors object
title object
comments object
journal-ref object
doi object
report-no object
categories object
license object
abstract object
versions object
update_date object
authors_parsed object
假设我们想用这个数据框架构建一个图表,我们想知道哪些作者发表了哪些论文,这些论文属于什么类别。然后,我们希望有三种不同的节点类型与之对应:作者、论文和类别。每个节点类型都有一两个属性。对于作者来说,我们知道他们的名字是有意义的。报纸可以有他们的 ID 和他们的标题。最后,类别拥有自己的名称也是有意义的。我们也有一些关系:作者作者论文和论文在某些类别中。
因此,我们的目标是拥有以下数据模型(用 arrows.app 绘制):
数据模型。(图片由作者提供。)
有几个专栏会对我们有用。例如,我计划保留id
,这样我们就可以用它作为每篇论文的唯一索引。之后,我想得到每个作者的个性化列表。此外,authors_parsed
列给了我们一个更清晰的所有作者的列表。我们肯定会将title
专栏作为报纸的主要属性。最后,我想保留categories
列。
下一步是稍微清理一下我们的数据,这样数据帧的每一行都有一个作者,每一行都有一个类别。例如,我们看到authors_parsed
列给出了一个列表,其中每个条目的名称后面都有一个多余的逗号。如果我们简单地将它导入到数据库中,我们将得到这样的作者节点(如一个小示例所示):
╒════════════════════════════════════╕
│"n" │
╞════════════════════════════════════╡
│{"name":["Balázs","C.",""]} │
├────────────────────────────────────┤
│{"name":["Berger","E. L.",""]} │
├────────────────────────────────────┤
│{"name":["Nadolsky","P. M.",""]} │
├────────────────────────────────────┤
│{"name":["Yuan","C. -P.",""]} │
├────────────────────────────────────┤
│{"name":["Streinu","Ileana",""]} │
└────────────────────────────────────┘
由于这不是一件令人愉快的事情(并且将导致不是最优雅的查询),我们需要稍微清理一下。我们还看到categories
列可以有一个类别,也可以有几个不是传统列表格式的类别(如本示例的最后一行所示):
╒═══════════════════════════════════╕
│"c" │
╞═══════════════════════════════════╡
│{"category":"hep-ph"} │
├───────────────────────────────────┤
│{"category":"math.CO cs.CG"} │
├───────────────────────────────────┤
│{"category":"physics.gen-ph"} │
├───────────────────────────────────┤
│{"category":"math.CO"} │
├───────────────────────────────────┤
│{"category":"math.CA math.FA"} │
└───────────────────────────────────┘
我们可以在 Cypher 中这样做,但是为了这篇文章的缘故,我们将在 Python 中进行清理,以便希望说明我们可以使用 Python 做我们想做的或多或少的事情。
让我们创建几个助手函数来清理这两列:
我们得到的数据帧现在看起来像这样:
已清理的数据帧。(图片由作者提供。)
现在我们有可以利用的东西了!
创建 Neo4j 沙盒
由马库斯·斯皮斯克在 Unsplash 上拍摄的照片
Neo4j 沙盒是一个很好的、免费的修补 Neo4j 的方式。您可以启动一个将持续 3 天的实例并开始工作!
出于本文的目的,当您进入沙箱时,您将创建一个基本的空白沙箱,如下所示:
创建空白沙盒。(图片由作者提供。)
正如您在创建窗口中看到的,还有许多其他有用的沙箱,但我们将选择此选项,因为我们将使用自己的数据填充数据库。坐几分钟,让它自己创造。一旦发生这种情况,您将获得您的连接信息,如下所示:
我们的沙箱的 Web 连接信息。(图片由作者提供。)
这个窗口有一些你需要的东西。首先,您将注意到 Bolt URL,以及它的端口号。您将需要它来通过 Python 建立连接。接下来,你还需要密码(这里是“困难-俯卧撑-缺口”)。这将需要在此实例中进行身份验证。我要指出的是,当这个实例被关闭 3 天后,这些信息就不再有效了,所以不要担心试图抓取我的沙盒和它的数据!
连接到 Neo4j 并填充数据库
现在我们需要在本地机器(或者任何有 Python 代码的地方)和沙盒数据库之间建立连接。这就是那些 BOLT URL 和密码的用武之地。
为此,我创建了一个助手类,它从这篇中篇文章稍微修改了一下:
酷毙了。现在我们可以开始填充数据库了。我们首先在数据库中创建一些约束,以确保节点不是重复的,同时还设置一些索引:
现在,我们创建三个函数来为 category 和 author 节点创建数据帧,我们将使用这三个函数分别将它们填充到数据库中:
这些函数将每一列放入变量$rows
中,这些列是列表格式的。UNWIND
命令获取列表中的每个实体,并将其添加到数据库中。在此之后,我们使用一个辅助函数以批处理模式更新数据库,这在您处理超过 50k 的上传时会很有帮助。
加载这些节点后,我们将添加纸张节点以及与以下函数的所有关系:
因此,以类似于类别和作者节点的方式,我们创建每篇论文,然后通过数据帧的每一行的:AUTHORED
或:IN_CATEGORY
关系将其连接起来(根据需要使用UNWIND
列表)。请注意,在这个函数中有更多的数据通过管道传输,因此减小批处理大小可能有助于防止超时错误。
此外,对于这一步,我们可能会尝试在完整的数据帧上使用类似explode.()
的方法,为每个列表的每个元素获取一行,并以这种方式将整个数据帧处理到数据库中。这是可行的,这正是我们将在下面对少量数据做的事情,如在categories
和authors
数据帧中的已删除重复的类别和作者节点列表。然而,对于较大的数据集,将数据加载到 Neo4j 中并不是一种非常有效的方式。因为 Neo4j 是一个事务数据库,我们将创建一个事务数据库,并在数据帧的每一行执行一条语句,这将导致加载过程非常缓慢。它也可能超出可用内存。沙盒实例大约有 500 MB 的堆内存和 500 MB 的页面缓存。因此,这进一步推动了以批处理方式更新数据库。
执行所有这些函数来填充图形,我们得到:
太好了!我们现在有了一个填充的数据库!该图的子样本应该是这样的(通过MATCH (a:Author)-[:AUTHORED]->(p:Paper)-[:IN_CATEGORY]->(c:Category) RETURN a, p, c LIMIT 300
获得):
图表的子示例,在带有 Neo4j Bloom 的沙盒中可视化。蓝色节点是作者,绿色节点是论文,粉色节点是类别。(图片由作者提供。)
让我们确保它里面有我们想要的东西…
查询数据库以获得一些答案
这里有一个提示:当您有一个填充的数据库时,您应该让 Neo4j 处理尽可能多的计算,然后再将答案返回到 Python 中(如果您需要的话)。在这种情况下,假设我们要计算每个类别的入度,并返回前 20 个类别的类别。显然,我们可以用 Python 来做这件简单的事情,但是让我们用 Neo4j 来做吧。在某些时候,您可能想要进行更复杂的计算(比如节点中心性、路径查找或社区检测),这些都可以而且应该在 Neo4j 中完成,然后再将这些结果下载回 Python。
要在 Cypher 中做到这一点,我们可以使用多种方法,但这里有一种快速有效的方法:
这应该会给我们:
按入度排名的前 20 个类别。(图片由作者提供。)
上述数据子集的入度分布如下所示:
图的子样本的入度分布。(图片由作者提供。)
这显示了数据库已经被填充,以及我们如何能够得到结果。值得一提的是,以列表形式返回相同结果的另一种方法是:
摘要
我们已经展示了如何从 Python 连接到 Neo4j 沙箱,并在我们确信数据包含我们想要的内容时上传数据。像编码中的其他事情一样,有许多不同的方法可以做到这一点,我们鼓励感兴趣的用户探索主要用 Cypher 而不是 Python 来做上面的演示。但是通过使用 Neo4j Python 连接器,可以很容易地在 Python 和 Neo4j 数据库之间来回切换,就像对任何其他主要数据库一样。这将开启数据科学和机器学习中各种令人兴奋的可能性,如自动节点分类、链接预测和节点聚类。请继续关注未来关于这些主题的博客帖子!
特别感谢 迈克尔饥饿 和 马克李约瑟 对本帖的协助!
从你的活动跟踪器的日志中创建一个热图
原文:https://towardsdatascience.com/create-a-heatmap-from-the-logs-of-your-activity-tracker-c9fc7ace1657?source=collection_archive---------25-----------------------
如何使用 Python 从应用程序和设备导入数据并从 GPX 文件创建热图。
热图(图片由作者提供)
我的电脑里有 7 年的步行记录。这些年来,从独立的 GPS 接收器,到 SportsTracker,再到 Garmin,这些都是通过几种设备和应用程序收集的。幸运的是,他们都有一个共同点,那就是记录的路线是 GPX 格式的。获取这些文件可能没有那么简单困难。
什么是 GPX?
GPS 交换格式(GPX)是 XML 格式的 GPS 数据格式。它是一种开放的、免许可的格式,描述了路点、轨迹和路线。它被广泛采用,因此是交换位置数据的绝对标准。位置以经度-纬度(十进制度数)对的形式存储,并可选择使用海拔(米)、时间(UTC)和供应商特定信息进行扩展。
GPX 格式的音轨(图片由作者提供)
上面的例子是 Garmin 存储的轨迹,例如 SportsTracker 和 Fitbit 存储的轨迹具有相同的结构,但细节不同。
根元素是 gpx 。它包含一个 元数据 元素和一个 trk 元素。 元数据 指定文件的来源和创建时间。 trk 元素包含存储的音轨。一个轨迹由一个或多个片段组成,每个片段存储在一个 trkseg 元素中。在曲目级别,有些字段包含曲目的名称和类型。该规范允许更多的字段,但这些字段并未被 Garmin 等公司使用。
trkseg 段元素包含一个轨迹点列表( trkpt )。线段是一组连续的点。如果跟踪被中断,例如失去连接或电源故障,应该创建一个新的段。
一个 trkpt 有强制属性 lat 和 lon 来指定位置。有时间( 时间 )和标高( ele )等可选字段。元素 扩展 允许每个设备/应用添加额外的信息,如心率(上面 Garmin 示例中的 hr )、速度或路线(Garmin 不使用)。
使用 SportsTracker 创建的轨迹包括经度/纬度属性以及时间和海拔元素。他们没有像 Garmin 那样的扩展。假设以下数据结构用于解析 GPX 文件:
<gpx>
<metadata>
<name>02-01-20 13:29</name>
</metadata>
<trk>
<trkseg>
<trkpt lat="52.12345" lon="6.31235">
<ele>71.1</ele>
<time>2021-08-02T12:29:18Z</time>
</trkpt>
</trkseg>
</trk>
</gpx>
导入 GPX 文件
为了读取 GPX 文件,有几个 Python 库可用,比如 gpxpy 。但是出于教育目的,提供了一个实现。这个实现利用了 Python 中默认 XML 实现的ElementTree
。要从目录中读取所有 gpx 文件:
这段代码从目录data
中检索所有文件,并解析扩展名为.gpx
的所有文件(来自第 18 行)。从文档中检索根元素(第 19 行),在本例中是<gpx>
元素。所有元素都位于第 6 行定义的名称空间中。
跟踪日志的开始时间存储在元素<metadata>
的子元素<time>
中。然后(第 21 行)选择音轨,在这种情况下使用.find()
方法。这将查找具有指定名称的元素的第一个匹配项。这就足够了,因为我的 GPX 文件中没有一个包含多个音轨,甚至是多个片段。在多轨道的情况下,可以通过迭代.findAll()
的结果来替换.find()
。track 元素包含元素name
和type
,这两个元素包含活动的名称和活动的类型(例如步行)(第 22–23 行)。
从轨道中选择第一个(也是唯一的)片段(第 24 行)。该段包含所有记录的位置,因此通过迭代该段,所有记录的位置都被解析(第 25 行)。点(元素trkpnt
)包含纬度和经度(26–27)两个属性,以及日志条目的时间戳和海拔(第 28–31 行)两个子元素。高程可能不存在,因此我们需要在转换之前检查它的存在(第 31 行)。
所有信息都被添加到一个数组中,该数组在第 33 行被转换成一个数据帧。最后,两个时间字段都被转换为时间戳对象,因此我们最终得到以下数据帧(在本例中有将近一百万个位置):
GPX 所有记录位置的数据框(图片由作者提供)
大部分的活动日志是在我居住的地方,在假期有少量的。过滤我家周围的位置可以得到热图的第一个概念。
df[(df.lat > LAT_MIN) & (df.lat < LAT_MAX) &
(df.lon > LON_MIN) & (df.lon < LON_MAX)]. \
plot.scatter('lon', 'lat', figsize=(10,10), s=0.1)
在(x,y)
坐标系中,经度为x
,纬度为y
。
跟踪的活动(作者图片)
创建热图
最初的图给出了所有活动的一个很好的概述,但是没有提供大多数访问区域的洞察力。为此,我们将创建一个热图。我们会从头开始做这个。
热图将在大小为<size_x, size_y>
的 numpy 数组中创建。所以首先我们要把经纬度转换成这个维度;最小经度到0
,最大经度到size_x
,纬度也一样。
首先,删除经度/纬度范围之外的所有位置。然后为x
和y
创建新的列,并使用线性转换为其分配适当的值。这些值被转换成整数,因为我们将使用它们来寻址 numpy 矩阵中的点。
对于那些感兴趣的人来说,线性回归背后的数学:
线性回归解释(图片由作者提供)
下一步是创建一个用所需大小的零填充的矩阵。每个被跟踪的点将被添加到这个矩阵中。不仅添加了确切的位置,还添加了围绕它的正方形(基于width
)。这对于高分辨率图像特别有用,在这种图像中,宽度为一个像素的线条几乎看不见。
我们可以迭代df2
并逐个添加每个点。但是我们通过首先对(x,y)
进行分组并计算出现的次数来优化它。当相同的位置出现例如 7 次时,它仅被添加一次而不是 7 次。由于宽度的使用,仍然需要加法(第 8 行)而不是赋值。由于宽度的使用,相邻的位置会累加起来。
由于宽度增加的附加效应,使用频率高的路线会变亮。为了防止他们丢弃较少使用的路线,计数被最大化(第 11 行)为数据集中路线的数量。可以添加一个因子来优化最终结果(第 10 行)。
现在我们已经用每个<x,y>
的出现次数填充了数组,我们可以把它转换成一个色标。将这些值标准化后,将应用 matplotlib 色彩映射表。在这种情况下,使用'hot
'色图,因为它在黑色背景下工作良好(从等于黑色的数组中的零开始)。
最后一步是使用 matplotlib 绘制图像:
origin=”lower”
是必需的,因为图像的零点在左下角,但默认是左上角。我们努力的结果:
生成的热图(图片由作者提供)
这是我们自己的热图。可以通过添加高斯模糊来使图片看起来更友好。但是现在,我对结果很满意。
最终世界
我们已经看到从任何来源导入 GPX 文件是多么简单。根据这些数据,我们创建了一个热图来直观显示游览地点。通过给图像添加模糊或者甚至添加一张地图作为背景,改进是可能的(很多工作,但是值得)。
在下一篇文章中,我将向你展示如何计算指标,如行驶距离、速度和方位。
我希望你喜欢这篇文章。要获得更多灵感,请查看我的其他文章:
- 用 Python 删除文本中的个人信息
- Python 中字符串的并排比较
- 用 Python 实现并行 web 请求
- 所有公共交通工具都通向乌得勒支,而不是罗马
- 使用 OTP 和 QGIS 可视化行程时间
免责声明:本文包含的观点和看法仅归作者所有。
用 FastAPI 和 Heroku 创建一个隐私过滤器 Web 服务
原文:https://towardsdatascience.com/create-a-privacy-filter-webservice-with-fastapi-and-heroku-4755ef1ccb25?source=collection_archive---------27-----------------------
如何使您的 PII 删除服务易于使用,增加使用率,从而提高隐私保护。
西蒙·马格 ( Unsplash )摄影
在我的上一篇文章中,我展示了如何构建一个 Python 类来过滤掉自由文本中的个人身份信息。在本文中,我们将使用 FastAPI 构建一个基于该类的 web 服务,并使其可用于 Heroku。
创建 API
用 FastAPI 创建一个 API 很简单,它使你能够为你的代码创建一个 REST API。首先,您需要安装 FastAPI,如果您想在本地运行它,还需要安装uvicon。Uvicorn 是一个轻量级、超快的异步 web 服务器实现。它将用于运行 FastAPI 服务器的本地副本。
现在,我们准备好了!
要运行 FastAPI 服务器,需要一个FastAPI-对象。可以使用方法标记添加该对象的终结点。一个简单的例子:
第 3 行创建了 FastAPI 对象,第 5 行添加了一个端点。端点的名称为“/过滤器”。当被调用时,它返回值“< PRIVATE >”。
要测试端点,需要一个 web 服务器。FastAPI 应用程序可以从命令行或 main 方法启动。使用最后一种方法,其工作方式如下:
PrivacyFilterAPI 是 python 源文件的名称,privacyFilterApp 是指在上一步中创建的 FastAPI 对象。运行 Python 脚本启动一个具有可用端点的 Uvicorn 服务器。Uvicorn 的 reload=True 参数允许在检测到源代码更改时重新加载应用程序。从编辑器中保存源代码足以在 Uvicorn 中重新加载应用程序,无需在代码更改后重启服务器。
在浏览器中打开http://127 . 0 . 0 . 1:8000/filter应该会得到 JSON 响应:
下一步是用文本 tot 过滤器向 API 添加一个参数。输入文本将作为 POST 请求的请求正文发送。使用 POST 是用参数调用 REST 服务的首选方式。参数作为请求体发送。定义请求体一个 Pydantic 模型。
通过从 Pydantic 扩展 BaseModel 来创建参数类。这个类保存一个变量,文本和方法的输入文本。方法签名被更改为 post(第 12 行),并有一个类型为参数的输入参数项。条目是一个 Python 字典,可以进行相应的访问。
最后,通过添加 PrivacyFilter 类,webservice 就完成了:
当 web 服务启动时, PrivacyFilter 类的一个实例被实例化和初始化。这个实例将用于每次调用过滤器方法。 /filter 端点返回包含原始文本和过滤文本的字典。
启动 web 服务后,文档可从 http://127.0.0.1:8000/docs 获得。这些 swagger 页面由 FastAPI 自动生成:
FastAPI 生成的 API 文档(图片由作者提供)
通过点击绿色的/过滤器部分,然后点击“试用”按钮,可以向 API 发送请求。这些参数在请求正文部分指定:
尝试 API(图片由作者提供)
按“执行”发送 post 请求并显示结果:
请求结果(图片由作者提供)
在响应中,原始文本和过滤后的文本都被返回。在这种情况下,我的名字被标记
确保服务安全
通过 HTTP 发送隐私信息不是个好主意,所以我们需要将 REST API 升级到 HTTPS。为此,我们需要一个密钥文件和一个认证文件。我们可以用 openSSL 创建这些文件:
这会产生两个文件,一个包含密钥,另一个包含证书。确保通用名称与 API 将在生产中运行的 URL 相匹配。我们可以通过指定密钥和证书文件在 HTTPS 模式下启动 Uvicorn 服务器:
该服务现在在地址https://127 . 0 . 0 . 1:8000/filter上可用,并且请求由 SSL 保护。
在 Heroku 上运行服务
Heroku 是一个支持 Python(以及其他)的云平台。在虚拟化的 Linux 容器中部署您的应用程序是可能的。你可以一个月免费运行 500 个小时集装箱。30 分钟不活动后,容器进入睡眠状态。如果你的账户里有一个容器,它可以免费运行 67%的时间。
要在 Heroku 上运行 FastAPI 服务,需要两个文件。首先, requirements.txt 文件需要是最新的。该文件指定了所有必需的 python 库。Heroku 使用这个文件创建一个能够运行应用程序的 Python 环境。如果不存在,您可以按如下方式创建该文件:
该命令将捕获所有已安装的模块及其版本,并将这些信息写入 requirements.txt 文件。
Heroku 需要的第二个文件是部署配置文件,名为 Procfile (没有扩展名)。Heroku 使用该文件来确定启动应用程序时要执行的操作。
这个 Procfile 告诉 Heroku 启动一个 web 应用程序并启动 Uvicorn。Uvicorn 启动指定的 API 应用程序。应用程序被指定为类似于本地运行。注意,Heroku 需要主机指定一个端口来连接到 Uvicorn 服务器。
导航到heroku.com并创建一个免费账户。在此帐户中,创建一个应用程序:
Heroku 应用创建(作者截图)
为应用程序取一个易于识别的名称,然后单击“创建应用程序”按钮。不需要将其添加到管道中。
Heroku 将从 Github 获取应用程序,因此下一步是连接 Gihub。单击 connect 按钮,按照在线流程连接到 GitHub OAuth 接口。
将 Heroku 连接到 GitHub(作者截图)
当 Heroku 成功连接到 GitHub 时,可以将 GitHub 存储库连接到 Heroku 应用程序。在搜索字段中键入存储库名称的一部分,然后按“搜索”。从搜索结果中选择适当的存储库。
连接 GitHub 库(作者截图)
当存储库连接成功时,可以在 Heroku 上部署一个分支。向下滚动到“手动部署”,选择正确的分支并点击“部署分支”按钮。
在 Heroku 上部署分支(作者截图)
这将启动构建过程,根据需求文件创建 Python 环境。第一次这将花费一些时间,但是连续的构建将使用缓存的环境(直到需求改变)。
检查应用程序日志(右上角的“更多”按钮)并等待构建成功的消息。该应用程序现已在 https://privacyfilter.herokuapp.com/发布。我们现在可以使用/docs 入口点在本地实例上运行相同的 API 测试。
恭喜你,你有一个隐私过滤器启动并运行!
请注意,Heroku 的免费版本仅限于 500MB 的容器。运行完整的隐私过滤器需要更多的空间,因此需要从 Heroku 订阅爱好。为了能够在免费版本中运行,我从过滤器中删除了街道名称,因为它们占用了大部分空间。
这个项目的所有源代码都可以在 GitHub 上找到: PrivacyFilter 。
我希望你喜欢这篇文章。要获得灵感,请查看我的其他文章:
- 用 Python 删除文本中的个人信息
- 用 Python 实现并行 web 请求
- 所有公共交通工具都通向乌得勒支,而不是罗马
- 使用开放数据和开普勒可视化荷兰火车的拥挤程度
- 使用 OTP 和 QGIS 可视化行程时间
免责声明:本文包含的观点和看法仅归作者所有。
创建量子贝叶斯网络
原文:https://towardsdatascience.com/create-a-quantum-bayesian-network-d26d7c5c4217?source=collection_archive---------29-----------------------
实用指南
本帖是本书的一部分: 用 Python 动手做量子机器学习 。
贝叶斯网络是对不确定领域的知识进行建模的概率模型。例如泰坦尼克号上一名乘客的生还。
贝叶斯网络建立在与朴素贝叶斯分类器相同的直觉上。但是与朴素贝叶斯相比,贝叶斯网络并不局限于只表示独立的特征。它们允许我们包含尽可能多的在当前环境下看起来合理的相互依赖。
贝叶斯网络被表示为具有节点和边的有向无环图。
作者弗兰克·齐克特的图片
这些节点代表随机变量,如乘客的性别或他/她是否是个孩子。
边缘对应于一个变量对另一个变量的直接影响。换句话说,边定义了两个变量之间的关系。箭头的方向也很重要。连接到箭头尾部的节点是父节点。连接到头部的节点是子节点。子节点依赖于父节点。
我们使用离散变量的条件概率表(CPT)和连续变量的条件概率分布(CPD)来量化这种依赖性。
下表描述了给定乘客性别(Sex
)的后验生存概率。
女性乘客比男性乘客有更好的生存机会。
虽然只有两种性别(在我们的数据集中),但有许多不同年龄的乘客。从技术上讲,作为一个离散变量,将年龄建模为一个连续变量似乎更合适。下图描述了给定乘客的Age
后验生存概率的 CPD。
作者弗兰克·齐克特的图片
乍一看,似乎乘客的年龄对生还的机会没有明显的影响。更糟糕的是,在随后的几个年龄段中,存活的几率相差很大。例如,一名 47 岁的乘客有 0.1 的生存机会,而一名 48 岁的乘客有 0.6 的生存机会。
这种变化似乎不合理。
相反,如果我们考虑作为一个孩子的特点(isChild
)而不是一个乘客的Age
。8 岁或以下的儿童比成人有更大的生存机会。
让我们考虑具有三个节点的贝叶斯网络。变量Sex
和 a Child
表示父节点。这些节点本身没有父节点。它们是根节点。他们的 CPT 以一组空的变量为条件。因此,它们等于边际(或先验)概率。注意,这些不是存活的概率,而是各自特征出现的概率。
Survival
泰坦尼克号沉船的子节点。此 CPT 取决于父节点的值,如下图所示。
作者弗兰克·齐克特的图片
给定这样一组 CPT,我们可以计算生存的边际概率。
由于节点Sex
和isChild
之间的独立性(它们的值是独立的,因为我们没有建模任何依赖性,但是它们对Survival
的影响不是独立的),乘客具有某个Sex
和isChild
的联合概率可以计算为 p(sex,ischild)=p(sex)⋅p(ischild).
因此,给定某个Sex
和isChild
的生存条件概率是 p(survival)=p(survival|sex,ischild)⋅p(sex)⋅p(ischild).
首先,贝叶斯网络是一种数据结构。首先,它代表了条件独立性假设的集合。没有通过边连接的任何两个节点都被认为是相互独立的。第二,贝叶斯网络以紧凑和分解的方式包含概率表和分布。
这种数据结构使我们能够推断人口的特性。贝叶斯网络支持正向和反向推理。例如,我们可以通过对子节点的分布进行积分来计算总的生存机会(正向推理)。并且,给定关于乘客生存的知识,我们可以推断出某些特征在多大程度上促成了他或她的生存。例如,如果我们查看子节点的图表,我们可以看到乘客的性别非常重要,除非乘客是孩子。按照妇孺优先的标准,他们并没有重男轻女。Sex
和isChild
之间的这种相互依赖性不能包含在朴素贝叶斯分类器中。
这种数据结构,贝叶斯网络图,可以用两种不同的方法创建。给定依赖关系的足够知识,它可以由开发者预先设计。或者,也可以由机器自己学习。
在我们通往量子机器学习的道路上,我们将双管齐下。我们从一个我们自己建模的小型量子贝叶斯网络(QBN)开始。然后,我们让机器从数据中学习。
电路实现
我们从目前为止我们的例子的实现开始,一个乘客的Sex
和作为一个孩子的isChild
对泰坦尼克号沉船的Survival
的影响。
贝叶斯网络中的每个节点都由一个量子位表示。因为我们所有的节点都是二进制的(Sex
、isChild
、Survival
),每个节点一个量子位就足够了。如果我们有更多的离散态或连续分布,我们将需要更多的量子位。量子位状态代表相应变量的边际(对于根节点)和条件(对于Survival
节点)概率幅度。
|0⟩代表男性乘客或成年人。|1⟩是女性还是儿童。量子位的叠加表示任一状态的概率
我们通过绕 Y 轴旋转来初始化这两个量子位。
我们计算成为孩子(第 21 行)和女性(第 25 行)的概率。我们使用 RY 门让量子位 q0(第 31 行)和 q1(第 34 行)代表这些边际概率。
接下来,我们将Survial
的 CPT 添加到电路中。这是一个多一点的工作。
父节点值有四种不同的组合,Sex
和isChild
。他们是,一个成年男性(|00⟩),一个男孩(|01⟩),一个成年女性(|10⟩)和一个女孩(|11⟩).)因此,我们有四个旋转角度,每个父节点组合一个。
对于这些组合中的每一个,我们使用一个受控的 RYRY-gate (CCRY)来指定Survival
的概率。如果有 n 个父节点,那么我们将实现一个 CnRY-gate。
如下图所示,我们将每个旋转封装到 X-gate 中。对于一个 CCRY-gate 来说,如果两个控制量子位都处于|1⟩状态,则只对控制量子位应用旋转,领先的 x-gate 选择相应的组合,而尾随的 x-gate 反转该选择。
例如,要应用一个成年男性(|00⟩)的条件概率,我们需要翻转两个量子位。这就是我们的工作。在应用具有相应角度的 CCRY-gate 后,我们将量子位翻转回初始状态。
作者弗兰克·齐克特的图片
在 Qiskit,没有 CCRY-gate。但是我们在这篇文章中学习了如何创建一个。函数ccry
(第 1-6 行)为我们的电路增加了这样一个门。
在下面的代码中,我们计算了四种情况下的条件概率。我们分离人群,例如,女性儿童(第 3 行),分离其中的幸存者(第 4 行),用幸存者人数除以乘客中女性儿童总数(第 5 行)计算他们的生存概率。
我们对女性成人(第 8-10 行)、男性儿童(第 13-16 行)和男性成人(第 19-21 行)也是如此。
接下来,我们选择代表这些乘客组的状态,并以相应的概率应用 CCRY-gate。
我们现在准备运行电路。让我们看一看。
作者弗兰克·齐克特的图片
我们可以看到八种不同的状态。这些属于四个组的受害者(量子位 q2=0)和幸存者(q2=1)。因此,幸存的总边际概率是量子位 q2=1 的所有状态的总和。
为了避免手动添加,让我们在电路中加入一个测量值。我们在电路中加入了一个ClassicalRegister
。
然后,我们需要应用所有的门(为简洁起见,跳过)。我们添加一个度量(第 3 行)。这里,我们对量子位 q2q2 感兴趣。
最后,我们选择合适的后端(qasm_simulator
)并运行电路几次(这里是 1000 次)(第 9 行)。
结果显示我们接近 0.38 的实际生存概率。实际结果略有不同,因为我们没有计算,而是根据经验模拟这一结果。
作者弗兰克·齐克特的图片
结论
对于一组二进制状态变量,量子贝叶斯网络的实现是直接的,因为我们可以用单个量子位来表示每个变量。即使我们有两个以上状态的变量,结构也不会改变。我们仍然会通过 X 门激活每个状态,并应用相应的受控旋转。但是,我们将不得不应付更多的州。
本帖是本书的一部分: 动手用 Python 学习量子机器 。
免费获取前三章这里。
创建重复测量的雨云
原文:https://towardsdatascience.com/create-a-repeated-measures-raincloud-96c6c9b33e81?source=collection_archive---------36-----------------------
用 R 可视化组间差异的有效方法
图片由梅格·杰拉德在 Unsplash 拍摄
雨云图
Raincloud 图将抖动的数据点与半小提琴和箱形图结合起来,给出了给定数据集的综合图。在的上一篇文章中,我介绍了使用 python 绘制雨云图。多亏了 Jordy van Langen 和他的同事们的工作,雨云图在 r。
R 中的 jorvlan raincloudplots 包展示了一种创建分组和重复测量数据的简单可视化的方法。此外,它提供了独立链接的重复测量可视化,这为许多主题间/主题内设计添加了细节和丰富性。下面,我们探索创建一个类似蝴蝶外观的 2 x 2 (2 个条件,2 组)重复测量图。
在此阅读有关 jorvlan/raincloudplots 知识库的更多信息:
https://github.com/jorvlan/raincloudplots
关于雨云地块的进一步阅读,请查看原始出版物:
https://wellcomeopenresearch.org/articles/4-63
装置
从 jorvlan 的存储库中安装 raincloudplots 包。
if (!require(remotes)) {
install.packages("remotes")
}
remotes::install_github('jorvlan/raincloudplots')
library(raincloudplots)
输入数据
本教程使用代表两种不同运动类型(内旋、外旋)的两种不同临床测试(进行、断开)的数据集,使我们的数据集成为 2x2 设计。通断测试通常由康复从业者进行,例如物理治疗师或运动训练师。在进行测试期间,患者施加力量对抗医师的手的阻力。在断裂测试期间,医师对患者的前臂施力。两项测试都评估了肩关节的内旋和外旋。力(磅 lbs)由专业人员用手持设备测量。
以下数据集展示了作者创建的示例数据,并不代表真实的患者数据。
df_2x2 <- read.csv(file = 'make_break.csv')
示例数据—由作者创建
- 每个患者的力(磅)列在 y 轴栏中
- 组分配列在 x 轴上
- 参与者分配列在 id 列中
- 一致性列在“组”列中
- jit 列中列出了抖动值
创造情节
绘制重复测量雨云。
raincloud_2x2 <- raincloud_2x2_repmes(
data = df_2x2,
colors = (c('dodgerblue', 'azure4', 'dodgerblue', 'azure4')),
fills = (c('dodgerblue', 'azure4', 'dodgerblue', 'azure4')),
size = 1,
alpha = .6,
spread_x_ticks = FALSE) +scale_x_continuous(breaks=c(1,2), labels=c("Make", "Break"), limits=c(0, 3)) +
ylab("Pounds of Force (lbs)") +
theme_classic()raincloud_2x2
蝴蝶般的雨云情节——作者创作
data_2x2
创建 2 x 2 重复测量雨云所需的长格式数据帧color
dodgerblue 和 azure4 区分群——内旋(IR)和外旋(ER)labels
连接两个组标签的字符串——接通和断开spread_x_ticks
2 个 x 轴刻度为假-同时显示两组
结论
本文概述了如何使用 jorvlan/raincloudplots 存储库来创建链接的重复测量可视化。如果你有兴趣了解更多用 R 创建 raincloud plots 的方法,请查看 JOR VLAN/rain cloud plotsgithub页面(也在上面列出)。
感谢您的阅读!
作者的相关文章—
使用 Neo4j 从节点属性创建相似性图
原文:https://towardsdatascience.com/create-a-similarity-graph-from-node-properties-with-neo4j-2d26bb9d829e?source=collection_archive---------12-----------------------
本文的原始版本和附带的视频使用的 Neo4j 沙盒版本已经过时。我已经更新了代码,以使用 GDS 2.0.1 和 Neo4j 沙盒的版本,该版本是 2022 年 7 月的版本。
聚类分析帮助我们发现隐藏在数据中的结构。我们可以使用无监督的机器学习算法将数据项分组到聚类中,以便项与其聚类内的其他项比与其聚类外的项有更多的共同点。
当我们将数据集组织成相似项目的子集时,诸如客户细分、推荐和异常检测等任务变得更加容易。
相似度 的概念是聚类分析的核心。Neo4j Graph 数据科学库为我们提供了工具,用于根据节点的属性 发现数据集中节点之间的相似性,即使我们的数据 中不存在预先存在的关系。
然后布鲁姆图可视化应用允许用户以一种可访问的、可解释的方式交互地探索相似性。这可以帮助无监督的机器学习远离黑盒魔法的领域,成为商业用户使用的直观工具。图形数据科学库随后允许我们基于相似性关系找到密切相关的节点集群。
对于这个例子,我使用了美国人口普查局提供的 2019 年美国社区调查五年估计值中关于大都市统计区域 (MSAs)的 数据。
我选择了四个人口统计特征来描述每个 MSA:
- 人口,
- 中等家庭收入,
- 房价中位数,以及
- 25 岁以上拥有学士学位的人口比例。
在本教程中,我们将使用相似性算法根据四个人口统计特征来识别相似的 MSA 对。然后,我们将使用相似性关系来识别 MSA 的聚类。
麦肯齐·韦伯在 Unsplash 上的照片
你可以和我一起创建一个免费的 Neo4j 沙箱。选择创建“空白沙盒—图形数据科学”,因为我们会加载自己的数据。然后点击“打开”按钮,启动 Neo4j 浏览器开始使用。
在加载数据之前,我们将为 MSA 的名称创建一个唯一的约束。
CREATE CONSTRAINT msa_name ON (m:MSA) ASSERT m.name IS UNIQUE
使用此命令从 GitHub 上的 CSV 文件加载 MSA 数据。
LOAD CSV WITH HEADERS FROM "[https://raw.githubusercontent.com/smithna/datasets/main/CensusDemographicsByMetroArea.csv](https://raw.githubusercontent.com/smithna/datasets/main/CensusDemographicsByMetroArea.csv)" AS rowWITH row WHERE row.name CONTAINS 'Metro'MERGE (m:MSA {name:row.name})
SET m.population = toInteger(row.population),
m.medianHouseholdIncome = toInteger(row.medianHouseholdIncome),
m.medianHomePrice = toInteger(row.medianHomePrice),
m.percentOver25WithBachelors = toFloat(row.percentOver25WithBachelors)
RETURN m
注意,LOAD CSV
实用程序将每个字段视为一个字符串,所以我们使用toInteger()
和toFloat()
函数将数值转换为适当的数据类型。运行该命令后,您应该看到已经创建了 MSA 节点。
代表大都市地区的节点。图片作者。
与大多数 Neo4j 项目不同,我们在开始时没有任何关系要加载。相反,我们将使用图形数据科学库来发现相似的节点,并在它们之间创建关系。
我们将根据 欧氏距离 来定义相似度。欧几里德距离公式是勾股定理的延伸,勾股定理说的是直角三角形斜边长度的平方等于其他两条边的平方之和。
勾股定理。图片作者。
在我们的例子中,我们是沿着四个维度而不是两个维度比较 MSA,但是概念是相似的。两个 MSA 之间的欧几里德距离是每个人口统计指标的平方差总和的平方根。
欧几里德距离公式
在计算距离之前,我们希望四个属性从最小值到最大值的范围大致相同。如果范围差异大,则范围大的属性将主导距离计算;范围较小的属性几乎不会影响距离计算。所以我们需要把它们都归一化到相同的范围。
运行这个查询来查看我们加载的四个属性的值的范围。
MATCH (n)
WITH n,
["population", "medianHouseholdIncome", "medianHomePrice", "percentOver25WithBachelors" ] AS metrics
UNWIND metrics as metric
WITH metric, n[metric] AS value
RETURN metric, min(value) AS minValue,
percentileCont(value, 0.25) AS percentile25,
percentileCont(value, 0.50) AS percentile50,
percentileCont(value, 0.75) AS percentile75,
max(value) AS maxValue
显示每个属性的值范围的表。图片作者。
人口范围从 54,773 人到 19,294,236 人。这与 25 岁以上拥有大学学位的人的百分比范围(从 12.9%到 67.4%)有着巨大的差异。
我们还可以看到,第 50 和第 75 百分位人口(336,612 名公民)之间的差异要比第 25 和第 50 百分位人口(94,771.25 名公民)之间的差异大得多。我下载了数据,并用标准刻度和对数刻度绘制了直方图,以检查分布情况。
单位和对数标度的度量直方图。图片作者。
如果我们应用对数变换,我们所有的指标看起来更接近正态分布。当我考虑到在一个拥有 60,000 人口的 MSA 中增加 10,000 名居民会对都会区的特征产生很大的改变,但是在一个拥有 1,900 万人口的 MSA 中增加 10,000 名居民产生的影响要小得多时,这在直觉层面上对我来说是有意义的。另一方面,在任何规模的 MSA 中,10%的人口变化都是显而易见的。
运行以下命令,将对数变换应用于人口、中值房价和 25 岁以上拥有学士学位的人口百分比。
MATCH (m:MSA)
SET
m.logPopulation = log(m.population),
m.logMedianHouseholdIncome = log(m.medianHouseholdIncome),
m.logMedianHomePrice = log(m.medianHomePrice),
m.logPercentOver25WithBachelors = log(m.percentOver25WithBachelors)
t he 图形数据科学库中的MinMax
缩放器将应用下面的公式来 重新缩放每个属性值 。最小值设置为 0,最大值设置为 1,所有其他值根据它们在原始数据集中的位置成比例地落在 0 和 1 之间。
最小最大标量公式
我们将创建一个名为“metro-graph”的 内存图 来一次有效地在所有节点上执行缩放计算。我们将把标签为MSA
的所有节点加载到内存图中。由于我们的图中还没有任何关系,我们将使用一个*
通配符作为占位符。
CALL gds.graph.project('msa-graph',
'MSA',
'*',
{nodeProperties:["logPopulation", "logMedianHouseholdIncome", "logMedianHomePrice", "logPercentOver25WithBachelors"]})
运行下面的命令,在内存图中创建一个名为scaledProperties
的新属性。新的属性将是一个由四个值组成的 vector (有序列表):population、medianHouseholdIncome、medianHomePrice、percentOver25WithBachelors。在将属性添加到 vector 之前,将对每个属性应用MinMax
缩放器,以便所有值都在范围[0,1]内。
CALL gds.alpha.scaleProperties.mutate('msa-graph',
{nodeProperties: ["logPopulation", "logMedianHouseholdIncome", "logMedianHomePrice", "logPercentOver25WithBachelors"],
scaler:"MinMax",
mutateProperty: "scaledProperties"})
YIELD nodePropertiesWritten
我们可以使用刚刚创建的scaledProperties
来计算节点之间的距离。欧几里德距离公式告诉我们在四维空间中MSA 相距多远。距离值越高,两个 MSA 越不相似。我们对 MSA 之间的相似性感兴趣,所以我们将使用一种将距离转换为相似性的算法。
欧几里德相似公式
属性similarity
的值越高,两个 MSA 越相似。
K-Nearest Neighbors 算法将根据欧几里德相似性公式在我们的图中创建从每个节点到其最近邻居的关系。topK
参数告诉算法创建从每个节点到其最近的 15 个邻居的关系IS_SIMILAR
。在 write 模式下运行算法之前,让我们在 stats 模式下运行它,并检查相似性得分的分布。
*CALL gds.knn.stats("msa-graph",
{
nodeProperties:{scaledProperties:"EUCLIDEAN"},
topK:15,
sampleRate:1,
randomSeed:42,
concurrency:1
}
) YIELD similarityDistribution
RETURN similarityDistribution-----------------------------------{
"p1": 0.8350143432617188,
"max": 0.9999847412109375,
"p5": 0.9390525817871094,
"p90": 0.996307373046875,
"p50": 0.9895782470703125,
"p95": 0.9975738525390625,
"p10": 0.9621849060058594,
"p75": 0.9938201904296875,
"p99": 0.998992919921875,
"p25": 0.9813117980957031,
"p100": 0.9999847412109375,
"min": 0.77587890625,
"mean": 0.9814872709261316,
"stdDev": 0.027092271447973864
}*
我们可以看到,99%的关系相似度得分在 0.835 以上,最小相似度在 0.776 左右。当我们用相似性关系更新内存中的图时,我们将使用similarityThreshold
参数来排除相似性分数在倒数 1%的关系。
*CALL gds.knn.mutate("msa-graph",
{nodeProperties: {scaledProperties: "EUCLIDEAN"},
topK: 15,
mutateRelationshipType: "IS_SIMILAR",
mutateProperty: "similarity",
similarityCutoff: 0.8350143432617188,
sampleRate:1,
randomSeed:42,
concurrency:1}
)*
在 mutate 模式下运行 KNN 在内存图形投影中创建了IS_SIMILAR
关系。现在将它们写到 Neo4j 图中,这样就可以用 Cypher 查询它们,并在 Bloom 中可视化。
*CALL gds.graph.writeRelationship(
"msa-graph",
"IS_SIMILAR",
"similarity"
)*
让我们给IS_SIMILAR
关系添加一个rank
属性,这样我们就可以过滤每个节点排名靠前的关系。
*MATCH (m:MSA)-[s:IS_SIMILAR]->()
WITH m, s ORDER BY s.similarity DESC
WITH m, collect(s) as similarities, range(0, 11) AS ranks
UNWIND ranks AS rank
WITH rank, similarities[rank] AS rel
SET rel.rank = rank + 1*
现在让我们看看 Bloom graph 可视化应用程序中的图表。返回 Neo4j 沙盒主页,选择“打开 Bloom”
启动 Bloom。图片作者。
使用您的沙盒凭据登录。因为这是我们第一次使用 Bloom 处理这个数据集,所以点击“创建透视图”然后,单击“生成透视图”让 Bloom 为您设置一个透视图。最后,点击你新生成的视角进入绽放场景。
单击“使用视角”以使用您的新 Bloom 视角。图片作者。
让我们配置“IS_SIMILAR”关系的显示,以便线宽对应于节点的相似性。单击屏幕右侧面板上的“关系”,然后单击“IS_SIMILAR”关系旁边的线条。
单击 IS_SIMILAR 旁边的行。图片作者。
在出现的弹出菜单中,选取“基于规则”然后,单击加号添加新的基于规则的样式。
从属性键下拉列表中选择“相似性”。选择“范围”的单选按钮单击“大小”按钮创建一条控制线宽的规则。切换按钮以应用大小规则。
在最小点框中,输入 0.83 并将最小大小设置为 0.25 倍。在最大点框中,输入 1 并将最大大小设置为 4 倍。您的配置应该如下图所示。
基于规则的样式配置。作者图片
现在,让我们使用 Bloom 来搜索 MSA 及其最接近的对等体。如果你开始在 Bloom 搜索框中键入“纽约”,Bloom 的自动完成应该会建议“纽约-纽瓦克-泽西城,NY-NJ-PA 都会区。”按 tab 键接受建议。一旦你有了纽约 MSA 的一个节点,Bloom 会自动建议涉及该节点的模式。选择从具有 IS_SIMILAR 关系的纽约节点扩展的模式,然后按 enter 键。
Bloom 搜索框。图片作者。
Bloom 将返回一个可视化结果,显示纽约 MSA 及其 15 个最相似的 MSA,基于我们使用的四个人口统计指标。
与纽约最相似的管理服务协议。图片作者。
基于出站箭头的粗细,我们可以看到洛杉矶是与纽约最相似的 MSA。
我们可能会惊讶地发现,有往来于纽约和洛杉矶、圣地亚哥、波士顿、华盛顿和西雅图的关系,但没有可视化中的其他城市。我们告诉欧几里德距离算法为每个节点的前 15 个最近的 MSA创建关系。如果我列出离纽约最近的 15 个 MSA,亚特兰大包括在内。然而,如果我列出离亚特兰大最近的 12 个 MSA,纽约没有入选。这就是为什么有从纽约到亚特兰大的关系,但没有从亚特兰大到纽约的关系。**
让我们过滤显示内容,查看与纽约最相似的前 5 个城市。单击 Bloom 屏幕左侧的漏斗图标以展开过滤器面板。在下拉列表中选择 IS_SIMILAR。选择“等级”属性。选择“小于或等于”条件,并将值设置为 5。切换“应用过滤器”以突出显示纽约的前 5 个最强相似性关系。
过滤关系。作者图片
我们研究了单个 MSA 的邻居。现在让我们来看一下全局。右键单击 Bloom 画布并从上下文菜单中选择“清除场景”。在搜索框中,输入“MSA”并按 tab 键。选择(MSA)-IS_SIMILAR-()模式,然后按 enter 键。我们会看到完整的 MSA 图。
完整的 MSA 相似图。图片作者。
再次打开过滤器面板。为大于或等于 0.96 的“相似性”在 IS_SIMILAR 关系上创建新过滤器。切换“应用过滤器”,然后单击面板底部的“消除过滤的元素”按钮。我们开始看到一些岛屿和半岛从主节点群中分化出来。有三个离群节点,其中它们的 15 个最相似的邻居没有一个具有大于 0.96 的相似性。我们将使用社区检测算法进一步探索图的结构。
过滤 MSA 相似图。作者图片
返回 Neo4j 浏览器,运行以下命令进行社区检测。我们将针对内存中的图形执行 Louvain 社区检测算法,并将社区 id 写回到主 Neo4j 图形中。我们告诉算法使用similarity
属性来加权节点之间的关系。通过将consecutiveIds
参数设置为 true,我们告诉算法我们希望生成的communityId
属性的值是连续的整数。
*CALL gds.louvain.write('msa-graph',{relationshipTypes: ["IS_SIMILAR"],
relationshipWeightProperty:"similarity",
writeProperty:"communityId"})YIELD communityCount, modularities
RETURN communityCount, modularities*
社区检测结果。图片作者。
输出显示我们检测到了 6 个社区。算法的连续迭代将社区分区的模块性从 0.625 增加到 0.667。
运行下面的查询来收集关于我们定义的社区的汇总统计信息。除了统计数据之外,我们还通过列出每个社区中与同一社区中的其他 MSA 具有最高相似性的三个 MSA 来添加上下文。这些管理服务协议应该是其社区的典型范例,而其他管理服务协议的社区内关系可能更少或更弱。
*MATCH (m:MSA)
WITH m
ORDER BY apoc.coll.sum([(m)-[s:IS_SIMILAR]->(m2)
WHERE m.communityId = m2.communityId | s.similarity]) desc
RETURN m.communityId as communityId,
count(m) as msaCount,
avg(m.population) as avgPopulation,
avg(m.medianHomePrice) as avgHomePrice,
avg(m.medianHouseholdIncome) as avgIncome,
avg(m.percentOver25WithBachelors) as avgPctBachelors,
collect(m.name)[..3] as exampleMSAs
ORDER BY avgPopulation DESC*
汇总社区功能的表格。图片作者。
knn 和 Louvain 算法是 id 81 社区中 MSAs 人口最多的社区,平均人口接近 200 万。社区 54 也有很高的 MSA 人口,但是收入和房价低于社区 81。社区 234 和 330 非常相似,但 234 人口更多,330 房价更高。与人口规模相似的社区相比,社区 75 拥有受过高等教育的公民。社区 264 有少量的 MSA。385 社区有低收入管理事务协议。
让我们给社区起一个比自动生成的 id 更人性化的名字。
*MATCH (m:MSA)
SET m.communityName = CASE m.communityId
WHEN 54 THEN "Large mid-cost metros"
WHEN 75 THEN "College towns"
WHEN 81 THEN "Large high-cost metros"
WHEN 234 THEN "Mid-size metros"
WHEN 264 THEN "Small metros"
WHEN 330 THEN "Mid-price metros"
WHEN 385 THEN "Low-income metros"
END
return m.communityName, m.communityId, count(*)*
要使 communityName 属性在 Bloom 中可搜索,请在该属性上创建一个索引。
*CREATE INDEX msa_community_name IF NOT EXISTS
FOR (m:MSA)
ON (m.communityName)*
让我们来看看 Bloom 中的结果。我们将配置透视图以反映我们添加的新社区。单击屏幕左上角的图标打开透视图面板。然后,单击数据库图标来刷新透视图,以包含我们添加到数据库中的新的communityName
属性。
刷新 Bloom 透视图以在数据库中包含新属性。图片作者。
在屏幕右侧的面板中,单击 MSA 旁边的圆圈来设置 MSA 节点的样式。在出现的弹出菜单中,选取“基于规则”然后,单击加号添加新的基于规则的样式。从属性键下拉列表中选择“communityName”。选择“唯一值”的单选按钮切换按钮以应用颜色规则。
communityName 的基于规则的样式配置。图片作者。
让我们添加第二个条件样式来根据人口设置节点的大小。单击加号添加新的基于规则的样式规则。
从属性键下拉列表中选择“人口”。选择“范围”的单选按钮单击“大小”按钮创建控制节点大小的规则。切换按钮以应用大小规则。
在“最小点”框中,输入 55000 并将最小大小设置为 1x。在 Maxpoint 框中,输入 19000000,并将最大大小设置为 4x。您的配置应该如下图所示。
基于规则的群体样式。图片作者。
现在右键单击并从上下文菜单中选择“清除场景”。在搜索框中,键入“大学城”,然后按 enter 键。返回的结果包括州立大学、PA Metro、Ithaca、NY Metro、Champaign-Urbana、IL Metro 和 Charlottesville、VA Metro。这些大都市区是宾夕法尼亚州立大学、康奈尔大学、伊利诺伊大学和弗吉尼亚大学的所在地。根据我们对这些大都市地区的了解,该算法似乎已经发现了一些明显的共性。
一些 MSA 通过搜索“大学城”返回。图片作者。
我们来看看还有哪些大都市和大学城最相似。点按 Command-A 以选择所有节点。然后右键单击其中一个节点,并从上下文菜单中选择 Expand:
最像大学城的城市。图片作者。
当我缩小时,我可以看到我们添加了几个大型地铁区域(紫色)、中型地铁区域(橙色)、小型中等收入区域(青色)和一个中型高成本地铁区域(红色)。双击节点或放大以查看节点详细信息。我们增加的几个 MSA,如麦迪逊、威斯康星大都会区和北卡罗莱纳州的达勒姆-查佩尔山恰好是主要大学的所在地。
使用该数据集进行实验,以进一步探索相似性图表。运行gds.alpha.similarity.euclidean
时,通过减少topK
参数或设置similarityThreshold
参数来减少相似性关系的数量,将会在运行gds.louvain
时产生更多的社区。运行gds.alpha.scaleProperties
时,尝试除MinMax
之外的缩放器。
图形数据科学库支持其他几种相似度算法。K-最近邻算法提供了一种基于余弦相似度生成链接的有效方法。
Louvain 社区检测是几个社区检测算法中的一个选项。通过运行标签传播算法,查看您的结果有何不同。
GitHub 上的数据 CSV 除了大都市统计区域外,还包括小城市统计区域。从LOAD CSV
脚本中移除WHERE row.name INCLUDES 'Metro'
来加载这些节点并探索它们的属性。
您会发现图实际上无处不在,即使一开始关系在数据模型中并不明显。