在 M1 Mac 电脑上使用 conda
运行多个 conda 发行版,从两个世界获得最佳效果。
如果你最近在工作中购买或获得了一台新的 M1 Mac,并且你正在使用 Python 开发或从事数据科学项目,你可能已经浪费了一些时间来运行一些包。我仍然在我的 Mac 上与 Python、Docker 和 conda 作斗争,但是我找到了一种让许多包在 conda 环境中运行的方法。
由于 M1 是基于 ARM 的系统,许多 Python 包无法正确安装,因为它们是为在 AMD64 (x86)上运行而构建的。像许多其他人一样,我使用 conda 为我的项目建立环境——最好是使用 Anaconda 或 Miniconda。
当我第一次想在我的 Mac 上安装 Tensorflow 时,我偶然发现了 mini forge(https://github.com/conda-forge/miniforge),它可以与 Miniconda 相媲美,但 conda-forge 是默认通道,并专注于支持各种 CPU 架构。Tensorflow 与 Miniforge 一起安装时工作正常。
但是当我需要安装我工作中使用的某些包时——比如 SimpleITK(现在也有 M1 Python wheel!)— Miniforge 无法安装它。这有点像赌博。在某个时候,我意识到我可以在同一个系统上同时安装和使用 Miniforge 和 Miniconda。
编辑:正如Lucas-Raphael müller给我指出的,你不需要两个都装,Miniconda 和 Miniforge。你可以像这里说的一样选择是使用针对 Intel 芯片编译的包还是针对 Apple Silicon 编译的包:https://github . com/Haydnspass/miniforge # Rosetta-on-MAC-with-Apple-Silicon-hardware。
安装 Miniforge 后,初始化命令将在您的。bashrc/。zshrc:
# >>> conda initialize >>>
# !! Contents within this block are managed by ‘conda init’ !!
__conda_setup=”$(‘/Users/xyz/miniforge3/bin/conda’ ‘shell.zsh’ ‘hook’ 2> /dev/null)”
if [ $? -eq 0 ]; then
eval “$__conda_setup”
else
if [ -f “/Users/xyz/miniforge3/etc/profile.d/conda.sh” ]; then
. “/Users/xyz/miniforge3/etc/profile.d/conda.sh”
else
export PATH=”/Users/xyz/miniforge3/bin:$PATH”
fi
fi
unset __conda_setup
# <<< conda initialize <<<
这将使用 Miniforge 初始化 conda。你只需要复制你的。bashrc/。zshrc 文件,并将 miniforge3 更改为 miniconda3,并选择默认情况下要使用的文件。更改非常简单,只需运行source .bashrc
进行所需的 conda 初始化。
例如,我正在做一个项目,在这个项目中,我需要 SimpleITK 来预处理图像,需要 Tensorflow 来训练一个模型。我无法让两者在 M1 的同一个小型锻造环境中工作。所以我把预处理和训练分成两个环境,一个利用 Miniconda 运行 SimpleITK,一个 Miniforge 环境运行 Tensorflow。
它的好处是你可以通过运行conda env list
同时看到 Miniconda 和 Miniforge 环境。唯一的区别是,您将看不到用其他安装程序构建的环境的名称,只能看到路径。初始化 Miniconda 后,您需要使用 Miniforge 环境的完整路径运行conda activate
。
这在 bash 脚本中仍然很容易管理,以便使用由多个 conda 发行版构建的多个环境来运行脚本。
我希望这只是一个临时的解决办法,直到越来越多的软件包可以在 M1 上工作,但是我确信这需要一些时间。
希望这能帮助一些在 M1 上使用 conda 处理 Python 包的人。
使用条件深度卷积 GANs 从文本描述生成自定义人脸
本项目代码见:【https://github.com/evanhu1/pytorch-CelebA-faCeGAN】
GANs(生成对抗网络)是无监督学习模型的一个子集,它利用两个网络以及对抗训练来输出与输入数据相似的“新”数据。更具体地说,GANs 通常涉及“捕获数据分布的生成模型 G,以及估计样本来自训练数据而不是 G [1]的概率的判别模型 D。”
生成性对抗网络。来源
条件甘是原始甘模型的修改,后来由 Mehdi Mirza 和 Simon Osindero 在论文“条件生成对抗网络”(2014)中提出。在 cGAN(条件 GAN)中,鉴别器被给予数据/标签对,而不仅仅是数据,并且除了噪声向量之外,生成器还被给予标签,指示图像应该属于哪个类。标签的添加迫使生成器学习不同训练数据类的多种表示,允许显式控制生成器的输出的能力。在训练模型时,标签通常与生成器和鉴别器的数据样本相结合。实现这一点的代码将在下面给出。
在本文中,我将描述 PyTorch 中条件深度卷积 GAN 的实现,它使用英文文本而不是单个数字作为标签。我们的模型是深度卷积 GAN (DCGAN),也就是说,它在其架构中使用深度卷积层,而不是原始论文中的全连接层。我们将在名人面孔的数据集上进行训练,图像被裁剪为 64x64。我们的模型架构包含五个卷积/转置卷积层,具有批量归一化和泄漏 ReLU 激活,以及用于鉴别器输出层的 sigmoid 激活和用于发生器输出层的 tanh 激活。使用 Adam 优化器和二元交叉熵损失。
参数和数据清理步骤由关于 GAN 训练的“传统智慧”指导,从诸如 GANHacks 和原始论文等来源收集。这些包括 Adam 优化器的学习率为 0.0002 (beta 0.5),步进卷积而不是向下/向上采样,使用高斯分布的自定义权重初始化(平均值为 0.0,标准差为 0.02),以及将真实图像从[0,1]缩放到[-1,1]以匹配伪图像中的 tanh 输出。
发生器模型的架构——鉴别器模型几乎完全相同,只是输入/输出维度和简单卷积层有所不同,而不是转置层。作者图片
在确定了设计之后,我们用 PyTorch 编写了我们的模型。
至于数据集,CelebA 为每张图像提供了 40 个二进制属性注释,如下例所示。
使用这些二元属性作为我们的标签或条件,我们可以训练我们的 cGAN 生成具有我们控制的特定特征的人脸。此外,我们可以选择多个属性进行训练和学习,只需将它们连接起来形成多维标签。给定足够的属性,我们可以生成具有不同人类特征的各种各样的人脸。例如,我们的初步训练结果显示,该模型可以学习二元属性,[男性,年轻],允许我们生成 4 种不同的面部类型组合(年轻男性,“不年轻”男性,年轻女性,“不年轻”女性)
作者图片
在我们的代码中,我们构建了一个定制的 PyTorch 数据集,它带有一个参数来指定在总共 40 个二进制属性中包含哪些属性,因为对所有 40 个属性进行训练太困难了。
对于我们模型的实际输入,我们创建了沿标签轴具有二维的多热点编码张量。具体来说,假设我们在训练中仅使用 64x64 图像的两个二进制属性,则生成器将接收 32x2x1x1(批量大小、标签数量和反卷积层要作用的 2 个“伪”图像尺寸)的 multi-hot 编码张量作为每个训练样本的标签。相反,鉴别器将接收 32×2×64×64 的多热编码张量,根据训练样本的二进制属性填充 0 和 1。
在训练期间,在每个标签通过卷积/去卷积层之后,使用 torch.cat()层将这些标签与数据样本连接在一起。创建标签并将其处理成正确尺寸的代码在训练循环中,该循环基本上与普通的 GAN 训练循环相同,只是增加了将标签与数据样本一起输入的步骤。
鉴别器模型的训练代码
在 Google Collaboratory GPUs 上,每个时期的训练时间约为 30 分钟,平均到第 5 个时期时产生了有趣的结果。我们尝试稳步增加训练数据中用于描述面部的属性数量,希望了解 cGAN 能够学习多少。
每个图像有 5 个二进制属性:
作者图片
10 个属性:
[‘秃头’,‘黑发’,‘金发’,‘棕发’,‘灰发’,‘男性’,‘无胡须’,‘后退 _ 发际线’,‘直发’,‘波浪发’]。作者图片
正如您可能看到的,随着属性数量的增加,结果会受到影响。考虑到我们有限的计算资源和时间,我们没有超过 10 个属性,但看看它能走多远,以及一个足够大的模型是否能学习 celebA 的所有 40 个二进制属性将会很有趣。
作为额外的工作,我们还在 celebA 数据样本上使用旋转变换进行实验,看看 cGAN 是否不仅可以学习二进制属性,还可以学习旋转等增强。从论文通过预测图像旋转的无监督表示学习中获得灵感,我们生成了旋转 90、180 和 270 度的样本用于训练。
作者图片
结果表明,令人惊讶的是,cGAN 模型确实能够学习面部属性以及图像增强。
总之,这是对 GANs 从数据中学习的明确能力以及 cGANs 令人印象深刻的灵活性的引人入胜的观察。我们希望你会觉得有趣,就像我们一样。
承认
这个项目是与来自伯克利机器学习的杰克·奥斯丁、雅利安·贾恩和布莱恩·刘共同合作的成果。
参考
[1]生成性对抗网络:https://arxiv.org/abs/1406.2661
利用卷积神经网络进行图像分类
纳斯蒂亚·杜尔希尔在 Unsplash 上的照片
卷积神经网络(CNN 或 ConvNet)是神经网络的一个子类型,主要用于图像和语音识别。其内置的卷积层在不丢失信息的情况下降低了图像的高维度。这就是 CNN 特别适合这个用例的原因。
图像处理问题
如果我们想使用一个全连接的神经网络进行图像处理,我们很快就会发现它不能很好地扩展。
https://medium.com/illumination/intuitive-guide-to-artificial-neural-networks-5a2925ea3fa2
对于计算机来说,RGB 符号的图像是三个不同矩阵的总和。对于图像的每个像素,它描述了该像素显示的颜色。为此,我们在第一个矩阵中定义红色分量,在第二个矩阵中定义绿色分量,然后在最后一个矩阵中定义蓝色分量。因此,对于 3 个像素大小为 3 的图像,我们得到三个不同的 3x3 矩阵。
3x3x3 RGB 图片|图片:作者
为了处理图像,我们将每个像素作为输入输入到网络中。因此,对于大小为 200x200x3 的图像(即 200 个像素对 200 个像素,具有 3 个颜色通道,例如红色、绿色和蓝色),我们必须提供 200 * 200 * 3= 120,000 个输入神经元。那么每个矩阵的大小为 200×200 像素,因此总共有 200 * 200 个条目。这个矩阵最终存在三次,分别代表红色、蓝色和绿色。问题出现在第一个隐藏层,因为那里的每个神经元都有来自输入层的 120,000 个权重。这意味着当我们增加隐藏层中神经元的数量时,参数的数量会迅速增加。
当我们想要处理具有更多像素和更多颜色通道的更大图像时,这一挑战变得更加严峻。这种具有大量参数的网络很可能会过拟合。这意味着该模型将为训练集提供良好的预测,但不会很好地推广到它尚不知道的新情况。此外,由于大量的参数,网络将很可能停止关注单个图像细节,因为它们将在纯粹的质量中丢失。然而,如果我们想要对图像进行分类,例如,图像中是否有狗,这些细节,例如鼻子或耳朵,可能是正确结果的决定性因素。
卷积神经网络
出于这些原因,卷积神经网络采取了一种不同的方法,模拟我们用眼睛感知环境的方式。当我们看到一幅图像时,我们会自动把它分成许多小的子图像,并逐个进行分析。通过组合这些子图像,我们处理和解释图像。如何在卷积神经网络中实现这一原理?
工作发生在所谓的卷积层。为了做到这一点,我们定义了一个过滤器,它决定了我们正在查看的部分图像应该有多大,以及一个步长,它决定了我们在计算之间继续多少像素,即部分图像彼此有多接近。通过采取这一步骤,我们大大降低了图像的维数。
下一步是池层。从纯计算的角度来看,这里发生的事情与卷积层相同,不同之处在于,根据应用,我们只从结果中取平均值或最大值。这保留了对任务解决方案至关重要的几个像素中的小特征。
最后,还有一个全连接层,正如我们从常规神经网络中已经知道的那样。现在,我们已经大大降低了图像的维度,我们可以使用紧密网格层。这里,各个子图像被再次链接,以便识别连接并执行分类。
现在,我们已经对各个图层的大致功能有了基本的了解,我们可以详细了解图像是如何成为一个类别的。为此,我们尝试从 4x4x3 图像中识别其中是否有狗。
细节:卷积层
在第一步中,我们想要减少 4x4x3 图像的尺寸。为此,我们为每种颜色定义一个尺寸为 2x2 的过滤器。此外,我们希望步长为 1,即在每个计算步骤之后,滤波器应该向前移动一个像素。这不会减少太多的维度,但图像的细节将被保留。如果我们用一个 2x2 迁移一个 4x4 矩阵,并在每一步中前进一列或一行,我们的卷积层将有一个 3x3 矩阵作为输出。矩阵的单个值通过取 2x2 矩阵的标量积来计算,如图所示。
卷积层|图片:作者
详细信息:池层
(最大)池层将卷积层的 3×3 矩阵作为输入,并尝试进一步降低维度,另外获取图像中的重要特征。我们希望生成一个 2x2 矩阵作为这一层的输出,因此我们将输入划分为所有可能的 2x2 部分矩阵,并在这些字段中搜索最高值。这将是输出矩阵字段中的值。如果我们使用平均池层而不是最大池层,我们将计算四个字段的平均值。
池层|照片:作者
汇集层还从图像中滤除噪声,即图像中对分类没有贡献的元素。例如,狗是站在房子前面还是森林前面,这一开始并不重要。
细节:完全连接的层
完全连接的层现在做的正是我们在开始时打算对整个图像做的。我们为较小的 2x2 矩阵中的每个条目创建一个神经元,并将它们连接到下一层中的所有神经元。这大大减少了我们的维度,也减少了培训所需的资源。
然后,这一层最终知道需要图像的哪些部分来进行狗或非狗的分类。如果我们的图像比我们的 5x5x3 示例大得多,当然也可以在进入全连接层之前连续几次设置卷积层和池层。通过这种方式,您可以将维数降低到足以减少训练工作量的程度。
数据集
Tensorflow 有各种各样的数据集,我们只需几行代码就可以下载和使用。当您想要测试新模型及其实现,并且因此不想长时间搜索适当的数据时,这尤其有用。此外,谷歌还提供了一个数据集搜索,人们可以通过点击几下找到合适的数据集。
对于我们的示例卷积神经网络,我们使用通过 Tensorflow 获得的 CIFAR10 数据集。该数据集包含总共 60,000 幅彩色图像,分为十个不同的图像类别,例如马、鸭或卡车。我们注意到,这是一个完美的训练数据集,因为每个类正好包含 6,000 幅图像。在分类模型中,如果可能的话,我们必须始终确保每个类在数据集中出现的次数相同。对于测试数据集,我们总共获取 10,000 张图像,因此训练数据集获取 50,000 张图像。
这些图像的尺寸都是 32×32 像素。像素依次具有 0 到 255 之间的值,其中每个数字代表一个颜色代码。因此,我们将每个像素值除以 255,以便将像素值归一化到 0 和 1 之间的范围。
为了检查所有图像是否正确显示,我们打印前十个图像,包括它们所属的类。由于这些只是 32×32 的图像,它们相对模糊,但你仍然可以分辨出它们属于哪一类。
建立一个卷积神经网络
在 Tensorflow 中,我们现在可以通过定义每层的序列来构建卷积神经网络。因为我们正在处理相对较小的图像,我们将使用卷积层和最大池层的堆栈两次。正如我们已经知道的,这些图像有 32 个高度维度、32 个宽度维度和 3 个颜色通道(红、绿、蓝)。
卷积层首先使用 32 个滤波器,然后使用 64 个具有 3×3 内核的滤波器,最大池层搜索 2×2 矩阵内的最大值。
经过这两次叠加后,我们已经将图像的尺寸显著减少到 6 个高度像素,6 个宽度像素,总共 64 个滤镜。利用第三个也是最后一个卷积层,我们将这些维度进一步降低到 4x4x64。在我们现在由此构建全网状网络之前,我们用 1024 个元素(4464)的向量替换每个图像的 3×3 矩阵,而不会丢失任何信息。
现在,我们已经充分降低了图像的维度,并且可以在模型结束于具有十个不同类别的十个神经元的输出层之前,再添加一个总共具有 64 个神经元的隐藏层。
该模型总共有 122,570 个参数,现在可以开始构建和训练了。
编译和训练模型
在我们开始训练卷积神经网络之前,我们必须编译模型。在其中,我们定义了应该根据哪个损失函数、优化器(即,根据哪个算法来改变参数)来训练模型,以及为了能够监控训练过程,我们希望显示哪个度量。
评估模型
在对卷积神经网络进行总共 10 个时期的训练之后,我们可以查看模型精度的进展,以确定我们是否对训练满意。
我们对图像类别的预测在大约 80%的情况下是正确的。这不是一个不好的值,但也不是一个特别好的值。如果我们想进一步增加这一点,我们可以让卷积神经网络训练更多的时期,或者可能以甚至不同的方式配置密集层。
这是你应该带走的东西
- 卷积神经网络用于图像和语音处理,并且基于人类视觉皮层的结构。
- 它们由卷积层、汇集层和完全连接层组成。
- 卷积神经网络将图像分成更小的区域,以便第一次单独查看它们。
- 使用 Tensorflow,卷积神经网络只需几步即可编程。
- 根据不同的使用情况调整卷积层和最大池层的安排非常重要。
如果你喜欢我的作品,请在这里订阅https://medium.com/subscribe/@niklas_lang或者查看我的网站 数据大本营 !还有,medium 允许你每月免费阅读 3 篇 。如果你希望有无限制的 访问我的文章和数以千计的精彩文章,不要犹豫,点击我的推荐链接:【https://medium.com/@niklas_lang/membership】每月花$5*获得会员资格*
*https://medium.com/codex/why-you-should-know-big-data-3c0c161b9e14 https://medium.com/@niklas_lang/understanding-mapreduce-with-the-help-of-harry-potter-5b0ae89cc88
参考
使用自定义图像作为 Tableau 中的地图
你知道你可以在 Tableau 里画出任何东西吗?
是的,你没看错。您可以使用任何图像作为背景,并在其上添加数据点。在这篇文章中,我将带领你创建你自己的自定义地图的步骤。
由 Unsplash 上的 GeoJango Maps 拍摄
最近,我试图为奥运会绘制时间表。出于本教程的目的,我将使用相同的 viz。
它是如何工作的?
我们知道我们需要两个坐标来绘制地图——一个位置的经度和纬度。如果您还记得散点图,我们基本上使用 X 和 Y 坐标来绘制数据点。因此,地图可以被认为是一个散点图,但在 Tableau 中有一个背景图像。你只需要坐标,就可以开始了。
如何向地图添加数据点?
为此,您需要首先准备数据源,添加图像并在数据源中添加所需的坐标。下面是详细的步骤。
1.准备数据源
打开一个电子表格文件,添加三列——X、Y 和一个标识符。我用的是年份。在 X 和 Y 列中输入随机数。
初始数据源(图片由作者提供)
2.设置工作表
转到 Tableau 中的新工作表,将 X 添加到 Columns shelf,将 Y 添加到 Rows shelf。右键单击 X 和 Y,然后选择“尺寸”。另外,将图表类型更改为地图。
(图片由作者提供)
3.找到图像
找到您想要使用的合适大小的图像。我用的图片尺寸是 1200 X 554。
请务必给予应有的学分,以使用图像。
一旦你有了图像,进入地图>背景图像。单击数据源的名称。将会打开一个弹出窗口。点击“添加图像…”
添加背景图片(图片由作者提供)
浏览到您的图像,并根据图像的大小设置 X 和 Y 字段限制。我的图像尺寸是 1200 X 554。如果需要,您也可以选择冲洗图像。单击确定。
你现在应该看到图像作为背景。在此阶段,最好将 x 轴和 y 轴固定在正确的范围内,以便图像与工作区域对齐。
将自定义图像添加为地图(作者提供的图像)
4.添加数据点
找到您添加到电子表格的一个数据点。右键单击该点,选择注释>点,然后单击确定。您也可以单击图像上的任意位置来注释该点。默认情况下,注释会显示 X 和 Y 坐标。
现在,将注释从(100,100)移动到图像上的一个点。你刚刚得到了第一个数据点。将这些坐标添加到电子表格中。根据所需的数据点数量重复此步骤。
使用注释获取坐标(图片由作者提供)
完成本练习后,您的电子表格应该如下所示。您可以添加更多包含与您的 viz 相关的详细信息的专栏。
(图片由作者提供)
保存电子表格并刷新数据源。
您的图像应该在刚刚映射的位置上有点。小白点是我们刚刚绘制的坐标。
映射的自定义图像(作者提供的图像)
瞧啊。您已经成功地使用了自定义图像并在其上绘制了数据。
你可以用这种技术做很多有趣的事情。这是我做的和我最终的 viz 看起来的样子。
来源:即
感谢阅读!
直到下一次…
使用 CycleGAN 在网络摄像头上执行风格转换
实践教程
关于如何设置 CycleGAN 和添加网络摄像头兼容性的教程
在我的网络摄像头上实时播放著名艺术家的作品。
注意:本文假设您了解 GANs。 这里的 是巨大的资源。
你有没有想过如果你是莫奈画的你会是什么样子?还是传说中的梵高?
随着我对 GANs 的了解越来越多,一个特别的应用引起了我的注意:风格转换。风格转移的目标是学习如何将一个域 X 的图像映射到另一个不同的域 y 的图像。一个经典的例子是让一个域成为一组照片,而另一个域包含一位著名艺术家(如克洛德·莫内)的绘画,并应用风格转移将普通照片转换为看起来像是他画的。
使用循环一致对抗网络的不成对图像到图像翻译。
这被称为图像到图像的转换,它传统上需要一个大型的成对图像数据集,这意味着为了学习上面例子中的映射,你需要相同位置、相同角度、相同时间的绘画和照片,等等。由于显而易见的原因,获得这种配对数据是不现实的,而且通常是不可能的。如果不用成对的例子就能把图像翻译成画,岂不是很棒?这个问题已经被探索,并且通过循环一致的对抗网络 (CycleGAN)已经实现了不成对的图像到图像翻译的有效方法,该方法使用 GAN 架构来学习必要的映射并执行高质量的图像翻译。我很好奇 CycleGAN 在视频上使用时有多有效,所以在这篇短文中,我将简要介绍 CycleGAN 的工作原理,然后介绍如何使用官方 CycleGAN 实现将莫奈、梵高和其他人的艺术风格应用到您自己的网络摄像头上。
周期根的直觉
CycleGAN 的整体架构相当复杂。记住 CycleGAN 的目标,以及这些目标如何影响它的架构,有助于使它更容易理解。CycleGAN 的目标如下:
- 学习将域 X 映射和转换到域 Y(反之亦然)
- 维护图像的一致性:来自域 X 的图像在翻译到域 Y 时(反之亦然)应该看起来像原始图像,但是应用了必要的风格变化。
为了实现第一个目标,我们使用具有两个相应鉴别器的两个生成器,并应用下面的对抗性损失:
其中生成器 G 获取图像 X 并生成看起来属于域 y 的图像 G(X) 。鉴别器 Dy 试图正确地区分所生成的样本和从域 y 中随机选择的真实图像。这个相同的目标可以用于映射和翻译域 Y →域 x。
仅仅这样还不足以实现想要的风格转换。仅用对抗性损失进行训练将导致从域 X 到域 Y 的成功生成,但是不能保证生成的图像看起来像原始图像。我们希望映射是“循环一致的”,这意味着(通过其生成器)转换到目标域,然后转换回其原始域的图像应该尽可能地类似原始图像:X→G(X)→F(G(X))→≈X其中 F 是从域 Y 转换到 X 的生成器
为了实施这一原则,并实现我们的第二个目标,我们在下面定义了周期一致性损失函数。损失函数鼓励X→G(X)→F(G(X))→≈X和 Y→ F(Y) → G(F(Y)) → ≈ Y.
使用循环一致对抗网络的不成对图像到图像翻译。
我们目前有三种不同的损耗,用于在训练期间更新 CylceGAN:
- G 对 Dy (X→Y)的对抗性损失
- F 对 Dx (Y→X)的对抗性损失
- 循环一致性损失
而这些足以训练出 CycleGAN。我将简单地提一下,添加一个身份损失是有益的,这有助于保留翻译图像的颜色和色调。
CycleGAN 的作者建议通过使用变量 lambda λ来赋予这些损失函数不同程度的影响——如果您对 CycleGAN 架构的这一方面或其他方面(如层架构)感兴趣,我建议看一看原始论文。有了一点 CycleGAN 直觉/更新,让我们用网络摄像头工作吧!
将风格转换应用到您的网络摄像头
为了将莫奈、梵高和其他风格应用到您的网络摄像头,我们将使用论文作者创建的预训练 CycleGAN 模型。首先克隆库并在终端/命令行中导航到根目录。从这里开始,您将运行./scripts
文件夹中提供的一组 bash 命令来加载必要的模型。
bash ./scripts/download_cyclegan_model.sh style_monet_pretrained
bash ./scripts/download_cyclegan_model.sh style_ukiyoe_pretrained
bash ./scripts/download_cyclegan_model.sh style_cezanne_pretrained
bash ./scripts/download_cyclegan_model.sh style_vangogh_pretrained
这些会将预训练的 CycleGANs 保存在./checkpoints
文件夹中。
我们现在将在根目录下创建一个名为webcam.py
的 Python 文件,它将是test.py
的修改版本,而不是通过 CycleGAN 运行数据集,而是通过它传递我们的网络摄像头馈送。
一旦你创建了webcam.py
,开始导入必要的包:
然后,使用来自test.py
的相同代码行来解析来自命令行的参数:
我们将通过编辑./options/base_options.py
来编辑webcam.py
的所需参数,并将参数--dataroot
的所需布尔值设置为 false,因为使用网络摄像头,我们不需要提供数据的目录。现在,我们使用 cv2 来设置我们的网络摄像头,如果设置失败,就会引发错误:
然后,我们添加代码来获取网络摄像头的每一帧并执行必要的转换,以便它可以被我们加载的模型读取和转换。
最后,我们在一个新窗口中显示风格化的框架。如果用户在任何时候按下“Esc”键,窗口将关闭。
此时,您应该能够使用根文件夹中的以下命令运行您选择的 CycleGAN 模型的webcam.py
。
python webcam.py --name MODEL_NAME --model test --preprocess none --no_dropout
如果你对此满意:太好了!您可以通过修改--name
参数来尝试其他预训练模型。在下一节中,我将展示如何添加一些额外的功能:通过按键实时切换样式。
在风格中循环
没有太多的修改必须作出,以便能够通过循环的风格,并应用到我们的网络摄像头实时。首先创建一个列表,列出您希望循环遍历的所有模型名称,并初始化一个变量来索引该列表。
在 while 循环之前插入以下代码。在我的代码中,这是在我们用 cv2 设置了网络摄像头之后。
我们还想在窗口的左上角添加文本,说明我们正在应用谁的艺术家的风格。首先为字体大小和位置设置一些参数。
除了前面的代码之外,在 while 循环之前插入以下代码。
为了将文本放置在左上角,我们将使用cv2.putText()
并改变样式,我们将添加一个条件,如果按下“c”键,它将加载style_models
列表中的下一个模型。下面是webcam.py
的完整的最终实现:
它可以用前面列出的相同 bash 命令运行:
python webcam.py --name MODEL_NAME --model test --preprocess none --no_dropout
结论
您可能会注意到每种风格都有一些闪烁/噪音。在视频上执行风格转换是一个相对较新的发展,许多酷的、计算昂贵的工作正在进行,试图使帧之间的转换更加一致。
CycleGAN 存储库文档教你如何在自己的数据集上训练,从而创建自己的风格!我认为收集漫画书作为一个数据集将导致一个非常酷的风格转移。
虽然已经有像 Photo Booth 这样的带有网络摄像头过滤器的程序,但风格转移很酷,因为他们学习了更高的理解,并且风格的细微差别可以有效地应用它。它可能不会在低分辨率的网络摄像头中显示出来,但在高分辨率的照片上,您可以真正看到它的威力:
Pietro De Grandi 原创图片
梵高的!
这也只是 CycleGAN 的一个具体应用,我建议浏览网页或查阅文献,看看它拥有的其他迷人的功能。
对于 webcam.py 和存储库文件,这里是我在 GitHub 上的 fork。
感谢阅读!
使用 D3.js 创建动态地图和视觉效果,展示 21 世纪相互竞争的气候变化情景
如何使用 D3.js、Angular、JavaScript 和 Python 为您的数据科学项目创建地图和动画的代码演练
利用 D3.js 制作未来 80 年气候变化预测的动画和地图:在zach-alexander.com/climate-change的完整可视化和故事|图片由作者提供
随着拜登政府下周正式上任,应对气候变化的努力出现了乐观情绪。正因为如此,我认为探索未来 80 年政策作为(或不作为)对这一问题的潜在影响将是有趣的。
最近,我致力于一个完整的数据可视化故事,比较两种竞争气候变化情景下的温度变化预测。 这两种情景(“A2”和“B1”)是 IPCC 在 21 世纪初制定的。这些情景概述了在这个问题上不同层次的全球合作及其对碳排放的潜在影响。如果你有兴趣阅读完整的数据故事并与其可视化互动,请随时前往:https://zach-alexander.com/climate-change【zach-alexander.com/climate-change】。
写完这个数据故事后,我意识到写一篇概述为观众创建 web 可视化的能力的文章可能会有所帮助。作为一名数据科学研究生(职业是数据工程师),我经常对我们如何传达我们不懈努力完善的分析和数据的结论缺乏后续跟进(包括我在内)感到失望。最后,有时我们创建的算法或模型可能会失败,如果它们没有给出上下文或以令人信服的方式传达给受众。虽然现在有很多数据可视化平台(PowerBI,Tableau 等。)可以快速制作图表,在网上构建数据故事可以让分析更上一层楼。
在这篇文章中,我将从我为数据故事创建的一个可视化中选取一部分,并希望为如何使用https://angular.io/和 D3.js 创建一个模拟 21 世纪气候变化模型的动画地图提供基础。
如果你想跟随完整的代码,你可以从这个库 中提取 。它将包含下面列出的所有代码,包括:
- 将 csv 数据合并和转换为 JSON(python)
- 运行本地角度应用程序(Angular-cli)
- 安装 D3.js 并将 json 文件加载到 Angular 组件中(Angular)
- 使用 D3.js 创建一个世界地图,并在 4 个时间间隔内制作动画(角度和 Javascript)
如果你发现自己想要在这篇文章中开始的动画的基础上构建,你 可以从我关于这个主题的综合数据故事中提取额外的代码 。
确定你的想象或故事的目标
在开始任何网站工作之前,开发任何数据可视化的关键的第一步是考虑你最终想要向你的观众描绘什么。
我的目标:我想根据 IPCC 的气候变化情景,直观地展示未来 80 年各国的土地温度变化(以华氏度为单位)。
带着这个目标,我开始寻找一个令人信服的数据集。
查找数据集并识别其结构
幸运的是,有无数的气候变化数据集可供使用,而这个 世界银行数据集 包含了预测未来一个世纪陆地温度变化的集合数据(基于全球环流模型和 IPCC 气候变化情景),正是我所寻找的。
太好了!我有一个数据集,现在我如何把它转换成一个网页?
嗯,在我们着手把这些数据放到网页上之前,我们确实需要认真考虑我们的数据的哪一方面是我们想要呈现给我们的观众的。此外,由于 D3.js 可以很好地处理以JavaScript Object Notation(JSON)格式 格式化的数据,我们必须在构建可视化之前进行一些数据转换。
因为我想创建一个世界地图,所以我们也在处理地理坐标,它采用了一个更具体的 json 结构,称为“geojson”。
什么是 geojson?
简而言之,geojson 结构是专门用于编码各种地理数据结构的 json 格式的扩展。在 D3.js 中使用地图时,有许多内置函数和过程依赖于以 geojson 或 topojson 格式定向的数据。这两者的区别可以在这篇 stackoverflow 帖子 中详细概述。我们将使用的格式 geojson 采用以下结构:
**{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [38.00,−97.00]
},
"properties": {
"name": "United States"
}
}**
对于上面这个简单的例子,我们可以看到,当这个数据被读入 D3.js 时,它会在相邻的美国的正中心画一个点(或点)。提到的“几何”是“点”的类型,附加到该点的“坐标”是该点将在网页上绘制的位置。您还可以将特定的属性附加到一个点上,比如一个“名称”,D3.js 也可以引用它(稍后我们将看到它在我们的调色板中发挥作用)。
虽然这是一个简单的例子,但你可以想象当你画特定的多边形(或形状)时,“坐标”会变得更长。本质上,当处理多边形时,您需要一个彼此相连的点的列表。每个多边形都有一组基于特定投影的坐标,然后这些坐标被渲染到页面上。作为一个实例,如果我们要查看内华达州的多边形坐标,您可以在下面找到它:
**{
"type": "Feature",
"properties": {"name": "Nevada"},
"geometry": {
"type": "Polygon",
"coordinates": [[[-117.027882,42.000709], [-114.04295,41.995232],[-114.048427,37.000263],[-114.048427,36.195153],[-114.152489,36.025367],[-114.251074,36.01989],[-114.371566,36.140383],[-114.738521,36.102045],[-114.678275,35.516012],[-114.596121,35.324319],[-114.574213,35.138103],[-114.634459,35.00118],[-115.85034,35.970598],[-116.540435,36.501861],[-117.498899,37.21934],[-118.71478,38.101128],[-120.001861,38.999346],[-119.996384,40.264519],[-120.001861,41.995232],[-118.698349,41.989755],[-117.027882,42.000709]]]
}
}**
我们可以看到,“几何图形”比我们的第一个例子长得多,“类型”现在是多边形而不是“点”。“坐标”是根据所使用的投影列出的,然后会呈现在页面上。
使用 python 将。csv 到。json
有了 geojsons 的新知识,我设计了一个计划,从 Kaggle 获取包含气候变化预测的 csv 文件,并最终将它们转换为 D3 的 json 文件。尽管许多数据操作可以通过许多 D3s 内置函数在 JavaScript 中正确完成( 您可以将 csv 数据直接读入 JavaScript ),但我认为在将数据加载到网页之前操作数据会更有效,因为数据集是静态的(不依赖于对第三方 API 的访问/连接)。这样做的好处是,它应该使代码更高效,我们的可视化更敏捷,并减少页面加载时渲染地图和图表所需的时间。
为此,我使用了 python。你可以在 Github 上找到记录我的数据转换的整个 jupyter 笔记本。
总之,在阅读了 Kaggle 的 csv 文件后,我首先必须对各种日期范围和模型输出进行大量的数据汇总。然后,我基本上采用了一个公共 geojson 文件,该文件包含世界上所有国家的多边形,并将 Kaggle csv 文件中的温度数据和其他属性(利用属性信息中的公共标识符)合并到每个国家的属性中。在最后一段代码中,我创建了一个自定义函数来将数据帧输出为 json 文件:
**# array of pandas dataframes with our various model data across the four time intervalsdataframes = [first20_med_a2, first20_med_b1, second20_med_a2, second20_med_b1, third20_med_a2, third20_med_b1, fourth20_med_a2, fourth20_med_b1]# empty array of json files that eventually will load in datajson_files = ['first20_med_a2.json', 'first20_med_b1.json', 'second20_med_a2.json', 'second20_med_b1.json', 'third20_med_a2.json', 'third20_med_b1.json', 'fourth20_med_a2.json', 'fourth20_med_b1.json']# custom function to take the pandas dataframes and store them in separate json filesdef createjsons():
for idx, d in enumerate(dataframes):
for i in features:
for index, row in d.iterrows():
if(row['Country'] == i['id']):
i['Change_c'] = row['Change_c']
i['Change_f'] = row['Change_f']
i['Date_range'] = row['Date_range']
i['Percentile'] = row['Pctile']
i['Scenario'] = row['Type']
else:
pass
with open(json_files[idx], 'w') as outfile:
json.dump(gj, outfile)createjsons()**
这一步的最终目标是创建单独的 json 文件,存储国家名称、温度变化(摄氏度)、温度变化(华氏度)、日期范围、模型计算百分比和场景类型。
正如我们在下面看到的,经过数据整理后,我的最终 json 文件中的一个 country 属性如下所示:
**# I abbreviated the length of the coordinates to cut down on size of code block{
"type": "Feature",
"id": "USA",
"geometry": {
"type": "MultiPolygon",
"coordinates": [[[[-155.54211, 19.08348], [-155.68817, 18.91619], [-155.93665, 19.05939], [-155.90806, 19.33888], [-156.07347, 19.70294], [-156.02368, 19.81422], [-155.85008, 19.97729], [-155.91907, 20.17395], [-155.86108, 20.26721], [-155.78505, 20.2487], [-155.40214, 20.07975], [-155.22452, 19.99302], ...]]]
},
"properties": {
"name": "United States of America",
"Change_c": 1.5040905413108334,
"Change_f": 2.7073629743595,
"Date_range": "2020-2040",
"Percentile": "median",
"Scenario": "a2"
}
}**
与上面的快速 geojson 示例类似,我们可以看到我们正在利用许多点来创建我们的美国多边形,但是我使用 python 来合并附加的“属性”,以便稍后用于我的可视化。我们很快就会看到,change_f
值将用于我们的 choropleth 着色。
json 文件准备就绪后,我们可以开始想象我们的可视化会是什么样子。从用户的角度来看,我们希望显示土地温度随时间的变化,这可以通过读取特定时间间隔内的 json 文件来实现——所有这些都通过 D3.js 制作成动画。
数据整理已经够了!是时候用 Angular 建立一个网页了。
好吧!现在我们已经准备好了数据文件,我们可以启动一个本地单页面应用程序。
根据您想要使用的 JavaScript 框架,您需要下载命令行界面(cli)来启动本地开发服务器和包管理器。
对于这个例子,我们将使用的包管理器是 npm。安装 npm 最简单的方法之一是下载 node.js,它也将在您的安装中包含 npm。 这方面的说明可以在这里 找到。
作为我们的 Javascript 框架,我们将使用 Angular。为了简化我们的操作,您可以下载 Angular cli 来启动开发服务器。 这里的指令可以找到 ,由四行组成。
下载 node.js 和 Angular cli 后,可以打开 VSCode 终端窗口(或任何终端窗口)并运行以下命令:
**// make sure npm is installed on your computer before running this:**npm install -g @angular/cli****
安装完成后,在你的电脑上找到一个你想要存储应用程序文件的地方,然后运行(将“我的梦想应用程序”改为你想要的目录名称):
****ng new my-dream-app****
这将需要一两分钟才能完全运行,但最终它将创建一堆文件,这些文件包含您的新 Angular 应用程序,并提供编译所需的目录结构。当命令完成时,您可以导航到新的应用程序文件夹并运行“ng serve”来启动开发服务器。
**// change directories into your new angular application**cd my-dream-app**// start the development server**ng serve****
如果一切运行正常,您应该能够编译新创建的 Angular 应用程序,并在您的终端中看到:
如果您的 Angular 应用程序编译成功,您应该会在您的终端窗口中看到此消息
为了保持这一部分的简短,我不会深入讨论 Angular 如何工作的更多细节,但如果你对 Angular, 完全陌生,请阅读这篇精彩的帖子 以了解基本的应用程序开发。此外, Angular 文档 对那些喜欢在杂草中获得更多的人非常有帮助。
让我们的网络可视化!
随着我们的 Angular 开发服务器的运行,我们现在可以开始构建我们的可视化。首先,我们需要从 npm 安装 D3.js 包,以便能够在我们的应用程序中使用这个库。为了这个视觉,我决定安装 D3 的版本 4(出于各种原因)。为此,在终端中停止开发服务器(ctrl + c ),并运行:
**npm install d3v4**
完成后,您可以通过运行以下命令来重新启动开发服务器:
**ng serve**
然后,您应该会看到与前面相同的“编译成功”消息。接下来,我们可以将 json 文件添加到应用程序内部的“assets”目录中(下面是文件夹结构):
**|- application-name
|- src
|- assets
|- first20_med_a2.json
|- second20_med_a2.json
|- third20_med_a2.json
|- fourth20_med_a2.json**
你可以在这里 找到这些已经预制好的 json 文件。然而,如果你愿意,你也可以利用上面的 python 脚本。
如果您使用的是 Angular,因为我们使用的是 Typescript,您可能还需要做一个快速配置,将 json 文件直接加载到 app.component.ts 文件中。 这篇文章 很好地总结了如何做到这一点。很可能,您只需将下面一行加粗的代码添加到您的 tsconfig.json 文件中:
**{
"compileOnSave": false,
"compilerOptions": {
.
.
.
**"resolveJsonModule": true,**
.
.
.
}
}**
渲染我们的第一张地图
随着我们的 json 数据存储在应用程序目录中,D3 库导入到我们的 node_modules 中,Angular 准备好接受 json 文件,我们可以开始在 web 上看到数据可视化的威力了!
为了呈现我们的一个 json 文件,我们首先需要确保我们在 app.component.ts 文件中引用它(下面是文件夹结构):
**|- application-name
|- src
|- app
|- **app.component.ts****
导航到 app.component.ts 文件,通过将加粗的代码添加到现有代码中,将 json 数据导入到组件中:
**import { Component} from '@angular/core';
**import * as d3 from 'd3v4';****// load the json file from the assets folder, give it a name**
**import * as firstModel from '../assets/first20_med_a2.json';**@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})export class AppComponent { **// make sure to reference the correct structure
firstModelData = firstModel['default'];** ngOnInit() { ** // print the json data in the browser console
console.log(this.firstModelData)** }
}**
保存这个文件,返回到您的浏览器,如果一切顺利,您应该能够在页面刷新后在开发工具中看到 json 数据打印到控制台:
Geojson 数据打印到 Google Chrome 控制台|作者图片
然后,我们需要删除 app.component.html 文件中的默认 html 语法,并创建一个快速的“div”。导航到 app.component.html 文件(文件夹结构如下):
**|- application-name
|- src
|- app
|- **app.component.html****
然后,删除当前存在的所有 html 代码,并添加以下 div:
**<div class = "world-map"></div>**
现在,json 数据读入组件,我们可以开始编写 D3.js 函数了。导航回 app.component.ts 文件,并在 AppComponent 类中编写下面的粗体代码:
**export class AppComponent { firstModelData = firstModel['default']; ngOnInit() {
console.log(this.firstModelData) } **setMap(width, height, dataset) {** **const margin = {top: 10, right: 30, bottom: 10, left: 30};
width = width - margin.left - margin.right;
height = height - margin.top - margin.bottom;** **const projection = d3.geoMercator()
.rotate([-11, 0])
.scale(1)
.translate([0, 0]);** **const path = d3.geoPath().projection(projection);** **const svg = d3.select('.world-map')
.append('svg')
.attr('viewBox', '0 0 1000 600')
.attr('preserveAspectRatio', 'xMidYMid')
.style('max-width', 1200)
.style('margin', 'auto')
.style('display', 'flex');** **const b = path.bounds(datapull),** **s = .95 / Math.max((b[1][0] - b[0][0]) / width, (b[1][1] - b[0] [1]) / height),** **t = [(width - s * (b[1][0] + b[0][0])) / 2, (height - s * (b[1][1] + b[0][1])) / 2];** **projection.scale(s).translate(t);** **svg.selectAll('path')
.data(datapull.features)
.enter()
.append('path')
.attr('d', path)** **}**
}**
简而言之,这段代码声明了一个函数setMap()
,它接受三个参数:宽度、高度和我们的数据集。然后,它定义一个边距,并从画布的所有四边减去边距像素。接下来,由于我们使用的是地图坐标,我们必须定义一个 地图投影 ,稍微旋转地图,这样俄罗斯的最东部就不会出现在画布的左侧,并设置我们的比例和平移。然后,我们将这个投影映射到我们的路径上,这将最终基于我们的投影输入和我们定义的画布尺寸来绘制我们的多边形。
然后,通过使用语法“d3.select(”选择空白 div 来创建我们的第一个 svg。世界地图”)。通过将 svg 附加到我们现有的 div,然后我们设置尺寸,并通过使用 viewBox 和 preserve spectra ratio 使其响应,并最终设置 1200px 的最大宽度,并将地图置于页面的中心(如果视口大于 1200px)。
然后,我们希望确保比例和平移图正确,并且我们画布的定义边界正确,因此变量s
和t
帮助定义我们墨卡托投影的边界。
最后,我们选择新添加的 svg,读入 geojson 特性,并在页面上绘制路径!为了在页面上呈现,我们需要使用实例化的函数并在ngOnInit()
中调用它。将这行代码添加到 ngOnInit()函数内的 app.component.ts 文件中。
**ngOnInit() {
console.log(this.firstModelData) // add this line of code below to render your map: **setMap(1000, 600, this.firstModelData)**}**
如果一切顺利,您应该会在页面上看到类似这样的内容:
setMap()函数首次渲染世界地图|图片作者
好吧!现在我们有所进展了!然而,不幸的是,我们的多边形填充是黑色的,我们希望根据以华氏度为单位的温度变化来创建每个国家的 choropleth 颜色。还记得我们使用 python 将该数据合并到每个国家的属性中吗?好了,现在我们可以使用每个国家的change_f
值来区分我们的填充颜色!
为此,我们可以在我们的setMap()
函数中添加以下代码(仍然在我们的 app.component.ts 文件中),然后向我们的 svg 添加一个属性:
**setMap(width, height, dataset) {**...****const color_domain = [2.5, 4, 7, 9, 10];****const color_legend = d3.scaleThreshold<string>().range(['#fee5d9', '#fcbba1', '#fc9272', '#fb6a4a', '#de2d26', '#a50f15']).domain(color_domain);****...**svg.selectAll('path')
.data(datapull.features)
.enter()
.append('path')
.attr('d', path)
**.style('fill', function(d) {
const value = d['Change_f'];
if (value) {
return color_legend(d['Change_f']);
} else {
return '#ccc';
}})
.style('stroke', '#fff')
.style('stroke-width', '0.5')**}**
简而言之,我们可以使用 D3.js 中的 d3.scaleThreshold()函数来帮助我们创建 choropleth 调色板。由于时间的原因,我不会深入讨论这个问题,但是如果你有兴趣的话,你可以在这里 阅读更多关于这些秤的信息。此外,在将属性添加到我们的路径之后,我还将多边形(国家)的轮廓变得更粗和更灰。
如果这些附加功能正常工作,您应该会在页面上看到以下内容:
添加色标后的地图渲染|图片由作者提供
让我们来制作动画!
如果你已经做到了这一步,你绝对可以拍拍自己的背!可视化的最后一步是在不同的时间间隔内制作动画。如果你还记得从一开始,我们的目标是显示每个国家在四个不同时间间隔的温度变化:
- 2020 年到 2040 年
- 2040 年至 2060 年
- 2060 年至 2080 年
- 从 2080 年到 2100 年
正如你现在看到的,我们能够用一个 json 文件创建一个静态 choropleth 地图,显示 2020 年到 2040 年之间的温度变化。然而,为了使它在其他三个时间间隔内具有动画效果,我们希望在一段时间内将其他 json 文件加载到这个函数中。D3.js 使这变得相对容易。
首先,我们必须将其余的 json 文件加载到我们的 app.component.ts 文件中,类似于上面的第一个文件。为此,您可以添加下面几行加粗的代码:
**import { Component, OnInit } from '@angular/core';
import * as d3 from 'd3';**# load the rest of the json files from the assets folder, give it a name**
import * as firstModel from '../assets/first20_med_a2.json';
**import * as secondModel from '../assets/second20_med_a2.json';
import * as thirdModel from '../assets/third20_med_a2.json';
import * as fourthModel from '../assets/fourth20_med_a2.json';**@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})export class AppComponent {**# make sure to reference the correct structure** firstModelData = firstModel['default']; **secondModelData = secondModel['default'];
thirdModelData = thirdModel['default'];
fourthModelData = fourthModel['default'];****jsons;**...ngOnInit() {...}**
然后,我们需要在页面加载时将 json 文件存储在一个数组中。因此,我们可以将其添加到我们的ngOnInit()
函数中:
**ngOnInit() {...**this.jsons = [this.firstModelData, this.secondModelData, this.thirdModelData, this.fourthModelData]**...}**
现在,为了让我们的动画工作,我们必须在我们的setMap()
函数下面创建一个新函数,叫做transitionMap()
:
**transitionMap(json, i) { const svg = d3.select('.world-map');
const color_domain = [2.5, 4, 7, 9, 10]; const color_legend = d3.scaleThreshold<string>().range(['#fee5d9', '#fcbba1', '#fc9272', '#fb6a4a', '#de2d26', '#a50f15']).domain(color_domain); svg.selectAll('path')
.data(json[i].features)
.transition()
.delay(100)
.duration(1000)
.style('fill', function(d) {
const value = d['Change_f'];
if (value) {
return color_legend(d['Change_f']);
} else {
return '#ccc';
}
})}**
这个函数将接受两个参数,json 和迭代器值,迭代器值将作为 json 数组的索引号。当调用该函数时,它将选择我们的地图 svg,刷新调色板,然后用相应 json 中引用的数据重新绘制我们的地图。因为我们的。data()函数正在引用 json[i],我们可以循环遍历刚刚创建的 json 数组,并在延迟一段时间后连续加载每个 json 文件。
现在,我们可以使用 Javascript 中的 setInterval()函数设置一个时间间隔来定义我们的“I”值。通过将以下代码添加到我们的 ngOnInit()函数的底部,该过程将在页面加载时开始:
**ngOnInit() {... let time = 1; let interval = setInterval(() => {
if (time <= 3) {
this.transitionMap(this.jsons, time)
time++;
} else {
clearInterval(interval);
}
}, 2000);}**
如果工作正常,您的页面上应该有一个成功的动画 choropleth 地图呈现:
最终 D3.js 地图动画|图片作者
恭喜你!接下来呢?
如果你已经看完了,我相信你可以开始想象一些额外的东西可以添加到这个可视化中——包括第二个气候变化场景的四个 json 文件。
对于添加按钮、滑块、图例和附加数据的代码,可以去我的 Github 拉更多我的代码!
把这一切放在上下文中
最后,本文的目标是为 web 构建一个相当复杂的地图动画。我们处理了一些不同的项目,从 python 中的数据整理,到基本的 web 开发原则,以及各种可视化技术。我希望你喜欢使用这个数据集,我鼓励那些有问题的人随时联系我。
此外,如果你喜欢这篇文章,请随时查看我的更多故事,在那里我讨论了我感兴趣的其他主题——即数据工程、机器学习等等!
也可以登陆我的网站【zach-alexander.com】联系提问!感谢阅读!
利用数据科学改善教育系统:印度尼西亚案例
变更数据
数据科学如何在实现印度尼西亚 2045 年教育路线图中发挥重要作用
我在印度尼西亚的小学建筑(来源:作者)
背景
学习是为了乐趣,所以学校应该是一个快乐的地方。这就是我在美国读小学时的感受。每节课都有一种令人兴奋的感觉,从做课堂项目的兴奋到看到我的老师装扮成她的科学家化身的幽默。我积极地和我的同学一起参加这些学习会议,我的老师是主持人,确保所有的声音都被听到。然而,当我搬到印度尼西亚时,我看到了如此显著的不同:学习主要是为了取得好成绩。课堂基本上是记忆课本和数学测验。主要目标是获得高分和班级前三名。老师被视为家长,而不是促进者。这改变了我对学校的看法,从一个快乐的地方变成了一种义务。然而,我现在很兴奋地看到变化即将到来。
2019 年,佐科·维多多总统任命科技独角兽 Go-Jek 的联合创始人 Nadiem Makarim 担任教育和文化部长,以改革这一体系。几个月后,他的团队发布了 2020 年至 2045 年的路线图,我觉得这非常令人兴奋。该路线图旨在通过一项名为 Merdeka Belajar (学习自由,这是下表所示的一系列系统性变化)的倡议,让年轻人更好地应对全球挑战。
来自 Merdeka Belajar 倡议的指示(来源:作者的分析)
这一举措将在大约 600 所学校进行试点,分为两组,100 所发达学校和 500 所发展中学校,根据准备情况区分不同的方法。试点小组的目标是到 2025 年底扩大到 10,000 所学校,并在未来十年内扩大到 30,000 所学校。学生应培养他们解决问题、认知和社交的技能,以体现以下特征:
- 高尚的
- 自主的
- 创造性的
- 合作的
- 批判思想家
- 全球意识
由于这似乎是一个伟大的方向,我的主要问题是如何确保正确的执行。这就是数据科学派上用场的地方。教育部确实在开发数字平台,以促进利益相关者的合作,提高学习效率。此外,这将是一个很好的工具,可以生成大量数据来收集关于该倡议实施情况的见解。要开始数据科学项目,我们需要首先定义项目章程,这将在下一节中讨论。
定义项目章程
在我们进入技术细节之前,我们必须首先确定目标、分析方法和利益相关者,这就是所谓的项目章程。就印度尼西亚的教育路线图而言,我们的目标是:
- 默迪卡·贝拉加测试在培养学生解决问题、认知和社交技能方面是有效的。
- 确定方向是否正确执行。
- 找出执行中的主要差距。
第一个目标需要一个最能代表有效性的北极星指标。根据路线图的最低评估部分,最好的衡量标准是学生在读写和计算方面的能力增长。这可以通过对默迪卡·贝拉加倡议前后的直接比较来实现。根据目标实现情况(使用公平基准)或与非试点学校的显著差异,试点学校的结果可被视为良好。
另一个值得考虑的北极星指标是评估学生的认知、社会意识和现实生活中解决问题的能力。这种方法可以使用能够捕捉这些方面的在线文章来专注于特定的主题。历史可能是一个很好的题材。我上学的时候,历史主要是记忆关键的日期和事件。除非老师鼓励,我的老师就是这么做的,否则学生不需要在这门课中运用批判性思维和解决问题的技巧。在这种情况下,可以向控制组(非飞行员)和治疗组(飞行员)提供在线论文。问题应该是:“从印度尼西亚的殖民历史中吸取教训,政府需要什么样的政策和制度来保护自己免受外国的剥削?”一个可接受的答案将提供殖民时期的真实案例,找出根本原因,并提出一套政策来防止类似事件在未来重演。对关键词进行分类的高级机器学习算法可用于预评估,以及专家的最终评估。论文评估结果将有助于确定的有效性。
对于下一个目标,我们需要对两组学生进行深入分析。Merdeka Belajar 可以作为一个框架,根据北极星标准来决定将学生分为哪几类。通过提取正确的数据,我们可以看到哪些领域存在重大差距,需要立即采取行动。
该分析可以转化为决策树,如下所示,以确定利益相关者的行动项目:教师、校长、地方当局和教育部。
印度尼西亚教育利益相关者决策树(来源:作者的分析)
为了应用这个决策树,需要一个完整的数据框架,这将在下一节讨论。
获取数据
在进行分析之前,我们需要确定如何提取、转换数据并将其加载到适当的数据库中。教育部目前有一些在线平台,如用于虚拟学习的 Rumah Bela jar(Study House),作为学校校长电子预算和商务平台的 Marketplace BOS,以及作为教师工作场所平台的 T2 Guru ber bagi(教师共享)。这些平台将有助于获取学校内部生态系统、教师表现、课程、教学法和评分系统的数据。地方当局也有平台更新学校的地理信息,以了解其当前的环境。父母也应该有一个平台,这样他们的参与程度就可以被追踪。将需要所有这些特征来提取关键成分以形成数据帧。请注意,非试点学校也需要这样做,以便进一步比较。
主要平台功能的主要数据输出(来源:作者的分析)
创建数据帧
数据框架中最重要的元素是拥有惟一的 ID:学校 ID、教师 ID 和学生 ID。这将使我们能够创建与各种数据集的关系,并形成一个整体数据源。下一步是将从平台中提取的数据转换成定义好的可量化指标。我想出了一些如下陈述:
我们模型的数据框架的关键列及其逻辑(来源:作者的分析)
在这些数据集被提取、转换并加载到数据仓库后,我们现在可以创建 DataFame 进行深入分析,如下图所示。请注意,数据应该处于相同的时间框架级别,在这种情况下,应该是每半年一次。
组装主要数据框架(来源:作者的分析)
应用数据科学模型
有了最终的数据框架,我们可以通过简单的分析得出关键的见解。我们可以创建简单的图表或重点表格,将北极星的结果与目标学校和/或非试点学校进行比较,并确定每个类别的主要差距。这种数据可视化将有助于为利益相关者提供总体分析。为了进行深入分析,我们可以使用数据科学来识别学生能力倾向增长或在线作文分数背后的关键因素。
我想到的第一个数据科学模型是 k-means 聚类。该算法将识别 k 个质心,然后基于相似性将学生聚类成 k 个组。一旦结果准备就绪,我们就可以看到哪些是最主要的集群,并根据最突出的指标进行描述。
k 均值聚类的例子(来源:scikit-learn.org)
在这种特殊情况下,我们可以从使用 k-means 算法对学生进行聚类开始,根据 6 个维度定义试点学校学生的共同特征。结果不仅会显示符合北极星标准的学生比例,还会显示他们的相似性。例如,数据可能会显示聚类 1 不仅在北极星中得分高,而且在生态系统和教育学方面也得分高,而聚类 2 则相反。下一步将是确定每个学校的主导集群,并根据决策树确定所需的支持类型。
使用线性回归模型,数据科学还可用于预测学生在应用改进措施后的北极星指标成绩。这个模型可以被设计来计算因果影响,北极星上升,从一套行动,以确定其有效性。它的工作方式是在没有干预的情况下,将实际结果与预测进行比较。这种预测将基于控制组,控制组可以是来自具有相似特征的非试点学校的学生。
线性回归的例子(来源:stackoverflow.com
结束语
当前的技术使我们能够收集和处理无限量的数据,并投入使用,包括改善教育系统。拥有多个数字平台,我很高兴看到数据科学如何帮助印度尼西亚教育部确保 2045 年路线图的无缝执行。本文中讨论的模型和技术只是一些例子,还有很多方法可以探索和分析教育发展的进程。
然而,主要的挑战实际上是解释和交流数据见解,以便做出正确的决策。总会有这样的情况,利益相关者由于对当前行为的强烈信念而选择否认这样的发现。有些人可能还会通过走捷径来实现指标,比如在能力测试之前上强化课,或者报告不符合实际的课程。另一个挑战是公众对试点和非试点学校的潜在抗议,因为许多利益攸关方可能对成为实验对象有负面看法,反之亦然。
然而,有了像 Nadiem Makarim 这样一位强有力的杰出领导人,我坚信这一路线图能够实现,数据科学将在其中发挥关键作用。从个人经验来说,我衷心希望印尼的下一代;在每个省、市、镇、村;将学校视为一个有趣的学习场所,而不仅仅是一种义务。
利用数据科学造福社会:移民及其致命路线
移民及其最终旅程的数据探索
过去——火车旅行
2016 年一个晴朗的夏日,我在从萨格勒布到维也纳的火车上,穿梭于欧洲各国首都之间,欣赏着窗外的风景,喝着小杯咖啡,做着客户演示。在距萨格勒布约 50 英里的小城瓦拉日丁,有一个短暂的预定停留,数百人开始涌入火车;他们无处不在——坐在厕所附近的地板上,随身带着袋子,里面装着他们曾经在自己国家生活过的小样本。一个家庭(我猜想)也进入了我的车厢,我拿起了放在一个空座位上的夹克;已经在车厢里的女乘客和我互相看着对方,我们通过眼睛对情况进行了短暂的非语言交流,并不情愿地接受了事情的现状。
凯蒂·穆姆在 Unsplash 上的照片
火车从车站开出后,这家人似乎有点舒服,清点了他们所有的财产。我开始和他们交谈,问他们要去哪里,他们用蹩脚的英语说,只要安全,他们就可以开始新的生活。我了解到他们来自叙利亚,夫妻俩都是一个村庄的教师,乘船到达希腊海岸,就在这时,一个小孩抱怨说饿了,打断了我们的谈话;这位母亲迅速在盒子里变出少量燕麦片,并从一个锡罐里拿出 baklava 形状的长面包,分成 8 块,分发给车厢里的每个人。我礼貌地拒绝了几次,但她很坚持,我勉强接受了。他们在火车上呆了一个小时左右,剩下的旅程多少有些沉默,只有断断续续的对话。我们互道再见,我告诉他们注意安全,并祝他们接下来的旅程好运。那次小小的互动就这样结束了。
我陷入沉思,决定写一篇关于这件事的博客,但我从来没有这样做。
现在——一项分析
几周前,我偶然发现了失踪人口项目和相关数据,它刷新了我对火车事故的记忆。所以,我花了一些时间在数据中寻找一些令人大开眼界的事实。
这篇文章并不是展示数据科学的能力,所以我不会在文章中添加代码块,但是如果你想继续,那么 GitHub 上有 python 代码和数据。 此外,我决定给主题赋予更多的单色观想。这是我的一点小小的尝试,来揭示一些人为了拯救自己的生命而不得不经历的致命而危险的旅程。
失踪移民项目正试图捕捉尽可能多的关于移民的信息,这些信息来自无数的来源——其中一些是合法的,其余的可能出于各种目的而被少报。esp 有很多缺失的数据。对于…
- 幸存者人数,85%失踪——人们可能在上岸后失踪,或出于政治原因,如安抚公民,没有太多的移民进入该国。
- 幸存儿童人数,86%失踪——轻微贩卖。
- 移民路线,55%失踪——由于政策,幸存者可能不告诉他们采取的确切路线,或者他们甚至不知道他们在哪里。
我处理了丢失的值,并更深入地查看了数据。数据时间线为 2014 年 1 月至 2021 年 2 月。
最主要的死因
溺水导致大多数死亡(图片由作者提供)
不出所料,溺水死亡人数最多。正如我所收集到的,数百人在几周的时间里乘着小船,任凭风的摆布,到达岸边。这些数字是根据找到的尸体数量估算的。你把浩瀚的大海和无情的暴风雨天气添加到图片中,然后进行计算。在我看来,x 轴上的数字更低。
致命的岁月
作者图片
不出所料,2016 年是移民危机新闻最多的一年。2020 年将会下降,但这可能是由于新冠肺炎或资源缺乏。
致命区域
地中海和北非仍然是温床(图片由作者提供)
地中海和北非的死亡人数最多,这可能是因为试图逃离该地区的人数太多。我从图表中选择的两个地区是美墨边境和东南亚。我确实知道中美洲的移民,但我从未把它等同于非洲/中东向欧洲移民的水平,尽管我知道洪都拉斯、危地马拉和尼加拉瓜的独裁政府以及委内瑞拉的失败经济。此外,孟加拉国移民到印度和缅甸的罗辛亚危机都是有据可查的新闻,但我没有与之相关的数字。
让我把死亡和幸存的人数加起来,看看移民的规模。
作者图片
看看数据告诉我们的在地中海前线所做的尝试的绝对规模。在大约 60,000 次尝试中,有 40,000 次成功,成功率超过 65%。
死亡原因
鉴于大多数路线是水上的,我预计大多数死亡是由于船只倾覆和船只失事。
地中海的数据高达 10k,我将其限制为 3k,这样人们也可以看到其他地区的条形高度(图片由作者提供)
美墨边境因枪击事件而闻名,但不知何故在这里却没有被捕捉到;上面写着死因是 【不明遗骨】 。大多数人步行几个月,他们的朋友和亲戚可能会在他们找到的任何地方埋葬他们,这就是骨骼遗骸出现在顶部的原因。
溺水仍然是大多数移民旅程的首要死因。
死亡时间表
对不起,坏的 x 轴,我知道它可以做得更干净,但我不记得如何。(图片由作者提供)
2016 年夏天的新闻充斥着欧洲移民危机,同样的情况也反映在上面的图表中,2016 年 5 月达到了顶峰。
出现峰值可能是因为两个原因:
- 2016 年 2 月,一条 125 英里长的反移民壕沟竣工,这条壕沟沿着突尼斯-利比亚边境延伸
- 北非的严重干旱(来源)
夏季月份预计会有更多的活动。
五月、六月、九月死亡人数最多(图片由作者提供)
迁徙旅程的温床
从上面的数据可以看出,我希望北非——靠近利比亚、中美洲和东南亚的地区——会被突出显示。
在地图上画出同样的东西,揭示了符合预期的真相。
作者图片
在过去 6 年的约 4 万例死亡中,我们没有信息对其中的约 2.8 万例进行分类。这表明,所有这些数字都是估计的,实际数字可能比我们面前的数字高得多。
作者图片
未来——未知的深渊还是希望?
尽管受到全世界的关注,这场危机仍然规模巨大。大规模的努力正在解决这个问题,但是到目前为止所取得的成绩是微不足道的。我知道这是一个多层面的危机,解决起来一点也不容易,但我们必须找到解决办法,否则人数将继续增加。
从火车上不知道家里发生了什么;我希望他们到达了他们想去的地方,开始了远离动荡的新生活。
Kein mensch 是非法的(没有人是非法的)
没有人是非法的(来源)
现在使用数据科学技能:让你的猫快乐。
使用 streamlit 和 API 在 30 分钟内创建一个亚马逊搜索 web 应用程序
图片由来自 Pixabay 的 Markus Bieck 提供
学习数据科学的组成部分既简单又有趣。无论是学习还是教授概念,关键之一就是要让它变得有趣。不是所有的概念都需要同时学习。简单点。让它变得有趣。
在数据科学中,你是否能挖掘出新的见解或训练出最好的模型可能并不重要。数据科学的一个重要方面是让您的用户或业务合作伙伴可以访问结果。一种方法是创建简单的交互式 web 应用程序来展示调查结果并与之交互。
在你开始学习高级技术之前,先试着做一些简单的事情。例如,你能以一种让你的猫感兴趣的方式呈现数据吗?
第一步:你的猫对什么感兴趣?
关键是找到感兴趣的话题。在这种情况下,什么话题能让你的猫保持兴趣?比特币?大概不会。猫薄荷玩具?现在你有所发现了。
第二步:数据在哪里?(5 分钟)
第一个想到的地方可能是亚马逊。这似乎是一个合理的初步猜测。
好的,你如何从亚马逊获得产品数据?你既不是合伙人也不是销售人员,所以你需要寻找外部 API。
一个快速的谷歌搜索就把我们带到了雨林 API。有 30 天的免费试用期(100 个电话)。免费很好。
同样好的是,有一个 API Playground 来帮助您生成可以在 web 应用程序中使用的 python 代码。注册并获得你的第一个代码片段不到五分钟。
使用 API Playground 创建代码片段—作者截图
3.构建一个简单的 Web 应用程序(5 分钟)
我强烈推荐 streamlit,它是一个快速简单的 web 应用程序。我已经在几个数据科学应用中使用过它,并且很满意。以后如果需要规模化,可以考虑 dash。但是现在,让我们看看 streamlit。
streamlit 的美妙之处在于您需要安装软件包,创建一个简单的。py 脚本,并运行应用程序。嘣,你跑了。你可以在一个窗口中更新代码,当你点击重新运行时,应用程序会自动选择更改。太棒了!
就我而言,我创造了一个新的环境。激活新环境后,我进行了 pip 安装 streamlit。我运行了一个简单的命令,然后我启动并运行了下面这个世界上最简单的脚本。说真的,就是这么简单。
运行 streamlit 应用程序—作者截图
进行代码更改并保存;Streamlit 提示您重新运行以获取更改—作者截图
4.剪切并粘贴我的雨林 API 代码(1 分钟)
我的下一步是将雨林 API 代码剪切并粘贴到我的脚本中,看看我在处理什么。在 streamlit 中使用 st.write(xx)而不是 print(xx)。
剪切、粘贴、重新运行—作者截图
5.重复直到你满意为止(15 分钟到 15 年)
因为我更喜欢使用数据帧而不是 JSON,所以我修改了 JSON 响应来创建更好的数据帧。这是它在幕后的样子。
将 JSON 转换成可读的数据帧——作者截图
我添加了两个按钮来选择两个特定的搜索。另一种选择是使用文本输入进行搜索。您可以很容易地看到如何将这个框架应用于 Amazon 搜索工具。
作者截图
下面是您可以运行的最终代码——当然是使用您自己的 API 密钥。
后续步骤和结论
进行调整和创建新的网络应用程序很简单。只要对我们的 cat 应用程序做一些调整,我们就有了一个通用的亚马逊产品搜索 UI。
作者截图
仅仅 5 分钟的编码就让我在一个交互式数据框架中显示原始数据,并将结果保存到一个. csv 文件中。您可以很容易地看到如何从一个有趣的小应用程序发展成为一个有用的数据科学工具!
作者提供的交互式数据帧的 gif
感谢您的阅读,我希望您能在创建自己的 web 应用程序时获得一些乐趣!通过添加新功能(图表、图形)慢慢增加你的技能,在你知道之前,你会用你的 viz 技能给每个人留下深刻印象。
使用数据科学预测负面客户评论
提高客户满意度,同时优化您的业务
如果你能自信地预测到一个顾客会留下一个负面评价,你的企业会有什么不同的做法?
- 主动干预以改善客户体验,并希望转移他们留下不好的公众评论分数?
- 从预测模型中的重要功能中学习,以解决客户体验不佳的根本原因?
在仔细考虑了成本效益权衡和公司实施纠正措施的能力后,答案是“是”。
“负面评论说服了 94%的消费者避开一个商家”——评论追踪者
商业问题——糟糕的顾客评价
巴西面向小企业的领先电子商务市场是 Olist。Olist Store 使巴西各地的商家能够使用 Olist 物流合作伙伴向客户销售和运送产品。交付后,客户会收到一份电子邮件满意度调查,使用 1(不满意)到 5(满意)的评分标准。
Olist 友好地发布了 2017 年至 2018 年超过 10 万笔交易的匿名客户评论和订单详情。这个流行的数据集已经被数据科学家下载了超过 76K 次。
按作者分类的 Tableau 图表
让我们为“坏顾客评论”建立一个预测模型,定义为在 5 分制中得到 1 分或 2 分。在我们已交付订单的大样本中,13.2%的评论得分为差(负面)。
我们将求解一个二元目标变量:review_bad = 1。
我们的目标是找到一个受监督的机器学习分类模型,它可以以最佳精度预测糟糕的客户评论。
高精度表明,当我们的模型预测一个差评时,它通常是正确的。这最大限度地降低了公司对预测的负面客户评论采取不正确行动的风险。
将数据转换为要素
Olist 提供了来自 8 个关系表的数据,它们具有很好的引用完整性。下图显示了一个熟悉的数据模型,它具有惟一的订单 id,便于连接多个商品和每个订单的付款。主数据表包括产品、客户和卖家。客户评论链接到一个整体订单,该订单可以包括多个产品或卖家。
由 Olist 通过 Kaggle 拍摄的图像
8 个表中的原始数据包括 52 个不同的列。我开发的预测功能可以按照这些领域进行分组。
作者图片
为了简洁起见,我没有包括这个项目中使用的全部代码。详情请参考我在 GitHub 上的 Jupyter 笔记本。
用于准备预测特征的数据转换:
- 过滤掉 2016 年的记录和未交付的订单(不到 1%)
- 只填写了少量存在空值的记录
- 如图所示,订单、付款、产品和卖家的综合指标
- 使用订单的生命周期日期计算的天数间隔指标
- 使用哈弗森函数中的中值纬度和经度,估计卖方和客户邮政编码之间的交付距离(公里)
- 为支付方式、客户状态、星期几和一天中的时段(上午、下午等)创建了一次性编码变量(标志)。)
- 清除任何订单的多个评论,仅保留最终评级;这影响了不到 1%的订单
视觉洞察力
在数据分析过程中,我通常将最终合并的数据帧从 Jupyter notebook 导出到 Tableau,以便更快地进行可视化检查。让我们来看看最有趣的观点。
按作者分类的 Tableau 图表
延迟交付天数: Olist 在订购时向客户提供预计交付日期,平均为 24 个预期处理/运输天数。如上所示,实际交付性能非常重要。对于延迟交付的订单(与预计日期的负差异),客户差评平均为 55%,而非延迟交付的订单为 10%。迟到天数越大,差评比例越高。
按作者分类的 Tableau 图表
**卖家-产品质量:**散点图描绘了延迟交付和差评之间的线性趋势,每个观察值都是卖家在所有客户中的平均表现。延迟订单并不能解释整个故事,因为许多卖家的交付绩效高于平均水平(圈出),但差评率更高。
按作者分类的 Tableau 图表
**产品种类:**使用树形图,我们可以看到不同产品类别差评率的变化。深入到一些单个产品,我们可以看到一些差评超过 50%的“狗”,它们显然没有达到客户的期望。产品的平均差评率是最终模型的一个重要特征。
按作者分类的 Tableau 图表
**地理分布:**巴西有 26 个州和 1 个联邦区。我们可以肯定地看到各州之间差评的差异。
- 圣保罗——在我们的数据中,该州占订单的 42%,在每一项指标上都表现出色。
- 里约热内卢——这个邻近的州占订单的 13%,在每项指标上都明显表现不佳。
这两个州都是巴西最大的两个城市之一的所在地,人口密度高,彼此相对接近。里约热内卢应该成为更深入挖掘交付绩效和产品组合的目标。为什么平均而言,客户会订购差评指数相对较高的产品?(148 的产品指数意味着平均购买的产品差评率比巴西整体平均产品差 48%)。
相关性分析
在 Python 中对我们的 review_bad 目标变量运行 Pearson 相关性,在很大程度上证实了我们在之前的图中看到的关联。
作者图片
当查看单个特征相关性时,我们看到所有形式的交付间隔(is_late、act_delivery_days、days_late 和 days_variance)都呈中度正相关。
我们还发现,产品和卖家总体差评率的正相关性分别为 0.23 和 0.17。
最后,我们看到了对订单/卖家商品数量、运费/订单价值和交付距离的一些其他次要影响。在 27 个州中,相关性大于 0.03 的仅有两个州是里约热内卢(+0.07)和圣保罗(-0.06),这支持了上面的州地图。
预测客户差评
七个监督学习分类模型在“精度”指标上进行优化,但寻找合理的“召回”(我们的模型正确预测的差评比例)。对于每个模型,我对 80%的训练数据进行网格搜索,并进行分层的 5 重交叉验证,以探索各种参数组合。
按作者分类的 Tableau 图表
比较的模型包括随机森林、AdaBoost、梯度增强、XG 增强、逻辑回归、SGD 分类器和高斯朴素贝叶斯。
相关特征使用 StandardScaler 进行缩放,因此我将一致的训练特征作为每个模型的输入(即使大多数模型不需要缩放)。
然后,每个分类器的最终“最佳模型”在之前未见过的 20%比例测试数据上运行,比较模型结果如上所示。
我推荐了具有以下性能的梯度增强模型:准确率 84%,召回率 29%,准确度 88%,AUC 64%。最佳估计值的参数为:
'learning_rate': 0.01, 'max_depth': 8, 'min_samples_leaf': 25, 'n_estimators': 100
使用这种具有标准 0.50 概率决策阈值的模型导致预测大约 1/3 的差评(召回),而仅在 6 次中有 1 次是错误的(精确度、假阳性)。这将是采取行动的一个开始,我们希望继续利用经验和更广泛的数据来完善这个模型。
按作者分类的 Tableau 图表
梯度推进模型中最重要的特性包括:
- Strong:延迟交付天数、天数差异、产品差评百分比、订单项目数
- 中等:订单上的卖家数量,卖家差评百分比
- 弱:实际交付天数、产品订单总数、卖方订单总数、订单运费、交付距离(公里)
总之,差评对延迟发货、产品/卖家历史、多个卖家/产品的配合最敏感。 Olist 应努力解决交付绩效不佳的根本原因。Olist 也可以尝试一个随机的成本效益试验,看看主动沟通、承认或客户让步是否可以防止差评被发布。
最终,负面评价是一份礼物。这表明你的顾客非常关心你的品牌,愿意花时间给你留下反馈。如果处理得当,即使是最糟糕的评论也可以变成积极的经历。— 艾米丽·希斯利普
数据质量观察
对数据质量的一些观察和本项目固有的假设。
- 样本与总体:100,000 个订单的样本,每个订单都有一个相关的评论评级,对于构建模型来说很好,但不能代表总体。鉴于只有 5-10%的客户写评论,而且不是每次都写,我们需要做一些工作来翻译我们的模型,以针对全部 Olist 订单进行归纳。
- 需要额外的功能:虽然 84%的准确率预测 29%的差评是一个开始,我们需要做得更好。我建议 Olist 为进一步的功能开发获取额外的数据:订单、客户退货、客户网络日志、客户服务互动、客户角色、人口统计、品牌/产品/卖家社会情绪的完整数据库,以及来自卖家的数据。
- 营销漏斗:Olist 还在 Kaggle 上发布了一个营销漏斗数据集,其中包含来自卖方资格认证流程的 2 个上游表格。当加入订单模式时,该数据不可用,因为它仅包含 2017-2018 年间注册的卖家,代表了这一时期实际订单的一小部分(大多数是由已建立的卖家完成的)。
https://chuckutterback.medium.com/membership
使用数据科学来预测病毒推文
数据科学
你能使用机器学习来预测哪些推文会传播开来吗?
亚历山大·沙托夫在 Unsplash 上的照片
在之前的一篇文章中,我写道为过去的数据科学竞赛构建了一个 XGBoost 模型来预测视频流行度。它涵盖了从加载数据和库到构建模型本身的所有内容。
Bitgrit 最近发布了一个新的竞赛,奖金为 $3000 💵待售商品:
⭐ 病毒推文预测挑战 ⭐
如果你想知道为什么推文会像病毒一样传播,这是你利用数据科学找到答案的绝佳机会!
比赛将于2021 年 7 月 6 日结束,因此注册以获取数据,并跟随本文开始吧!
如果你不能通过付费墙,请点击这个链接阅读这个故事。
目标
开发一个机器学习模型,根据推文内容、推文附带的媒体和发布日期/时间等属性,预测每条推文的病毒级别。
数据是什么样的?
📂 **Tweets**
├──test_tweets_vectorized_media.csv
├──test_tweets_vectorized_text.csv
├──test_tweets.csv
├──train_tweets_vectorized_media.csv
├──train_tweets_vectorized_text.csv
└──train_tweets.csv
📂 **Users**
├──user_vectorized_descriptions.csv
├──user_vectorized_profile_images.csv
└──users.csv
tweets 文件夹包含我们的测试和训练数据,主要特征都在tweets.csv
中,其中有日期、标签数量、是否有附件以及我们的目标变量——病毒率等信息。矢量化 csv 文件是推文文本和媒体(视频或图像)的矢量化格式
“用户”文件夹包含有关用户的关注者和关注计数、推文计数、他们是否被验证等信息。他们的个人简历和图像也矢量化成单独的 csv 文件。
数据之间的关系
用户数据通过user_id
关联,而推文数据通过tweet_id
连接。
下面是这种关系的可视化。
关于竞赛指南部分数据的更多信息。
现在你有了目标和一些给你的数据信息,是时候开始做数据科学任务了,以实现预测推文病毒式传播的目标。
所有的代码都可以在Google collab或者 上找到威风凛凛的 。
注意,出于轻量级的目的,并非所有的代码都包含在本文中,所以请参考笔记本以获得完整的代码。
加载库
与所有数据科学任务一样,您首先要为自己配备完成各种任务所需的库。
加载数据
你可以在 2021 年 7 月 6 日之前在这里报名参赛获取数据。
打印每个数据的形状:
我们可以看出,我们的数据集中总共有 52 个用户有多条推文。请注意,矢量化媒体的行数比推文少,这意味着并非所有推文都有媒体,还要记住,一些推文有多个媒体。这将在合并数据时导致一些问题,但我们稍后会担心这个问题。
还要注意,矢量化的媒体/图像都有相同数量的列/特征——2048,而矢量化的文本都有 769 个特征。
现在让我们继续进行一些探索性的数据分析,以便更好地理解我们的数据。
探索性数据分析
EDA 对于发现数据趋势以及确定需要哪些转换和预处理来为建模准备数据非常重要。
数据是什么样子的
看数据,看起来挺标准的。我们有两个主键、特征和目标变量——病毒率。
但是请注意tweet_topic_ids
是如何包含数组的?稍后,我们将不得不做一些预处理来处理这个问题。
我们的矢量化数据看起来很标准,其中每一列代表数字特征空间中的一个坐标。
现在让我们分析一下我们的 tweets 数据中的特征。
推特数据特征分析
我们的推文中总共有 11 个特征。
首先,我们来看看病毒式传播。
我们看到,平均来说,病毒水平为 2,大部分是 1。
查看时间特征,我们看到来自我们数据的推文在 2020 年有最高的计数,大多数推文是在 12 月和第 27 天创建的。他们也大多在晚上发推文(17 小时)。
继续讨论标签、网址和提及次数。大多数推文没有标签,只有一个网址,也没有提及。
绘制附件类和语言 id,我们看到 A 类是最普遍的,而 b 类很少。至于语言 id,很大一部分是 0,我们可以假设是英语。
大多数推文也有媒体附件。
特征的相关性
现在让我们看看我们的特征是如何相关的,或者换句话说,我们的特征和病毒之间的线性关系有多强。
形象化的一个好方法是使用热图。
从我们的热图中,我们可以看出,我们的特征与病毒传播无关,但一些特征确实彼此相关。
以数值表示相关性,我们看到相关性相当低,其中一些是负的。
尽管如此,这并不意味着我们的特征是无用的,因为它们仍然具有预测能力,所有这一切意味着它们不能“线性地”预测病毒水平。
现在让我们看看我们的用户数据。
用户数据分析
我们在用户中总共有 10 个功能。
可视化计数数据,我们可以观察到,喜欢计数大多在 0 到 5000 个喜欢之间,离群值在 300k 左右。
对于users_followers_count
来说,很大一部分用户在 0 到 100k 的范围内,部分用户的关注者高达 160 万。
对于users_following_count
来说,大部分也在 0 到 100k 的范围内,但也有一小部分超过 1m。
对于users_listed_on_count
来说,他们中的大多数在 0 到 5000 之间,一些用户被列在多达 40 万的名单上。
我们的用户大多拥有 50 万左右的 tweet 数,大多数账户都是在 2011 年和 8 月份创建的。
转到二进制数据,我们的大多数用户在他们的帐户上列出了位置,他们在他们的简历中有一个 URL,并且他们中的大多数没有被验证。
现在我们已经对数据做了一些 EDA,让我们开始为建模做准备。
数据预处理
这些是我们将在这个特定示例中执行的几个预处理任务。注意肯定有各种各样的方法来实现它,更不用说还有更复杂的预处理和特征工程可以做,所以只把下面的方法作为一个例子,而不是一个客观的方法。
处理缺失数据
使用我编写的助手函数(笔记本中的代码),我们将检查行中缺失数据的数量以及用户和推文数据的百分比
在主题 id 列中有一些丢失的数据,所以我们将处理它。我们还将使用热图来可视化缺失的数据,因为这对于搜索特定模式非常有用。我们丢失的数据似乎很分散。
为了处理na
值,我们将用一个 0 — [‘0’]
的数组填充它们,以表示该特定 tweet 没有主题 id。我把它放在一个数组中的原因是,以后当我们进行单热编码时,它可以表示为一个零的 topic_id。(同样,这只是一种方法,还有其他方法可以解决这个问题)
数据清理是一项必备技能。如果您想提高您的数据清理技能,请查看我们的 使用 Python 进行数据清理的文章。
我还注意到 hashtag、URL 和 reference 的计数都是浮点数据类型。然而,它们根本没有小数位,它们有唯一的值,可以被认为是分类的,所以我把它们转换成整数,如下所示。
tweets 功能上的一个热门编码
对于 topic_ids,数据是一个数组,所以非常棘手。你能做的是将数组分解成单个的值,然后将它们变成虚拟的。
对于年、月、附件等其他列,使用 pandas 库中的get_dummies()
进行编码非常容易。
至于小时数据,由于我们必须考虑时间数据中的时间特征,我们必须进行循环编码。
在我们对我们的特性进行编码后,我们可以删除旧的特性,然后加入新的编码特性。
现在,我们的火车推文数据有多达 151 列!
一个关于用户特征的热编码
我们还将对我们的用户特性进行一次热编码,主要是年、月和用户验证列。就像我们对火车推特数据所做的那样。
推文数据的特征选择
矢量化数据有大量的特征,如果我们能够“将小麦从谷壳中分离出来”,或者选择可以帮助我们预测病毒传播的最佳特征,那将是最好的。这可以帮助我们节省尺寸,加快我们的模型训练时间。
我们将从我们的train_tweets_vectorized_media
数据开始。由于不是所有的推文都有媒体,我们必须将每条推文的病毒式传播添加到有媒体的推文中。这可以通过在 tweet_id 上进行右连接来实现。这样,每条推文的所有病毒式传播都可以与推文图像特征相匹配。
因为我们不希望 train_tweets 中除了病毒式传播之外的列与我们的矢量化数据合并,所以我们可以使用.difference
函数只获得病毒式传播。
然后,我们可以利用这个数据集,开始进行特征选择。
我们的目标是病毒式的,特性是包含“img_”的列
使用集合库,我们可以计算模型选择的特性的数量。在这种情况下,只有两个特性被认为是不“有价值”的,所以它不是那么有用。
尽管如此,通过我们模型中的索引,我们可以将它们与我们的媒体和 tweet id 连接起来,形成比以前少了两列的最终train_tweets_media
数据。
对于train_tweets_vectorized_text
,和上面的情况一样。我们必须做一个正确的连接来匹配每条推文的病毒式传播,然后进行特征选择。
用户数据的特征选择
为了对用户数据进行特征选择,我们需要为每个用户添加病毒级别。但由于每个用户都有多个推文,一种方法是获得他们的病毒率的中位数,然后执行右连接,以匹配每个用户的病毒率中位数。然后,使用这个新的数据框,我们可以执行特征选择。
使用熊猫的groupby
和agg
,我们可以找到中间值,然后合并它们。
将一切融合在一起
现在是时候将所有内容合并到最终的列车数据帧中了。
我们面临两个主要问题:
- 不是所有的推文都有媒体,有些推文有多个媒体。我们如何将它与我们的火车推文数据框架结合起来?
- 用户矢量化数据和我们的 tweets 矢量化文本数据具有相似的列名,这将在合并时导致问题(pandas 将向列追加 _x 和 _y)
一种方法是根据 tweet id 获取特征的平均值,以处理第一个问题。我们可以使用groupby
函数来实现。
那么要解决特征列名称重叠的问题,我们可以使用重命名功能。
现在我们可以合并所有的数据框。
你可以有不同的方法来处理这个问题,但我的方法基本上是首先合并推文数据。因为不是所有的 tweets 都有媒体,所以会有数据丢失,所以用零填充这些 NA 值。
下一步是合并用户数据。之后,我将我的 tweets 数据加入到train_tweets
中,然后是用户数据。
我们数据框的最终形状是 2946 列。
我们在训练中所做的预处理必须在测试数据上重复。如果不这样做,我们使用训练数据训练的模型将无法用于我们的测试数据。(这里没有显示测试数据预处理的代码)
为训练和测试匹配列数
在对我们的测试数据应用相同的预处理之后,我们面临另一个问题。
训练和测试的列数不匹配,这是因为它们中的任何一个缺少某些功能。
为了解决这个问题,我们可以在列上使用 set 函数,然后将它们相减,找出它们之间的差异。然后,我们可以将那些缺失的列添加到数据中,并将它们设置为零。
我们还发现我们的火车在测试中缺少列,但幸运的是没有。
构建轻量级 GBM 模型
与 XGBoost 相比,使用 LightGBM 有几个好处,主要是更快的训练速度和更高的效率,以及更准确和使用更少的内存。
我们将建立一个非常简单的基础模型,没有任何参数调整。如果您想更多地尝试调整模型,我在下面链接了一些资源。
列车测试分离
列virality
、tweet_user_id
、tweet_id
和user_id
不是特性,所以我们可以删除它们。然后,我们将病毒率设为我们的目标变量。
然后,我们将数据分成 70%的训练数据和 30%的测试数据。
使数据符合模型
创建基本 LGBM 分类器模型。
安装x_train
和y_train
,我们可以训练我们的基本轻型 GBM 模型。
然后利用它,我们可以在测试数据集上预测它。
我们可以使用sklearn.metrics
中的accuracy_score
函数轻松地打印出我们模型的准确度分数
我们的基本模型达到了 66.45%的准确率!
我们还可以绘制出模型中重要的特征。
这里我们看到user_follower_count
在预测病毒传播中是最重要的,这很有意义,因为你的粉丝越多,你的推文就越有影响力。
我们还在前 10 个特性中看到相当多的user_vectorized_profile_images
特性,还有user_has_location
和user_like_count
这种准确性仍然可以提高,但我们将在这里结束,并使我们的模型适合公开数据。
使模型适合测试/公共数据
瞧啊。我们有一个简单的模型来预测推文的病毒传播水平。
这样,您就可以发布提交文件并上传到 Bitgrit 竞赛了!
提高准确性的技巧
赢得数据科学竞赛并不容易,仅仅有一个工作模型是不够的。您需要一个具有高精确度的模型来战胜其他解决方案,更不用说还能很好地处理看不见的数据了。
提高准确性的一些技巧:
一个很好的学习方法是通过 Kaggle 上的好笔记本。这里有一些可能会有帮助。
这篇文章到此为止,谢谢你的阅读,希望你学到了新的东西!
另外,如果你认为我有更好的方法来解决这些问题,请在下面留下评论。我将非常感激。
本次比赛由 Bitgrit 主办,如果你喜欢这篇文章,也许你会喜欢这些文章:
关注 Bitgrit 数据科学出版物了解更多信息!
关注 Bitgrit 的社交网站📱了解讲座和即将举行的比赛的最新消息!
使用数据成为敏捷分析团队
我们如何使用可操作的敏捷来改进我们的工作流程 30%
回到今年(2021 年)3 月,我开始了解我团队的 JIRA 董事会是否达到了应有的效率。我向工作中的一位敏捷教练寻求帮助(你好,Zara)。接下来是一段旅程,我的思维方式和工作方式发生了完全的转变,这是我没有想到的。
在我们的第一次会议中,Zara 提到我们 JIRA 董事会的状态非常好,并且符合敏捷最佳实践。作为一个分析团队,我们试图“采用”看板方法和思维方式来帮助管理和可视化我们的工作。利益相关者会提出待处理的问题单,并与他们合作,我们会相应地安排优先级。不幸的是,这就是我们采用看板的终点。我们没有做任何事情,甚至没有代表敏捷的核心哲学。我们不是一个敏捷的团队!
看板板设置
下面的截图显示了我们当前的看板。如果你使用看板方法,你的看板可能看起来像这样:
产品分析团队 JIRA 董事会
我们用来管理工作流的列有待办事项、本周、进行中、评审中、完成和等待(希望名称不言自明)。我们用泳道来代表我们支持的不同团队。还有一个专用于职能工作的泳道,包括个人发展、数据质量改进、招聘等
可操作敏捷(AA)
在我们查看了董事会设置后,Zara 问我是否遇到了 可操作的敏捷 。我没有。但当 Zara 从演示帐户加载这个散点图给我看 AA 时,我就被迷住了。我不知道我在看什么,我只知道不管它是什么,我想要它——毕竟我是一名分析师。“周期时间散点图”的屏幕截图,演示数据如下:
可操作的敏捷演示数据
什么是可操作的敏捷?
可操作的敏捷是一种帮助你理解和可视化你的团队工作如何在过程中移动的方法(专栏)。有许多图表可以帮助您分析关键的工作流程指标,例如:
- 周期时间—票证从“积压”中取出后到达“完成”栏所需的时间
- 吞吐量—任何时间段内完成的票据数量
你也可以运行蒙特卡罗模拟来预测一件工作需要多长时间。下面是你可以用 AA 做的所有事情的列表。我已经标记了我们每周用来帮助我们处理过程的那些。
了解可操作的敏捷
尽管我对图表有明显的热情,但在我完全理解我在看什么以及我们如何从中受益之前,我不会天真到改变团队的工作方式。所以我和 Zara 开了一系列的会议来学习更多关于敏捷工作方式和可操作的敏捷。
以下是我和 Zara 一起参加的为期 3 周的速成班的总结和结果:
可操作的敏捷让我能够在宏观层面上分析我的团队的平均周期时间(见下图),并在微观层面上理解何时票据有风险。使用 AA 中的数据,我建立了我的团队的历史基线数字,并确定了我们应该采取的行动来改善它们。我还对 JIRA 董事会做了一些改动,以便我们能够更有效地使用 AA。了解了足够多的信息,知道这是我们可以从中受益的东西,并对我所谈论的内容充满信心,我与团队分享了 AA-他们对图表同样感到兴奋。一旦他们都买了,我们为自己创造了一个 OKR。
设定目标
我们的目标是减少数据的可变性,并作为一个团队变得更加可预测。关键结果是将 Q2 第 80 百分位循环时间减少了 30%。
结果
注意:每个点代表一张或多张 JIRA 门票,y 轴是周期时间,即门票移动到“完成”需要多长时间。x 轴是票被移动到“完成”的日期。一起创造了我们工作的时间序列。
以前
敏捷前图表
在…之后
后敏捷图
乍一看,可能不容易看出影响,但如果仔细观察,您会发现以下情况:
- 散点图上的数据点被压缩得更多,异常值明显更少**(可变性降低)。**
- 第 80 百分位线已经从 30 天变成了 19 天**(改善了 37%)。** OKR 实现了!
- 第 70 和第 50 百分位线分别下降了 30%和 33%。
我们是如何做到这一点的?
访问我们的历史数据是有用的,因为它让我们看到我们作为一个团队是如何做的,但是如果我们想看到我们的周期时间有所改善,我们需要改变我们的工作方式。
1)站立
我们做的最基本的改变是引入了单口站立!我们每周一都有团队会议,涵盖了一大堆主题,包括团队在做什么,但我们很少看 JIRA 的董事会。因此,我们决定花前 30 分钟浏览每个泳道和栏目中的每张有效门票。我们还在周三早上增加了一个更短的 15 分钟站立。
看黑板这个简单的动作经常在这方面发挥巨大的作用。也许这只是你把票移到“完成”时产生的多巴胺冲动。不管是什么原因,做倒立肯定有积极的心理影响。我甚至可以肯定,我们减少的周期时间中有一部分是因为我们及时地移动和关闭了票证。
2)减少在制品
每周一,我会向我们所有的利益相关者发送我们正在做的事情的更新,但到了周中,很明显团队不会完成他们承诺的一半。这不是他们的错!持续不断的会议、数据问题、反馈循环、电子邮件、松散信息和“小”请求意味着不可能找到固定的时间来专注于实际工作。
所以除了站立,下一个改变是减少我们每周的工作量。我们承担的更少,所以我们可以交付更多。再一次,进展中的事情越少的心理影响,意味着团队可以更集中精力,更频繁地交付。
3)审查进行中的老化工作
我们在每次会议中使用的第二个图表是“老化工作进行中”图表。这个图表让我们可以看到每个活动票证的年龄,并发现任何有风险的内容。有时事情太多,很容易忘记时间。拥有识别风险的简单方法,意味着我们可以快速行动。这可能是更新利益相关者,重新安排工作的优先次序或寻找依赖。(是的,我知道有一张票漂浮在红色区域。我们只是人类)。
4)更好地界定更大任务的范围
我们还没有完善这一点,但我们更加关注它。有一项分析花了两个月才完成,事后看来,我们应该把它分解成更小的任务。事实上,这个分析是促使我联系 Zara 的催化剂。结果是更好地界定了工作范围,与利益相关方商定了明确的成果,并在需要时使用了 epics。
5)控制可控性
以上所述让我们意识到,虽然我们容易受到许多我们无法控制的因素的影响,但作为分析师,有太多东西是我们可以控制的。当有人要求我们做不在优先考虑的事情时,说“不”或“还没有”就是其中之一。直到今天,我知道团队仍然会对“小恩惠”说“是”,但是他们说的越来越少了。我还观察到团队态度的变化。他们不再纠结于任务,从而更多地限制了自己的时间。当 SQL 查询超时时,它们会继续前进。当他们在等待利益相关者的反馈时,他们会继续前进。
经验教训
我们已经看到我们的工作流指标有了巨大的改进,我真的相信我们学到的东西可以应用于任何分析团队,但如果你自己也开始了这一旅程,我想分享一些最后的经验教训。
- 为你的团队创造一个安全的空间 —这不是一个点名羞辱的练习。他们应该能够开诚布公地讨论为什么事情比他们希望的时间长,而不会感觉像在显微镜下一样。
- 保持纪律d——在任何情况下都不要跳过单口相声。
- 继续适应和迭代——我们仍然没有做到完美。不断回顾你的过程。
- 说实话 —这些数字的提高是因为你改进了你的流程,还是你在操纵这些数字?
- 采用良好的 JIRA 实践 — AA 并不完美,所以要养成使用 JIRA 的特性来帮助你去除数据中的噪音的习惯。
最后的话
我不知道我们是否已经达到了敏捷团队的状态,但是我们肯定不是三月份的那个团队了。
我非常感谢 Zara 让我看到了一个全新的数据世界,但更重要的是,它有耐心帮助我了解如何正确使用它。如果你足够幸运,在你的公司里有敏捷教练,我建议你去找他们。在过去的 5 个月里,我学到了很多。
你可以在 Twitter 上关注我,也可以不费吹灰之力在 Medium 上关注我和 废话连篇 。如果你喜欢这篇文章,请向下滚动,给它一些掌声:)
阿黛尔是一个了不起的歌手-数据可以说明为什么!
如果你想证明你最喜欢的歌手有多棒,为什么不用数据呢?
马特·博茨福德在 Unsplash 上的照片
ONG 已经存在了很久,并以这样或那样的方式慢慢进入了人们的生活。我从 9 岁左右开始定期听歌,近十年后,我已经沉浸在许多不同流派的歌曲中。
这些年来,在我听过的所有艺术家中,我最喜欢的是阿黛尔。如果你听过她最著名的歌曲如“ 你好”、“有人喜欢你” 或 “在深处打滚” ,你就会知道她的唱腔是丰富的,令人着迷的,她的歌真的把强烈的情感倾注到你的心里。它们让你感受到从未有过的感觉。
听“有人喜欢你”,让我 10 岁的时候第一次感到心碎。
作为数据科学项目的一部分,我决定利用我对歌曲和阿黛尔的欣赏,分析 这个 数据集。它收集了 1921 年至 2020 年间在 Spotify 上发布的 16 万多首歌曲的音频特征。
Spotify 是一项数字音乐、播客和视频流媒体服务,让您可以访问来自世界各地艺术家的数百万首歌曲和其他内容。
结果呢?
我想出了问题的数据驱动原因:为什么阿黛尔是一个了不起的歌手?
主要支持问题
为了恰当地展示阿黛尔的神奇,我需要问一些支持性的问题,并在数据集中找到它们的答案。
我有三个问题:
- 最近歌曲有什么值得注意的趋势吗?
- 与 2020 年的竞争对手相比,阿黛尔的受欢迎程度如何?
- 阿黛尔和她的顶级竞争对手之间的主要区别是什么?
在下面的章节中,我将只讨论与我的论点相关的部分发现。如果你想要一套完整的发现,可以去看看我的 Kaggle 笔记本 或者我的 github 。
更多关于数据的信息
在我们深入研究答案之前,我将首先解释数据集的一些相关但不那么直观的特性。如果您不确定某项功能的含义,请随意返回此处。
valence
: 一首歌在音乐上有多积极/快乐。popularity
: *一首曲目在获取数据时的受欢迎程度。*要知道数据集是 2020 年 6 月发布的,所以我们这里使用的所有流行度特征,都是指 2020 年 6 月的赛道流行度。explicit
: 曲目是否包含露骨内容。 1 为显式,0 为不显式。speechiness
: *一个音轨中的口语单词等级。*更接近于 1 意味着只专门包含语音。接近 0 表示仅包含音乐。
1.近年来宋的发展趋势
对于这一部分,我把“最近几年”框定为从 2010 年开始。换句话说,我所做的观察,是从 2010 年到 2020 年每一年的平均歌曲特征中得出的。
数据外观图片|作者图片
此外,我还获得了 2010 年至 2020 年每年 100 首流行歌曲的平均特征表。
我在这部分有一些非常有趣的发现。
a)从 2010 年开始,歌曲变得越来越悲伤,但从 2017-2018 年开始,歌曲变得越来越快乐
多年来普通歌曲和流行歌曲的价格比较|作者图片
多年来普通歌曲和流行歌曲的能量比较|作者图片
- 从 2010 年到 2017 年至 2018 年,普通歌曲的价格和能量大多下降,然后再次飙升,这意味着歌曲在反弹之前在音乐上变得越来越悲伤和沉闷。
- 2010–2020 年的流行歌曲也遵循这一趋势,在 2016–2018 年达到最悲伤和最没有活力的水平。
- 这些趋势可能表明,2016 年至 2018 年是一个充满心碎的时期,因此更多的歌曲更悲伤,这些严肃的歌曲最终变得流行。然而,我们需要做更多的数据挖掘来证明这一点。
- 足够有趣的是,2020 年似乎鼓励歌曲在快乐和积极方面大幅飙升。
在 2020 年所有的消极中,我想这个世界转向了歌曲来获得积极的突破。
b)歌曲变得越来越适合跳舞。
多年来普通歌曲和流行歌曲的可跳性呈上升趋势 | 作者图片
普通歌曲和流行歌曲的可跳性呈上升趋势。
c)歌曲越来越露骨。
多年来普通歌曲和流行歌曲清晰度的上升趋势|作者图片
随着时间的推移,普通歌曲更容易露骨,这种露骨的歌曲越来越受欢迎。
d)这些趋势与阿黛尔有什么关系?
在这一点上,你可能想知道,这些趋势与阿黛尔有什么关系?简单来说:
阿黛尔并不“新潮”。
看看下面的数字:
歌曲的价格和可跳舞性分布|按作者分类的图像
阿黛尔没有追随最近歌曲的潮流。与 2020 年的歌曲相比,她的歌曲平均价低,平均可跳性也低。
除此之外她的明确度仅为 2020 年歌曲的1/10:
清晰|作者图片
至少在过去三年左右,所有这些特征都呈上升趋势,如果阿黛尔坚持自己的风格,她可能会进一步落后于潮流。
第 1 节的结论:
自 2017-2018 年以来,歌曲一直趋向于变得更快乐,更适合跳舞,更明确。但阿黛尔的音乐类型属于 流行、R & B 和灵魂乐 的范畴。因此,她的歌曲更像是饱含深意的情感歌谣——它们不追随快乐、乐观的潮流。
因此,很容易得出这样的假设:阿黛尔的歌曲在最近一段时间可能不那么受欢迎了。嗯,这就把我们带到了下一个问题。
2.与 2020 年的竞争对手相比,阿黛尔的受欢迎程度
根据我们掌握的数据,发现阿黛尔在 2020 年有多受欢迎是很简单的。歌曲特征已经包括了popularity
,所以为了得到阿黛尔受欢迎程度的一个很好的代理,我们可以总结她所有歌曲的受欢迎程度,并将其与所有其他艺术家的受欢迎程度相比较。
这样做,我们得到:
作者图片
这个数字看起来很合理,但我们必须记住,数据集也包含许多 20 世纪的旧曲目。也就是说,当我们使用这种方法时,我们是在将阿黛尔的歌曲与弗兰克·辛纳屈、猫王等的传奇经典进行比较。
事实上,根据这种方法,以下是最受欢迎的五位艺术家:
根据合计人气排名的前 5 位人气艺人|作者图片
称披头士或弗兰克·辛纳特拉为阿黛尔的“竞争对手”似乎不太公平。毕竟,他们是永恒的传奇,几十年来,他们的歌曲已经享誉全球。与此同时,阿黛尔的第一首歌《故乡的荣耀》在 2007 年才发行。
因此,我从 2007 年开始发行歌曲的艺术家中挑选了一部分,认为这些艺术家是阿黛尔的竞争对手。
结果如下:
前 5 名最受欢迎的艺术家(2007 年以后发行的歌曲)+ Adele |作者图片
阿黛尔受欢迎的确切数字|作者图片
从这一点开始,当我们讨论前 5 名艺术家时,我们指的是在 2007 年以后发行歌曲的艺术家。
第 2 节的结论
阿黛尔在 2020 年极受欢迎。她是 Spotify 全球排名前 1.63%的艺人之一,也是 2007 年以来发行过歌曲的前 0.3%的艺人之一。
带着这个想法,我试图找到最后一个问题的答案。
3.阿黛尔和她的竞争对手之间的主要区别
知道了阿黛尔的受欢迎程度,我想进一步发现是什么把前五名最受欢迎的艺术家与阿黛尔区分开来。
她是否在某些方面有所欠缺?前 5 名艺人之间有什么共同点吗?
通过更多的操作,我找到了前 5 名艺术家的平均轨迹特征。与阿黛尔的平均轨迹特征相比,以下是获得的结果:
a)他们的歌更快乐,更有活力,人们更可能随着他们的歌起舞
****
与阿黛尔相比,前 5 名艺术家的能量和效价|作者图片
与阿黛尔相比,前 5 名艺术家的舞蹈能力|作者图片
- 在三个特征能量、价和可舞性中,所有前五名艺人的平均曲目都比阿黛尔的平均曲目高。
- 换句话说,就拥有快乐和振奋人心的歌曲旋律而言,前五名艺术家比阿黛尔更追随流行歌曲的最新趋势。
b)大多数前 5 名的歌曲具有较高的口语词比率
与阿黛尔相比,前五名艺术家的演讲|作者图片
- 德雷克、未来、利尔·简自豪·维特、李尔·韦恩的平均语速都是阿黛尔平均语速的至少 2.5 倍。
- 这是意料之中的,因为除了泰勒斯威夫特,前 5 名的其余艺人都是说唱歌手。
c)前五名艺术家中的大多数都发行了许多更露骨的歌曲
与阿黛尔相比,前 5 名艺术家的清晰度|作者图片
- 再一次,除了泰勒·斯威夫特之外,所有前五名艺术家的清晰度都比阿黛尔高得多(相差超过 10 倍)。
- 有人可能会认为,因为他们是现代说唱歌手,他们有很多明确的曲目。嗯,需要注意的一点是, 相关性并不等同于因果关系 。
- 换句话说,不能因为他们都是现代说唱歌手,内容露骨度高,就代表因为前者,后者就跟着来了。
d)有趣的是,阿黛尔的歌曲比大多数歌曲的平均受欢迎程度都高。
与阿黛尔相比,前 5 名艺术家的清晰度|作者图片
- 平均来说,阿黛尔的歌曲实际上比未来、里尔·简自豪·维特、李尔·韦恩和泰勒·斯威夫特更受欢迎。
- 她的歌曲在流行程度上也接近德雷克的歌曲。
那么为什么阿黛尔不在前 5 名艺术家之列呢?
e)阿黛尔所缺乏的
好吧,因为我们总结了每个艺人歌曲的流行度,作为一个艺人受欢迎程度的代表,这导致了一种可能性——与前 5 名艺人相比,阿黛尔发布的歌曲很少。
果然,经过更多的数据探索,我们可以看到:
轨道数量比较
注意:这里我用了“已经涉及”这几个字,因为只要一首 Spotify 的歌把一个艺人列为它的创作者之一,我就把这首歌包括进去了。
第 3 节的结论
与前五名艺术家相比,阿黛尔的音乐在风格和情绪上相对不同。然而,这并不是阿黛尔不在前 5 的原因。
相反,这仅仅是因为与前五名艺人相比,她很少创作歌曲。
总体结论:那么为什么阿黛尔是一个伟大的歌手/音乐家?
原因是我们之前的三个结论的汇总。
1.阿黛尔的音乐更悲伤,更缓慢,更深情的音乐类型没有遵循最近流行歌曲的趋势,快乐和乐观的歌曲。
2.然而,数据显示,她仍然是最受欢迎的艺术家的前 0.3%(从 2007 年开始发行的歌曲)。
3.事实上,她不在前五名的原因,不是因为她不新潮的风格,而是因为她发行了一些小曲。她的歌曲质量不言自明,因为它们的平均受欢迎程度可与前 5 名艺术家发行的歌曲相媲美。
既然我们已经结束了,我想问你几个问题:
当提出这些论点时,你会同意阿黛尔是一个伟大的音乐家/歌手吗,即使你不喜欢她?
这种数据驱动的论点是否遗漏了什么?
感谢您阅读本文!我希望你觉得这很有趣。热烈欢迎任何评论或批评。
此外,请随时与我联系,就这些话题进行交流,并通过 LinkedIn 与我联系。
在 ML 管道中使用数据块集群
运行生产 Spark 作业,并在 Databricks 作业集群上培训 ML 模型。
在这篇文章中,我想描述一下我在 Databricks 作业集群上执行 production Spark 和 ML 作业的经历。
到目前为止,我是 Databricks 解决方案的忠实粉丝,因为我发现它们比我用过的替代方案好得多,不,我不是 Databricks 的员工。
在我的日常工作中,我开发了一个自动化的基于人工智能的预测分析平台,该平台简化并加快了构建和部署预测模型的过程。
过去两年,我一直在构建数据和 ML 管道,包括数据清理、结构化、特征工程、培训、评估、预测和监控工作。
有两个原因让我开始使用 Databricks:
- 我想让别人帮我管理 Spark。我不想在 Spark echo-system 上花费太多时间(安装、配置、优化和调优等)。
- 我们在 Kubernetes 上使用 JupyterHub 作为游戏环境。管理它相当具有挑战性,尤其是当我们希望它可扩展并运行繁重的 Spark 任务时。
自从我开始使用 Databrikcs 以来,我发现了许多我喜欢的更强大的功能,我将在这篇文章中讨论这些功能。
在数据块集群上运行生产作业
我们根据自己的需求开发了定制的 Databricks 气流操作器,用于执行生产任务。这个 Airflow 操作符根据作业的类型和工作负载为每个作业创建两种类型的集群之一:
- 标准群集—包含 3–512 个节点(自动横向扩展和纵向扩展)的 Spark 群集,我们将这种类型的群集用于 Spark 作业。
- 单节点集群—我们还运行非分布式训练算法,在这种情况下,常规的多节点集群不适用。
每个作业都有一个专用群集,该群集在作业完成后立即关闭。为了执行许多独立的任务,可以并行运行许多集群。
操作员知道使用正确的参数在正确类型的集群上执行每个作业,管理故障、重试等。
使用 Databricks REST API 创建集群很简单,这是一个创建单节点集群的请求示例:
{
"run_name": "my_run",
"new_cluster": {
"spark_version": "7.4.x-gpu-ml-scala2.12",
"aws_attributes": {
"instance_profile_arn": "my_instance_profile",
"availability": "SPOT_WITH_FALLBACK",
"zone_id": "my_zone",
"ebs_volume_count": 1,
"ebs_volume_size": 100},
"num_workers": 0,
"spark_conf": {
"spark.master": "local[*]",
"spark.databricks.cluster.profile": "singleNode"},
"node_type_id": "p3.2xlarge",
"spark_python_task": {
"python_file": "s3://my-bucket/my-file.py",
"parameters": []},
"libraries": [{"pypi": {"package": "dill==0.3.1.1"}}],
"max_retries": 1,
"timeout_seconds": 36000
}
你可以在文章[1]的结尾找到关于不同参数的更多信息。
积分福利
Managed Spark
Spark 已经安装并配置完毕,支持快速按需创建集群,轻松管理集群,并在任务完成后关闭集群。
data bricks Runtime data bricks 提供了几个可用的运行时配置,例如“Databricks Runtime ML”,它可以自动创建针对机器学习优化的集群。
该配置包括最流行的机器学习库,如 TensorFlow、PyTorch、Keras、XGBOOST、Scikit-Learn、Pandas 等等。
它加快了集群创建时间,我可以用特定的运行时配置“标记”我的作业,这样我就可以在推理管道中再次使用它。它承诺在训练管道和预测管道之间有相同版本的库,使它们相互兼容。
调试简单 使用“数据块-连接”[2]可以调试作业。它只需要安装在本地虚拟环境中,并使用 Databricks 帐户详细信息进行配置。
它支持在集群上远程调试作业,并且变得非常有用,特别是当我们想要调试大量不适合本地机器内存的数据时。
易于使用自己的 Python 包
可以在集群上安装 Python 包,并从我们的作业中访问它们。它使得使用内部包、公共对象和代码变得非常容易。
可以从几个来源安装软件包,并使用 UI 或 API。
库安装— Databricks 统一分析(来源:作者)
内置 AWS 和 Azure 集成 Databricks 和 AWS 以及 data bricks 和 Azure 之间存在集成。我们可以使用单个 API 在两个云中执行作业,而不是在我们这边构建这些集成。
笔记本和数据目录 Jupyter 笔记本已经上市,具备预配置的 spark 会话和开箱即用的可视化功能。
还可以轻松执行繁重的工作负载,并且可以将处理后的数据帧保存到数据目录中,让其他团队和同事使用他们的笔记本来访问它们。
结论
在这篇文章中,我简要描述了为什么我喜欢使用 Databricks 集群作为基础设施来运行 Spark 作业和训练模型。有太多的细节我没有描述,因为我想给出一个主题的概述,而不是太深入。
如果有什么具体的东西让你感兴趣,我会很感激你的评论,我会在我的下一篇帖子里写出来。
**链接:
1。**数据块工作 API: https://docs.databricks.com/dev-tools/api/latest/jobs.html
2.data bricks Connect:
https://docs . data bricks . com/dev-tools/data bricks-Connect . html
使用数据流提取、转换和加载自行车共享多伦多乘客数据到 BigQuery
关于构建 ETL 管道的说明,该管道用于将 Bike Share Toronto ridership 数据加载到 BigQuery 表中,以便它可以用作 Data Studio 创建数据可视化的源
安德烈·费塔多在 Unsplash 上拍摄的照片
在我之前的博文中,我使用 Google Data Studio 和 BigQuery 作为数据源来分析疫情是如何影响自行车共享出行的。在这篇博客文章中,我将一步一步地演示在尝试将 Bike Share Toronto ridership 数据从云存储中直接加载到 BigQuery 时遇到的一些问题,以及如何通过使用 Dataflow 使用 Apache Beam 执行 ETL 过程来解决这些问题。
下载数据
- 让我们首先在云壳中打开一个会话,并将 2020 年自行车共享多伦多乘客数据下载到一个单独的文件夹
'2020'
。
wget [https://ckan0.cf.opendata.inter.prod-toronto.ca/dataset/7e876c24-177c-4605-9cef-e50dd74c617f/resource/5f5d78c4-d810-4048-9dac-c18273abffac/download/files-1.zip](https://ckan0.cf.opendata.inter.prod-toronto.ca/dataset/7e876c24-177c-4605-9cef-e50dd74c617f/resource/5f5d78c4-d810-4048-9dac-c18273abffac/download/files-1.zip) -O temp.zipunzip temp.zip -d 2020rm temp.zip
上面的第一个命令下载名为temp.zip
的 zip 文件,第二个命令将其解压到名为2020
的文件夹中,第三个命令删除下载的 zip 文件。
2.让我们通过运行下面的命令来看看文件解压缩后的内容。
ls 2020
我们看到,2020 年的乘客数据分为 12 个 CSV 文件,都以2020
开头:
2020–01.csv 2020–02.csv 2020–03.csv 2020–04.csv 2020–05.csv 2020–06.csv 2020–07.csv 2020–08.csv 2020–09.csv 2020–10.csv 2020–11.csv 2020–12.csv
3.我们可以通过读取 CSV 的标题来读取列名:
head -n 1 2020/2020–01.csv
这将输出以下列名:
Trip Id,Trip Duration,Start Station Id,Start Time,Start Station Name,End Station Id,End Time,End Station Name,Bike Id,User Type
将文件复制到云存储桶
接下来,让我们将文件复制到云存储桶中。这将允许我们利用对云存储 URI 的通配符支持,用一个命令将多个文件批量加载到一个 BigQuery 表中。
4.首先,用您的项目 ID 设置一个项目变量,并设置项目属性。
export PROJECT=my-project-idgcloud config set project $my-project-id
5.使用 make bucket gsutil mb
命令在项目中创建一个新的 bucket。
gsutil mb -l northamerica-northeast1 gs://my-bucket-name
6.使用gsutil cp
命令将文件复制到我们刚刚创建的云存储桶中。
gsutil cp 2020/* gs://my-bucket-name
7.检查文件是否已成功复制。
gsutil ls gs://my-bucket-name/
8.一旦数据被成功复制到云存储桶,就从云外壳中删除该文件夹。
rm -r 2020
创建大查询数据集
9.在将数据装载到 BigQuery 表之前,我们需要为该表创建一个 BigQuery 数据集。
bq --location=northamerica-northeast1 mk mydataset
尝试直接从云存储中将数据加载到 BigQuery 时出错
10.接下来,让我们尝试使用bq load
命令将数据加载到一个 BigQuery 表中,并使用一个通配符,在基础上附加一个星号(*
)
bq load --autodetect --source_format=CSV mydataset.biketrips2020 gs://my-bucket-name/*
然而,我们得到一个错误:
- gs://my-bucket-name/2020-10.csv: Error while reading
data, error message: CSV table references column position 9, but
line starting at position:3401930 contains only 9 columns.
该错误消息表明加载作业失败,因为至少有一行的列数少于自动检测到的架构规定的列数。
11.为了找到这些错误的来源,我们可以检查错误字节位置附近的 CSV 文件。为此,我们使用 gsutil cat
命令。
gsutil cat -r 3401700–3402200 gs://my-bucket-name/2020–10.csv
由此,我们发现有许多行中的Trip_Id
和Trip_Duration
的值被错误地连接在一起。例如,下面的第二行应该以10000084,625,7120,…
开始
10000083,720,7239,10/03/2020 13:28,Bloor St W / Manning Ave — SMART,7160,10/03/2020 13:40,King St W / Tecumseth St,5563,Annual Member10000084625,7120,10/03/2020 13:28,Gerrard St E / River St,7120,10/03/2020 13:38,Gerrard St E / River St,5250,Annual Member10000085,1526,7239,10/03/2020 13:28,Bloor St W / Manning Ave — SMART,7544,10/03/2020 13:53,Foster Pl / Elizabeth St — SMART,3956,Annual Member
我们需要找到所有这样的串联值,并将它们拆分。这是在 BigQuery 中无法完成的数据转换。因此,我们需要构建一个 Apache Beam 管道来转换数据并加载到 BigQuery 中。
此外,我们看到上述行中的Start_Time
和End_Time
列不符合 BigQuery 兼容的 [datetime](https://cloud.google.com/bigquery/docs/reference/standard-sql/data-types#examples)
格式。我们还需要用数据流进行转换。
12.处理错误的一个选择是在bq load
中设置max_bad_records
标志。这将忽略坏行,并且不会将它们加载到表中。例如,我们可以将max_bad_record
标志设置为 100:
bq load \
--autodetect \
--max_bad_records=100 \
--source_format=CSV \
mydataset.biketrips2020 \
gs://my-bucket-name/*
然而,这仍然会给我们带来错误,尽管是不同类型的错误。
Could not parse ‘NULL’ as INT64 for field Bike_Id (position
8) starting at location 5061057 with message ‘Unable to parse’
出现此错误是因为对于 BigQuery,在 CSV 中表示空值的标准方式是使用空字段。我们可以通过在bq load
命令中设置标志null_marker=NULL
来处理这个错误,从而指定这个特定的文件使用字符串 NULL 来标记 NULL。例如:
bq load \
--autodetect \
--max_bad_records=100 \
--source_format=CSV \
--null_marker=NULL \
mydataset.biketrips2020 \
gs://my-bucket-name/*
这处理了由于解析空值引起的错误。然而,我们还将在 Apache Beam 管道中包含这种转换,以便单个管道执行所有必要的转换。
建立数据流管道
13.接下来,我们编写一个 Apache Beam 管道,它提取文件,执行转换,并将数据加载到 BigQuery 中。Python 文件[etl_pipeline.py](https://github.com/bilalmkhan/etl-pipeline-beam)
https://github.com/bilalmkhan/etl-pipeline-beam/blob/main/etl_pipeline.py包含管道的 Python 代码。三个函数执行主要的转换:deconcat()
、replace_nulls()
、format_datetime_bq()
。我们可以使用云壳编辑器上传 Python 文件。
设置 Python 环境
14.在云 Shell 中运行以下命令,设置虚拟环境来运行我们的代码:
sudo pip install virtualenv virtualenv -p python3 venv source venv/bin/activate pip install apache-beam[gcp]==2.24.0
运行管道
15.运行 Python 文件[etl_pipeline](https://github.com/bilalmkhan/etl-pipeline-beam/blob/main/etl_pipeline.py).py
会创建一个运行DataflowRunner
的数据流作业。我们需要指定一个云存储桶位置,用于在管道仍在运行时暂存和存储临时数据,以及包含 CSV 文件的云存储桶。
python etl_pipeline.py \
--project=$PROJECT \
--region=northamerica-northeast1 \
--runner=DataflowRunner \
--staging_location=gs://my-bucket-name/test \
--temp_location gs://my-bucket-name/test \
--input gs://my-bucket-name/*.csv
--save_main_session
16.当数据流作业完成时,我们可以在 Gooogle 云控制台中导航到云数据流,并查看作业图表和其他作业完成详细信息:
17.导航到 BigQuery 验证数据是否成功加载到表中。这些数据现在可以用作 Cloud Data Studio 创建可视化的数据源。
感谢您的阅读!如果您对此工作流程有任何建议,请在评论中分享。
利用深度学习对抗新冠肺炎
人工智能如何以 98%的准确率可视化和诊断新冠肺炎
如果你收听了去年的新闻,新冠肺炎患者死亡的主要原因与无法通过充满肺部的液体呼吸有关。这缩小了我们肺部的总容量,使呼吸更加困难。这种液体可以使用 CT 或计算机断层扫描来观察。当急诊室的病人出现呼吸问题时,CT 扫描通常是医生建议进一步治疗的第一个预后工具。如果可以通过 CT 扫描正确诊断 Covid,这可以加快对处于危急或危及生命状况的患者的诊断,或者在测试用品有限时提供一种诊断方法。
为了预测新冠肺炎,之前的工作和在 建立的数据集被用于新型冠状病毒识别 (Soares et al. 2020) 的真实患者 ct 扫描的大型数据集。这包含来自 250 名 COVID 阴性患者和 247 名 COVID 患者的健康肺的约 1300 次 CT 扫描,以及 Covid 感染肺的约 1300 次 CT 扫描。这个数据集然后被应用于一个名为 ResNet-18 的卷积神经网络架构,训练一个新的模型来将健康患者与 Covid 感染患者进行分类。ResNet 的工作原理是利用剩余学习,或者替代直接前馈神经网络的概念,允许跳过连接,这允许激活跳过网络中的一层,从而简化网络并帮助解决消失梯度问题。如果您对 ResNet 架构是如何构建的感兴趣,这篇面向数据科学的文章将详细解释这一点。
该网络的总体 F-1 分数为 97.87%,不仅超过了原始数据集的研究,而且与最准确的 Covid 测试一样好,如果不是更好的话。全部结果如下表所示。
ResNet-18 结果
为了建立在这些结果的基础上,并提供新冠肺炎看起来像什么的一般化模型,在相同样本上开发了第二无监督自动编码器模型。
自动编码器是一种神经网络,用于学习一组数据的表示(编码)。一旦学习了这种表示,就可以将其重建为可视图像(解码)。这使得我们可以忽略图像中的噪声,而专注于所有图像之间的相似性。我们的特定网络获取大小为 244x244x1 的图像,学习大小为 500x1 的编码,并将其解码回 244x244x1 的图像(最后的 x1 表示灰度与彩色图像)。完整的架构可以在下图中看到。
新冠肺炎自动编码器
这种自动编码器的结果非常有说服力——下面是 4 次 CT 扫描及其相应输出的示例。
自动编码器生成的图像
很明显,自动编码器确定图像的重要部分是肺本身,选择使该区域变暗并忽略肺内部的大部分成分。还可以看出,covid 感染的肺只有健康肺总肺活量的 50%左右。
这项研究背后的希望是,这两种算法可以帮助需要立即诊断的医生,并在持续抗击新冠肺炎的前线提供援助。
如果你想看完整的研究,GitHub 库可以在这里找到!这也包括对研究结果的更多验证!
你喜欢这篇文章吗?我希望这有助于展示机器学习如何用于医学预测。如果你喜欢它,请跟随并查看我的其他文章,如这篇我运行了一些 GPU 性能测试!
没有我的队友:安德鲁·马蒙、德万什·辛格、帕拉维·米斯拉和里什·古尔纳尼,这篇文章是不可能完成的
用微分方程模拟浮油的扩散
变更数据
将数学技术应用于环境问题
我们将调查一个假设的海面浮油扩散的场景。不时地,但不定期地,一架直升机被派遣去拍摄浮油。每次飞行,直升机都会到达浮油上空。飞行员拍了一张照片,等了 10 分钟,又拍了一张照片,然后回家。在七次航行的每一次中,浮油的大小(平方英里的面积)都是从两张照片中测量的。
我们将使用微分方程来模拟浮油的扩散,预测不同时间浮油的平方英里数,绘制预测函数相对于时间的曲线,并确定记录下表中观察值的时间。需要注意的是,我们将完成一系列具体的任务,这些任务来源于本文末尾的参考资料。
第一部分:为浮油的大小建立一个模型
首先,我们可以在上表中添加一列,描述 10 分钟时间段内浮油面积的变化率,也等于δA(t)/δt(其中 A ( t )表示时间 t 时的浮油面积)。计算方法如下:
因此,我们得到了下表,并附加了列δA(t)/δt。
现在,我们可以用浮油面积的变化率来画出最初的观察值。
根据 Microsoft Excel 计算(如上图所示),最佳拟合的直线为y=–0.001x+0.0102,即δA(t)/δt=–0.001x+0.0102。这也可以表示为一阶线性微分方程模型:
将该微分方程的两边除以–0.001x+0.0102,然后相对于 t 进行积分以分离出 A ( t )得出:
假设第一次观测发生在时间 t = 0,我们可以代入初始条件( t ,a(t)=(0,1.047),求解 c₆.简化后,我们得到 c₆ = 0。因此:
(b)部分:预测 t = 10 分钟、t = 20 分钟和 t = 120 分钟时浮油的未来大小。
我们必须将我们给定的t-值 10、20 和 120 代入之前找到的函数 A ( t )。
第©部分:绘制你的模型,将浮油的大小作为时间的函数。
下面是基于功能 A ( t )的模型。
(d)部分:找出浮油面积为 8 平方英里的时间。
我们必须设置 A ( t )等于 8,并求解 t 。
(e)部分:确定第一次、第三次、第五次和第七次初次观察的时间。
我们可以使用与第(d)部分所示相同的过程来找到第一次、第三次、第五次和第七次初始观察的时间。
第一次初步观察
第三次初步意见
第五次初步意见
第七次初次意见
结论
通过这个项目,我们探索了如何通过首先绘制油膜面积变化率的初始观测值,计算精确的趋势线(R 值非常高,为 0.9967!),并利用数学生成浮油面积的预测方程。当用我们的函数 A ( t )和我们的初始数据执行“现实检查”时,我们看到这个函数是合乎逻辑的,因为它对于浮油开始快速增长然后随着时间的增加快速减慢到小得多的增长率是有意义的。我们还能够计算出进行某些观察的时间,以及估计浮油未来的大小。
我们可以用来模拟浮油扩散的另一种方法是根据 10 分钟后的观察值绘制初始观察值,而不是根据面积变化率。当执行时,这是通向微分方程的另一条途径。虽然我们可以预期这些结果与我们目前的方法提供的结果略有不同,但它们应该非常接近。
这种方法的一个局限性是,它假设浮油面积的变化只遵循一个微分方程。其次,它没有考虑任何可能影响浮油扩散程度的环境因素。这就很难扩展到其他场景。
总的来说,我们通过将一阶微分方程的技巧应用到现实生活场景中,练习了对浮油区域的分析和建模。在根据给定数据推导精确模型的过程中,我们使用了积分、数学建模和求解给定初始值的微分方程。
参考
[1]贾德森,T. W. (2020 年 8 月 1 日)。常微分方程项目。斯蒂芬 f 奥斯汀州立大学。http://faculty . SF ASU . edu/judson tw/ode/html-2020 08 01/ode project . html
[2]温克尔,b .(未注明)。浮油扩散。用微分方程模拟调查和机会的系统倡议。https://www . simode . org/resources/2038/download/1-5-S-oil click-student version . pdf
用蒸馏来保护你的神经网络
蒸馏是如何被用来保证神经网络安全的
蒸馏是一个热门的研究领域。对于蒸馏,你首先训练一个深度学习模型*、*、、、来解决你的任务。然后,你培养一个学生网,可以是任何模式。
教师接受真实数据的培训,学生接受教师输出的培训。它预测老师的输出:无论是标签,标签的概率分布,还是其他。
查尔斯·德鲁维奥在 Unsplash 上拍摄的照片
注:有蒸馏的变体。一种是自学,老师和学生的网络是一样的!
Bermix 工作室在 Unsplash 上拍摄的照片
蒸馏的好处
蒸馏有不同的好处。例如,您可以选择一个比教师网络小的学生网络。你将能够达到比从头开始训练学生模型更高的精确度。同时,你会有一个比老师更小、更简单、更快的模型。
蒸馏还提供了正则化,使你的网络更加一般化。在这篇文章中,我们将讨论蒸馏的一个主要用途:保护你的神经网络免受攻击!
为什么有效
就像这篇关于反思正则化的文章一样,蒸馏提供了更平坦的局部极小值。因此,输入数据的微小变化不太可能改变预测值。为什么这很重要?攻击者可以创建对抗性示例。这些例子包括导致错误预测的真实输入的小变化(例如,改变几个像素)。
这是我的上一篇关于 COVID mask 预测的文章中提到蒸馏的部分原因。如果没有提取,通过修改几个像素来欺骗掩模预测模型是相当容易的。
一个特别危险的例子是:自动驾驶汽车。想象一下,如果一名黑客在停车标志上贴了一张贴纸。贴纸可能看起来像最初的停车标志,但 2%的像素变化会让自动驾驶汽车错过停车标志。这些变化被称为对抗性扰动。有了蒸馏,黑客将需要使用更定制的攻击或改变更多的像素,这可能是显而易见的。
前进
照片由威利安·贾斯登·德·瓦斯康塞洛斯在 Unsplash 拍摄
你往往不需要万无一失的安全性,只需要比同类目标更好的安全性。如果我们能找到一种方法使每个神经网络高度安全,那将是理想的,但目前看来这是遥不可及的。
安全是一场猫捉老鼠的游戏,攻击往往比防御发展得更快。蒸馏是一种基本的防御手段,可以用来 让你的网络对攻击 更加稳健。你可以使用像 KD_Lib 这样的库来尝试提取你的网络。
当攻击变种进化到回避防御时,蒸馏变种也进化到对这些攻击免疫。蒸馏会让攻击变得更难,但并非不可能。这是您安全工具箱中的一步。