深度学习中的视觉注意模型
摘要
本练习的主要目的是研究视觉注意模型的发展现状和主要工作。研究了两个数据集:扩展 MNIST 和支持向量回归机。前一个数据集侧重于规范问题——手写数字识别,但具有杂乱和翻译,后一个数据集侧重于现实世界的问题——街景门牌号码(SVHN)转录。在本练习中,我们以培养良好直觉的方式研究了以下论文,以选择合适的模型来应对上述挑战。
对于扩充的 MNIST 数据集:
- 基线模型基于经典的 2 层 CNN
- 参考文献[2],目标模型是具有 LSTM 循环注意模型(RAM)
对于 SVHN 数据集:
- 基线模型基于 11 层 CNN:用卷积网络提取图像特征,然后用多个独立的密集层预测有序序列,参考文献[1]
- 参考文献[3],目标模型是具有 LSTM 和卷积网络深度循环注意模型(DRAM)
此外:
- 空间变换网络也作为视觉注意机制的最新发展进行了研究,参见论文[5]
上述两个数据集挑战都集中在数字识别上。在本练习中,MNIST 用于演示一位数识别的解决方案,而 SVHN 用于显示多位数序列识别的结果。
扩充 MNIST 数据集
数据扩充
由于原始 MNIST 数据集是用于说明深度学习的规范数据集,其中简单的多层感知器可以获得非常高的精度,因此原始 MNIST 被增加了额外的噪声和失真,以便使问题更具挑战性,并导致诸如 SVHN 的真实世界问题。
增强后的 MNIST 数据集示例如下所示:
上面的增强 MNIST 数据集杂乱无章,没有中心。增强过程如下:
(1)在 100x100 的画布中随机选择一个位置对原始的 28x28 图像进行平移,生成平移。
(2)通过随机选择一个训练/验证 28x28 图像,然后随机裁剪 8 次 9x9 补丁,然后将所有 8 个裁剪的图像拼接成增强的 100x100 图像,来产生失真噪声
对于经典方法来说,扩充的 MNIST 数据集似乎很难,让我们首先尝试一下。
数据预处理
除了数据扩充之外,每个图像像素值在[0,1]的范围内被归一化。
MNIST 数据集非常平衡。没有应用额外的数据预处理。
基线方法:仅 CNN
基线方法是使用经典卷积模型架构,该架构适用于原始 MNIST 数据集。MLP 没有被用作基线模型,因为它没有表现出经典模型的最佳效果。卷积模型架构取自 keras 示例,该示例声称在原始 MNIST 数据集上达到 99.25%的准确率。
模型架构如下所示:
由于 MNIST 手写数字相对简单,因此只有 2 个卷积层和最大池用于特征减少和空间不变性。退学用于转正。平坦/密集图层用于要素交互。
有 60k MNIST 图像数据,其中 54k 用于训练,6k 用于验证,10k 用于测试。测试数据在最后一步只使用一次。
验证动态如下所示。我们可以看到,验证准确度稳定在大约 50%的准确度。并且最终的一次性测试准确率在 100 个历元时为 50.87% (由于每个训练图像为 100x100,所以在 Tesla K80 GPU 服务器中的总训练时间需要几个小时)。
目标方法:重复注意模型(RAM)
为了更好地解决上述问题,谷歌在 2014 年发布了一个非常简洁和酷的想法,请参考论文[2]。
I 灵感 大意是从人眼的工作原理,即视网膜中获取灵感,如下图所示。我们的眼睛可以捕捉到一个非常广阔的世界,然而,我们倾向于“扫视”全景,只关注视图的特定区域,而其他部分则有点“模糊不清”。
source: https://en.wikipedia.org/wiki/Visual_perception
视觉注意力模型试图利用这一想法,让神经网络能够将其“注意力”集中在图像的有趣部分,在那里它可以获得大部分信息,而在其他地方给予较少的“注意”。
这种方法的优点是:
(1)模型可以更多地关注图像的相关区域
(2)因此降低了所需的图像处理能力
(3)“离焦”模糊区域仍然捕捉到正在发生的事情的一般概念
这种直觉可能有助于我们的增强 MNIST 数据集挑战,其中只有手指周围的图像区域需要更多的关注。
A 架构 整体架构中组件很少。
惊鸿传感器 惊鸿传感器是视网膜的实现,如下图所示:
这个想法是让我们的网络“看一眼”给定位置周围的图像,称为一瞥,然后提取这一瞥并将其调整为不同比例的图像作物,但每个比例都使用相同的分辨率。例如,上述示例中的 glimpse 包含 3 个不同的刻度,每个刻度具有相同的分辨率(也称为传感器带宽),例如 12x12。因此,中间最小比例的作物最清晰,而外环最大的作物最模糊。总之,Glimpse 传感器拍摄全尺寸图像和位置,输出给定位置周围图像的“类似视网膜”的表示。
Glimpse Network
一旦我们定义了 glimpse sensor,Glimpse Network 就是一个简单的环绕 Glimpse Sensor,拍摄全尺寸图像和位置,通过 Glimpse Sensor 提取图像的视网膜表示,展平,然后使用隐藏层和 ReLU 将提取的视网膜表示与 Glimpse 位置组合,发出单个矢量 g。该矢量包含“什么”(我们的视网膜表示)和“哪里”(图像内的聚焦位置)的信息。
递归网络
递归网络从 Glimpse 网络获取特征向量输入,通过其隐藏状态(和记忆单元)记忆有用信息。
位置网络
位置网络将递归网络中的隐藏状态作为输入,并尝试预测下一个要查看的位置。该位置预测将在展开的递归网络中的下一个时间步中成为 Glimpse 网络的输入。位置网络是整个想法中的关键组成部分,因为它直接决定了在下一个时间步骤中要注意的地方。为了最大化这个位置网络的性能,本文引入了一个随机过程(即高斯分布)来产生下一个位置,并使用强化学习技术进行学习。它也被称为“硬”注意,因为这个随机过程是不可微的(与“软”注意相比)。随机性背后的直觉是平衡开发(利用历史预测未来)和探索(尝试前所未有的东西)。请注意,这种随机性使得组件不可微,这将在反向传播期间引发问题。并采用强化梯度策略算法来解决这一问题,具体在强化学习部分讨论。
激活网络
激活网络将递归网络中的隐藏状态作为输入,并尝试预测位数。此外,预测结果用于生成奖励点,奖励点用于训练位置网络(因为随机性使其不可微)。
架构组合
结合以上所述的所有元素,我们就有了下面的网络架构。f_g 是瞥见网络,f_h 是循环网络,f_l 是位置网络,f_a 是激活网络。下图是为说明目的而展开的 2 个时间步长的递归。特别是,时间步数=每张图片的扫视次数
R 强化学习
由于位置网络是不可微的,所以采用强化学习,具体来说就是策略梯度法来训练网络的这一特殊部分。首先让我们看一下强化学习的概述。
概述 强化学习就是试错。强化学习的概述如下图所示。我们有以下组件:
- 代理人:大脑,也就是我们正在建模的神经网络。
- 环境:地球,是我们可以与之互动的未知世界。默认情况下,我们对环境一无所知。
- 相互作用:红色箭头,是代理和环境之间的相互作用。它可以是行动(将改变环境的代理输出)、观察(作为代理行动的结果的环境变化的结果)和奖励(代表代理行动“有多好”的一些标量值)。代理的目标是最大化它收集的报酬。
source: http://www0.cs.ucl.ac.uk/staff/d.silver/web/Teaching.html
强化学习的各种方法取决于我们试图优化的目标,分类如下:
- 政策:从状态到行动的映射。给定我们所处的位置(即状态),执行哪个操作
- 价值:评价一个状态有多好。处于某个状态有多好
- 模型:预测环境会怎样。了解敌人有助于赢得战争。
关于 RL 的更详细和全面的解释可以在这里找到。本文选择政策梯度作为 RL 方法,属于上述第一类。
应用到我们的问题 回到我们的问题,既然我们在用政策梯度来解决我们的问题,那我们就来谈谈“政策”本身。在我们的问题中,“政策”决定了我们如何选择下一个瞥见的地点。我们的答案(即策略)是,通过从参数为μ和σ的高斯分布中抽样,其中μ是均值,σ是标准差。这个高斯分布就是我们的随机过程。在这个实现中,我们将σ固定为网络超参数,只尝试学习μ。
为了说明随机网络的训练过程,下图显示了一个高级概念。蓝色箭头代表向前传球,红色箭头代表向后传球。我们的过程从将输入图像传入我们的网络开始。可微分网络将正常工作(例如 XW + b),表示为机器人头部。然后,随机网络(在我们的情况下是位置网络)将应用随机过程(在我们的情况下是高斯分布)来生成结果(在我们的情况下是下一次扫视位置的预测)。它被表示为抛硬币,以表示一个随机过程。然后由环境评估位置预测(以及使用 glance 的分类结果),现在我们有了开始反向传播的奖励。从概念上讲,通过随机网络的反向传播可以被认为是我们使我们的硬币更偏向于未来会给我们带来更多回报的方向,换句话说,我们学习高斯分布参数。这一步被描绘成一把锤子砸在一枚硬币上,来表示我们想要“锻造”对我们有利的硬币。
那么如何锤我们的硬币呢?我们来看看政策梯度的推导。假设我们有一个函数 f(x ),它可以告诉我们,如果我们有一个样本点 x,我们会得到多少回报,也就是一个得分/回报函数
Source: http://karpathy.github.io/2016/05/31/rl/
上面告诉我们,如果我们有一个样本点 x,为了在下一轮有更高的得分,我们应该“锻造”我们硬币的方式是得分函数的梯度方向(方程的左手边),这与样本点 x 的对数似然最大化的方向相同,具有 f(x)本身的振幅(方程的右手边)。
正式地说,我们“敲打”硬币的方式是增强算法,它代表REwardIncrement =Non negativeFactor timesOffsetRE enforcement timesCcharacter isticEligility(有人非常努力地拼出“增强”…)。原文参见[6]
Source: http://www0.cs.ucl.ac.uk/staff/d.silver/web/Teaching.html
安德烈·卡帕西的博客有一个更好的解释:
A visualization of the score function gradient estimator. Left: A gaussian distribution and a few samples from it (blue dots). On each blue dot we also plot the gradient of the log probability with respect to the gaussian’s mean parameter. The arrow indicates the direction in which the mean of the distribution should be nudged to increase the probability of that sample. Middle: Overlay of some score function giving -1 everywhere except +1 in some small regions (note this can be an arbitrary and not necessarily differentiable scalar-valued function). The arrows are now color coded because due to the multiplication in the update we are going to average up all the green arrows, and the negative of the red arrows. Right: after parameter update, the green arrows and the reversed red arrows nudge us to left and towards the bottom. Samples from this distribution will now have a higher expected score, as desired.
现在我们知道如何计算随机网络的梯度。然而,在实践中,tensorflow 计算图将默认自动计算梯度。因此,为了实现如 REINFORCE 所述的定制梯度更新,有两种方法可以做到:
(1)设置tf.stop_gradient
将梯度直接传递到可微分网络,然后使用混合损失函数仅训练可微分网络作为近似。这里的论点是,由于我们固定了高斯分布的 std,并且仅试图“学习”均值作为分布参数,所以锤打硬币本身将大致等同于锤打我们的可微分网络参数,以便从可微分网络发出我们期望的均值。参考本回购和本回购
(2)用优化器构建一个单独的计算图,并使用tf.gradients
具体计算所需的梯度 w.r.t 相关参数,然后使用optimizer.apply_gradients
仅更新这些参数。参考本回购
Training Methodology
作为上面讨论的实现细节,在本练习中,在实现中使用了混合损耗,方法(1)如上。
R = actual reward, b = score function, b_freeze = tf.stop_gradients(b)
由于 plus gate 在反向传播过程中充当梯度分配器,因此我们仅使用以下 3 个具有相同权重的目标来有效地优化我们的可微分网络:(1)用于预测正确性的交叉熵(2)用于回归最优μ作为随机网络的参数输入的 MLE)用于将分数函数回归到实际回报的分数函数(因此分数函数更准确)。
另一个技巧是蒙特卡罗抽样。由于我们在网络中有随机过程,我们可以复制相同的图像 10 次(由于随机性,这将产生 10 个略有不同的结果),然后将它们平均作为我们对训练和测试的预测。
训练参数如下所示。只比较了两种情况。
培训动态如下所示。上表中的训练时间是使用 Tesla K80 GPU 服务器进行基准测试的。训练准确率(每批平均)稳定在 80%,最终一次测试准确率为 79.68% ,与基准方法 50% 相比有显著提高。
L 仿 本节讨论的 RAM 方法的局限性包括:
(1) Glimpse 传感器使用扁平化+致密层。对于 MNIST 特征可能是足够的,然而,为了适合真实世界的图像,可以使用卷积层
(2)递归网络使用单层 RNN 单元。这个 RNN 细胞应该学习图像特征(为了预测数字标签)和位置特征(为了预测下一个扫视位置)。这种责任混合可能会导致一些内部问题。
(3)在展开 RNN 的初始步骤,位置网络随机选择一个位置聚焦其扫视作为起点。这可以改进为具有“更少的随机”开始。
谷歌在参考文献[3]中发表的后续论文解决了上述所有限制。本文将在下一节中作为处理 SVHN 数据集的目标架构进行讨论。
SVHN 数据集
SVHN 数据集是真实世界的街景门牌号数据集。如下图所示:
source: reference [1] paper
在 SVHN 数据集中,提供了以下信息:
(1)位数的长度
(2)每个位数
(3)位数的最大长度是 5
SVHN 数据集是我们的增强 MNIST 数据集挑战的扩展,从某种意义上说:
(1)图像中有噪声和模糊效果
(2)有数字的转换
(3)在我们的增强 MNIST 数据集中,它是有序的数字序列,而不是单个数字
数据预处理
对于图像,进行以下预处理:
- 从训练(和测试)数据中获取边界框位置
- 裁剪边界框的联合,以便将图像缩小到最大
- 调整到 32x32
- 转换为灰度
- 在[0,1]之间归一化
下图显示了一个示例图像:
对于标签,进行以下预处理:
- 0–9 代表数字,10 代表结束标记(或空标记,如果有多个)
- 将最大序列长度设置为 5
- 使用结束/空标记 10 填充
- 丢弃长度超过 5 位数的数据
例如,上面的图像标签将是:[1, 0, 5, 10, 10]
简介
研究了以下两种方法。
(1)一种“仅 CNN”的方法。主要思想是同时查看多个数字,并且如果该数字丢失,目标是以固定长度的数字顺序用空白填充来“分类”数字序列。这一思想借用了文献[1]中发表的论文。然而,为了快速建立比较基准,实现在一定程度上不同于本文。
(2)一种“RNN + CNN”的深度循环注意模式方法。其主要思想是引入深度视觉注意模型(DRAM ),参考文献[3]以扩展他们先前工作[2]中的循环注意模型(RAM)。其中提出了两层 LSTM 来分离扫视位置预测和图像特征处理。
基线方法:仅 CNN
问题描述 门牌号转写问题有以下几个因素需要我们注意:
- 存在多个数字(我们需要识别所有数字)
- 所有的数字都是有序的(我们需要识别序列)
- 有一个特定长度的数字序列(序列的长度不同)
设 P 表示概率,S 表示输出数字序列,L 表示数字序列的长度,X 表示输入图像数据。我们的目标可以解释为最大化以下内容:
在测试时,我们的预测是上述模型的 argmax:
这个模型包含了上面提到的所有 3 个因素。在本练习中,为了快速形成基线,实施了上述模型的一个小变化,但仍保留了以下 3 个因素:
- 长度大于 5 的门牌号将被丢弃
- 该模型将 5 个数字按顺序分类,每个数字的范围从 0 到 10。0–9 代表数字,10 代表空白填充。例如,门牌号“258”将导致正确的标签序列
[2,5,8,10,10]
- 没有使用长度,因为空白填充意味着长度信息
方法 本练习采用的总体思路是在架构上有两个网络:卷积网络和分类网络。
卷积网络用于从馈送图像中提取门牌号数字的特征,然后是分类网络,该分类网络使用 5 个独立的密集层来共同分类 5 个数字的有序序列,其中 0–9 表示数字,10 表示空白填充。
我们期望分类网络通过反向传播来学习数字布局的空间信息,使得每个密集层分别只拾取序列中的一个数字。
网络架构 原论文采用 8 卷积层的网络架构。在本练习中,为了快速形成基线,使用了一个更简单的网络(同时仍保留图层类型),如下所示:
请注意,在分类网络中,5 个独立的密集层负责将现有要素分类为 0-10 类标签,其中 0-9 表示数字标签,10 表示空白填充。
训练方法 本文在 SVHN 数据集上取得了 96.03%的转录准确率,模型性能最好。在本练习中,随着模型、图像预处理和网络架构的变化,准确率达到了 87.64%,参见本文
限制 理想情况下,图像预处理步骤应仅适用于训练数据(例如,裁剪掉边界框的并集),其中保持验证/测试数据不变。然而,在实施中,参考本报告,验证/测试数据也在边界框周围裁剪。原始论文提到在图像预处理阶段首先定位数字周围的包围盒矩形。然而,它没有提到执行这种定位的确切方法。
TODO :或者,仅使用裁剪训练数据执行另一个基准
目标方法:深度循环注意模型(DRAM)
除了以前在循环注意模型(RAM)中的工作,让我们扩展以修复限制并应用于 SVHN 数据集。这个想法被称为深度循环注意模型(DRAM)。
架构 DRAM 的架构与 RAM 类似,除了:
- 位置网络→发射网络
- 提出了两层 RNN 单元:专用于预测下一个扫视位置位置 RNN(表示为 r 上标 2),以及专用于预测数字标签的分类 RNN(表示为 r 上标 1)。
- 引入上下文网络,利用下采样的粗糙图像设置位置 RNN 的隐藏状态。想法是将图像的一般上下文馈送到位置 RNN,以便它生成对聚焦扫视的第一位置的良好猜测(与 RAM 方法中开始的随机位置相比)。
顺序分类 为了扩展 RAM 的思想并申请顺序分类,提出了以下工作。
M onte Carlo 采样 它与 RAM 的想法相同,通过多次复制相同的图像,然后取平均值作为预测(文中提到的取对数平均值给出最佳性能)
C 通过这种方式,网络将更专注于对具有迫近误差的有序序列进行分类。
A 累积奖励 为了简化多对象分类,使用累积奖励,即与正确预测的标签成比例的奖励。
S 序列对数似然 序列对数似然呈现在以下目标函数中:
该目标函数是 MLE,其合并了来自发射网络(与 RAM 中的位置网络相同)的位置概率和来自分类网络(与 RAM 中的动作网络相同)的分类概率。
F 这里的解决方案是采用相同的训练数据,但让网络预测数字的反向序列,然后取平均值作为最终预测。这种方法提高了准确性。
结果 DRAM 在这个练习中没有实现(至少没有成功)。
Accuracy 参考论文,下表报告了 DRAM 在 SVHN 数据集上的准确率:
相对于我们的 11 层 CNN 的基线方法(3.96%的错误率),这不是一个显著的改进(3.9%的错误率)。然而,这种改进更多的是在计算开销上。
C 计算成本 计算成本如下图所示:
正如所观察到的,就所使用的参数数量和浮点操作数量而言,DRAM 明显更好,这是因为它采用了用于视觉注意力的一瞥的想法。
还有一件事:空间变压器网络
我觉得有义务提一下这篇论文(太受欢迎就不提了)。它以一种全新的不同方式解决这个问题。这个想法不是使用“硬”注意力,远离强化学习,而是建立一个完全可区分的“软”注意力模型。详情请参考文献[5]。
直觉是,既然注意力都是关于选择性地裁剪图像的一部分作为“注意力”,为什么不使用仿射变换,它以完全可微分的方式处理裁剪、平移、旋转、(各向同性)缩放和倾斜。神经网络需要做的唯一事情是学习这些仿射变换参数。因此,下图展示了一个很酷的想法。
u 是我们的原始输入图像。它首先被传递到定位网络,定位网络是具有可学习参数θ的仿射变换,例如如下所示。
然后,采样器将对变换图像的输出进行采样,以提供原始输入图像的“校正和调整大小”版本。通常,采样过程是双线性插值,这也是一个可微分的过程,如下所示。
这样,原始图像将被仿射变换(或处理)成校正后的输出图像,如下所示:
这个视频展示了空间转换器的效果,令人印象深刻。
结论
总之,我们已经讨论了以下方法来解决增广的 MNIST 和 SVHN 问题:
对于 MNIST:
(1)使用经典的 2 层 CNN,参考 keras 例子
(2)使用“硬”注意力模型 RAM,参考论文【2】
对于 SVHN:
(1)使用 11 层 CNN,参考文献[1]
(2)使用 DRAM 作为 RAM 的扩展,参考文献[3]
最后但同样重要的是,空间转换网络,作为“软”注意力解决方案
关于数据集
MNIST
原始的 MNIST 数据集可以从这里获得:http://yann.lecun.com/exdb/mnist/
SVHN
谷歌街景门牌号图片(SVHN),可从这里获得:http://ufldl.stanford.edu/housenumbers/
- 10 类,每个数字一类。数字“1”的标签为 1,“9”的标签为 9,“0”的标签为 10。
- 73257 位用于训练,26032 位用于测试,以及 531131 个额外的、难度稍低的样本,用作额外的训练数据
参考
[1]使用深度卷积神经网络从街景图像中识别多位数。Ian J. Goodfellow、Yaroslav Bulatov、Julian Ibarz、Sacha Arnoud 和 Vinay Shet (2013 年)。https://arxiv.org/abs/1312.6082
[2]视觉注意的循环模型,沃洛季米尔·姆尼,尼古拉斯·赫斯,亚历克斯·格雷夫斯,科雷·卡武克库奥卢,https://arxiv.org/abs/1406.6247
[3]视觉注意下的多物体识别,吉米·巴,沃洛季米尔·姆尼,柯雷·卡武克库奥格鲁,
[4]用无监督的特征学习读取自然图像中的数字,尤瓦尔·内策尔、王涛、亚当·科茨、亚历山德罗·比萨科、吴波、安德鲁·y·Ng 在 2011 年 NIPS 深度学习和无监督的特征学习研讨会上发表。http://ufldl . Stanford . edu/house numbers/nips 2011 _ house numbers . pdf
[5]空间变换网络,马克斯·贾德伯格,卡伦·西蒙扬,安德鲁·齐塞曼,科雷·卡武科库格卢,https://arxiv.org/abs/1506.02025
[6]联结主义强化学习的简单统计梯度跟踪算法,Williams 等,http://www-anw . cs . umass . edu/~ barto/courses/cs 687/Williams 92 Simple . pdf
[7] Github 回购
可视通信
视觉传达是一个可以在不同领域听到的术语。这也是我们理解数据世界的主要技能。但是它实际上是如何工作的呢?我们生活在信息时代,被成堆的数据所包围,但我们需要翻译这些数据的能力,以便每个人都能理解。当您开始进行更详细的分析时,探索您的数据可以为您节省大量时间。通过图形可视化数据是快速探索和产生未来分析想法的好方法。
探索数据应该是任何分析的第一步,它包括汇总、可视化和对数据集中记录级细节的评估。为此,我将使用开源工具: python 、 Numpy (科学计算)、 pandas (数据操作)使 python 可用于数据分析、matplotlib/seaborn(制作图形)。
我们来探究一些实际数据。
https://www . ka ggle . com/Megan risdal/la-county-restaurant-inspections-and-violations/home
这是来自 kaggle 的洛杉矶县餐馆检查和违规数据集。
**背景:**洛杉矶县的餐馆和市场定期接受卫生法规违规检查。根据卫生部的说法,严重的违规行为会导致食物污染或疾病。一些严重的违规行为,如厨房里的啮齿动物,往往会引起公众的警觉,而一些违规行为,如错误的食物温度或未标记的清洁化学品,最容易开始传播食源性疾病。
在开始之前,最好在头脑中有一些问题和假设。
所以我们有两个文件:inspections.csv 和 violations.csv。
**违规:**该数据集包含洛杉矶县餐馆和市场的环境卫生违规。洛杉矶县环境卫生部门负责检查所有未合并地区和该县 88 个城市中的 85 个城市的食品违规行为。
**检查:**该数据集包含洛杉矶县餐馆和市场的环境健康检查结果。
我希望找到最有可能出现严重违规的食品机构,以便首先检查它们,并让关心的人避开它们。为此,我们需要计算完整检查的数量,并探索风险水平。
设置图书馆:
import numpy as np
import pandas as pd
import seaborn as sns
import plotly.plotly as py
import matplotlib.pyplot as plt
要获得数据集的第一个视图,我们可以使用以下 pandas 命令:
- df.describe()
- df.head() #显示了几行
- df.shape()
- df.columns() #列名
- df.info() #数据类型
inspections.info() 的输出应该是这样的:
在这里,我们可以看到数据集中有多少行,具有给定的 20 列数据类型的名称,以及关于空值的信息。Inspections.csv 不包含任何空值,这在现实生活中很少见。通常情况下,数据需要一些清理和转换。
正如所定义的,让我们按检验日期探究食品检验的次数。使用来自 inspections.info() 的信息,我们可以看到 activity_date 列的数据类型为“object ”,但是由于我们想要查看时间序列数据,我们需要将其更改为 dateTime。因此,下一步是创建一个数据框架,我们可以在其中计算每天的检查量,并创建一个时间序列数据图。
# groupby activity_day to create new column with the name count
count_ins = inspections.groupby(['activity_date']).size().reset_index(name='count')
x = pd.DataFrame(count_ins['activity_date'])
y = pd.DataFrame(count_ins['count'])# create separate df
timePlot = pd.concat([x,y], axis=1)# change data type 'object' to 'dateTime'
timePlot.activity_date = pd.to_datetime(timePlot.activity_date)
timePlot.set_index('activity_date', inplace=True)# show the first 10 raws, what we get
timePlot.head(10)
确保在设置数据帧timePlot
的索引时包含inplace
参数,以便实际修改原始索引并将其设置为'activity_date'
列
我们还可以找到最小/最大日期,因此我们可以定义执行检查的确切时间段。
inspections.activity_date.max()
'2017-12-29'
inspections.activity_date.min()
'2015-07-01'
现在我们有了一切可以在图中形象化的东西:
timePlot.plot.area(figsize=(20,6), linewidth=5, fontsize=15, stacked=False)
plt.xlabel('Activity Date', fontsize=15)
Number of Food Inspections by Inspection Date
鉴于检查员必须完成大量的检查,发现严重违规行为所花费的时间和精力可能意味着在一些食品企业长期暴露在潜在的疾病和不卫生的条件下。
从这张图表中,你可以立即开始思考一些问题,以便进一步分析:
每个检验员执行多少次检验?一个月中是否有增加或减少检查的时间?
现在只看检查员检查平均值就足够了:
count_id = inspections.groupby(['employee_id']).size().reset_index(name='count')
x = pd.DataFrame(count_id['employee_id'])
y = pd.DataFrame(count_id['count'])
count_id = pd.concat([x,y], axis=1)
count_id['count'].describe()
我们在这里可以看到,有 250 个不同的检查员,他们的“雇员 id”和平均值是:在给定的时间内,每个检查员大约检查 765 次。
我们调查的下一步是找到最严重违规的食品企业,这些企业需要长期特别关注。我们有 18 种不同的风险等级。从下面的柱状图可以看出,最大的群体是餐馆高风险等级。
*# Number of Food Inspections by Risk*sns.set(rc={'figure.figsize':(14.7,8.27)}) # set size for a chartg = sns.countplot(x="pe_description", data=inspections, order = inspections['pe_description'].value_counts().index, palette="Blues_d")
g.set_xticklabels(g.get_xticklabels(),rotation=90)
g.tick_params(labelsize=10)
Number of Food Inspections by Risk (sorted by count):
让我们来定义餐厅(0-30)座位风险高的前 20 家餐厅。
rsk = inspections.loc[inspections['pe_description'] == "RESTAURANT (0-30) SEATS HIGH RISK"]
pd.crosstab(index=rsk['facility_name'], columns='count').sort_values(by=['count'],ascending=False).head(20)
要查看整个高级别风险组,我们需要创建一个新要素,该要素仅包含餐馆和食品市场的风险级别。我们有三组级别:高、中、低。
**55.37%**的检查是针对高风险餐厅的。
为了得到这个图表,我做了以下工作:
# new feature: risk_level
inspections['risk_level'] = inspections['pe_description'].apply(lambda x: x.split(")")[1])
制作图表:
# replace SEATS with RESTAURANT to make it clearinspections['risk_level'] = inspections['risk_level'].str.replace('SEATS', 'RESTAURANTS')
ax = inspections['risk_level'].value_counts().plot(kind='barh',colormap='Blues_r', figsize=(15,7), fontsize=13);
ax.set_alpha(0.5)
ax.set_title("Risk Level", fontsize=18)
totals = []
*# find the values and append to list*
for i **in** ax.patches:
totals.append(i.get_width())
*# set individual bar lables using above list*
total = sum(totals)
*# set individual bar lables using above list*
for i **in** ax.patches:
*# get_width pulls left or right; get_y pushes up or down*
ax.text(i.get_width()+.3, i.get_y()+.38, \
str(round((i.get_width()/total)*100, 2))+'%', fontsize=10, color='dimgrey')
*# invert for largest on top*
ax.invert_yaxis()
在下一个条形图中,我们可以看到检查数量最高的食品企业:
inspections['facility_name'].value_counts().nlargest(20).plot(kind="bar", figsize=(15, 6), fontsize=12, colormap='Blues_r')
The top 20 Food Establishments (sorted by count of inspections)
地铁检查量最高。让我们调查一下风险水平。
subway = inspections.loc[inspections['facility_name'] == 'SUBWAY']
pd.crosstab(index=subway['risk_level'], columns='count').sort_values(by=['count'],ascending=False)
Risk Level for Subway
正如我们所看到的,赛百味只有中度风险。
现在,如何可视化风险级别组和食品机构检查已经足够清楚了。让我们继续讨论健康法规。
我想看到十大违反卫生法规的描述。我们可以在水平视图中使用条形图来查看前 10 个代码描述。为此,我们需要合并两个数据集。
df_merge = inspections.merge(right=violations.reset_index(), how='left', on='serial_number', suffixes=('', '_codes_'))# create a plot using seaborn
sns.set(rc={'figure.figsize':(14.7,10.27)})
top10 = sns.countplot(y="violation_description", data=df_merge, order = df_merge['violation_description'].value_counts().nlargest(10).index, palette="Blues_d")
top10.tick_params(labelsize=20)
排名第一的健康准则是№44 层楼、墙和天花板:正确建造,保持良好的维修和清洁。我想说,这是意料之中的事。
在这篇文章中,我最不想看到的是按邮政编码排列的食品检验数量。
Number of Food Inspections by Zip
结论:
我完成了第一阶段的探索。在对数据集进行简要分析后。我们发现,在洛杉矶县有持续的检查,检查食品企业是否违反卫生法规。不同的违法行为反映了对公众健康和安全的不同程度的风险。从 2015 年 7 月 1 日到 2017 年 12 月 29 日,共进行了 191371 次检查,其中 55.37%为高风险级别。我们还创建了一份清单,列出了检查次数和检查风险水平最高的食品企业。除此之外,我们还有 10 大代码描述和今天遇到它们的概率。
对于探索性数据分析、数据收集和处理,需要记住以下几点:
- 这可能会占用数据科学家 80%的时间
- 这是从数据语言到人类语言的转换
- 这是一种分析数据集以总结其主要特征的方法
- 它应该为您提供一个新问题列表,以探索您的数据集。
祝你胃口好。😃
卷积神经网络的视觉可解释性
通信网中的可视化技术介绍
Photo by Shane Aldendorff on Unsplash
**更新:**我已经在 PyData meetup 的一次演讲中详细介绍了这篇博文。可以看下面的 YouTube 视频。
在应用程序编程中,我们有调试和错误检查语句,如 print、assert、try-catch 等。但是当涉及到深度神经网络时,调试变得有点棘手。幸运的是,卷积神经网络(ConvNets 或 CNN)具有人类可以视觉解读的输入(图像),因此我们有各种技术来理解它们如何工作,它们学习什么以及它们为什么以给定的方式工作。而对于其他深度神经网络架构,可视化甚至更加困难。尽管如此,可视化神经网络给了我们关于神经网络世界的良好直觉。在这篇文章中,我们将深入研究 convnet,了解图像分类器如何工作,以及当我们将 224x224x3 的图像输入到 conv net 时会发生什么。
具体来说,我们将尝试各种可视化技术来了解:
- 每次卷积操作(可视化中间激活)后的输出是什么
- 每个过滤器从输入图像中提取什么特征(可视化过滤器/内核)
- 如何将每个卷积层的输出追溯到输入图像(使用解卷积网络又名解卷积/转置卷积进行可视化)
- 为 convnet 的每个图层在输入图像中可视化感兴趣区域(可视化热图)
“尽管取得了这么多进展,但人工智能领域的几乎所有重要问题似乎都没有答案。许多人甚至还没有被正式问过。”—弗朗索瓦·乔莱
VGG16 卷积神经网络
本文假设读者对 convnets 中的前向传播及其架构组件(如卷积、池和激活函数)有基本的了解。在整篇文章中,我们将使用 VGG16 模型进行可视化。每个可视化的 Jupyter 笔记本都是用 Keras 编写的,可以在我的 GitHub 存储库中找到:
[## himanshurawlani/conv net-可解释性-keras
使用 Keras-himanshurawlani/conv net-可解释性-keras 可视化 VGG16 卷积神经网络
github.com](https://github.com/himanshurawlani/convnet-interpretability-keras)
让我们看看 VGG16 模型是什么样的:
VGG16 convolutional neural network
每个卷积块的输出通过一个激活函数(本例中为 ReLU)传递。
可视化中间激活
在这种技术中,给定一幅输入图像,我们将简单地绘制出在每一层中卷积运算后每个滤波器提取的内容(输出特征)。例如,在 VGG16 中,输入层尺寸为 224x224x3,第一次卷积运算后的输出尺寸为 224x224x64(参见block1_conv1
)。这里,64 是用于在第一次卷积运算后提取输入特征的滤波器数量,因此我们将只绘制这 64 个 224x224 输出。
Visualizing the output of convolution operation after each layer of VGG16 network
释义:
- 初始层(
block1
和block2
)保留了大部分输入图像特征。看起来卷积滤波器在输入图像的每个部分都被激活。这给了我们一种直觉,即这些初始滤波器可能是原始的边缘检测器(因为我们可以认为一个复杂的图形是由不同方向的小边缘组合而成的。) - 随着我们越来越深入(
block3
和block4
),过滤器提取的特征在视觉上变得越来越难以解释。对此的直觉是,convnet 现在正在提取输入图像的视觉信息,并试图将其转换到所需的输出分类域。 - 在
block5
(尤其是block5_conv3
)中,我们看到很多空白的卷积输出。这意味着在输入图像中找不到由过滤器编码的图案。最有可能的是,这些图案必须是不存在于该输入图像中的复杂形状。
为了详细说明第 2 点和第 3 点,我们可以将这些见解与我们自己的视觉感知进行比较:当我们看一个物体(比如自行车)时,我们不会坐下来观察该物体的每个细节(比如把手、挡泥板、车轮防滑钉等)。).我们所看到的是一个有两个轮子的物体,轮子由一根金属棒连接着。因此,如果我们被告知要画一辆自行车,这将是一个简单的草图,仅仅传达了两个轮子和一个金属杆的想法。这些信息足以让我们决定给定的对象是一辆自行车。
类似的事情也发生在深层神经网络中。它们充当信息提取管道,将输入图像转换到视觉上不太容易理解(通过移除不相关的信息)但数学上对 convnet 从其最后一层的输出类中做出选择有用的域。
可视化过滤器
我们上面看到的可视化是卷积运算的输出。卷积运算最基本的术语是滤波器/内核和输入图像之间的相关性。与给定输入区域最匹配的滤波器将产生幅度更高的输出(与来自其他滤波器的输出相比)。通过可视化过滤器,我们可以了解每一层已经学会从输入中提取什么模式。
我们首先将一些随机噪声作为输入图像,并使其通过 convnet。我们获取给定层的输出,我们希望可视化该层的过滤器,并找到该层中每个过滤器的平均值。这个寻找每个滤波器的平均值的步骤形成了我们的损失函数。例如,block1_conv1
的输入为 224x224x3,输出为 224x224x64,因此它有 64 个过滤器。这里,我们沿着 x 和 y 方向找到每个 224x224 滤波器的平均值,并且我们对所有 64 个滤波器都这样做。在每一步中,我们采用一个滤波器,计算其平均值(即损失)并更新我们的输入图像,使得该滤波器的输出最大化。我们使用梯度上升来更新我们的输入图像,以便最大化损失(特定滤波器的响应)。所得的输入图像将是所选滤波器最大程度响应的图像。
Visualizing the filters/kernels of each layer of VGG16 network
释义:
- convnet 中的每一层都简单地学习一组滤波器,使得它们的输入可以表示为这些滤波器的组合。初始图层(
block1
和block2
)滤镜看起来像是简单的方向性边缘和颜色(或者在某些情况下是彩色边缘)的集合。这是我们在之前的视觉化中的第一个观察的原因。 - 随着我们深入(
block4
和block5
),我们看到更多复杂的形状被过滤器编码。这些过滤器可能有助于提取眼睛、鼻子、耳朵等。随着形状变得越来越复杂,它们出现在给定输入图像中的机会越来越少。这就是我们在之前的可视化中的第三个观察的原因。 - 许多这样的滤波器是相同的,但是旋转了一些非随机的因子(通常为 90 度)。这意味着,通过找到一种使卷积滤波器旋转不变的方法,我们有可能大幅压缩 convnet 中使用的滤波器数量。
这种经过训练的模型的可视化不仅可以洞察其操作,而且有助于诊断和选择更好的架构。ZF 网(2013) [1]的论文使用这种技术来可视化 AlexNet (2012) [2]架构的第一层和第二层过滤器。他们发现,第一层过滤器是极高和极低频率信息的混合,很少覆盖中频(图像中的低频意味着像素值在空间中缓慢变化,而高频内容意味着像素值在空间中快速变化)。此外,第二层可视化显示了由第一层卷积中使用的大步幅引起的混叠伪像。
他们通过将第一层滤波器大小从 11x11 减小到 7x7 来解决这些问题,并将卷积的步长从 4 改为 2。新架构在第一层和第二层功能中保留了更多信息。更重要的是,它还提高了分类性能。
使用 deconvnets 可视化
解进化网络(deconvnet),是由泽勒等人提出的,2011 [3]。deconvnet 可被视为使用相同组件(过滤、池化)的 convnet 模型,但方向相反,因此 deconvnet 不是将像素映射到要素,而是将要素激活(卷积输出)投影回输入像素空间。
A deconvnet layer (left) attached to a convnet layer (right). [1]
为了可视化 convnet,deconvnet 被附加到它的每个层,提供返回图像像素的连续路径。首先,将输入图像呈现给 convnet,并计算各层的特征。为了检查给定的 convnet 激活,我们将该层中的所有其他激活设置为零,并将特征映射作为输入传递给附加的 deconvnet 层。然后,我们连续地(I)取消 pool,(ii)校正和(iii)过滤,以重建引起所选激活的下层中的活动。然后重复这一过程,直到到达输入像素空间。参见 ZF 网论文[1]的第 2.1 节,了解更多关于未冷却、精馏和过滤的详细信息。
对于给定的层,我们取具有最高激活(幅度)的前 4 个滤波器的输出。我们使用类似的函数来计算激活幅度,就像我们对可视化过滤器所做的那样(损失函数)。在那里,我们计算所有维度的平均值,但在这里,我们计算所有维度的总和,并按降序对过滤器进行排序。例如,对于给定的输入图像block1_conv1
,要激活前 4 个滤波器,我们找到沿 x 和 y 方向的所有 64 个 224x224 滤波器的输出之和,按降序对它们进行排序,并将前 4 个输出馈送到我们的 deconvnet。这给了我们由这些滤波器看到的输入图像的 4 种不同变化。
释义:
- 每个图层的投影显示了网络中要素的等级性质。
block1
响应角点和其他边缘/颜色连接。block2
和block3
具有更复杂的不变性,捕捉相似的纹理(例如网格图案)。block4
尝试定位图像的部分,如眼睛、鼻子、嘴等。block5
显示整个局部人脸。
将特征激活投影回输入空间,让我们类似地了解这些层中的过滤器是在什么情况下被激活的。我们看到一些投影具有突出的水平边缘,一些具有突出的垂直边缘。一些投影覆盖眼睛,鼻子,嘴,一些覆盖整个脸。将每个顶部激活分别向下投影到像素空间揭示了输入图像中激发给定特征图的不同结构。
可视化热图
在这项技术中,我们使用 GradCAM 并试图了解输入图像的哪些部分导致了 convnet 做出特定的分类决策。该技术的一般类别被称为“类激活图”(CAM)可视化,包括在输入图像上产生“类激活”的热图。“类别激活”热图是与特定输出类别相关联的分数的 2D 网格,针对输入图像中的每个位置计算,指示每个位置相对于所考虑的类别有多重要。这有助于我们调试卷积神经网络的决策过程。我们也可以使用相同的技术来定位图像中的特定对象。看看这个演示:http://gradcam.cloudcv.org/
在 GradCAM 中,我们采用给定输入图像的卷积层的输出,并通过预测类的梯度对该输出中的每个通道进行加权。假设我们给 convnet 输入了一些图像,得到了“大象”作为预测。最后一个预测层可以被认为是具有一些输入的函数(在这种情况下是block5_conv3
的输出)。所以,如果f
是预测层,x
是block5_conv3
的输出,那么预测层的输出可以被给定为y
,其中y=f(x)
。同样的,我们可以证明block5_conv3
是一个有一些输入的函数g
(本例中是block5_conv2
的输出)。让我们把block5_conv2
的输出看作z
然后x
(可以把block5_conv3)
的输出看作x=g(z)
等等…
使用上述类比,我们可以将具有输入的预测层的输出视为其所有先前层(以嵌套方式)。我们对某个先前层(我们希望热图可视化的层)中的每个通道的预测输出 w.r.t .进行偏导数,这给出了每个通道对预测输出的重要性。然后,我们将每个通道与其对应的梯度(重要性)相乘,以对负责预测输出的每个通道进行加权,并计算通道平均值,以获得该层的热图。
Heatmap visualization using GradCAM technique for each layer of VGG16 network
释义:
- VGG16 网络只是一个图像分类器,能够在输入图像中定位大象。
- 该网络以 90%的准确率预测了输入图像中的“非洲象”,主要是因为小象的面部和耳朵部分(见
block5_conv3
)。这大概就是网络如何区分非洲象和印度象的。
当我们看到不同层的热图时,我们看到图像的不同部分被激活。这是因为早期的图层有滤镜,可以看到图像的不同部分。但是类别预测很大程度上取决于预测之前层的激活,因此,可视化预测层之前层的热图(在这种情况下为block5_conv3
)告诉我们输入图像的哪个部分导致了特定的预测。
结论
- 这些可视化技术不仅告诉我们模型已经学会在图像中识别什么,还告诉我们它的性能可以在哪里改进。它为我们提供了关于模型可解释性的有用见解,因此我们可以放心地在现实世界的用例中部署这些模型。
- 令人惊讶的是,我们不仅可以重新训练分类器来识别图像中的对象,还可以使用 GradCAM 可视化技术来近似定位它们。看看这个演示:https://www.youtube.com/watch?v=COjUB9Izk6E
- 在一天结束时,由 convnets 学习的所有参数和过滤器的目标是最小化给定训练数据的成本函数。这个成本函数和训练数据定义了我们的 convnet 的能力。
进一步阅读
- 可解释性的基石:https://distill.pub/2018/building-blocks/
- 通过深度可视化理解神经网络:http://yosinski.com/deepvis
- 想象一下康夫尼特学到了什么:http://cs231n.github.io/understanding-cnn/
- 跟踪网络中发生的事情的有用工具箱:https://cs.stanford.edu/people/karpathy/convnetjs/
参考
[1]可视化和理解卷积网络,https://arxiv.org/abs/1311.2901v3
[2]使用深度卷积神经网络的 ImageNet 分类,https://papers . nips . cc/paper/4824-ImageNet-class ification-with-Deep-convolutionary-Neural-Networks
[3]用于中高级特征学习的自适应去进化网络,【https://ieeexplore.ieee.org/document/6126474
[4]可视化 convnets 学习的内容,https://github . com/fchollet/deep-learning-with-python-notebooks/blob/master/5.4-Visualizing-what-conv nets-learn . ipynb
[5]卷积神经网络如何看待世界,https://blog . keras . io/How-convolutionary-neural-networks-see-the-world . html
数据框可视化概述入门
数据可视化不仅是在清理数据后分析数据和交流结果的一种方式,也是在初始阶段理解整个数据框架的一种方式。在这里,我举例说明了 3 个简单的方法(每个方法 2 行代码),用于可视化地探索整个数据帧的组成、相关性和分布。
ggpairs
ggpairs 将绘制变量矩阵,并根据它们是分类的还是数字的来使用合适的视觉类型。
library(GGally)
ggpairs(iris, aes(colour = Species, alpha = 0.4))
特色剧情
插入符号中的特征图可以在方框/密度图中单独绘制每个变量的网格,或者在散点图矩阵中成对绘制。
library(caret)
featurePlot(x=iris[,1:4], y=iris[,5], plot="box", scales=list(x=list(relation="free"), y=list(relation="free")), auto.key=list(columns=3))
表格图
Tableplot 将绘制每个变量的表格。对于范畴来说,这是探索其构成的好方法。如果存在缺失值,它也会显示出来。
library(tabplot)
tableplot(iris)
这些方法更适用于少于 10 维的数据帧,其中的列主要不是自由文本,因为它们可以相对容易地可视化数字和分类变量。探索更多适合不同类型的数据框架(重文本、高维)的方法。
这是我第 100 天项目的第 6 天。
用 R 视觉化伦敦的犯罪(上)
我最近在使用 r 可视化伦敦犯罪的时间序列数据。我忍不住创建了地图,让我可以更好地分析数据。
我创建本教程是为了:
- 有一个用 R 绘制地图的简单例子
- 展示在地图中可视化数据的优势,以便更容易地识别模式和趋势。
在本教程中,您将学习如何使用SpatialPolygonsDataFrame
访问绘制行政区所需的数据,以及如何使用ggplot2
创建相应的地图。
本教程的代码和数据可以在 github 链接上找到。
访问数据
犯罪数据
本教程中使用的数据集来自伦敦数据存储库,这是一个开放的数据共享平台,其统计数据由伦敦市长办公室提供。为了使教程简单,我只包含了一个名为crime_data.csv
的 CSV 文件,其中只包含绘制犯罪率所需的数据。
上面的代码加载犯罪数据并更改标题的名称。它将显示以下内容:
行政区的空间数据
你现在需要使用readOGR
来加载LondonBoroughs.shp
。
LondonBoroughs.shp
是项目的‘Map _ data’文件夹中的 shapefile。您会注意到几个名为“LondonBoroughs”的文件具有不同的文件扩展名。你需要它们,因为 shapefile 是由许多不同的文件组成的。prj,。dbf 和. shp。
readOGR
将简单地提取 shapefile 中的信息。
上面的代码将显示以下数据:
将犯罪数据与空间数据联系起来
既然您已经有了两个数据集,那么您需要将它们链接在一起。为此,您只需使用left_join
并将name
和bourough
用作 id。
运行代码后,您会注意到两个数据集现在已经链接在一起:
将空间数据转换为数据帧
准备好数据的最后一步是使用fortify
将其转换成数据帧。这是必需的,因为ggplot
需要一个数据帧来创建地图。
如果您运行上面的代码,您会看到数据看起来是一样的。唯一的区别是它现在是一个数据帧(注意,您不再需要使用@data
来查看信息):
如果你不信任我,就在你的控制台上运行下面的代码,仔细检查你使用的数据类型😃
Just a test!
可视化地图
现在,您已经有了绘制第一批图表的数据。
如下图所示,你需要的只是ggplot
。使用fill=
2013``根据列“2013”中的数据创建颜色渐变,这是相应年份每个区的犯罪率。
假设您不需要long
和lat
出现在图形中,那么您需要删除轴和记号。
通过运行上面的代码,您应该能够看到您的第一个图表:
如果您想创建一个 GIF 来显示一段时间内的变化,您需要首先以下列方式之一将每年的图表保存为图片:
- 通过使用
ggsave()
(例如:ggsave("plot_2013.png")
),或者 - 通过右键单击图表并导出
确保所有图表的图例值保持相同(如果图例发生变化,可能会影响地图的大小)。为此,只需将limits(0, max_value)
添加到scale_fill_gradient2
中。在这种情况下,max_value 可以是 140。scale_fill_gradient2
的最终结果如下所示:
scale_fill_gradient2(low = "#BDBDBD",high = "#2196F3", # colors
name = "Crime rate", limits = c(0, 140))
然后你需要做的就是把这些图片添加到 gif 创建工具中,就像从 Giphy 中得到的一样。最终结果将如下所示:
从上面的图表中,你可以注意到随着时间的推移,所有行政区的犯罪率都下降了。远离市中心的行政区似乎犯罪率最低,而靠近市中心的行政区似乎犯罪率最高。
犯罪率最高的行政区
如果您只想给犯罪率高于特定水平(例如 90)的行政区着色,那么您需要做的就是将填充中的值更改为fill=
2013>90
。
该图的完整代码如下所示:
结果如下图所示:
Boroughs with crime rates above 90 in 2013
从上面可以看到,2013 年犯罪率在 90 以上的行政区有兰贝斯、哈克尼、哈林盖、纽汉等。
下一个教程
在下一个教程中,我将展示如何在一个图表中绘制每年的地图。这真的很容易。
我希望你喜欢这个教程❤.
如果您有任何问题,请使用下面的评论部分。
谢谢!
关于作者
我是 Valeria,我热衷于通过美丽的可视化和分析进行数据发现。我希望你喜欢这篇文章!
你可以在 Twitter 和 Instagram 上找到我,或者访问我在 valeria.io 的页面。
使用 Plotly 可视化经济数据
因为我是一名经济学家,热爱编程和数据科学,所以我想把这些激情结合起来,做一些有趣的数据分析。这篇文章利用各种 python 库来抓取和可视化经济数据。我希望这能对你们中的一些人有用,并且你们能像我一样喜欢阅读这篇文章。
我需要做的第一件事是获取一些数据。既然维基百科是所有互联网知识的来源(不是!!)就从这里开始吧。我决定从下面的维基百科页面中抓取一个表格:[ 维基 ]。我认为观察世界上一些最富有和最贫穷的国家会很有趣。这张表是根据人均 GDP 对各国进行排名的。
在我继续讲下去之前,简单解释一下什么是人均 GDP 可能是个好主意(你会想当然地认为很多人并不真正讲“经济学”)。简单来说,它是衡量一个国家富裕程度的指标。它实质上是一年内在一个国家境内生产的所有商品和服务的价值除以人口。这给了我们一种描述该国人均财富水平的方法。这是一个非常重要的经济变量,通常用于比较不同国家和不同时期的财富水平。
一般来说,人均国内生产总值可以增加,原因如下。
1。国内生产总值增加
2。人口减少
3。两者的结合。
这一指标通常被认为比 GDP 更能反映一个国家的富裕程度。现在我们有了简单的经济学入门,让我们深入分析一下。正如我之前提到的,我将废弃维基百科上的数据,所以使用美丽的汤似乎是显而易见的。这个库极大地简化了从网页中提取数据的过程,是 python 中 web 抓取的首选库。
什么是 BeautifulSoup?
Beautiful soup 是一个 python 库,用于从 html 和 xml 文件中提取数据。这使得这个库对于从网页中提取信息非常有用。如果你想知道更多关于这个库是如何工作的,以及你可以用 beautiful soup 执行的各种任务的信息,请随意阅读[文档
为了使用漂亮的汤,有必要了解一些简单的 html 标签。对 html 有一点了解将会使我们更容易搜索到我们想要的数据。例如,维基百科在其网页上显示的表格中使用了表格标签。知道了这一点,我们就可以简单地解析 html,只寻找包含在这些标签中的信息。
首先,我需要导入分析所需的所有库。
import requestsfrom bs4 import BeautifulSoupimport matplotlib.pyplot as pltimport seaborn as sns%matplotlib inlinefrom bubbly.bubbly import bubbleplotfrom plotly.offline import download_plotlyjs, init_notebook_mode, plot, iplotimport plotly as pyimport plotly.graph_objs as goinit_notebook_mode(connected=True) #do not miss this linefrom plotly import tools
现在我已经加载了库,我们准备开始分析。下面的代码允许我们将网页加载到我们的 Jupyter 笔记本中,并将其传递给 BeautifulSoup 类以创建一个 Soup 对象。
web_page=“[https://en.wikipedia.org/wiki/List_of_countries_by_GDP_(PPP)_per_capita](https://en.wikipedia.org/wiki/List_of_countries_by_GDP_(PPP)_per_capita)"req=requests.get(web_page)
page = req.text
soup = BeautifulSoup(page, ‘html.parser’)
soup.title
好了,看起来它工作了,我们可以在 soup 对象上使用一些函数并提取我们想要的数据。我之前提到过我们对表标记感兴趣。下面是从 wiki 页面提取所有表格的代码。
table = soup.find_all(“table”, “wikitable”)
len(table)from IPython.display import IFrame, HTML
HTML(str(table))
上面的代码返回一个列表,其中每个条目包含页面上的一个表。这个页面只有五个表,所以很容易得到我们需要的表,它恰好是列表中的第一个条目。我们还可以通过使用 IPython.display 中的 HTML 命令来确认它是否正确,该命令会打印出维基百科上显示的表格。
现在我们有了表格,接下来的问题就是得到国名和人均 GDP。要做到这一点,我们需要知道更多关于 HTML 表格的结构。特别要知道、和标签。它们分别代表表头、表行和单元格。好的,让我们试着提取一些数据。
GDP_PC = table[0]
table_rows = GDP_PC.find_all(‘tr’)
header = table_rows[1]table_rows[1].a.get_text()
这段代码查找所有指示表格行的 tr 标签。然后我们得到表格的标题,并打印出来,给出下面的结果。这对应于国家名称,我们使用 a.get_text()提取我们需要的名称。table_rows 中的每个索引对应一个国家,国家名位于标签中,对于索引的每个值都是相同的。
现在,我们需要做的就是遍历 table_rows,提取数据并添加到一个列表中。
countries = [table_rows[i].a.get_text() for i in range(len(table_rows))[1:]]
cols = [col.get_text() for col in header.find_all(‘th’)]
Python 有一个非常好的简洁的方法,使用列表理解来编码这类循环。注意我跳过了 table_rows 的第一个条目,因为它不对应于一个国家。我们还使用列表理解来提取列标题,这在以后会很有用。上面的代码相当于下面的 for 循环。
country = []
for i in range(len(table_rows))[1:]:
country.append(table_rows[i].a.get_text())
接下来是标签。这是我们的人均 GDP 数据存储在表中的位置。然而,数据是相当混乱的,我们可以使用许多变通方法将正确的数据转换成正确的格式。让我们快速看一下其中一个数据点。
temp = GDP_PC.find_all(‘td’)
temp[5].get_text()
这给了我们’ 114,430\n '。我们可以看到所有的数据都被定义为字符串
,每个单元格中都有逗号和换行符,所以我们需要稍后修复这个问题。首先,让我们集中精力将数据放入一个列表中。
temp = GDP_PC.find_all(‘td’)
GDP_per_capita = [temp[i].get_text() for i in range(len(temp)) if “,” in temp[i].get_text()]
GDP_per_capita = [i for i in GDP_per_capita if ‘\xa0’ not in i]temp_list = []
for i in range(len(temp)):
temp_list.append(temp[i].get_text())
new_list = temp_list[-11:]numbers = [i for i in new_list if “\n” in i]for i in numbers:
GDP_per_capita.append(i)rank = list(range(len(countries)))
上面的代码中有很多内容,让我们一步一步来看。我做的第一件事是找到 GDP_PC 中的所有单元格,并存储在一个临时变量中。
下一行循环遍历该变量,并获取包含逗号的文本。我这样做是因为大多数条目都是以千为单位的,因此包含一个逗号。然而,这种方法确实错过了最后四个条目,因为它们花费了数百美元,所以我必须创建一个解决方法,这就是 new_list 和 numbers 变量正在做的事情。最后,我将这些条目添加到人均 GDP 列表中,并生成一个 rank 列,其中只有从 1 到 192 的数字。这可能不是最有效的方法,可能有更好的方法,但它确实有效,所以我很满意。
在提取了排名、国家和人均 GDP 这三列列表后,我们需要将它们合并在一起,创建一个熊猫数据框。这将使绘制和分析数据更加简单。有一个名为 zip 的便捷函数允许我们创建两个独立的数据框。一个是最富有的 20 个国家,一个是最贫穷的 20 个国家。下面的代码实现了这一点。
data = zip(rank[0:21],countries[0:21], GDP_pc[0:21])
import pandas as pd
cols = [‘Rank’, ‘Country’, ‘GDP Per Capita’]
data1 = pd.DataFrame(list(data), columns = cols)data2 = zip(rank[-21:],countries[-21:], GDP_pc[-21:])
data2 = pd.DataFrame(list(data2), columns = cols)
我们现在有了熊猫数据框中排名前 20 和后 20 的国家。在我们绘制数据之前,我们需要做一些清理工作。数据目前被定义为字符串,所以我们需要解决这个问题,以便使用某些熊猫函数。下面的代码删除了 HTML 换行符“\n”、逗号,并将数据类型定义为 int。
data1['GDP Per Capita'] = data1['GDP Per Capita'].apply(lambda x: x.replace('\n', '')).astype(int)data2['GDP Per Capita'] = data1['GDP Per Capita'].apply(lambda x: x.replace(',', '')).astype(int)
我们终于准备好数据来创建一些好看的可视化。
Plotly 简介
现在我们可以进入 Plotly 来创建我认为非常好的可视化。我真的很喜欢这个库,它足够简单,可以制作出非常互动的情节。如果你想知道你能创建什么样的图表,我鼓励你阅读文档[ 网站
下面的代码创建了一个简单的世界上最富有的 10 个国家的条形图。首先,我们将数据传递到。条形图创建一个条形图,x 轴表示国家名称,y 轴表示人均 GDP。然后,我们将它存储在一个列表中,并传递给 go。图形方法。这里的相同步骤适用于在 Plotly 中创建所有不同类型的地块。有些结果可能会让你吃惊,也可能不会。例如,排名前 10 位的国家中,不乏卡塔尔和科威特等高度依赖石油生产的国家,这些国家政府收入的大约 70%至 94%来自石油。这些国家中的许多往往人口相对较少,经济规模较大,因此根据这一标准(相对较少的人口分享了大量财富),它们非常富有并不令人惊讶。
trace1 = go.Bar(
x = data1.Country,
y = data1[‘GDP Per Capita’])data = [trace1]
layout = go.Layout(
title=’Top 20 countries ranked by GDP per Capita’)fig = go.Figure(data = data, layout = layout)
py.offline.iplot(fig)
很简单,对吧?现在对于最贫穷的国家来说。毫不奇怪,这些国家往往集中在非洲,那里人口增长迅速,经济落后于更发达的国家。
在快速了解了排名前 10 和后 10 的国家之后,让我们试着从整体上对世界进行更广泛的了解。做这件事的一个好方法是使用地图。在 Plotly 中,你可以创建 choropleth 地图,它基于一些变量对不同的区域进行着色。在我们的例子中,这是人均国内生产总值。人均 GDP 较高的国家会有较深的红色阴影。关于这段代码,需要注意的最重要的事情是传递到 locations 参数和 location mode 参数中的国家名称。这些必须匹配,情节才能起作用。你也可以使用国家代码,甚至经度和纬度来实现相同的情节,但我认为这可能是最简单的方法。请注意,Plotly 允许您放大特定区域以进行近距离观察,这是一个非常好的功能。
我们可以看到,最富裕的国家往往集中在北美和欧洲,而最贫穷的国家在非洲,用较浅的颜色表示。
data = [ dict(
type=’choropleth’,
locations = data_all[‘Country’],
autocolorscale = True,
z = data_all[‘GDP Per Capita’],
locationmode = ‘country names’,
marker = dict(
line = dict (
color = ‘rgb(255,255,255)’,
width = 2
)
),
colorbar = dict(
title = “Millions USD”
)
) ]layout = dict(
title = ‘Top Countries by GDP per capital’)fig = go.Figure(data = data, layout = layout)
py.offline.iplot(fig)
富裕国家的人更长寿吗
好了,现在我已经用 Plotly 展示了一些简单的情节,我想更进一步,创造一些真正酷的东西。有一个名为 bubbly 的非常好的库,它可以创建气泡图,并且有一些有趣的功能来增强您与图表的交互性。你可以用 Plotly 做到这一点,但是要达到想要的效果需要相当多的编码,而 bubbly 让它变得超级简单。此库归功于[Aashitak]。还有一个漂亮的[ kaggle 内核]展示了这个库是如何工作的,绝对值得一试。
我想做的是创建一个气泡图,看看人均 GDP 和预期寿命。该图表还考虑了每个国家的人口以及该国位于哪个洲。我从世界银行网站上获得了所有的数据。下面是在使用 pandas 中读取数据的代码,我创建了一个国家、大陆和年份的唯一值的列表,这对处理数据很有用。事实证明,这是一个由 gapminder 基金会创造的非常著名的可视化。他们有一个非常好的工具来绘制这个和其他可用的图表[在这里],如果任何人
想看看的话。
我在这里使用的世界银行数据与 Kaggle 上的 gapminder_indicator 数据集(该图最初是基于该数据集)的格式完全不同。要使用 bubble 库,我们需要数据采用后者的格式,因此需要一些数据操作。我之所以使用世界银行的数据,是因为它的时间序列稍微长一点,我想了解更多最近的发展情况。下面的代码将数据集加载到中,并提取 gapminder 数据集中使用的相同国家。
gdp = pd.read_csv(“gdp_per_capota.csv”, engine = “python”)
life = pd.read_csv(“LifeExp.csv”, engine = “python”)
pop = pd.read_csv(“population.csv”, engine = “python”)
gapminder_indicators = pd.read_csv(“gapminder_indicators.csv”, engine = “python”)countries = gapminder_indicators.country.unique()
continents = gapminder_indicators.continent.unique()
years = gapminder_indicators.year.unique()[‘Country Name’,
‘1982’,
‘1987’,
‘1992’,
‘1997’,
‘2002’,
‘2007’,
‘2010’,
‘2013’,
‘2016’]# Filter countries first
gdp_new = gdp[gdp[‘Country Name’].isin(countries)]
life_new = life[life[‘Country Name’].isin(countries)]
pop_new = pop[pop[‘Country Name’].isin(countries)]# # Now filter years
years = [str(year) for year in years]
years = years[6:]
for i in [‘2010’, ‘2013’, ‘2016’]:
years.append(i)years.insert(0,”Country Name”)gdp_new = gdp_new[years]
life_new = life_new[years]
pop_new = pop_new[years]
gapminder_indicator 数据集具有用于绘图的正确格式(长格式,见下文)的数据,因此本质上我们需要将三个数据集处理成相同的格式,并在我可以使用 bubbly 绘制它们之前将它们合并在一起。
country continent year lifeExp pop gdpPercap
Afghanistan Asia 1952 28.801 8425333 779.445314
Afghanistan Asia 1957 30.332 9240934 820.853030
Afghanistan Asia 1962 31.997 10267083 853.100710
Afghanistan Asia 1967 34.020 11537966 836.197138
Afghanistan Asia 1972 36.088 13079460 739.981106
世界银行数据集的格式不同,每年的人口被分配到不同的列(宽格式)。下面是我用来将世界银行数据转换成正确格式的代码。
Country name 1960 1961 1962
Aruba 54211.0 55438.0 56225.0
Afghanistan 8996351.0 9166764.0 9345868.0
Angola 5643182.0 5753024.0 5866061.0
Albania 1608800.0 1659800.0 1711319.0
Andorra 13411.0 14375.0 15370.0 melted_gdp = pd.melt(gdp_new, id_vars = ["Country Name"], var_name = "Year", value_name = "Data")grouped_gdp = melted_gdp.groupby(["Country Name"]).apply(lambda x: x.sort_values(["Year"], ascending = True)).reset_index(drop=True)melted_life = pd.melt(life_new, id_vars = ["Country Name"], var_name = "Year", value_name = "Data")grouped_life = melted_life.groupby(["Country Name"]).apply(lambda x: x.sort_values(["Year"], ascending = True)).reset_index(drop=True)melted_pop = pd.melt(pop_new, id_vars = ["Country Name"], var_name = "Year", value_name = "Data")grouped_pop = melted_pop.groupby(["Country Name"]).apply(lambda x: x.sort_values(["Year"], ascending = True)).reset_index(drop=True)temp = pd.merge(grouped_gdp, grouped_life, on = ['Country Name', 'Year'], how = 'inner')temp = pd.merge(temp, grouped_pop, on = ['Country Name', 'Year'], how = 'inner')cols= ['Country Name', 'Year', 'Data_x', 'Data_y', 'Data']temp = temp[cols]data = temp.copy()
让我解释一下我在这里做什么。melt 函数将所有年份列折叠成一行,并在值行中列出每年的值。然后,我按国家名称分组,并按年份对每一行进行排序,这样我就得到一个数据集,其中国家按字母顺序排序,年份按时间顺序排序。这与 gapminder_indicators 相同。然后,这些数据集是根据国家名称和年份合并的数据集。我认为你可以用一个 Pandas 函数来完成,但是我决定用一种更像手工的方式来完成,因为这是一种逐步练习如何操作数据的好方法。
我们现在需要做的另一件事是创建一个大陆列,它将国家映射到正确的大陆,因为这些信息将在绘图时使用。为此,我们使用 gapminder 数据集创建一个字典,然后将这个字典映射到我的合并数据集中的一个新列。
dictionary = dict(zip(gapminder_indicators[‘country’], gapminder_indicators[‘continent’]))
data[“continent”] = data[“Country Name”].map(dictionary)data.rename(columns = {‘Data_x’: ‘GDP_pc’, ‘Data_y’: ‘Life Expectancy’, ‘Data’: ‘Population’}, inplace=True)
最后,我们有一个完成的数据集,我们可以创建我们的图。我们使用 bubbly 库中的 bubbleplot 函数来完成这项工作。该函数创建了一个美丽的预期寿命与人均 GDP 的互动图,并根据该国人口绘制了泡沫的大小。气泡还被大陆着色,我们能够绘制所有这些跨时间的信息,这真的很好。最显著的变化是中国和印度,用最大的紫色气泡表示。在样本开始时,它们属于最贫穷的国家,预期寿命相对较低。然而,随着时间的推移,出现了向图表右上方的大幅移动,表明人均国内生产总值和预期寿命都有大幅增长。这很大程度上反映了我们所看到的中国在过去 20 年左右成为经济强国的情况。
从图表中还可以清楚地看出,人均国内生产总值和预期寿命之间存在正相关关系。随着一个增加,另一个也趋于增加。当然,这并没有告诉我们任何因果关系,也不清楚是因为富裕国家的预期寿命更长,还是因为富裕国家的预期寿命更长。这也许是一篇经济学研究论文的问题,而不是这篇博文。
这就是你如何使用漂亮的汤从互联网上提取数据,以及如何使用数据可视化来解释和揭示数据中的趋势,这些趋势在原始数据中看起来可能并不明显。
from bubbly.bubbly import bubbleplotfigure = bubbleplot(dataset=data, x_column=’GDP_pc’, y_column=’Life Expectancy’,
bubble_column=’Country Name’, time_column=’Year’, size_column=’Population’, color_column=’continent’,
x_title=”GDP per Capita”, y_title=”Life Expectancy”, title=’Gapminder Global Indicators’,
x_logscale=True, scale_bubble=3, height=650)iplot(figure, config={‘scrollzoom’: True})
我的博文原文链接:https://d poly . github . io/blog/2018/08/10/Economic-data-plot ly . html
用 GA、BigQuery 和 R 可视化用户如何开始他们的网站之旅
帮助你的业务人员了解你的网站或应用程序的用户如何开始他们的旅程是为他们设计最佳体验的关键;从关注哪些登录页面最重要,到在用户初次体验后吸引他们。
数据可视化是向利益相关者传达这一点的有力方式,在这篇文章中,我们将看看如何使用 sunburst d3.js R 包装器来可视化用户在你的网站上浏览的前 4 个页面。要查看 sunburst 的 d3.js 版本,请查看交互式数据可视化这里。
第一步——启动并运行 SunburstR
首先,您将使用下面的脚本来获得一个在 r 中运行的示例,它使用了 CRAN 上可用的 sunburstR 包和来自 Kerry Rodden 的 github repo(该包的创建者)的数据集。
在 2 分钟内创造出这个令人敬畏的互动视觉化…
在 R 中运行这段代码…
**哇塞!**在您继续用自己的数据(更难的部分)尝试之前,看到一些东西与现有的数据集一起工作总是很好的
注意:任何人都可以复制下面的教程,因为它将使用 Bigquery 的公共演示 GA 数据,但是要用您自己的 Google Analytics 数据复制它,您需要有 Google analytics 360(付费版本)来访问 BigQuery 中收集的原始数据和查询数据的权限。
步骤 2 —您的数据需要什么格式?
因此,您首先需要了解的是,您的数据需要是什么格式,以便轻松地使用这个包中的 sunburst() 函数。
让我们看一看。你会在例子中看到。csv 下面有两列:一列是旅程中每页的,用连字符“-”分隔,第二列是****导航通过此旅程的会话总数。
例如,在这个样本数据集中,22,781 个访问者在他们的帐户中开始了他们的旅程,并且随后的 5 次页面访问也在帐户页面上。然后,sunburst 函数将使用这些整数值自动计算每次旅行的用户百分比。
图片来自【https://gist.github.com/kerryrodden/7090426】
第 3 步—从 BigQuery 获得这种格式的数据
Google 友好地提供了一个 GA Bigquery 数据集样本,完全用于学习和测试目的。了解如何按照本文档‘Google Analytics Sample dataset for big query’中的说明设置运行查询,并在 google.bigquery.com 上创建一个帐户
等等……这个样本数据来自哪里?
它来自一个名为谷歌商品商店的网站。
下面的代码将把你的数据转换成第二步中所有访问你的网站的相同格式。
- 子查询为会话中的每次命中创建一个带有行的表。此表包含会话 ID、点击数(点击数是一个页面视图或事件)、点击数、点击数页面路径(即 url)以及点击数之后的 3 个页面路径。它获得了 x7 天的数据(每一天的数据都在它自己的表中)。它只过滤页面浏览量的点击,所以我们忽略所有其他点击类型。****
- 当您对自己的数据集运行下面的查询时,您只需替换子查询中列出的表名。
- 外部查询然后从每个会话中选择一行,其中第一次点击是登录页面,然后统计有多少会话在此开始了它们的旅程以及它们的 3 次后续页面查看。如果有下一页,则 Concact 函数会在该页和下一页之间添加一个连字符。这最后一个专栏“全页之旅”是你将插入到 sunburst 的专栏。
- 我在多个步骤中构建了这个查询,所以我鼓励您删除外部查询,以了解它是如何工作的。
在 BigQuery 中运行此查询…
你会得到这样的输出……
步骤 3 —对您的数据进行质量评估
好的,你想知道你的数据是正确的。你可以通过在谷歌分析中查看 2 份报告来回答这个问题。你可以在这里添加谷歌分析账户,这也是谷歌商品商店的账户。
- 登陆页面报告—来自行为>站点内容>登陆页面
通过登录页面匹配检查会话 —要使用登录页面报告对您的数据进行 QA,请删除第 2–8 行和第 34–38 行,这将删除按多条路径分组,以便您只按登录页面分组。运行查询,您的总数应该与这些页面上的会话总数相匹配。
2.“下一页”报告—在同一页的“入口路径”选项卡下
检查特定页面的“下一页”会话 —在这里,您可以检查特定登录页面移至下一页的会话数是否与 GA UI 和您的查询相匹配。例如,将下面的行添加到您的外部查询中,以查看在登录到“/home”页面后移动到特定页面的会话数。
其中 t.page_path = '/home ’
****你的任务完成了!确保它们匹配或匹配误差很小(在 Bigquery 中采样和定义会话会使其与 GA UI 完全匹配变得很困难)然后就可以开始了。
步骤 4 —以. csv 格式下载
这是容易的部分。将表格下载为. csv 格式,并将其保存在合适的地方。“下载”为。csv 按钮在步骤 2 的图像中高亮显示。
步骤 5-更新您的 R 脚本,从您的。csv 文件并运行
调整步骤 1 中的 R 脚本,使其指向您计算机上的新位置(要实现这一点,您可以右键单击您的。csv 文件,然后选择“属性”以获取文件的路径)
您根据自己的选择更新配色方案,这就是您将从样本 GA 数据中获得的输出。****
第六步——分析你的发现
所以,你并没有做所有这些艰苦的工作,只是为了创造一个令人惊叹的互动数据,即,在这一点上挑选出你从与你的创作互动中发现的任何有趣的学习。你可以回答一些问题,比如:
- 最重要的登录页面是什么
- 这些页面中第二受欢迎的页面是什么
- 最流行的整页路径是什么(5 步?)
- 大多数离开你网站的用户来自哪里?
对所有这些问题的回答将产生讨论点,并引发进一步的探索性分析
第七步——将你的惊人创造导出为. html 文件,与世界分享
很好,您已经有了数据可视化,R 为您提供了一种很好的方式将您的作品导出为. html 文件*。这意味着你现在不必担心把它托管在一个闪亮的服务器上或一个仪表板上,你的用户仍然可以很容易地与它交互。***
下一步做什么的一些想法:
- 把它放在屏幕上,让你的同事与它互动
- 通过电子邮件发送给同事
- 如果你有一个闪亮的服务器,你可以把你的小部件添加到一个仪表板上(这篇文章没有涉及)。
第八步——祝贺自己
您已经使用了 BigQuery,R 并接触到了 d3.js 数据可视化的交互性!关于所有这些工具,还有很多需要学习的地方,但一些关键要点是:
- 对于 Google 360 用户来说,在 BigQuery 中访问底层数据允许您以 GA 用户界面中不可能的方式提取和可视化数据。你能回答的问题是无穷无尽的。
- d3.js 的 R 中的包装器真的很有帮助,因为你不必深入到定制 javascript、html 和 json 的世界来创建可视化;一些友好的灵魂已经为你做了艰苦的工作(如果你遇到任何其他伟大的灵魂,请分享)。然而,为了获得一些关于 d3 的其他可能性的灵感。看这里https://d3js.org/
- 如果你认为它看起来像一个饼状图,你很担心——我也有同样的想法。我想说的是,这种可视化的主要目的不是让用户能够在一瞬间理解指标,而是让他们与 it 的互动激发他们的兴趣,以了解更多关于用户如何与你的网站互动的信息,并在你的分析团队中推广可能性的乐趣。
可视化机器学习:我们如何使智能人性化?
Photo by Jamison McAndie on Unsplash
对于数据科学专业人士来说,这是激动人心的时刻。随着分析技术的快速发展,特别是在机器学习、深度学习和人工智能方面,世界各地的研究人员和从业人员已经开始将这些技术应用于影响人类的深度应用。
高级分析时代
社交谈话充斥着各种对话,这些对话已经从自动驾驶汽车转变为飞行汽车,从智能机器转变为已经在我们家中安静协作的机器人,从聊天机器人转变为对话式人工智能,这种人工智能正变得无处不在,与环境相关,与人类的反应无法区分。
许多人引以为豪的事实是,作为一个人类,我们已经设法创造了实时智能,一种没有自然进化的智能。随着各学科的进步,我们终于攻克了模拟人类智力的几个难题,并开始在某些领域超越它。
Video synthesis to re-enact politicians using Recurrent neural networks: University of Washington
伟大的分析分歧:救赎还是巫术?
有趣的是,在这一点上,世界各地的公众意见也开始出现明显的分歧。在这个光谱的另一端,有人质疑人工智能的存在和意图,不仅就高级分析的可信度,而且就其实用性进行了深入的辩论。
在某种程度上,大多数消费者都有一种恐惧感。对潜在应用领域的乐观描述存在一种诡异的不确定性,人们对其可行性、规模和影响提出了质疑。
技术的进步和人们对它产生的原始恐惧感之间有一种联系。—唐·德里罗
在过去的几十年里,技术的快速进步总是伴随着恐惧的升级。虽然早期的技术很复杂,但它是完全理性的。有了深度学习和人工智能,我们再也不能声称这一点,因为它们现在超越了人类逻辑和理解的领域。
分析消费的挑战
缺乏基本意识是当今分析学科面临的最大挑战,这比围绕其采用的道德困境排名更高。随着用户对新技术的理解越来越失去控制,围绕其感知效用和采用问题的噪音变得越来越大。
虽然终端消费者对高级分析的大规模采用仍在逐步进行,但这已经是企业面临的一个明确而现实的挑战。尽管他们在数据科学上投入了数百万美元来收集智能见解,但企业面临着来自内部的巨大阻力。
企业项目中最大的挑战不是模型工程或准确性,而是分析应用的实地采用和这些智能模型提供的建议的实施。更有甚者,当他们最终违背行业直觉时&直觉。
Model accuracies from a forecasting project, where neural networks outshines other models
高精度低接受度的模型
在实施高级分析项目的这些年里,我们遇到了太多的例子,其中杰出的复杂模型(黑盒)以非凡的准确性满足了项目目标,但未能满足人类接受标准。
虽然像神经网络这样的黑盒模型带来了准确性的显著提升,但这通常是以失去可解释性和人类理解力为代价的。相比之下,用直观的 if-then-else 条件和简单的阈值来解释决策树模型就容易多了。
然而,在项目中,复杂的黑盒模型可能带来的商业利益的改善太诱人了,不容忽视。作为数据科学从业者,我们的责任是弥合这一鸿沟,实现机器学习见解的消费,并温和地推动规范的行动。
如果不能简单的解释,说明你理解的不够好。——阿尔伯特·爱因斯坦
机器学习的可视化框架
虽然图表在传达信息方面更强大,并且可以证明远远优于数字表,但视觉框架在将机器学习的智能人性化方面可能特别有效。
让我们看看这个可视化框架的 4 个关键元素,它们可以促进简单理解,并有助于揭开高级分析模型的神秘面纱。
A visual framework for humanizing Machine learning
1.信息设计:
数据的视觉故事讲述是最重要的方法,它不仅呈现数字表,而且重要的是呈现统计结果和算法结果的解释,以达到规定的行动。
一个标准化的方法以用户为中心的信息设计方法,通过设计正确的导航工作流程,相关的表现和相关的视觉设计是开始这个旅程的正确地方。
Demonstration of how a static visual presentation can encapsulate & illustrate model results well
2.适应性抽象:
洞察一个系统最有效的方法是通过*跨越抽象层次。*数据科学家和设计师本能地在不同层面上上下移动,以收集见解&为用户设计解决方案。
当务之急是让用户拥有一定的流动性,这样他们就可以鸟瞰全局(抽象的摘要),消化底层细节,并根据上下文和用户的专业知识进行动态导航。
Bret Victor 的 抽象阶梯 是一个有用的参考,其中他演示了通过抽象时间、算法和数据来绕开问题。以一种上下文相关的、领域驱动的方式应用它,可以通过揭示底层的设计方法来揭开分析解决方案的神秘面纱。
Bret Victor’s ladder of abstraction with a toy car example as a walk-through
3.模型分解
在用户的入门之旅中,同样重要的是向他们提供对模型内部的窥探,尽管不是以压倒性的方式。虽然像神经网络这样的算法如何学习或将数据映射到期望的输出仍然令人类困惑,研究在这一领域进展迅速。
有几个早期的 尝试来解开深度学习的内部步骤序列,特别是在分类和图像识别等领域。让用户免受有毒 统计术语的危害,如果我们能够解压缩模型并实现对输出的简单可追溯性,这将大大有助于让人们欣赏这些黑盒模型的美丽。
A powerful methodology for classification models; Distill has setup a prize for outstanding work in this area
4.用户交互性:
用户交互性是将这个框架的各种元素粘在一起的强有力的粘合剂。它实现了一个可视化的讲故事界面,促进了跨抽象级别的有意义的用户旅程,以理解机器学习模型的显著性和操作。
通过使所有的用户交互一致、可感知、可学习和可预测,整个体验可以从一个令人怀疑的事物转变为有意义和令人敬畏的事物。
Case study: What-if modelling (move the sliders) for prescriptive action, enabled in a Visual causal analysis
摘要
虽然数据科学和人工智能学科经历了令人兴奋和振奋的进步,但保持用户的期望和体验是重要的。这一点非常关键,因为相当一部分目标人工智能用户正随着日益加深的脱节和不信任而迅速疏远。
弥合这一差距不需要太多的想象力。我们的工具包中已经有了许多建立用户信任和促进理解所需的使能因素,该领域的研究正在迅速解开其余的难题。
我们需要的是承认这种差异,并在实施机器学习解决方案时,通过调整上述视觉框架以及组成的 4 个关键方面,有意识地努力解决这一问题。
对数据科学充满热情?随意在 LinkedIn 或者Twitter上加我。
在其他网站上包含此 LinkedIn 个人资料
www.linkedin.com](https://www.linkedin.com/in/ganes-kesari/)
可视化我的脸书网络集群
一个月前,我无意中发现了一个由 @Nicky Case 做的名为群众的智慧和疯狂的杰出项目。这个互动游戏描述了信息、成瘾、假新闻和行为如何在人际网络中传播。我强烈建议你在进一步阅读之前尝试这个项目,因为它会帮助你理解上下文。
Crowds explains network theory concepts using mini DIY interactives
项目摘要出现在结论页之前。他们说——“一个健康的社会需要群体内部的纽带和群体之间的桥梁*”,并用一个有用的图表来说明。*
For healthy flow of ideas, one needs a mix between bridging and bonding in their network
这个项目让我们深入了解了两极分化的机制——既是孤立网络的一部分,又是超连接网络的一部分,这是如何让我们生活在泡沫中的——让我们更难获得与我们现有观点不一致的信息。
这些想法让我睡了几个晚上。我很好奇,想知道我是群体思维泡沫的一部分,还是一个孤立的网络。
所以我决定把我的脸书网络形象化——亲眼看看我在 2000 多个朋友的网络中处于什么位置。
以编程方式构建我的网络
脸书对数据不太友好,尤其是在剑桥分析事件之后。它不提供对提供用户连接的结构化列表的 API 的访问。Twitter 在数据访问方面更友好,但由于我在脸书比在 Twitter 上更活跃,它将是我现实生活网络的更好指标。
我使用 Selenium 作为 web 抓取工具来获取我所有 2000 多个朋友的列表,并将其存储为 JSON 文件。然后我有计划地访问了他们的个人资料,并搜集了我和他们共同的朋友的名单。
Scraping Facebook to get list of mutual connections of friends
经过 65 个小时的搜索和一次临时阻塞,我设法获得了我所有朋友的列表,以及我与他们共享的所有共同朋友的列表。
Structured list of mutual friends with every friend stored as JSON files
处理数据
现在我有 2000 多个 JSON 文件,每个朋友一个文件,其中包含我和他们有共同之处的朋友列表。我所需要做的就是将这个网络可视化——作为一个由 2000 个节点连接而成的图表。
我用了一个叫做 Gephi 的开源软件来做这个。Gephi 需要两个文件来绘制网络——“节点”和“边”——前者列出了所有具有唯一 ID 的节点和关于每个节点的一些附加数据,后者列出了节点之间的所有连接以及关于连接的附加信息,例如方向性和权重。
我决定使用我与一个人交换的消息数量来包含在可视化中,以查看我的亲密朋友在网络中的位置。我用我的脸书档案数据来计算这个。
所有的数据,因此被提炼成两个简洁的文件— nodes.csv 和 edges.csv
Processed files ready to be visualized
可视化网络——终于!
好了,现在是隆重亮相的时候了!
鼓声
A block made of 2000 ‘friends’
嗯。嗯,这有点违反气候。
所以我们在这里看到 2000 个不同颜色的点。节点越暗(越大),我和节点代表的人互动越多。
这张 GIF 图有助于更好地解释。
Every node represents a friend — the connected nodes hightlight on hovering
现在,节点已经连接,但我们需要根据它们的连接程度将它们分组。一种方法是应用力导向算法——Gephi 中的一种内置功能,模拟基于物理的网络转换,使连接的节点相互吸引,断开的节点相互排斥——从而根据它们的相互连接将它们排列在整齐的集群中。
我应该强调的是,没有额外的数据,如我的朋友来自哪里,他们的背景是什么,等等,被输入到这个模拟中。它将纯粹在网络互连的基础上工作。说得够多了,让我们来看看实际行动。
运行强制定向算法
我在这个视频中记录了整个模拟过程,如果你已经完成了,我强烈建议你观看其中的一部分。
我输入模拟的数据没有关于我朋友个人细节的信息,但该算法将我的网络排列成整齐的桶,准确地代表了我生活中的背景——按城市或工作场所排列。
从图表中得出的推论
Generated graph of my network
- IIT·卡拉格普尔在我的好友列表中占了 60%以上,由于其极其密集的相互联系,这使得我的网络非常容易受到群体思维的影响。难怪我的脸书反馈极度偏颇,大多与我自己的 20 多岁的男性——印度——IIT——建筑观点一致。
- 有很高的 冗余度— 有是网络的整个区域,有我从未交往过的人脉很广的人。事实上,我在脸书上 50%的信息都是和 9 个朋友交流的。在我自己的“朋友圈”里,即使没有上千人,也有数百人实际上是陌生人。
- ——我的大多数亲密朋友都位于群集的交叉点——这意味着我们共享两个以上的子网络,因此我们的生活中有更多的“区域”交叉,这有助于更丰富的经历,从而更丰富的友谊。
- 个体集群中有影响力的人位于子网络的中心:我的许多受欢迎的亲戚和大学生群体中的职位承担者由于与其他人的高联系而占据了网络的中心。
- 我的网络的平均路径距离是 2.4,这意味着每个人与其他人的平均距离是 2.4。这意味着我的关系网或多或少是紧密相连的。
那都是乡亲们!
我和麻省理工学院媒体实验室的 Judith Sirera 还制作了另一个数字工具,名为“与自己约会”(https://www . Media . MIT . edu/projects/A-Date-With-Yourself/overview/),它可以帮助你与过去的自己创造互动体验。
源代码?
如果你喜欢我的工作,可以考虑通过 请我喝咖啡 来支持我的工作😋💝作为感谢,我会给你提供一个链接到这个项目的源代码与指示,使你自己的网络图🌟 💫✨
使用 Python 可视化南非婚姻数据
数据可视化是一个非常重要的工具,可以发现影响特定市场、人群或用户和客户行为的趋势。在处理大数据时,这种价值尤其强大。可视化通过将数据转换为更直观的视觉效果,使数据更容易消化和解释,因为人类通常以视觉为导向。
有许多工具可以在这个过程中提供帮助,包括 Excel。然而,出于本文的目的,重点是使用 Python 来执行这种分析。Python 是一种理想的编程语言,通常用于可视化和数据分析,尤其是在与大型数据集交互时。
本文的目的只是向读者介绍从 URL 上传数据、清理数据(在本例中不需要太多清理工作)并以最合适的方式可视化数据的步骤。
数据
我决定查看 StatsSA 关于 2006 年至 2015 年间记录的民事婚姻数据。数据帧总共有 130 万个条目。该数据框架中的一些列包括:I .)province code-代表南非给定省份的代码。)MarriageMonth —表示给定月份的整数,iii。)BridegroomAge,四。新郎和新娘之间的年龄差距。我选择不看各省的婚姻状况,因为这些数字与每个省的人口规模相对应。
在这篇文章中,我们将只关注视觉化;从 2006 年到 2015 年,一年的结婚总数按月份和新郎新娘的平均结婚年龄来划分。
按月份和年份可视化婚姻总数
表示这种可视化的最佳方式之一是通过堆叠条形图,因为这是比较该数据集时间段内每月总结婚数的最直观方式,并且实现起来相对简单。
执行此分析的第一步包括从源获取此数据的 csv 格式,读取它并将其保存为 dataframe。
import pandas as pd
import numpy as np
import io
import requests
url = "https://data.code4sa.org/api/views/r4bb-fvka/rows.csv"
file=requests.get(url).content
c=pd.read_csv(io.StringIO(file.decode('utf-8')))
然后,您希望导入 python 库,这将允许您将数据绘制成可视化的图形。我还导入了一个库,它使我能够生成一个彩色地图,我将使用它来使读者更容易识别堆叠条形图中的不同月份。
import matplotlib.pyplot as plt
from matplotlib.colors import ListedColormap
下一步涉及实际的可视化。为了完成这项工作,我将数据按照我要计算的婚姻总数的列进行了分组;年和月。这将返回一个具有两个堆叠级别数据的数据框架,即一年被细分为几个月。然后,我开始分解这些数据。这个过程将月份转换成列,以便我将数据绘制成清晰的堆积条形图。
然后绘制数据,并根据与结婚月份整数相对应的月份重命名图例。
c.groupby(['MarriageYear', 'MarriageMonth']).size() \
.unstack().plot.bar(stacked=True, colormap='GnBu', figsize=(12, 14))\
.axes.legend(['January','February','March','April','May','June','July','August','September','October','November','December'])
结果
结果是一个漂亮的彩色堆积条形图,显示了 8 年来结婚人数的持续下降。
这一趋势表明,人们更倾向于在年底结婚,12 月是结婚的首选月份。
table = c.groupby(['MarriageYear', 'MarriageMonth']).size().unstack()
print("December:",sum(table[12]*100/table.values.sum()))
print("November - December:",(sum(table[12])+sum(table[11]))*100/table.values.sum())
事实上,2008 年至 2015 年间,16.09%和 25%的婚姻分别发生在 12 月和 11 月至 12 月。像六月和七月这样较冷的月份正好相反,六月的结婚率低至 6.3%,六月和七月为 12%。
平均结婚年龄
对于 2008 年至 2015 年之间的平均年龄组,使用 seaborn regplot 似乎是最合适的方式来表示这些数据,一个用于新娘,另一个用于新郎。Seaborn Regplot 类似于散点图,有一条线穿过代表移动平均值的数据。
我没有将所有 130 万个条目都绘制在这张图上,而是计算出了大约 1070 个合适的样本大小。
https://www.surveysystem.com/sscalc.htm(置信水平- 99%,置信区间- 3)。
*#average age of BrideGroom*
dfSample = c.sample(1070)
xdataSample, ydataSample = dfSample['MarriageYear'], dfSample['BridegroomAge']
sns.regplot(x=xdataSample,y=ydataSample, color ='g')
plt.show()
MarriageYear
2008 36.121894
2009 36.394938
2010 36.820361
2011 36.705663
2012 36.845890
2013 37.062966
2014 37.288561
2015 37.959784
Name: BridegroomAge, dtype: float64
2008 年,新郎新娘的平均结婚年龄为 36 岁,到 2015 年上升到 37.9 岁(可能受到异常值的影响),而到 2015 年,平均年龄从 34 岁上升到 36 岁。
*#mean for bride*
dfSample = c.sample(1070)
xdataSample, ydataSample = dfSample['MarriageYear'], dfSample['BrideAge']
sns.regplot(x=xdataSample,y=ydataSample, color ='b')
plt.show()
新娘的平均年龄比新郎新娘小 4 到 5 岁,平均年龄从 31.7 岁开始,到 2015 年慢慢上升到 33.65 岁。初婚新娘的平均年龄从 29 岁开始,到 2015 年上升到 31 岁。
用 Networkx 可视化股票相关性
在最近的一堂网络分析课上,我们被要求可视化股票之间的相关性。作为投资者,你对通过选择不同类型的投资来分散风险感兴趣。因此,你可能希望看到哪些股票表现相似(正相关)或非常不同(负相关)。
使用一个包含所选股票随时间变化的价格的数据集,我们将创建一个关联矩阵,并通过 Networkx 可视化。
Github 上的 Jupyter 笔记本(也可以在 HTML 文件中看到)的完整代码。
图书馆
a.计算相关矩阵
我们首先加载数据集,并用.corr()
创建相应的相关矩阵。
下图显示了数据帧的快照。
然后我们存储股票名称,这样我们就可以命名图形中的节点,并将数据帧转换为矩阵,这样在 networkx 中创建图形就更容易了。
b.创建图表
我们现在将基于相关矩阵创建一个图表。G.edges(data=True)
将显示所有的边及其相应的权重。
c.(英)可视化(= visualization)
第 1 部分:基本图表
你会得到这样的东西:
Graph — Part 1
第 2 部分:区分负相关和正相关
现在,我们将从图 G 创建一个名为 H 的副本。在 H 中,如果我们想要可视化所有正相关,我们将删除所有负的边,反之亦然。
这样做之后,我们需要更新代码,将“G”改为“H”。
下面我们可以看到负相关和正相关的图表。我们可以注意到,可用的负相关性更少(右图)。
Left: create_corr_network_2(G,corr_direction=”positive”) | Right: create_corr_network_2(G,corr_direction=”negative”)
第 3 部分:根据权重设置边的样式
我们现在需要提取边的权重,以便它们作为图中边的宽度。鉴于相关性非常小,我们将使用函数1+abs(x))**2
来修改每一个,这样它们在图中就不会看起来太薄。
如果相关性为正,我们将使用标度颜色plt.cm.GnBu
,否则使用plt.cmPuRd
。
然后,我们需要将所有这些值添加到nx.draw_networkx_edges
中。
我们的图表现在看起来像这样:
Left: create_corr_network(G,corr_direction=”positive”) | Right: create_corr_network(G,corr_direction=”negative”)
第 4 部分:用最小相关性过滤边缘
上面的图表看起来太密集了,所以我们现在将添加一个最小相关性,这样我们只能看到更强的相关性。
对于前面的代码,我们只需要添加正相关的or weight["weight"] < min_correlation
和负相关的or weight["weight"] > min_correlation
。如果一条边不符合这个标准,那么它将被删除。
使用最小值。相关性为 0.7 和-0.7,我们得到下图:
Left: create_corr_network(G, corr_direction=”positive”, min_correlation = 0.7) | Right: create_corr_network(G, corr_direction=”positive”, min_correlation = -0.7)
第 5 部分:根据链接边的数量(度数)设置节点样式
最后一步是根据节点链接到多少条边(也称为节点的度数)来设置节点的样式。为此,我们在 node_sizes 中解包所有节点,并将其缩放到x**3
,以便它们看起来更大。
最终的图表如下所示:
Left: create_corr_network(G, corr_direction=”positive”, min_correlation = 0.7) | Right: create_corr_network(G, corr_direction=”positive”, min_correlation = -0.7)
创建上述图表的最终代码如下:
将阿姆斯特丹的温度可视化为 R 中的热图—第一部分
我最近在玩热图,决定用它来可视化阿姆斯特丹的温度数据。
获取数据:
荷兰皇家气象研究所(Koninklijk Nedarlands Meteorologisch Instituut in Dutch,或简称为 KNMI )免费提供追溯到 20 世纪 50 年代的历史天气数据。你可以从他们的测量和观察页面获得你选择的气象站的数据(荷兰语)。他们给出每小时和每天的读数。我从本页的中获得了史基浦机场(气象站编号 240)的每日数据。
阅读和理解数据:
数据被格式化为 CSV 文件。前几行有用荷兰语和英语描述每个字段的解释。这些行没有任何注释字符(通常是#)作为前缀,所以我们在读取文件时会跳过它们。我们感兴趣的内容从第 48 行开始,即标题行。
t <- read.csv('~/Downloads/etmgeg_240.txt', skip=47)
str(t)'data.frame': 24311 obs. of 41 variables:
$ X..STN : int 240 240 240 240 240 240 240 240 240 240 ...
$ YYYYMMDD: int 19510101 19510102 19510103 19510104 19510105 19510106 19510107 19510108 19510109 19510110 ...
$ DDVEC : int 188 153 203 193 207 185 240 203 246 176 ...
$ FHVEC : int 77 41 15 77 82 57 134 77 67 51 ...
$ FG : int 87 41 21 77 87 62 144 82 72 62 ...
$ FHX : int 195 82 51 103 144 123 180 103 129 103 ...
$ FHXH : int 18 4 24 15 21 22 13 20 12 21 ...
$ FHN : int 41 10 0 51 36 0 62 51 21 26 ...
$ FHNH : int 24 21 3 1 24 3 24 1 24 3 ...
$ FXX : int NA NA NA NA NA NA NA NA NA NA ...
$ FXXH : int NA NA NA NA NA NA NA NA NA NA ...
$ TG : int 12 13 3 12 48 64 67 61 41 26 ...
$ TN : int -13 7 -20 -7 18 46 58 36 6 -8 ...
$ TNH : int 1 4 9 6 1 4 24 2 24 5 ...
$ TX : int 26 18 16 19 84 86 86 70 63 61 ...
$ TXH : int 20 19 23 16 21 24 1 14 1 24 ...
$ T10N : int NA NA NA NA NA NA NA NA NA NA ...
$ T10NH : int NA NA NA NA NA NA NA NA NA NA ...
$ SQ : int NA NA NA NA NA NA NA NA NA NA ...
$ SP : int NA NA NA NA NA NA NA NA NA NA ...
$ Q : int NA NA NA NA NA NA NA NA NA NA ...
$ DR : int NA NA NA NA NA NA NA NA NA NA ...
$ RH : int NA NA NA NA NA NA NA NA NA NA ...
$ RHX : int NA NA NA NA NA NA NA NA NA NA ...
$ RHXH : int NA NA NA NA NA NA NA NA NA NA ...
$ PG : int 9891 9876 10019 10098 10059 10043 10026 10084 10089 10090 ...
$ PX : int 9957 9923 10097 10114 10094 10087 10105 10115 10151 10148 ...
$ PXH : int NA NA NA NA NA NA NA NA NA NA ...
$ PN : int 9837 9853 9931 10084 10030 9980 9957 10040 10034 10016 ...
$ PNH : int NA NA NA NA NA NA NA NA NA NA ...
$ VVN : int NA NA NA NA NA NA NA NA NA NA ...
$ VVNH : int NA NA NA NA NA NA NA NA NA NA ...
$ VVX : int NA NA NA NA NA NA NA NA NA NA ...
$ VVXH : int NA NA NA NA NA NA NA NA NA NA ...
$ NG : int 7 8 6 7 8 8 8 7 5 5 ...
$ UG : int 90 93 94 94 95 89 82 93 89 89 ...
$ UX : int 98 98 100 97 100 100 94 97 96 95 ...
$ UXH : int 6 9 21 12 5 3 4 8 1 2 ...
$ UN : int 73 88 83 89 89 72 76 88 76 78 ...
$ UNH : int 20 1 12 8 14 23 16 17 14 12 ...
$ EV24 : int NA NA NA NA NA NA NA NA NA NA ...
因此,我们有各种各样的天气观测——尽管有些指标的读数不是每年都有的。越往过去走,数据越粗略。在我们的练习中,让我们从 2016 年的每日气温数据开始。YYYYMMDD
是日期栏,而TX
和TN
栏分别包含最高和最低温度。温度以 0.1°C 为单位(例如,10°C 在本文件中显示为 100 ),因此我们将它们除以 10。
过滤和修改数据:
我们将使用dplyr
包中的filter
函数来过滤 2016 年的数据。然后我们将使用select
函数来挑选我们需要的字段,并将这个子集分配给一个新的数据帧。
library(dplyr)
t %>% filter(YYYYMMDD >= 20160101 & YYYYMMDD <= 20161231) %>% select(YYYYMMDD, TN, TX) -> t.2016
接下来,我们将对此数据进行一些更改。每次观察的日期(YYYYMMDD
列)存储为整数。我们将把它转换成一个适当的日期对象,然后把它分解成方便的单位——年、月、周、工作日和日——供以后使用。同时,我们也将温度除以 10。我们将使用lubridate
包来处理日期。
library(lubridate)
t.2016 %>% mutate(
date = as.Date(as.character(YYYYMMDD), format="%Y%m%d"),
year = year(date),
month = month(date, label=T, abbr=T),
week = strftime(date,"%W"),
wday = substring(wday(date, label=T, abbr=T),1,2),
day = day(date),
TN = TN / 10,
TX = TX / 10
) -> t.2016
head(t.2016) YYYYMMDD TN TX date year month week wday day
1 20160101 1.1 8.0 2016-01-01 2016 Jan 00 Fr 1
2 20160102 4.6 6.5 2016-01-02 2016 Jan 00 Sa 2
3 20160103 5.3 8.5 2016-01-03 2016 Jan 00 Su 3
4 20160104 4.3 7.2 2016-01-04 2016 Jan 01 Mo 4
5 20160105 4.4 7.7 2016-01-05 2016 Jan 01 Tu 5
6 20160106 1.8 4.4 2016-01-06 2016 Jan 01 We 6
可视化数据:
让我们首先尝试将最高温度可视化为热图。我们将使用绿色调色板来绘制热图。
library(ggplot2)
library(viridis)
ggplot(data = t.2016, aes(x=day,y=month)) + geom_tile(aes(fill=TX)) + scale_fill_viridis()
我们可以清楚地看到阿姆斯特丹夏季从 5 月到 9 月的延伸,7 月是一年中最热的一天,1 月和 12 月有几天非常冷。
我们现在将做一些更小的调整:
- 我们将在 x 轴上标记所有的日子,而不是让 ggplot 为我们选择一些东西。毕竟我们知道一个月不会超过 31 天。此时,我们将确保日期(x 轴)从 1 开始,而不是从 0 开始。我们还会将 y 轴向热图靠近一点。
- 因为这是最高温度,我想选择一个能唤起温暖的调色板。Viridis 有 3 个以上的调色板-岩浆,等离子和地狱,我们将选择岩浆主题来完成这项工作。
- 在上面的截图中,平铺看起来很漂亮,但是根据你的绘图窗口的大小,它们可能看起来被压扁了。我们将锁定图块,使其始终保持 1:1 的比例,而不考虑绘图窗口的宽度和高度。
- 最后,我们将使用不同的主题隐藏背景中的灰色网格。我是来自 ggthemes 套装的塔夫特主题的粉丝。
**library(ggthemes)**
ggplot(data = t.2016, aes(x = day,y = month)) +
geom_tile(aes(fill = TX)) +
**scale_x_continuous(breaks=c(1:31), expand=c(0,0))** + **coord_equal(ratio = 1) +** scale_fill_viridis(**option="magma"**) + **theme_tufte(base_family="Helvetica")**
我个人认为岩浆主题会让夏季更加突出。
链接:
- 如果你喜欢
viridis
库,请务必阅读插图。我还发现小插曲中提到的 SciPy2015 视频很有教育意义。 - 我从 Bob Rudis 的这个帖子中学到了很多我在这里使用的技术。
接下来:
虽然我对我们的进展很满意,但我们还可以利用一年的温度数据做更多的事情。在下一篇文章中,我将分享一种让热图看起来像真实日历的方法。
将阿姆斯特丹的温度可视化为 R 中的热图—第二部分
在这个两部分系列的的最后一部分中,我们研究了如何获取阿姆斯特丹的天气数据,处理这些数据并创建一个简单的热图。下面是我们的数据在第一部分结束时的样子:
YYYYMMDD TN TX date year month week wday day
1 20160101 1.1 8.0 2016-01-01 2016 Jan 00 Fr 1
2 20160102 4.6 6.5 2016-01-02 2016 Jan 00 Sa 2
3 20160103 5.3 8.5 2016-01-03 2016 Jan 00 Su 3
4 20160104 4.3 7.2 2016-01-04 2016 Jan 01 Mo 4
5 20160105 4.4 7.7 2016-01-05 2016 Jan 01 Tu 5
6 20160106 1.8 4.4 2016-01-06 2016 Jan 01 We 6
我们现在将根据这些数据创建另一个热图,并使它看起来像一个日历。让我们首先在 y 轴上绘制星期,在 x 轴上绘制星期几:
ggplot(data = t.2016, aes(x = wday, y = week)) +
geom_tile(aes(fill = TX)) +
coord_equal(ratio = 1) +
scale_fill_viridis(option="magma") + theme_tufte(base_family="Helvetica")
注意 x 轴上的星期是按字母顺序排列的。我们将把它们转换成与一周中的天数相对应的系数:
t.2016$wday <- factor(t.2016$wday, levels=c("Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"))
接下来,我们将在month
上应用一个facet_wrap
来给每个月分配它自己的面板。注意,我们设置了scales = "free"
,这样每个月都有自己独立的 x 和 y 轴。
ggplot(data = t.2016, aes(x = wday, y = week)) +
geom_tile(aes(fill = TX)) +
coord_equal(ratio = 1) +
scale_fill_viridis(option="magma") + theme_tufte(base_family="Helvetica") +
**facet_wrap(~month, nrow = 3, scales = "free")**
我们现在很亲密。让我们使用geom_text
在每个图块上添加日期:
ggplot(data = t.2016, aes(x = wday, y = week)) +
geom_tile(aes(fill = TX)) +
coord_equal(ratio = 1) +
scale_fill_viridis(option="magma") + theme_tufte(base_family="Helvetica") +
facet_wrap(~month, nrow = 3, scales="free") + **geom_text(aes(label=day), color="grey", size=3)**
差不多了,但还不完全是。看到问题了吗?我们的约会颠倒了!
基本上,一个月的第一周应该在顶部(即远离 x 轴),最后一周应该在底部。我们可以通过将周转换为按相反顺序排序的因子来实现这一点:
t.2016$week <-
factor(t.2016$week, levels=rev(sort(unique(t.2016$week))))
在此期间,我们还将添加一些收尾工作:
- 隐藏每个月的 y 轴刻度线和标签。我们还将隐藏主轴的 x 和 y 轴标题。
- 将 x 轴标签移动到顶部并隐藏其刻度线。
- 默认情况下,月份标签将放置在面板内部。我们将把它们移到外面,否则 x 轴标签会出现在它们上面。我们还将增加月份标签的字体大小,并将它们左对齐。
- 向图表添加标题。
ggplot(data = t.2016, aes(x = wday, y = week)) +
geom_tile(aes(fill = TX)) +
coord_equal(ratio = 1) +
scale_fill_viridis(option = "magma") +
theme_tufte(base_family = "Helvetica") +
facet_wrap(~month, nrow = 3, scales="free") +
geom_text(aes(label = day), color = "grey", size = 3) + **# hide y-axis ticks and labels** theme(axis.ticks.y = element_blank()) +
theme(axis.text.y = element_blank()) +**# hide main x and y-axis titles** theme(axis.title.x = element_blank()) +
theme(axis.title.y = element_blank()) +**# move x-axis labels (week names) to top, hide ticks** scale_x_discrete(position = "top") +
theme(axis.ticks.x = element_blank()) +**# move panel title (month names) outside (above week names)** theme(strip.placement = "outside") +
theme(strip.text.x = element_text(size = "14", hjust = 0)) +**# center-aligned plot title** ggtitle("2016: Heatmap of maximum temperatures in Amsterdam") +
theme(plot.title = element_text(size = "16", hjust = 0.5))
最终结果:
更新: 源代码
充分利用回答机器人:基于 t-SNE 的主题群可视化
最初发表于 Zendesk Engineering
客户服务的世界充满了问题。在 Zendesk 我们提供一种叫做支持的产品,公司可以用它来处理这些问题。例如,当客户发送电子邮件时,公司代理可以使用支持来快速响应,从而(希望)带来积极的解决方案和幸福的关系。然而,人们通常会遇到类似的问题,因此我们也提供了一个名为 Guide 的产品,用于发布常见问题的答案。
答案机器人是一个人工智能系统,它通过搜索在 Zendesk 指南中找到的答案来自动响应支持票。它通过摄取大量的文本数据来学习语言模型,然后用它来读取传入的门票。了解了收到的票证后,它会就哪些指南文章可能会回答最终用户的问题提出明智的建议。
把单词变成数字
驱动该系统的基础数学的一个有趣的结果是将指南文章和支持票转换成称为分布式表示或嵌入的数字向量。
举个例子,
*'How do I change my password'* → Answer Bot → [0.4, 3.35, 0.2, 5.04]
答案机器人真的很擅长把内容接近的票和文章分配给向量空间接近的向量。这在评估指南和支持中的内容范围时具有很大的实用价值,因为我们可以使用机器学习技术(如聚类)来识别主题。然后,我们可以用它来生成简单的可视化效果,让 Zendesk 客户鸟瞰:
- 在其指南实例中呈现内容。
- 他们在票证上看到的问题类型。
第二个是我们即将推出的产品 Content Cues 的主要目标,该产品旨在帮助指导内容创建者根据他们的支持标签中发生的对话制作相关内容。
将 Answer Bot 产生的分布式表示可视化的困难在于它们是 100 维向量,这比我们习惯绘制的通常的 2 或 3 维向量要多得多。因此,虽然我们可以从数学上定义跨门票和文章的信息聚类,但没有一种自然的方式来将这些数据点投影到一个易于人类查看和解释的图上。
幸运的是,有一些强大的方法可以让我们将高维数据映射到低维空间。我们在这里选择使用的方法被称为 t 分布随机邻居嵌入,或 t-SNE 。
t-SNE:一种可视化高维数据的有用技术
t-SNE 算法很有趣,因为它使用联合概率分布来描述数据点的接近程度。算法是这样的:
- t 分布用于产生描述高维点接近程度的联合概率分布。
- 第二组低维数据点(对应于每个高维数据点)被随机初始化,并且 t 分布被用于创建另一个联合概率分布。
- 梯度下降用于通过更新低维数据点的值来最小化两个分布之间的差异。
最终结果为我们提供了反映高维数据结构的数据点,并且能够绘制在 2D 或 3D 图上。
例如:
*'How do I change my password'* → Answer Bot → T-SNE → [0.65, 0.209] *'How do I reset my password'* →Answer Bot → T-SNE → [0.65, 0.319]*'How do I return an item'* → Answer Bot → T-SNE → [0.32, 0.85]
*'I need to return a purchase'* → Answer Bot → T-SNE → [0.36, 0.75]
t-SNE can be used to project high dimensional data points in to low dimensional space while preserving their relative closeness.
可视化数据
在我们第一次通过时,我们决定将重点放在传入支持票证的内容上。我们采样了几千张票,用答案机器人把它们转换成 100 维向量,然后用 t-SNE 把它们投影到 2D 空间。
100-Dimension Support tickets embedded into 2D space. Each point represents a unique ticket. The axis ticks can be ignored. A quick note about the plot: We also ran the original data through a variant of the KMeans clustering algorithm, which we used to colour groups of dots within the plots. Purple dots represent point deemed outliers from clusters.
正如您所看到的,如果我们将来自给定帐户的所有样本支持票嵌入到同一个 2D 空间中,事情看起来很混乱,很难解释。我们可以看到一些票组的分离,但我们没有看到清晰分离的漂亮紧密的集群。因此,接下来,我们删除了离群点,以获得聚类数据的清晰图像。
100-Dimension Support tickets embedded into 2D space with outlier points removed.
尽管在移除异常数据点后,该图的可解释性显著提高,但该图看起来仍然有些杂乱。因此,为了让这个图更好看,我们在使用 t-SNE 的之前消除了异常值*。这产生了更加美观和可解释的结果。*
Clusters are now clearly separated. Each of these clusters represent a group of related Support tickets that all talk about the same thing.
调整情节
t-SNE 图的局部和全局聚类结构在很大程度上受两个参数的影响:困惑和迭代次数。困惑与分配联合概率的方式有关,迭代的次数就是算法运行的次数,以便最小化描述数据的联合概率分布之间的差异。为了更好地探索这两个参数的影响,请查看如何有效地使用 t-SNE。
我们探索了改变困惑和迭代对审美和可解释性的影响,发现作者建议的默认设置通常效果最好。由于数据是在绘制之前采样的,我们能够将每个聚类的数据点数量限制在 100 个点,这在不同客户之间产生了相当一致的结果。一般来说,随着困惑的增加,集群的紧密度增加。
Grid comparison of t-SNE using a range of perplexity and iteration settings.
帮助公司成为客户想要的样子
如果你回想一下上面图中的每个点代表一张票的内容,就会发现一个深刻的效用。使用 t-SNE 来可视化支持票证,我们能够直观地捕获传入的支持票证数据流的结构,这为我们提供了向任何一个客户提出的问题的总体分布情况。对于 Zendesk Guide 平台来说,这是非常有价值的,因为它为我们提供了一种方法来帮助我们的客户弄清楚他们的客户在问什么。
如果我们的客户更了解他们的客户需要什么,那么他们可以提供更好的客户支持。在 Zendesk,这就是我们的全部。
感谢以下朋友和同事对这篇博文的有益反馈:阿尔温·格里芬、安·丁、克里斯·豪斯勒、宋伊·谢、埃里克·帕克、迈克·莫蒂默
延伸阅读:
- 范德马腾律师事务所。使用基于树的算法加速 t-SNE。机器学习研究杂志15(10 月):3221–3245,2014。 PDF [ 补充材料 ]
- 范德马滕和辛顿。使用 t-SNE 可视化高维数据。机器学习研究杂志9(11 月):2579–2605,2008。PDF补充材料谈
- https://lvdmaaten.github.io/tsne/
- (Sci-kit learn 实现)https://github . com/Sci kit-learn/Sci kit-learn/blob/a 24 c8 b 46/sk learn/manifold/t _ SNE . py # L442
可视化——从灾难中学习:泰坦尼克号
我最近一直在学习数据分析,我的旅程带我参加了关于“从灾难中学习:泰坦尼克号”的 kaggle 练习。我还受到启发,从我遇到的一些其他资源中对数据集进行了一些可视化分析。
该数据集提供了泰坦尼克号上乘客的详细信息,并有一个关于乘客存活率的专栏。幸存的人被表示为“1”,而未幸存的人被表示为“0”。本练习的目的是确定是否有可能通过乘客的其他特征/信息来确定哪些人可能幸存。
名词(noun 的缩写)b:专栏、专题和信息这三个术语在这里都有相同的含义,可以互换使用。
我会获取一些特征/列,并将其可视化,以深入了解数据集,并确定某些特定特征是否可能决定某个乘客能否生还。
首先,清理数据集以移除或替换丢失的值。数据集中的列有:
乘客 Id: 乘客身份
生还: 乘客是否生还
乘客类别: 车票类别
姓名: 乘客姓名
性别: 乘客性别(男或女)
年龄: 乘客年龄
SibSp: 与乘客同行的兄弟姐妹和/或配偶人数
Parch: 与乘客同行的父母和/或子女人数
车票: 票号
票价: 票价
乘客性别
存活下来的雌性比雄性多。
年龄
票的类别(Pclass)
**
第一张图显示,平均而言,Pclass 1 更贵,而 Pclass 3 最便宜,第二张图显示,持有 Pclass 1 车票的乘客更有可能幸存,而 Pclass 3 车票的持有者不太可能幸存。
港口登船
**
第一个图表显示端口 C 的平均成本高于其他端口。第二张图显示,在 C 港上船的人生还的可能性稍大一些。
我们上两节已经告诉我们,为旅行支付更多费用的人更有可能幸存下来。
家庭成员
我已经添加了兄弟姐妹/配偶列和父母/子女列,形成了一个家庭列。我们现在将使用这个家庭栏来想象有家人在船上的乘客是否可能生还。
概要 : 一名女性,购买了一张 Pclass 1 船票,在 C 港上船,船上有一至三名家庭成员,年龄不到 10 岁,生还的可能性更大。
十年 Twitter 数据的可视化(第二部分——设计)
这是关于我的数据可视化项目http://tany.kim/twitter。阅读上一篇关于数据清理和处理的文章。
有了102 万条推文和 349 个好友的海量数据集,我得出了两个主要观点(推文和好友)。每个视图都有一系列的交互式可视化,其中一些通过在其中一个视图中发生的用户交互来链接和更新。在这里,我描述了决策过程——为什么我选择这些可视化类型和交互。讨论设计过程不可避免地包括可视化的见解。
按类别排列的推文堆积条形图
Stacked bar charts of tweets categorized with interaction type during a selected time range
对于推文的分析,我选择了 4 个类别(交互、媒体、语言、来源)。每个类别中的推文属于 2-3 种类型中的一种,并以颜色编码。那些不属于任何类型的推文以浅灰色显示。为了显示推文的时间线,我按月统计推文——一个月的推文用一组堆叠的条形表示。通过这个堆积条形图,我可以看到我很少转发,我从 2015 年末才开始引用。此外,我发现过去一年我提到的次数(即与朋友交谈的次数)比以前多。
同样的技术也用于显示每小时或每天的推文数量。在下图中显示了推文的来源,我可以看到一个清晰的模式,我一醒来就用手机发推文,然后开始工作时用电脑发推文,然后晚上使用手机的比例增加。
Stacked bars to show the source of tweets (green: big screen, orange: small screen)
类型比率饼图
Pie charts of four categories. Selected Category is highlighted.
堆积条形图有助于调查推文随时间的变化。除此之外,我想提供一种更简单的方式来显示给定时间内推文类型的比率。这四个饼图/圆环图汇总了所选时间范围内的所有推文。
天/小时的矩阵(热图)视图
Number of all tweets (not categorized) by day and hour
我只对“所有推文”使用了矩阵视图,所以我只能将数据集的一个属性(推文的数量)编码成一个可视属性(区域填充颜色的不透明度)。在我过去的项目中,我喜欢在两种颜色中使用数量有限(通常最多 7 步)的热图。这样,每种颜色都可以代表整个系列中的一个独立群体。我喜欢这种与众不同的颜色使用的美学,但是对于这个项目,我想展示 7x24 数据点之间的细微差异,这也是一种更简单的编码选择。
不透明度是一种很好的方式来区分与相邻元素的相对差异。但是尽管数据范围的图例显示为梯度,但精确的值很难解码。为了支持这一点,我添加了触发工具提示的鼠标悬停交互。较小的屏幕不支持此功能。
用于朋友搜索的所有连接的可视化
与具有常规子菜单类型的内容结构的 Tweets 视图相反,Friends 视图是搜索驱动的单页样式。
四个组件(朋友的搜索/下拉列表、线图、力定向网络图和散点图)用作用户界面,通过该用户界面可以选择朋友。当朋友被选择时,朋友视图中的所有可视化被更新,指定朋友的状态。
向朋友提及的折线图
Early prototyping of line graphs for friends
这是我为这个项目做的第一个可视化。该图是早期开发阶段的截图。这可能很有趣,但太混乱了,所以我想对数据集的一个维度进行编码,可能是分类数据,这样就可以使用颜色。我之前解释的将朋友标记为现实世界和/或网上朋友的想法最初来自于这种需求。这是迭代数据可视化设计的一个很好的例子;数据集在交给设计师之前并不总是完整的。有趣的可视化想法可以触发新数据属性的创建。
通过颜色编码,我可以清楚地看到我与现实世界中已经认识的人交谈,然后我将我的网络扩展到我从未见过的人。然后,当我有机会访问他们居住的城市时,我见到了他们中的一些人。我见过他们中的一些人很多次,我很感激 Twitter 创造的网络。
散点图
对二维数据进行编码的最简单的可视化方法之一是散点图。我用这个来编码提及次数(X 轴)和对话持续时间(Y 轴)。每个点代表一个朋友,并用线形图中使用的匹配类别进行颜色编码。
力定向图
通过追踪每条推文中提到的账户,我分析了我的朋友们是如何相互联系的。一种常见的可视化形式是力导向图,我开始用编写这个例子。每个节点(圆圈)的颜色编码与线图和散点图相同,边(两个圆圈之间的线)的厚度代表在一条推文中一起出现的次数。当选择一个朋友时,相应的节点和边被突出显示。
直方图和分布曲线和排名
在制作散点图之前,我制作了两个独立的直方图来显示提及次数的分布和交流持续时间的分布。在我制作这些直方图之前,我预计外观将接近正态分布。但事实非常令人吃惊。我的许多 Twitter 朋友(349 人中的 250 人)收到的总提及次数少于 100 次,而少数人超过了 2000 次。持续时间图不像计数图那样极端,但仍显示类似的模式。事实上,这些螺旋分布导致我制作散点图来显示每一个朋友,并列两个维度-计数和持续时间。此外,在分析了网络图数据后,我认为显示共享好友数量的分布也会很有趣。
我把分布曲线放在直方图上,然后列出每个类别中的前 10 个朋友。直方图本身不具备互动功能,但显示选定的朋友的状态。
使用 Tableau 中的经度和纬度值可视化地理数据
如今,人口普查数据集和许多公共数据集都包含经度和纬度值。通过在地图上绘制经度和纬度坐标,可以直观地显示隐藏的地理信息。本文将提供一个分步指南,并举例说明如何在 Tableau 中构建地理可视化工作表。
以下是房地产数据集中经度和纬度值的示例。这些字段是地块级经度和地块级纬度。
longitude and latitude values
在 Measures of Tableau 中,右键单击宗地级别经度(数据集中的字段名),然后选择地理角色 > 经度。然后右键宗地级别纬度,选择地理角色 > 纬度。
将包裹级别经度拖至列架,将包裹级别纬度拖至行架。
将复合属性联动键即属性唯一键拖动到标识卡上的明细处。这就是我们用 Tableau 绘制的地图。
拖动到司徒市上的色标记牌。如下所示,添加了 Situs City 维度来编码关于城市属性位于哪个城市的信息。
Color Encoding
Situs City
可视化地理数据有助于我们发现不同的变量如何与地理位置相关联,方法是将这些变量在地图上分层。本文展示了如何使用 Tableau 中的经度和纬度值构建交互式可视化。
感谢阅读。如果您有任何问题,或者您有任何地理可视化的示例想要分享,请告诉我。
报名参加🦞:的 Udemy 课程
具有机器学习和统计的推荐系统
使用 Python 中的 Seaborn 可视化世界趋势
研究和分析数据是任何数据科学工作的第一步。您需要获得关于数据的性质和分布的一般信息,以便相应地规划您的工作流。这就是我们所说的“一张图胜过千言万语”的可视化的来源。有了信息丰富的图表,更容易从数据中获得见解,也更容易将见解传达给其他人。
在本帖中,我们将看到如何使用丰富的可视化来获得关于世界趋势数据的见解。该数据集包含了 1960 年和 2013 年的国家名称、国家代码、互联网用户统计、出生率和预期寿命。数据集和代码可以在 github 链接中找到
在 GitHub 上创建一个帐户,为数据科学的发展做出贡献。
github.com](https://github.com/sambit9238/DataScience/blob/master/SeabornPlotsOnWorldTrendSurvey.ipynb)
在分析数据之前,我们需要首先导入所有需要的依赖项。为了丰富的可视化,我们将在这里使用 seaborn,它在 matplotlib 库上工作,以提供更好的和信息丰富的情节。
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
这里我用的是 python 3.5,numpy 1.13,pandas 0.18,matplotlib 1.5,seaborn 0.8,statsmodel 0.8.0。在做任何事情的时候,我总是面临一个问题,由于软件包中的一些更新或版本兼容性等原因,我会收到很多反对警告。在编码时,这些可能看起来令人沮丧。让我们忽略所有的警告,这样它就不会显示在屏幕上。
import warnings
warnings.filterwarnings("ignore")
现在首先使用 pandas 的 read_csv 函数将数据加载到数据框中。
df = pd.read_csv("world_trend_survey.csv")
df.head() #to show top 5 rows
输出-
我们可以用 Seaborn 的分布图来看看 1960 年和 2013 年的互联网用户数、出生率、平均寿命和平均寿命的数据分布。为了让两个情节并排,我们可以为两个要绘制的次要情节创建一个次要情节框架。
f, ax = plt.subplots(2,2,figsize=(8,4))
vis1 = sns.distplot(df["Internet users"],bins=10, ax= ax[0][0])
vis2 = sns.distplot(df["Birth rate"],bins=10, ax=ax[0][1])
vis3 = sns.distplot(df["LifeExp1960"],bins=10, ax=ax[1][0])
vis4 = sns.distplot(df["LifeExp2013"],bins=10, ax=ax[1][1])
情节看起来像-
在平均预期寿命上可以看到一个有趣的分布。在 1960 年,数据分布是均匀的,而在 2013 年,它类似于正态分布。此外,我们可以绘制收入群体和互联网用户之间的箱线图,以了解他们之间的相互关系。通过首先使其成为图形对象,可以将打印的图形保存到本地文件。
vis5 = sns.boxplot(data = df, x = "Income Group", y = "Birth rate")
fig = vis5.get_figure()
fig.savefig("fig1.png")
情节看起来像-
Income Group vs Internet Users
从图中很明显,互联网的使用随着个人收入的增加而增加。通过绘制收入群体与出生率、国家地区与互联网用户、国家地区与出生率的图表,可以得出类似的见解。
Country Region vs Internet Users
在绘制了这四幅图之后,看起来互联网用户的数量和出生率之间有关系。让我们画一个共同的图来看看他们的关系。
vis6 = sns.jointplot(data = df, x = "Internet users", y = "Birth rate", kind='kde') #here kde means kernel density plots
这里,皮尔逊系数-0.82 意味着它与负斜率成线性关系。p 值< 0.001 表示该信息在统计学上高度显著。
Internet Users vs Birth Rate
从图中可以看出,当人们更多地使用互联网时,他们可能没有太多的时间生孩子。所以,高收入人群的出生率更低,这很直观,因为他们会有更多的意识。从这些图中也可以得出类似的其他见解。为了使这些结论更有说服力,让我们绘制 2D 线性图:
vis7 = sns.lmplot(data = df, x = "Internet users", y = "Birth rate",fit_reg=False, hue = "Income Group",size = 6, aspect=1.5, scatter_kws = {'s':200}, )
此处,“色调”用于为不同类别的标记提供不同的颜色,“纵横比”是长度和宽度之间的纵横比,“scatter_kws”是散点图的关键字参数,散点图从 matplotlib 调用。“s”表示此处标记大小设置为 200,以使绘图更具信息性。
Internet Users vs Birth Rate
从这里很明显,低收入群体出生率高,互联网使用率低。这与高收入群体完全相反。其中,中低收入群体和中高收入群体的结果差异很大。也许国家地区因素在这里也起了作用。让我们绘制国家地区的统计数据。
vis8= sns.lmplot(data = df, x = "Internet users", y = "Birth rate",fit_reg=False,\
hue = "Country Region",\
size = 6, aspect=1.5, scatter_kws = {'s':200}, )
Internet Users vs Birth Rate
由此可见,国家地区对出生率起着重要作用。在欧洲地区,互联网的使用情况各不相同,但出生率却相当一致。在非洲地区,大多数国家出生率很高,互联网使用率很低。最有趣的结果是在亚洲地区获得的。在这里,结果是高度多样化的,因为它是中等收入群体。可以想象,也许亚洲地区的大部分人口属于中等收入群体。所以,让我们一张一张地来了解全国各地区的收入群体分布情况。
sns.countplot(y="Income Group", hue="Country Region", data=df);
Income Group
从上图可以看出,非洲对高收入群体的贡献几乎为零,而对低收入群体的贡献最大,这与欧洲的情况正好相反。最有趣的情况是亚洲地区。收入群体似乎几乎是均匀分布。
现在来看看不同人口统计中的预期寿命状况,让我们使用蜂群图。
vis9 = sns.swarmplot(x="LifeExp1960", y="Country Region", hue="Income Group", data=df)
vis9.legend_.remove()
plt.legend(loc="upper left", bbox_to_anchor=(1,1))
plt.show()
Life Expectancy at 1960 vs Country Region
从上图可以看出,在 1960 年,收入是影响预期寿命的一个重要因素。收入越高,预期寿命越高。但是乡村地区也起着很大的作用。从中东和大洋洲可以看出,高收入人群的预期寿命也较低。让我们看看 2013 年的趋势变化。
vis10 = sns.swarmplot(x="LifeExp2013", y="Country Region", hue="Income Group", data=df)
vis10.legend_.remove()
plt.legend(loc="upper left", bbox_to_anchor=(1,1))
plt.show()
Life Expectancy at 2013 vs Country Region
在 2013 年,情况似乎与 1960 年没什么不同。每个地区的预期寿命都有所提高,特别是高收入群体和中上收入群体。但是非洲地区似乎仍然处于特权之下。
用方面可视化您的数据
数据很乱。它通常是不平衡的,贴错标签的,并散布着古怪的价值观,让你的分析和机器学习训练失去了方向。
清理数据集的第一步是了解需要清理的地方。今天,我找到了合适的工具。
可视化您的数据
理解数据是为机器学习清理数据集的第一步。但这可能很难做到,尤其是以任何一种概括的方式。
Google Research 的一个名为 Facets 的开源项目可以帮助我们可视化我们的数据,并以各种方式将其切片,这可以帮助我们开始了解我们的数据集是如何布局的。
通过允许我们找到数据看起来与我们期望的不一样的地方,Facets 有助于减少以后的灾难。
让我们看看 Facets 是什么样子的。该团队在网上有一个演示页面,所以你不用安装任何东西就可以从 Chrome 上试用 Facets。此外,Facets 可视化使用由 Typescript 代码支持的聚合物 Web 组件,因此可以很容易地嵌入到 Jupyter 笔记本和网页中。
方面有两个部分:方面概述和方面分析。让我们更详细地看一看每一个。
方面概述
刻面概述给出了数据集的概述。在《T4》前几集中,我们看到了像熊猫这样的工具如何帮助我们了解数据集是如何分布的。使用 Facets Overview 工具,我们可以获得这类信息的稍微升级的视图。
它将我们的数据列拆分成显著的信息行,显示缺失百分比、最小值和最大值等信息,以及平均值、中值和标准偏差等统计信息。它还有一个显示零值百分比的列,这完全有助于捕捉大部分值为零的情况。
The tool highlights high percentages of zeros, which is a good gut check for certain columns.
对于数据集的每个要素,您还可以查看数据在训练集和测试集中的分布。这是一种很好的方式,可以再次检查测试集是否与训练数据集具有相似的分布。
那又怎样?
是的,的确,从技术上来说,最好的做法是自己独立完成至少这一级别的分析,但是我肯定忘记了检查我的每一列数据的所有这些方面。该工具将有助于确保您不会错过这一关键步骤,并突出任何异常情况。
多面跳水
现在我们来看看刻面跳水。这就是事情变得真正有趣的地方。它允许您更加清晰地了解您的数据集,甚至可以一直放大以查看单个数据!
您可以通过数据集的任何要素按行和列对数据进行“分面”。这看起来就像你在网上购物,比如说,买鞋子,然后根据不同的类别比如尺码、品牌和颜色过滤。让我们来看一个深潜的例子,让它更加具体。
该界面分为 4 个主要部分。中间的主要区域是数据的可缩放显示。在左侧面板中,您可以使用各种下拉选项来更改数据的排列,以控制刻面、定位和颜色。正下方是中间显示的图例。最右边是特定数据行的详细视图。您可以单击中间可视化中的任何一行数据,查看该特定数据点的详细读数。
现在让我们看看这一切是如何组合在一起的。
为此,我们将使用“人口普查数据集”,这是巴里·贝克尔从 1994 年美国人口普查中提取的经典数据集。它的目标是根据各种普查统计数据预测一个家庭的年收入是高于还是低于 5 万美元。
逐行刻面
我们将首先按照年龄范围分割数据,并根据目标值给数据点着色。这里蓝色表示小于 50K,红色表示大于 50K。
按列分面
现在我们可以按年龄来看数据的另一个特征。在不同的年龄范围内,每周不同的小时数会产生不同的结果吗?让我们通过每周小时数的专栏来找出答案。
我们看到,17-26 岁的人群中有很大一部分每周工作 15-29 小时,这可能是孩子们做暑期工的结果。我们还可以看到,随着年龄的增长,工作 29-43 小时的人越来越少,而 43-57 小时的时间段在图表的中间年份保持相对稳定。
配置
但是这仍然没有告诉我们我们在寻找什么。让我们尝试改变剧情的定位,获得更详细的外观。我们将定位切换到“分散”,并且仅按年龄分面。我还将选择“每周小时数”作为垂直排序顺序,以便更容易地查看不同年龄组的工作时间。现在我们可以看到,在图表的中间,每周的工作时间在上升,而在两边,工作时间在下降。
你应该继续探索这些数据,看看你能找到什么趋势和关系。例如,您可以按原产地分面,这将显示数据严重失真。这可能会告诉您,您可能想要收集更多的数据点,以获得更平衡的数据集。
加载你的数据
如果这很有趣,您可能想知道如何将数据集加载到 facets 中。在这里,你有两个选择。
你可以使用 web 界面,直接上传数据并在浏览器中播放,或者你可以使用项目的 GitHub 页面上的说明,将该库安装为 Jupyter 笔记本扩展。
Facets 是一个非常有用的工具,可用于查看数据集,查看不同要素之间的关系,以及确保数据集中没有缺失或意外的值。
感谢阅读这一集的云人工智能冒险。如果你喜欢这个系列,请为这篇文章鼓掌让我知道。如果你想要更多的机器学习动作,一定要关注媒体上的我或订阅 YouTube 频道以观看未来的剧集。更多剧集即将推出!
使用 Google Data Studio 可视化您的数据
在努力用我珍贵的数据创建一个简单、互动和可访问的仪表板时,我撞见了数据工作室并坠入爱河。
基础知识
1.创建仪表板
2.添加数据源
连接器
创建新数据源时,您可以使用 Data Studio 连接器或探索社区连接器,如 data.world、facebook ads、salesforce 等。
Available Connectors
3.构建图表
Available Charts
你可以建造
- 时间序列图表
- 条形图
- 组合图
- 圆形分格统计图表
- 桌子
- 地理图
- 记分卡片
- 分散
- 项目符号图
- 对比图
- 数据透视表
现在让我们学习一些技巧和窍门
掌握谷歌数据工作室
我们将构建一个很酷的仪表板,并展示 Data Studio 的一些隐藏功能。
我们将使用来自 data.world 的脸书指标 数据集,欢迎亲自探索。
每个原则都适用于任何其他连接器,特别是 BigQuery 这种常见的数据源。
预赛
了解你的客户
您的客户是将要使用仪表板的一群人,无论他们是经理、R&D 团队还是您应该与他们会面的其他公司,他们了解您的数据如何能够让他们受益,并且定义指标。
比方说,脸书的 R&D 正在向 Facebook 页面发布一项新功能。该团队对帖子互动感兴趣,特别是付费和非付费页面之间的差异。
定义指标
我喜欢从目标开始,所以在我们构建仪表板之前,我们应该定义我们想要可视化的指标和 KPI。
我们一起设定并定义了这些是我们在发布新的付费功能期间想要遵循的指标。
- 随着时间的推移相互作用
- 喜欢分销
- 按组列出的职位类型(有偿与无偿)
- 互动的季节性(每周和每年)
塑造您的数据
设置度量标准后,我们通常需要在可视化数据之前转换数据——可能是 tablify(强制关系模式)、反规范化和创建自定义视图。
我们的数据已经被收集和预处理,我们剩下的唯一事情是使用 data.world 特殊列添加一个 id 列。
SELECT row_index, dataset_facebook.*
FROM dataset_facebook
data.world Data Connector
仪表板
主题
我建议使用你公司的颜色作为仪表板主题,这是时候设置你的主要和次要颜色,你的图表托盘和字体。
你可以利用你的 UX 设计师来帮助你获得公司的托盘颜色和与仪表板的最终结构。
Setting a Theme
设计
这是一个好主意,添加你的标志作为一个图像,添加一个页面标题,并考虑每个页面的一般结构。
General Structure
数据
过滤数据
有时您不想显示所有的数据,无论您想基于多个条件过滤空值还是某些值,您可以简单地创建一个过滤器。
Filter Nulls
添加动态过滤器
我们可以创建基于日期的过滤器或基于数据的过滤器。由于我们没有日期时间列,所以让我们使用月份列来过滤帖子。
Filter Posts by Month
自定义查询
让我们用帖子点赞的宁滨创建一个自定义的 data.world 查询
你可以使用 BigQuery 做同样的事情,这里是官方教程。
图表
柱状图
构建直方图需要宁滨和行数。
宁滨可以通过创建自定义字段或自定义查询来实现,正如我们在上面所学的那样。
宁滨可以通过创建自定义字段或自定义查询来实现,正如我们在上面所学的那样。
在我们得到一个索引列和一个宁滨列之后,剩下的工作就是设置宁滨列的维度和索引列的计数。
我建议添加文本来明确说明直方图的维度。
Binning → Histogram
饼图
饼图是显示类别如何构成整体的好方法。
在 google data studio 中构建饼图时,您可以控制圆环的宽度、颜色和图例位置,以创建简洁的设计。
Designing Pie Charts
水平条形图
水平图表是我最喜欢的比较类别的方法。
创建水平条形图:
- 创建条形图
- 设置尺寸和度量
- 样式→水平
- 勾选显示数据标签
Horizontal Bar Chart
堆积条形图
堆积条形图是比较不同组之间类别的好方法,例如付费页面和非付费页面:
- 创建一个水平条形图
- 添加另一个维度
- 勾选堆叠条形图
- 可选:100%堆叠
Stacked Bar Chart
100% Stacked Bar Chart
警告
结论
当开始使用 Google Data Studio 时,您会期望简单性伴随着有限的功能。
我希望我展示了有很大的回旋余地,就性价比而言,我认为 Data Studio 是一个很好的选择。
行动呼吁
取一个简单的 csv 文件或使用现有数据集的 data.world 连接器并试用 Google Data Studio 。
它是免费的、简单的、可分享的。
Final Dashboard
如果你喜欢这篇文章,请按下鼓掌键👏🏽如果你对接下来的帖子感兴趣,一定要关注我
【中:】https://medium.com/@talperetz24 推特:https://twitter.com/talperetz24 领英:https://www.linkedin.com/in/tal-per/