TowardsDataScience-博客中文翻译-2019-七-

TowardsDataScience 博客中文翻译 2019(七)

原文:TowardsDataScience Blog

协议:CC BY-NC-SA 4.0

“等式到代码”机器学习项目演练—第 3 部分 SGD

原文:https://towardsdatascience.com/an-equation-to-code-machine-learning-project-walk-through-part-3-sgd-e4167225504b?source=collection_archive---------15-----------------------

用 Python 实现随机梯度下降(SGD)和小批量梯度下降的详细说明

from Shutterstock

大家好!这是“等式到代码”演练的第 3 部分。

在前面的文章中,我们在中谈到了线性可分问题第一部分,在第二部分中谈到了非线性可分问题。这次我们将根据等式实现随机梯度下降(SGD)

第 3 部分是独立的。但对于 part 2 中重复的内容我就不做过多解释了。如果你觉得有些东西很难理解,我推荐你先阅读 part 2

下面是数据代码

内容结构如下。*表示如果您已经完成第 2 部分,可以跳过这一步。

  1. 预览*
  2. 随机梯度下降
  3. 小批量梯度下降
  4. 摘要

1 预览

如果您已经阅读了第 2 部分,您可以跳过这一步

首先,我们看看我们在第 2 部分做了什么。

这里是数据, non_linear_data.csv

x1,x2,y
0.54508775,2.34541183,0
0.32769134,13.43066561,0
4.42748117,14.74150395,0
2.98189041,-1.81818172,1
4.02286274,8.90695686,1
2.26722613,-6.61287392,1
-2.66447221,5.05453871,1
-1.03482441,-1.95643469,1
4.06331548,1.70892541,1
2.89053966,6.07174283,0
2.26929206,10.59789814,0
4.68096051,13.01153161,1
1.27884366,-9.83826738,1
-0.1485496,12.99605136,0
-0.65113893,10.59417745,0
3.69145079,3.25209182,1
-0.63429623,11.6135625,0
0.17589959,5.84139826,0
0.98204409,-9.41271559,1
-0.11094911,6.27900499,0

数据如下图所示。

在对数据作图后,我们发现一条直线无法将 X 和 o 分开,这类问题被称为非线性可分问题,数据不是线性可分的。

所以我们引入多项式 logistic 回归,在线性函数中增加一个多项式项。

polynomial function

我们用θ来表示参数。左边的θ标记表示函数 f(x)有参数θ。右边的θ表示有两个参数。最后一项是多项式项,它使模型推广到非线性可分数据。

注意,我们在 non_linear_data.csv 中有 x1 和 x2 两个特征。我们选择 x1 作为多项式项。所以功能应该变成低于形式。

a specific form fit to our data

然后我们引入标准化。

  • 𝜇在每一栏都很刻薄
  • 𝜎是每列的标准偏差

对于预测模型,我们使用 sigmoid 函数。下面是矢量表示。

我们用 z 来表示线性函数,并将其传递给 sigmoid 函数。sigmoid 函数将给出每个数据样本的概率。我们数据中有两个类,一个是1,另一个是0

好了,我们准备了数据、模型(sigmoid ),还需要什么?是的,一个目标函数。目标函数可以指导我们如何以正确的方式更新参数。对于 sigmoid(逻辑回归),我们通常使用对数似然作为目标函数。更具体地说,我们需要计算对数似然函数的导数。这里我直接给出最后的更新方程式。(如果你对如何得到这个方程感兴趣,这个视频应该会有帮助)

θj 是第 j 个参数。

  • η是学习率,我们设为 0.001 (1e-3)。
  • n 是数据样本的数量,在我们的例子中,我们有 20 个。
  • I 是第 I 个数据样本

类似 Numpy 数组的版本可能容易理解。

我们绘制模型线和精度线。

model line

accuracy line

下面是我们在第 2 部分之后留下的全部代码。

如果你觉得有些东西难以理解,你可以阅读第 2 部分获得详细解释。

2 随机梯度下降法

我们使用 SGD 的主要原因是为了避免局部最小值。

the parameter is trapped in a local minimum

基本思想是通过在每次更新中随机选择一个数据来更新参数。所以参数更容易走出局部极小值。

gradient descent

这是梯度下降形式。我们可以看到,为了更新θj,我们使用了整个训练数据(σ部分)。代码如下。

# initialize parameter
theta = np.random.randn(4)# update parameter
**for _ in range(epoch):
    theta = theta - ETA * np.dot(f(mat_x) - train_y, mat_x)**

但是在 SGD 中,我们一次只用一个数据。

stochastic gradient descent

这里的k是指我们随机选取的数据。

# initialize parameter
theta = np.random.randn(4)# update parameter
for _ in range(epoch):    # sgd
    **p = np.random.permutation(len(mat_x))
    for x, y in zip(mat_x[p, :], train_y[p]):
        theta = theta - ETA * (f(x) - y) * x**
  • p 包含整个数据集的随机索引列表,例如,[ 5,12,17,14,8,9,10,2,13,18,15,16,1,0,6,11,7,4,3,19]
  • for 循环每次取一个数据来更新参数θ

你可以这样想 SGD。在每个历元中,梯度下降和 SGD 都使用整个数据集来更新参数。用完整有序数据梯度下降更新参数。但是 SGD 用一个随机选择的数据来更新参数,这样更容易走出局部最小值

精确线。我们可以看到收敛比梯度下降快。

3 小批量梯度下降

SGD 是好的,但是由于每次用一个数据更新参数,计算效率不高。

使用整体数据会造成局部极小问题(梯度下降),每次使用一个数据效率低。这就是为什么我们使用小批量梯度下降。

与 SGD 不同,我们可以用几个数据样本更新参数。这里的K是包含m个随机选择的数据样本的索引集。

我们有 20 个数据样本,我们将批量大小m设为 5。

**import math**# initialize parameter
theta = np.random.randn(4)**# batch size
batch = 5****# calculate steps based on batch size
steps = int(math.ceil(len(train_x)/batch))**# update parameter
for _ in range(epoch):
    **p = np.random.permutation(len(mat_x)) 
    shuffle_x = mat_x[p]
    shuffle_y = train_y[p]****for step in range(steps):
        x = shuffle_x[step:step + batch, :]
        y = shuffle_y[step:step + batch]
        theta = theta - ETA * np.dot(f(x) - y, x)**

请注意,我们必须在每个时期混洗数据。该计算与通过矩阵乘法的梯度下降相同。如果你感兴趣,你可以在第一部分或第二部分找到详细的解释。

精确度线

收敛速度与梯度下降相同。但是计算效率更高。

4 摘要

在第 3 部分中,我们讨论了如何实现 SGD 和小批量梯度下降。你可以在下面找到完整的代码。留下评论让我知道我的文章是否易懂。请继续关注这个关于正则化的“公式到代码”系列的最后一篇文章。

查看我的其他帖子 中等 一个分类查看
GitHub:
bramble Xu LinkedIn:徐亮 博客:bramble Xu

“等式到代码”机器学习项目演练—第 4 部分正则化

原文:https://towardsdatascience.com/an-equation-to-code-machine-learning-project-walk-through-part-4-regularization-be3b44bb296a?source=collection_archive---------28-----------------------

用 Python 从头开始实现正则化的详细说明

大家好!这是“公式到代码”演练的第 4 部分,也是本系列的最后一部分。

在前面的文章中,我们谈到了中的线性可分问题中的第一部分第二部分中的非线性可分问题第三部分中的随机梯度下降(SGD) 。就像其他部分一样,第 4 部分是独立的,您可以忽略前面的文章。

在第 4 部分中,我们将讨论如何实现回归问题的正则化,这可以使我们的模型更加健壮。

下面是完整的代码,regression _ without _ regulation . pyregression _ with _ regulation . py

内容结构如下。

  1. 正规化
  2. 伪造一些数据样本
  3. 预处理
  4. 没有正规化的执行
  5. 正规化实施
  6. 摘要

1 正规化

如果我们的模型过于复杂,它会很好地拟合训练数据,但在新数据中会失败。我们把这种问题称为过拟合

from ISCG8025

为了“不是很好地拟合训练数据”(上图中间),我们通常使用一些技术来避免过度拟合,如交叉验证、剔除、批量标准化等。

这一次,我们将讨论 L2 正则化项,它在大多数机器学习模型中被广泛使用。

2 伪造一些数据样本

我们使用 beblow 多项式函数来伪造一些数据样本。

为了让数据更加真实,我们在其中加入了一些噪声。你可以在代码中看到。

import numpy as np
import matplotlib.pyplot as plt# random seed to make sure reimplement
np.random.seed(0)# the real model line
def g(x):
    return 0.1 * (x + x**2 + x**3)# add noise to the model for faking data
train_x = np.linspace(-2, 2, 8)
train_y = g(train_x) + np.random.randn(len(train_x)) * 0.05# plot
x = np.linspace(-2, 2, 100)
plt.plot(train_x, train_y, 'o')
plt.plot(x, g(x), linestyle='dashed')
plt.ylim(-1, 2)
plt.show()

虚线表示我们想要建模的真实线。

3 预处理

在第一步中,我们谈到了当模型过于复杂时,需要进行调整。例如,上面的实线是 3 次多项式函数。

a polynomial function of degree 3

但是如果我们选择一个 10 次多项式函数,这个模型可能会更复杂。

a polynomial function of degree 10

因为我们有 10 度和一个偏项,所以我们也有 11 个参数。

我们实现这个来模拟复杂的情况。

import numpy as np
import matplotlib.pyplot as plt# random seed to make sure reimplement
np.random.seed(0)# the real model line
def g(x):
    return 0.1 * (x + x**2 + x**3)# add noise to the model for faking data
train_x = np.linspace(-2, 2, 8)
train_y = g(train_x) + np.random.randn(len(train_x)) * 0.05# standardization
mu = train_x.mean()
std = train_x.std()
def standardizer(x):
    return (x - mu) / std
**std_x = standardizer(train_x)** 
# get matrix
def to_matrix(x):
    return np.vstack([
        np.ones(x.size),
        x,
        x ** 2,
        x ** 3,
        x ** 4,
        x ** 5,
        x ** 6,
        x ** 7,
        x ** 8,
        x ** 9,
        x ** 10,
    ]).T**mat_x = to_matrix(std_x)**# initialize parameter
**theta = np.random.randn(mat_x.shape[1])**# predict function
def f(x):
 **return np.dot(x, theta)**
  • 标准化:首先我们标准化我们的数据
  • 获取矩阵:我们把数据做成矩阵形式进行矩阵运算,模拟 10 次多项式函数
  • 初始化参数:根据输入数据的大小初始化参数
  • 预测函数:这是我们的预测函数,就像上面的等式一样。

4 未正规化的实施

我们使用均方误差(MSE)作为代价函数。

# cost function
def E(x, y):
    return 0.5 * np.sum((y - f(x))**2)# initialize error
error = E(mat_x, train_y)

我们使用梯度下降来更新参数。

类似 Numpy 数组的版本可能容易理解。这里我只列出三个参数,只是为了看清楚这个方程。

代码

# learning rate
ETA = 1e-4# update parameter
for _ in range(epoch):
    theta = theta - ETA * np.dot(f(X) - train_y, mat_x)

我们将代码组合在一起

# learning rate
ETA = 1e-4# initialize difference between two epochs
diff = 1######## training without regularization ########
while diff > 1e-6:
    # mat_x = (20, 4)
    # f(x) - y = (20,)
 **theta = theta - ETA * (np.dot(f(mat_x) - train_y, mat_x))**    current_error = E(mat_x, train_y)
    diff = error - current_error 
    error = current_error# save parameters
theta1 = theta########## plot line ##########
plt.ylim(-1, 2)
plt.plot(std_x, train_y, 'o')
z = standardizer(np.linspace(-2, 2, 100))# plot the line without regularization
theta = theta1
plt.plot(z, f(to_matrix(z)), linestyle='dashed')
plt.show()

我们可以看到我们学到了什么。

下面是完整的代码,regression _ without _ regulation . py

5 正规化实施

L2 监管术语看起来是这样的

我们将代价函数和正则项结合在一起。

因为我们增加了正则项,所以我们也需要相应地改变更新方程。

注意,我们不使用 lambda 来更新偏差参数θ0。

代码

# regularization parameter
LAMBDA = 1# initialize difference between two epochs
diff = 1# initialize error
error = E(mat_x, train_y)######## training without regularization ########
while diff > 1e-6:
    # notice we don't use regularization for theta 0
 **reg_term = LAMBDA * np.hstack([0, theta[1:]])**    # update parameter
 **theta = theta - ETA * (np.dot(mat_x.T, f(mat_x) - train_y) + reg_term)**    current_error = E(mat_x, train_y)
    diff = error - current_error
    error = current_error# save parameters
theta2 = theta########## plot the line with regularization ##########
plt.ylim(-1, 2)
plt.plot(std_x, train_y, 'o')
z = standardizer(np.linspace(-2, 2, 100))theta = theta2
plt.plot(z, f(to_matrix(z)))
plt.show()

模型看起来是这样的。

我们可以看到,在添加正则化后,模型线变得更加平滑,更像原始的 3 次线。

下面是完整的代码,regression _ with _ regulation . py

6 摘要

这是“等式到代码”走查项目的最后一篇文章。希望对你有帮助。留下评论让我知道我的文章是否易懂。感谢阅读。

查看我的其他帖子 中等 一分类查看
GitHub:
bramble Xu LinkedIn:徐亮 博客:bramble Xu

基于深度学习的单幅图像超分辨率进化

原文:https://towardsdatascience.com/an-evolution-in-single-image-super-resolution-using-deep-learning-66f0adfb2d6b?source=collection_archive---------9-----------------------

从经典插值到具有生成对抗网络的深度学习方法

在计算机视觉领域中,从对应的低分辨率图像重建高分辨率照片级真实感图像一直是一项长期的挑战性任务。当只有一张低分辨率图像作为输入来重建其高分辨率图像时,这项任务变得更加困难。

什么是超分辨率?对来自的一幅高分辨率(HR)** 图像和一幅低分辨率(LR)图像的估计被称为超分辨率(SR)** 。换句话说,LR 是一个单幅图像输入,HR 是地面真实,SR 是预测的高分辨率图像。当应用 ML/DL 解决方案时,LR 图像通常是添加了一些模糊和噪声的下采样 HR 图像。

Photo by Robin Mathlener on Unsplash

进化的第 0 代:插值

首先,非常早期的解决方案是图像处理中的插值方法。这里,低分辨率图像使用一些插值方法,如最近邻法、双线性或双三次插值法,以 2 倍或 4 倍的因子调整大小。

“插值的工作原理是使用已知数据来估计未知点的值。图像插值在两个方向上起作用,并试图根据周围像素的值获得像素强度的最佳近似值。”— 塔尔图大学的数字图像处理电子书

Figure: Effect of interpolation (source)

从上面的插图可以清楚地看出,合成的图像是模糊的,不真实的。

进化的第一代:SRCNN

随着全卷积神经网络(FCNN)在解决语义分割方面的成功,它在计算机视觉的其他领域迅速普及。FCNN 是一个后面没有任何密集连接(全连接层)的 CNN。每个 CNN 有两个主要功能块,I)特征提取器和 ii)分类器。CNN 后面的密集连接是分类器,其任务是将提取的特征映射到类别概率。我认为 FCNN 是 DL 中从输入图像生成/预测输出图的基本设计实践。输出图可以是语义分割图、风格转移图甚至超分辨率图。换句话说,FCNN 是一个图像到图像的映射引擎。FCNN 在超分辨率中的一个这样的初步应用是 SRCNN

在 SRCNN 中,首先使用双三次插值对图像进行上采样,然后馈送到简单的 FCNN。需要注意的是,这里不涉及池操作。因此,产生与上采样输入图像相同空间大小的输出。最后,我们计算目标 HR 图像与输出之间的 MSE 损失。

Figure: SRCNN Model (source)

进化的第二代:SRResNet 和用于上采样的子像素卷积

由于使用 SRCNN 在单幅图像的超分辨率方面取得了一些成功,激发了其他人对该架构进行进一步的改进。众所周知, ResNet (带跳跃连接的 CNN)比传统 CNN 更好。 SRResNets 用残差块代替简单卷积块。结果,精确度显著提高。

Figure: SRResNet Model (source)

许多深度学习模型还结合了转置卷积进行上采样。双线性和双三次上采样是不可学习的,这意味着,它只能在深度学习架构之前或之后使用,而不能在两者之间使用。可学习的上采样的其他优点是它的速度和准确性。

但是正如人们可能已经观察到的那样,上面用步进卷积梯度实现的上采样操作增加了零值来放大图像,这必须在以后用有意义的值来填充。更糟糕的是,这些零值没有梯度信息可以反向传播。

“应付那个问题,石等人。al 提出了我们认为是最近最有用的 convnet 技巧之一(至少在我作为一个生成模型研究者看来是这样!)他们提出了一个用于升级的子像素卷积神经网络层。这一层基本上使用常规卷积层,然后是一种称为相移的特定类型的图像整形。换句话说,他们在较低分辨率下计算更多的卷积,并将结果图的大小调整为放大的图像,而不是在像素之间放置零并进行额外的计算。这样就不需要无意义的零了。”—[https://github.com/atriumlts/subpixel

利用相移进行图像整形也叫“像素混洗”,将 H × W × C r 张量的元素重新排列,形成 rH × rW × C 张量,如下图所示。

Figure: Sub-pixel convolution operation (source)

进化的第三代:知觉丧失

在像超分辨率这样的应用中使用 MSE 或 MSE 类型的误差方法作为损失函数的主要缺点是它是按像素计算的。也就是说,它仅测量预测图像和目标图像中两个对应像素之间的变化。这鼓励寻找似是而非的解决方案的像素平均值,这些解决方案通常过于平滑,因此具有较差的感知质量。这个论点也适用于不仅仅使用 PSNR 作为质量指数,因为它也是按像素计算的。因此,我建议在比较这类任务中任何两种方法的性能时,不要只检查 PSNR。

感知损失通过基于来自预训练 CNN 模型的高级表示比较两幅图像来计算。该函数用于比较图像之间的高级差异,如内容和风格差异。

换句话说,目标和预测输入都通过预先训练的网络,并计算两个结果特征图之间的欧几里德距离(在同一阶段)。感知损失函数的工作原理是将所有像素之间的所有平方误差相加并取平均值。这与每像素损失函数相反,每像素损失函数将像素之间的所有绝对误差相加。

进化的第四代:SRGAN

生成对抗网络(GANs)提供了一个强大的框架来生成具有高感知质量的看似真实的自然图像。GAN 过程鼓励重建向搜索空间中包含照片级逼真图像的概率较高的区域移动,从而更接近自然图像流形。

SRGAN 是基于 GAN 的网络,其中生成器(G)学习从尽可能接近 HR 的 LR 图像生成 SR 图像。鉴别器(D)学习区分生成的 SR 图像和真实图像。G 利用 ResNet 和子像素卷积进行上采样。它还将感性损失与生成性或对抗性损失结合起来计算其损失。

Figure: Architecture of Generator and Discriminator Network in SRGAN. (source)

损失

Equation of modified perceptual loss in SRGAN. (source)

结论

研究使用深度学习估计单幅图像超分辨率的发展,显然,基于 ResNet 的 GAN 结合了感知损失和生成损失,并应用亚像素卷积进行上采样,可以生成更好的照片级逼真超分辨率图像。

显著的信誉

我要感谢 Katarzyna Kańska 关于“单图像超分辨率” : Youtube 视频— 你能增强一下吗?单幅图像超分辨率——Katarzyna kańska

使用 Hyperopt 在 XGBoost、LightGBM 和 CatBoost 上优化超参数的示例

原文:https://towardsdatascience.com/an-example-of-hyperparameter-optimization-on-xgboost-lightgbm-and-catboost-using-hyperopt-12bc41a271e?source=collection_archive---------1-----------------------

额外奖励:Hyperopt-Sklearn

Source: Pexels

我保证,这次会比上一次更高级:

[## 配对交易中强化学习的温和实现

TensorFlow 中结构化编程的一个例子

towardsdatascience.com](/a-gentle-implementation-of-reinforcement-learning-in-pairs-trading-6cdf8533bced)

介绍

梯度推进决策树(GBDT)

梯度推进决策树上的附加训练技术。 XGBoost官方页面给出了非常清晰的概念解释。基本上,不是运行静态的单个决策树或随机森林,而是迭代地添加新的树直到无法实现进一步的改进。除了正则化之外,集合技术对于防止过拟合是至关重要的。尽管该模型可能非常强大,但仍有许多超参数需要微调。

XGBoost、LightGBM 和 CatBoost

这些是众所周知的梯度增强包。与通过遍历所有要素找到最佳分割的传统 GBDT 方法相比,这些包实现了基于直方图的方法,将要素分组到条柱中,并在条柱级别而不是要素级别执行分割。另一方面,他们也倾向于忽略稀疏输入。这些显著提高了它们的计算速度(更多细节见此处)。需要注意的几个关键点:

XGBoost :著名的 Kaggle 中奖包。树的生长是基于逐层的树修剪(树在一层的所有节点上生长),使用来自分裂的信息增益,为此需要对样本进行预分类,以便在每一步中计算所有可能分裂的最佳分数,因此比较耗时。

等级和树叶(树从特定的树叶开始生长)训练都是可用的。它允许用户选择一种叫做基于梯度的单侧采样(GOSS)** 的方法,这种方法根据最大梯度和一些具有较小梯度的随机样本来分割样本。背后的假设是梯度越小的数据点训练得越好。另一个关键算法是专有特征捆绑(EFB) ,它研究特征的稀疏性,并将多个特征组合成一个,而不会丢失任何信息,因为它们在一起决不非零。这些使得 LightGBM 比 XGBoost 更快。**

CatBoost :专为分类数据训练设计,也适用于回归任务。GPU 上的速度号称是这些库中最快的。在中将分类特征转换为数字中有多种方法。其速度的关键与两个 Os 挂钩: 遗忘树有序推进不经意树是指采用对称二进制分裂的逐层树构建(即每层上的每片叶子都被一个特征分裂),而有序提升应用排列和顺序目标编码来转换分类特征。更多详情请参见此处此处此处。**

贝叶斯优化

与作为强力方法的 GridSearch 或纯粹随机的 RandomSearch 相比,经典 贝叶斯优化通过高斯过程逼近目标函数(即随机样本被迭代地抽取(基于序列模型的优化(SMBO))并且样本之间的函数输出被置信区域逼近),在搜索最优参数时结合了随机性和后验概率分布。将在置信区域的高均值和方差处从参数空间中提取新样本,用于勘探和开发。查看此以获得更多解释。

远视

Hyperopt 是一个用于搜索空间优化的 python 库。目前它提供了两种优化算法: 1。随机搜索2。Parzen 估计器树(TPE ),这是一种贝叶斯方法,它使用 P(x|y) 而不是 P(y|x) ,在计算预期改善时,它基于对由阈值而不是一个阈值分隔的两个不同分布的近似(参见)。它曾经适应高斯过程和回归树,但现在这些不再被实现。

******

UL: Feature binning; UR: Tree growing; BL: Bayesian Optimizing ; BR: Gradient-based One-Side Sampling**

履行

装置

查看以下安装指南:

远视示例

fmin()是 hyperopt 中用于优化的主要功能。它接受四个基本参数并输出优化的参数集:

  1. 目标函数— fn
  2. 搜索空间— space
  3. 搜索算法— algo
  4. (最大)评估数量— max_evals

我们也可以将一个 Trials 对象传递给trials参数,它跟踪整个过程。为了进行试验,目标函数的输出必须是至少包括关键字'loss''status'的字典,这两个关键字分别包含结果和优化状态。可以通过以下方式提取临时值:

  • trials.trials -字典列表包含所有相关信息
  • trials.results -收集函数输出的字典列表
  • trials.losses() -损失清单(每次‘ok’试验的浮动)
  • trials.statuses() -状态字符串列表
  • trials.vals -采样参数字典

让我们看看下面的例子:

Example of hyperopt implementation

****

Example of hyperopt implementation - progress and the corresponding results

优化后的 x0.5000833960783931 ,接近理论值 0.5 。正如你可能注意到的,样本在最小值附近更加浓缩。如果您将algo切换到使用随机采样的hyperopt.rand.suggest,那么这些点将在hp.uniform下更均匀地分布。

还有几件事需要澄清:

****搜索算法:或者hyperopt.tpe.suggest或者hyperopt.rand.suggest

搜索空间: hp.uniform('x', -1, 1)用标签‘x’定义一个搜索空间,它将在-1 和 1 之间被均匀采样。目前由 hyperopt 的优化算法识别的随机表达式是:

  • hp.choice(label, options):选项的指标****
  • hp.randint(label, upper):随机整数【0,上)
  • hp.uniform(label, low, high):低/高值一致
  • hp.quniform(label, low, high, q) : round(uniform(.)/q)*q(注意该值给出的是一个浮点数,而不是整数)
  • hp.loguniform(label, low, high) : exp(uniform(low, high)/q)*q
  • hp.qloguniform(label, low, high, q) : round(loguniform(.))
  • hp.normal(label, mu, sigma):正态分布抽样
  • hp.qnormal(label, mu, sigma, q) : round(normal(nu, sigma)/q)*q
  • hp.lognormal(label, mu, sigma) : exp(normal(mu, sigma)
  • hp.qlognormal(label, mu, sigma, q) : round(exp(normal(.))/q)*q

详见

如果你想从远视空间采样,你可以调用hyperopt.pyll.stochastic.sample(space),其中space是上面的hp空间之一。

使用 Hyperopt 优化 XGBoost、LightGBM 和 CatBoost

下面是本文中的主要示例。所有三个 boosting 库都有一些相似的接口:

  • 训练:
  • 交叉验证: cv()
  • sci kit-学习 API:
    -回归器:XGBRegressor()LGBMRegressor()CatBoostRegressor()
    -分类器:XGBClassifier()LGBMClassifier()CatBoostClassifier()

以下示例使用回归器接口。让我们首先为所有三个库定义参数空间(reg_params用于对象实例化;fit_paramsfit()功能):

请注意,许多参数共享公共的参数名或别名。有关更多信息,请查看以下链接和相应的 API 页面:

一些基本参数:

  • learning rate【X/L/C】:学习率(别名:eta)
  • max_depth【X/L/C】:树木的最大深度
  • n_estimators【X/L/C】:升压迭代次数
  • min_child_weight【X/L】:一个孩子所需的最小体重总和
  • min_child_samples【信用证】:一叶数据的最小数量
  • subsample【X/L/C】:训练实例的子样本比率(注意,对于 CatBoost,只有在选择了泊松或伯努利bootstrap_type时,才能使用该参数)
  • colsample_bytree【X/L】:树木建筑中柱子的子样比
  • colsample_bylevel【X/C】:树型建筑中各层柱子的子样比
  • colsample_bynode【X】:各节点列的子样率
  • tree_method【X】:树形构造法
  • boosting【L】:树形构造法
  • boosting_type [C]: Ordered表示有序升压,或者Plain表示经典
  • early_stopping_rounds【X/L/C】:用于fit()的参数——如果验证数据的一个指标在最后early_stopping_rounds轮中没有改善,则停止训练
  • eval_metric【X/L/C】:验证数据的评估指标

有关 CatBoost 中分类特征设置的更多设置,请查看参数页面中的 CTR 设置。

在设置参数之后,我们可以创建一个类HPOpt,它用训练和测试数据实例化,并提供训练函数。这里我只包括回归变量的例子。您可以在课程中添加自己的分类、训练或交叉验证功能。

例如,给定预定义的数据帧x_trainx_testy_trainy_test,我们可以通过调用process()来运行优化过程:

额外奖励:Hyperopt-Sklearn

Hyperopt-Sklearn 是一个非常高级的优化包,目前仍在构建中。让我们来看一个官方例子:

source: https://hyperopt.github.io/hyperopt-sklearn/

你可能会好奇什么是any_classifier?如果我们检查它的 GitHub 库:

似乎涵盖了 SVMKNN随机森林甚至 XGBoost 等多个分类器和回归器。正如官方页面所说:

hyperopt 中可用的任何搜索算法都可以用来驱动估计器。也可以提供自己的算法或混合使用不同的算法。

基本上,它几乎为您搜索所有内容,包括模型和超参数。虽然这听起来很方便,但在把一切交给电脑之前,我会三思而行。但是,如果数据集和参数空间的大小不是很大,那么值得一试。

最后

这是对主要 boosting 库和 hyperopt 的介绍。在文档中有更多关于并行运行的主题,可以提高 GPU 和 MongoDB for hyperopt 的计算速度,您可能也会有所启发。

实施人工智能和机器学习的执行官指南

原文:https://towardsdatascience.com/an-executives-guide-to-implementing-ai-and-machine-learning-2f1dc2d18b60?source=collection_archive---------14-----------------------

我在应用人工智能/机器学习支持业务目标方面学到的一些经验

作为首席分析官,我必须在业务需求和数据科学家之间架起一座桥梁。根据我的经验,如何弥合这一差距就是人工智能(AI)和机器学习的价值和前景实现程度的差异。以下是我学到的一些东西。

AI =机器学习(至少在 2019 年)

机器学习是一条通往人工智能的道路。至少到 2019 年,这是我所知道的唯一可行的路径。在未来几年,可能会有其他方法。这两个术语不可互换,但出于我们的目的,我将专注于机器学习。

机器学习是一类工具和方法,其中给计算机一个包含“答案”的大型训练数据集。然后,机器学习如何从输入的组合中获得答案。然后根据不同的测试数据集测试该模型,以确定其准确性。

机器学习作为一个类别可以包括适合这种方法的基本统计工具(例如线性回归)。它还包括神经网络、决策树和其他一些工具。

机器学习是你试图解决的问题的正确工具吗?

这一个在过去曾经绊倒过我。

例如,最近我有一个数据集,其中有许多从医院收集的数据,每个员工都有 50 个测量值(例如,他们是否按时上班,或者他们是否始终是当班唯一有经验的人),以及他们是否会在接下来的几周或几个月内辞职的指标。问题是:给定这个数据集,我们能否创建一个模型来预测哪些员工会在辞职前辞职,从而让医院能够及早干预?

我们花了几个月的时间审查数据集,并使用基本的数据可视化方法来确定一组规则。例如,刚被雇用的员工辞职的可能性是已经在医院工作了十年的员工的两倍。某些临床专业的员工和特定年龄段的员工有不同的平均辞职率。被要求每月两周或两周以上每周工作 60 小时以上的员工辞职的可能性要高 50%。

这个问题是机器学习的好候选吗?难道我们不能把这些规则组合起来,建立一个统计模型吗?

最终,我相信它是一个很好的候选,但类似的问题可能不会出现。加州理工学院教授亚塞尔·阿布·穆斯塔法描述了机器学习候选问题需要具备的三个品质:

1 -有足够的数据。

  • 相对于其他选择,机器学习成为更好的方法,你有越多的数据来训练它。如果你只有几百行数据,它可能不工作或者不能有效地工作。

你的输入和你试图预测的东西之间有关系。

  • 在我的例子中,我们对数据的视觉回顾显示有很多这样的关系。

3 -这种模式无法用简单的英语描述。

  • 在我的例子中,这个不太清楚。因为我们能够用简单的英语描述许多模式,为什么我们不能在这些模式上建立一个模型呢?在我们的案例中,既有我们无法辨别的隐藏模式,也有我们无法辨别或描述的变量之间的关系。例如,如果一个人既工作了很多小时,又是轮班中最有经验的成员,那么两者的影响是相加的吗?

从这里开始并确保部署正确的工具可能会节省您很多时间。即使以上对于您的数据集来说是真的,它们真的足以证明对这种方法的投资吗?

从投资回报率的角度来看,预测一个事件发生的价值是否等于错误预测一个不发生的事件的成本?

数据分析师基于准确性比较和优化模型。准确性是在预测尽可能多的将要发生的事件和不正确地预测尽可能少的不会发生的事件之间的权衡。有一些方法可以调整模型的阈值,以便在模型运行后进行权衡,但是解释这样的结果需要一些脑力劳动。

对于业务所有者来说,更好的方法是在根据业务目标运行模型之前建立模型。在我们的例子中,正确预测将辞职的雇员的价值可能价值数千美元(即,避免用新雇员替换他们的价值),而错误预测雇员辞职的成本可能很小。然而,这是有门槛的:如果每年有 10%的员工辞职,我们对客户的了解告诉我们,我们不能识别超过 20%的高风险进行干预。这些标准需要从业务需求和术语(如 ROI)转化为模型输入(如惩罚矩阵)。

重要的一点是确定这种权衡的相对成本和价值,并确保构建的模型在此基础上进行优化。

最著名的机器学习实现之一,Netflix 奖,我相信忽略了这一点。该奖项颁给了能够最准确预测观众喜欢的电影的模型。在他们的案例中,准确性是公正的,不管我们给他们可能喜欢的电影打低分,还是给他们可能不喜欢的电影打高分。然而,这是正确的业务需求吗?如果网飞向我推荐五部电影,而我知道我会非常不喜欢其中的两部,作为一个用户,我很可能在未来对他们的任何推荐都打折扣。但是如果我看到了五部推荐给我的电影,而其中没有一部我知道我会喜欢的……那对我来说真的不是问题。

模型中需要稳定性吗?换句话说,如果输入中的一件小事发生变化,输出大幅波动是可以的吗?

以我的经验来看,模型越精确(至少按照机器学习对精确度的定义),投入产出关系就越不连续。

如果你有一系列照片,并且你想要一个机器学习模型来标记那些包括消防栓的照片,你可能很好地接受这种程度的不稳定性,因为没有用户会改变照片中的像素并期望输出保持相似的情况。
然而,对我们来说,某种程度的稳定是重要的。如果我们长期跟踪一名员工,我们不希望当他们的年龄从 31.1 岁到 31.2 岁到 31.3 岁时,他们的预测辞职风险每月都不可预测地上升。

您需要知道哪些输入字段对预测输出有贡献吗?或者有一个完整的黑匣子也可以吗?

神经网络是黑盒模型。你给它你的输入,它会返回一个输出;就是这样。你不知道它是如何得到输出的,也不知道在决定输出时哪些输入的权重最大。神经网络往往比其他模型更准确,但从业务需要来看,这额外的几个百分点的准确性值得你完全不透明吗?

其他模型,如线性回归和决策树,将向您显示导致输出的输入组合。数据分析师可能想要运行多个决策树,并获取所有输出的平均值。这可能会提高模型的准确性,但可能会降低了解其工作原理的能力。

我发现混合模型是获得两种方法优点的一种方式。一个模型是神经网络模型(带有一些阻尼因子以保持稳定性),它给出了周转风险值。另一个模型是确定关键驱动因素的线性回归。我们向用户显示两者的结果。存在一些风险,因为不能保证模型会匹配(换句话说,神经网络可能会识别其他模型无法识别驱动因素的高风险事件),但有一些方法可以解决这一问题。

总之……

上面的问题和讨论部分是基于我在试图弥合业务目标和分析团队之间的差距时的经历。商业目标需要艺术和科学的结合。机器学习背后的科学越来越商品化:模型可供任何人运行,并且有大量资源可用于获得数学上稳健的结果。但是你正在建立的事业不是数学上的。这是用户需求、营销需求以及集成和部署解决方案的实用性的混合。部署机器学习解决方案的艺术让我特别感兴趣,希望这些能给我一些思考。

也发表在strategister . blog上,在那里我分享了关于构建基于分析的产品和业务的想法。本文中提及或参考的任何书籍或其他资源都列在这里

Kickstarter 最近怎么样?

原文:https://towardsdatascience.com/an-exercise-on-basic-r-hows-kickstarter-doing-these-days-3476a4b9e7ab?source=collection_archive---------27-----------------------

使用 tidyverse 和 ggplot2 进行基本数据操作和可视化,使用 mediumR 发布

It’s a practice story!

我没有意识到从 R 直接导入到 Medium 后,桌子/桌子的形状会很差。如果有人曾经面临过这种情况,请给我一个链接供我参考!

我从 Kaggle 获得了 2018 年 1 月 Kickstarter 数据集。对于门外汉来说,也就是说,如果你一直生活在岩石下,Kickstarter 是一个项目众筹平台。所以你发布你想要实现的项目,它可以是艺术项目,音乐,电影,新玩意,艺术,食物食谱,视频游戏,等等。见鬼,曾经有个家伙在 Kickstarter 上建了一个页面来帮他做土豆沙拉。当这位老兄说他只需要 10 美元买一些土豆沙拉时,他得到了 55,000 美元。

因此,人们张贴他们想做什么样的东西,项目的细节,设定一个资助目标,并让人们“承诺”他们的项目。Kickstarter 遵循“全有或全无”的资助计划,这意味着如果到了资助截止日期,你的项目还没有达到目标,所有承诺的资金都将返还给贡献者。通常期限是 30 天或 60 天。但是如果你真的达到了你的融资目标,你会得到这笔钱,但是 Kickstarter 会给你 5%的提成。

所以今天我们将试着回答或提出更多的问题,有几点:

  • Kickstarter 还是独立项目可行的资金来源吗?如果有,通常什么样的项目能成功获得资助?
  • 如果项目资助失败,失败的可能性有多大?什么样的项目会失败?

我们首先对我们面临的数据集有一个概念。我们有从 2009 年 3 月到 2018 年 3 月的大约 378,000 个项目的数据(顺便提一下,Kickstarter 是 2009 年 4 月推出的,但无论如何)。

瞧,原始数据(名为“ks”):

ks## # A tibble: 378,661 x 16
##        ID name  category main_category currency deadline     goal
##     <int> <chr> <chr>    <fct>         <chr>    <date>      <dbl>
##  1 1.00e9 The ~ Poetry   Publishing    GBP      2015-10-09   1000
##  2 1.00e9 Gree~ Narrati~ Film & Video  USD      2017-11-01  30000
##  3 1.00e9 Wher~ Narrati~ Film & Video  USD      2013-02-26  45000
##  4 1.00e9 Tosh~ Music    Music         USD      2012-04-16   5000
##  5 1.00e9 Comm~ Film & ~ Film & Video  USD      2015-08-29  19500
##  6 1.00e9 Mona~ Restaur~ Food          USD      2016-04-01  50000
##  7 1.00e9 Supp~ Food     Food          USD      2014-12-21   1000
##  8 1.00e9 Chas~ Drinks   Food          USD      2016-03-17  25000
##  9 1.00e9 SPIN~ Product~ Design        USD      2014-05-29 125000
## 10 1.00e8 STUD~ Documen~ Film & Video  USD      2014-08-10  65000
## # ... with 378,651 more rows, and 9 more variables: launched <dttm>,
## #   pledged <dbl>, state <fct>, backers <int>, country <chr>, `usd
## #   pledged` <dbl>, usd_pledged_real <dbl>, usd_goal_real <dbl>,
## #   wrap_main_category <chr>

因为我们想看看什么样的项目得到了资助,什么样的项目失败了,所以首先存储新的变量来区分失败和成功的项目是有意义的。

ks$wrap_main_category<-str_wrap(ks$main_category,width=5)

success.fail.bar <- ggplot(ks, aes(x=wrap_main_category, fill=state))
success.fail.bar + geom_bar() + theme_economist() + labs(x="Project Category",y="Count of Projects", title="Kickstarter Projects State")

我们看到,对于大多数项目类别,成功率将低于 50%。下面是更详细的数据。我们创建新的变量,计算每个类别中有多少项目,以及每个类别中有多少项目失败,然后简单地将它们相除,以找到失败率。

ks.all<- ks %>%
  group_by(main_category)%>%
  summarise(count=n()) %>%
  arrange(desc(count))

ks.allfail<- ks.fail %>%
  group_by(main_category)%>%
  summarise(count=n()) %>%
  arrange(desc(count))

ks.rate <- ks.all %>%
  mutate(fail=ks.allfail$count/ks.all$count) %>%
  arrange(desc(fail))
ks.rate## # A tibble: 15 x 3
##    main_category count  fail
##    <fct>         <int> <dbl>
##  1 Journalism     4755 0.787
##  2 Games         35231 0.742
##  3 Fashion       22816 0.729
##  4 Food          24602 0.700
##  5 Technology    32569 0.697
##  6 Publishing    39874 0.692
##  7 Theater       10913 0.685
##  8 Art           28153 0.658
##  9 Design        30070 0.649
## 10 Film & Video  63585 0.628
## 11 Comics        10819 0.619
## 12 Music         51918 0.534
## 13 Crafts         8809 0.497
## 14 Photography   10779 0.462
## 15 Dance          3768 0.380**note: the column "count" represents the amount of projects belonging to the category in the data-set, the column "fail" indicates how often projects belonging to that category fails**

事实证明,以新闻为主题的项目失败了很多。另一方面,我们得到了失败最少的舞蹈分类项目。两者都有相对较少的提议项目。为什么?或许这与筹资目标有关?人们会被那些有着巨大资金目标的项目吓住吗?或者,资助目标金额较小的项目是否被认为不够雄心勃勃?资金目标是答案吗?我们将抽取 1%的人口作为样本。

ks.sample <- sample_frac(ks,0.01)

viol <- ggplot(ks.sample,aes(x=state,y=goal),options(scipen=1000000))

viol + geom_violin(scale="area") + coord_cartesian(ylim=c(0,1000000)) +
  theme_economist() + labs(x="Project Outcome",y="Funding Goal",title="Distribution of Funding States by Funding Goal")

事实证明不是。这只表明有一些疯狂的雄心勃勃的项目(这些项目失败了或被取消了)但筹资目标似乎并不真正影响成功。有道理。也许我们需要仔细看看。

viol + geom_violin(scale="area") + coord_cartesian(ylim=c(0,100000)) +
  theme_economist() + labs(x="Project Outcome",y="Funding Goal",title="Distribution of Funding States by Funding Goal")

看,大部分成功资助的项目都处于资助目标的低端。相反,其他州(失败)分布得很好。这是否意味着更低的资助目标意味着更好的计算项目,或者仅仅是,更容易资助?也许我们应该看看他们离他们的筹资目标还有多远?

ks2 <- ks%>%
  mutate(failhard=(ks$pledged/ks$goal)) %>%
  filter(state!="successful", state!="live") %>%
  select(ID:pledged,failhard,everything())
ks2## # A tibble: 241,906 x 17
##        ID name  category main_category currency deadline     goal
##     <int> <chr> <chr>    <fct>         <chr>    <date>      <dbl>
##  1 1.00e9 The ~ Poetry   Publishing    GBP      2015-10-09   1000
##  2 1.00e9 Gree~ Narrati~ Film & Video  USD      2017-11-01  30000
##  3 1.00e9 Wher~ Narrati~ Film & Video  USD      2013-02-26  45000
##  4 1.00e9 Tosh~ Music    Music         USD      2012-04-16   5000
##  5 1.00e9 Comm~ Film & ~ Film & Video  USD      2015-08-29  19500
##  6 1.00e9 Chas~ Drinks   Food          USD      2016-03-17  25000
##  7 1.00e9 SPIN~ Product~ Design        USD      2014-05-29 125000
##  8 1.00e8 STUD~ Documen~ Film & Video  USD      2014-08-10  65000
##  9 1.00e8 Of J~ Nonfict~ Publishing    CAD      2013-10-09   2500
## 10 1.00e9 The ~ Crafts   Crafts        USD      2014-10-02   5000
## # ... with 241,896 more rows, and 10 more variables: launched <dttm>,
## #   pledged <dbl>, failhard <dbl>, state <fct>, backers <int>,
## #   country <chr>, `usd pledged` <dbl>, usd_pledged_real <dbl>,
## #   usd_goal_real <dbl>, wrap_main_category <chr>

我增加了一个名为“失败”的栏目,通过划分承诺金额和目标金额来显示一个项目离获得资助还有多远。但是这里没有显示。

我们添加了一个新列来计算项目资金目标的完成百分比。通过这种方式,我们可以衡量他们离获得资助还有多远。

ks.sample2 <- sample_frac(ks2,0.01)

viol2 <- ggplot(ks.sample2,aes(x=state,y=failhard),options(scipen=1000000))

viol2 + geom_violin(scale="area") + coord_cartesian(ylim=c(0,1)) +
  theme_economist() + labs(x="Project Outcome",y="Funding Completion",title="How Hard did They Fail?")

大多数项目都失败了,甚至没有超过 25%。是否可以得出结论,不是资助目标太大,就是 Kickstarter 设定的资助期限太小?也许仅仅是因为这些项目没那么有趣。

总而言之,我们可以得出结论,坦率地说,60%的失败率是相当低的!我最初认为只有很小一部分项目能够成功获得资助。结果 40%的人达到了筹资目标。项目要么得到了资助,要么与目标相差甚远。显示它仍然是命中或错过,但嘿,40%的融资机会是相当大的,如果你问我。

我们下次再继续。毕竟,这是我第一次和 r 一起竞技。

ClinVar 数据库中人类遗传变异的探索

原文:https://towardsdatascience.com/an-exploration-of-human-genetic-variants-in-the-clinvar-database-fa50bcd87dea?source=collection_archive---------30-----------------------

每一个生物的核心不是火,不是温暖的呼吸,不是“生命的火花”。它是信息,文字,指令。如果你想理解生活,不要去想充满活力、悸动的凝胶和渗出物,想想信息技术。理查德·道金斯

正如道金斯在他一贯直言不讳、经常嘲讽的感叹中所描述的那样,我们越来越认同这样一个事实,即 DNA 是最典型的信息分子——一种由 4 个字母组成的小型字母表中的密码,构成了一个人。从纯粹的有用性来看,这是后元古代时代使用最频繁的信息技术。

数十亿年前,生命采用 DNA 作为信息分子。一开始,生命并不像今天这样复杂,无论是在机体外部还是内部。随着复杂的身体模式和器官模式的进化,DNA 的数量也随之增长。增长是惊人的——从细菌的兆碱基到人类的千兆碱基。毕竟,这是增加由 4 个字母组成的线性字符串的复杂性的唯一方法。然而,继续“长度增长”战略来跟上复杂性是不可能的。为了应对这种情况,进化发明了其他现象,如体细胞超突变、重组和交替剪接,以增加多样性,而不会永远增加基因组的大小。

Genome size comparison (x-axis in log scale)

进化的变异就像股票市场的波动。没有前者,后者就不会存在。变异是进化的食物和饲料。随着新物种的进化,它们继承的 DNA(变体)与它们的前辈略有不同。当条件改变时,这些变异中的一些相对于其他种群获得优势,成为优势物种(T2 的胡椒蛾进化)。这是进化的潮起潮落——从一个进化到下一个。不管是好是坏,它必须继续下去。

脱氧核糖核酸

一个人活着。生物体的完整描述已经写在蛋里了。—悉尼·布雷内

DNA 是生命的蓝图;它携带了制造生物体所需的所有信息。这是你的基因组——总体规划——生命的秘密

人类的 DNA 有 30 亿个碱基对长,由 4 个核苷酸碱基组成:腺嘌呤腺嘌呤、腺嘌呤腺嘌呤腺嘌呤、鸟嘌呤鸟嘌呤胞嘧啶。它所拥有的信息是它唯一的功能。为了制造蛋白质,DNA(更准确地说是 mRNA,它是 DNA 蛋白质编码区的代理)被破译为三联体或密码子。密码子是 3 个碱基的任意组合——也就是 4 个,加起来就是 64 密码子。每个密码子编码一个特定的氨基酸,由于只有 20 个氨基酸,有些氨基酸有不止一个密码子。这就是变体发挥作用的地方。DNA 序列的变异意味着氨基酸序列的改变、蛋白质组成的改变和一种无序状态。DNA 变异的这一方面对于评估个体对遗传条件的易感性至关重要。

为什么选择 ClinVar?

不久前,我们发现捕捉关于人口变化的洞察力是一个强有力的工具。它催生了生物学研究史上一些最重要的事业。 1000 个基因组1001 个基因组瓶中基因组OMIM宇宙ClinVar 等。是一些例子。 ClinVar 是一个公共知识库,包含关于基因组变异及其表型的信息和证据。如果您对您的基因组进行测序,并将其与 ClinVar 数据集中的基因组位置进行比较,您可以找出您的遗传变异及其表型。截至 2019 年 11 月,数据库中有超过 50 万(准确地说是 502252)个条目。ClinVar 由国家生物技术信息中心(NCBI)管理。

是什么导致了变异?

Variation in the corn kernel color caused by transposons

玉米穗中的每一粒都是一次独立减数分裂的产物。这意味着,令人惊讶的是,一只耳朵可以捕捉到玉米植株的整个基因组。几乎就像数据科学家的仪表板。但是,有一个问题;籽粒的颜色似乎不遵循孟德尔遗传。原因可能是什么?通过她在玉米遗传学方面的开创性工作,她获得了 1970 年的国家科学奖章和 1983 年的诺贝尔奖,芭芭拉·麦克林托克展示了某些遗传元素可以改变基因组中的位置,从而产生非孟德尔遗传模式。这些元素被称为转座子,当它们从染色体的一部分跳到另一部分时,它们会产生复杂的遗传变异,如缺失、复制和倒位。在人类中, Alu 元素 是最丰富的转座子——约占我们基因组的 10%。

第二个主要原因是电离辐射和高能辐射。它们引起点突变(单核苷酸变异)和染色体断裂。

如何识别变体?

我们使用两种主要的方法来描述变异——基因组的和功能的——在这里我将着重于基因组方面。在计算基因组学中,通过将给定序列与参考基因组进行比对来识别变异。正如你可能会想到的,参考基因组是而不是完美的基因组——它是一个单倍体镶嵌图——它是由 13 个匿名捐赠者任意选择的一整套基因组序列拼接而成的。顾名思义,它是分析的参考。

我们通过称为变体调用的多步骤过程来找出 DNA 变体。分析的输出是一个变体调用格式文件,通常称为 VCF 。如果你想自己试试这个,建议你看一下银河平台。它是免费使用的,而且他们为初学者提供了很棒的入门教程。下面的分析来自参考基因组 GRCh37 的 ClinVar VCF 文件。

人类基因组中最常见的变异是什么?

The proportion of variant classes in our genome

每一个数据都有些令人困惑——计算需要一种'剥洋葱'的方法,一次一层。ClinVar 数据集可以大致分为七类变量。正如你所看到的,毫不奇怪,大约 90%的 ClinVar 数据集由单核苷酸变异体(SNVs)组成。snv 倾向于在基因组中累积一段时间,因为大多数 snv 都是不影响中心法则的微小缺失。另一方面,多核苷酸变异是致命的,尽管很罕见,它们是由复杂的基因组重排形成的——这是一个危险的策略。

所有的变异都是对我们有害的吗?

很明显,从图表来看,答案是否定的,不是全部。然而,缺乏变化是危险的;一会儿我会告诉你为什么。如果以上是真的,那么这个图表应该立即有意义。变异的影响也很大程度上取决于它在 DNA 中的变化类型和变异的位置。外显子或启动子中间的缺失将是灾难性的。然而,如果它位于内含子或 3’非翻译区,其影响可能是良性的。

SNVs 是什么原因造成的?

Different types of base conversions among the SNVs

臭氧是救生员,是上层大气中的一层面纱,保护我们的基因组免受紫外线的破坏。然而,一些更长的紫外线波长确实设法逃脱并落在我们身上。这个紫外线波长恰好在 T hymine 和 C ytosine 的吸收光谱内。辐射能的激发使它们与附近的碱基反应,产生嘧啶二聚体。暴露在阳光下的每一秒钟都会在我们的皮肤细胞中引发上百次这样的反应。但是我们有一个对策,核苷酸切除修复,切除损坏的碱基以减轻损害。如果这些得不到纠正,DNA 可能会永久变异。SNV 的另一个来源是碱基的错配,因为它们被紫外线、X 射线和γ射线电离。

这些事件属于两类颠换 。如图所示, 转换 是我们基因组中最常见的点突变(C - > T,G- > A,A- > G,T- > C)。

为什么缺失是致命的?

Shows what proportion of each variant contribute to pathogenicity

出生时患有啼哭综合症或猫哭综合症的婴儿经常像猫一样哭——这是 5 号染色体缺失的原因。高能辐射,如 x 射线和γ射线以及转座子会导致基因组损伤。结果往往是致命的,导致缺失。缺失会破坏 DNA 中编码信息的连续性,从而停止信息传递,并对细胞发育造成严重破坏。如图所示,大多数缺失都与致病性有关。

Number and size of deletions on human chromosomes

删除的最大大小似乎在 5KB 左右。可能存在选择偏差,使得任何大于 5Kb 的缺失都是致命的。

为什么染色体变异不同?

The variant landscape of human chromosomes

人类染色体是按大小递减的顺序编号的。也就是说 1 号染色体最大,22 号最小。从逻辑上来说,染色体越大,突变的几率越高,但事实并非如此,从直方图中可以明显看出。

谈到逻辑,19 世纪一些最伟大的头脑被生物学的逻辑玩弄于股掌之间——在他们努力破译遗传密码的过程中。大爆炸的创始人之一伽莫夫等人认为这是一个明显的组合学案例——20 个氨基酸&三胞胎(你可以在这里 阅读他 1954 年的自然论文 ),后来被克里克证明是错误的。逻辑没问题,但是想象力和实验性更好!说够了。

Human chromosomes

看一看第 17 号染色体;它和 1 号染色体**的变异一样多。这个很耐人寻味。期待一篇后续文章,我将对每个染色体的结构做一些挖掘。目前,我们可以得出结论,17 号染色体的突变率比其他染色体高得多。人们还可以观察染色体带,很快发现与其他染色体相比,17 的异染色质(暗带)非常少。

你可能已经注意到 Y 染色体缺乏变异;这是因为它在全基因组关联研究(GWAS)和全基因组/外显子组测序研究(WGS/WES)中代表性不足。

变异导致的紊乱有哪些?

首当其冲的是癌症和退化性疾病。缺失倾向于使个体倾向于不同形式的癌症。然而,有趣的是,在退行性疾病中没有缺失。

为什么变异会导致紊乱?

Pathogenic variants and their molecular consequences

DNA 美丽的双螺旋结构解决了信息存储的问题,但直到很久以后才解决了信息传递的问题。最初,一个学派认为它可能类似于莫尔斯电码。然而,没有人能找出莫尔斯电码中分隔单词的停顿的基因等价物。事实上,遗传密码中没有停顿。这是一个无限的信息——一个一维的核苷酸阵列,读作三元组,只有那些知道从哪里开始,什么时候停止的人才知道。这些基本原则结晶成了我们今天所知的 中心法则——从 DNA 到 RNA 到蛋白质的单向信息流。

正如你在 y 轴上看到的,这些变体可以在许多方面偏离中心教条,当它们偏离时,就会导致混乱。移码变异改变阅读框架,无义突变引入过早终止密码子,剪接变异影响 RNA 加工,等等。所有这些都会影响细胞功能。

你可能已经注意到在 frameshift_variant 类别中缺少 SNVs 这是因为 SNVs 是 到位 突变。

为什么有些染色体比其他的更具致病性?

Distribution pathogenic variants on human chromosomes

生存是一门艺术,我们的基因组是这门艺术的大师。进化的一个共同主题是在系统中引入冗余。我记得这个基因丝兰,我在加州大学戴维斯分校做博士后研究时广泛研究过它。细胞中有超过八个这种基因的副本,每次我突变一个,另一个就会打开并取代前者的位置。毕竟,没有植物能够在没有生长素的情况下存活,生长素是丝兰基因的产物,总共价值八份,你说呢!

染色体有各种类型,大的、小的、异色的、末端着丝粒的等等。每条染色体都有两对并不是偶然的——这是大自然创造备份的方式——就像我们会定期备份我们的电脑一样——你明白了。但是这个系统并不完美,看看 X 和 Y 染色体——在男性中,没有备份!如果你看一下图表,你可以看到 X 染色体上的高致病性变异负担,也许是其独特性的结果。我们很幸运有备份,否则每一个突变都会对我们的生活产生不利影响。

上图还表明,2 号和 17 号染色体有突变热点,这使它们极易发生变异。此外,这些热点可能藏有一些关键基因。

哪些基因受变异影响最大?

一些基因比其他基因更容易重排,因为它们在染色体上的位置和它们的序列,如 CpG 岛。这里,都与乳腺癌有关的 BRCA1BRCA2 的缺失水平最高。乳腺癌是全球女性中最常见的癌症,这是由于在 BRCA 位点的染色体重排增加。如果你是一个男人,不要认为你摆脱了困境。根据疾病预防控制中心的说法,携带 BRCA 突变的男性更有可能患高级别前列腺癌、胰腺癌和乳腺癌。

不再平衡!

Top variant genes and their allele frequencies

达尔文的自然选择理论,一个令人困惑的简单想法,可以解释生命的整体,它的设计,复杂性和多样性。然而,它未能解释机会变异是如何产生并代代相传的。尽管达尔文和孟德尔是同时代的人,但没有人看到解释自然选择的明显联系。根据 Hardy-Weinberg 平衡,如果没有自然选择的作用,一个群体中等位基因的频率应该保持不变,这在这个星球的大部分生命中都是如此。疫苗等发现扭转了局面;现在,是人类的选择决定了微观进化。因此,我们将在图表中看到导致严重疾病的变异频率上升。

等位基因频率是变异在人群中流行程度的指标。频率越高,表明该等位基因在人群中出现的范围越广。在图表中,你可以看到小提琴图中较高的隆起,表明概率在变化。

变体似乎太麻烦了;我们不能摆脱他们吗?

“生命不会被遏制。生命挣脱了束缚。它扩张到新的领域,冲破障碍,痛苦地,甚至危险地。”伊恩·马尔科姆博士,侏罗纪公园

抛开陈词滥调,我有一个故事给你:20 世纪 70 年代的玉米穗腐病。一种叫做玉米小斑病菌的玉米疫病菌摧毁了美国的玉米种植带,美国 85%的玉米都种植在这里。据估计,这一连锁反应给美国经济造成了数千万美元的损失。

那里会发生什么?玉米是如何变得容易受到广泛的真菌攻击的?美国科学院进行的一项研究发现,玉米带中的大多数玉米植物都来自“德克萨斯雄性不育细胞质”,也就是 T 细胞质。换句话说,所有植物的 T 细胞质在遗传上是一致的。

将 T-细胞质导入玉米植株是一种极好的(?)促进高产、杂交玉米种子快速和有利可图的生产的方法。公司立即采用了它,并将其商业化,却没有完全了解其潜在的后果。当玉米小斑病菌的一个新品系进化时,它被证明是完美的 T 细胞质杀手,因为玉米群体中没有变异——想要深入研究,这里的就是论文。你看,克隆和 CRISPR 婴儿并不能解决我们的健康问题。我们不应该努力消灭变异,而是学会与之共存——真正的解决方案是 个性化医疗

我是 Aneesh。我是 Insight Data Science 的健康数据科学研究员。我开始写这篇文章时,脑子里想的是数据探索。原来我也有一些故事要分享。如果你今天学到了什么,我会很高兴。下次再聊!

神经网络玩电子游戏的探索

原文:https://towardsdatascience.com/an-exploration-of-neural-networks-playing-video-games-3910dcee8e4a?source=collection_archive---------13-----------------------

A brief look at a curiosity-driven model playing Mortal Kombat 3 for the Sega Genesis. The curiosity-driven model is the player on the left.

感谢我的团队成员:Benjamin Guo、 Christian HanCooper Shearer 、【Justin Qu】和 Kylar Osborne

介绍

电子游戏不仅仅是好玩。它们为神经网络提供了一个平台,可以学习如何与动态环境交互并解决复杂的问题,就像在现实生活中一样。几十年来,视频游戏一直被用来评估人工智能的表现,最近又出现在新闻中,像 DeepMind 这样的公司成功开发了能够击败顶级电子竞技专业人士的人工智能系统

我们的团队希望探索各种机器学习算法如何在玩一些我们最喜欢的经典视频游戏时发挥作用。我们的目标不是创建特定游戏的最佳模型,而是观察它们的行为特征以及它们对不同游戏任务的适应性。

背景

在我们开始深入我们项目的细节之前,让我们看看这些模型是如何在基础层面上工作的,以及我们是如何与视频游戏交互的。

强化学习

强化学习是机器学习的一个领域。它不同于监督学习,因为不需要标记的输入和输出。相反,代理在环境中执行一些动作,环境返回一个观察和一个奖励。基于这种奖励,代理人可以学习继续展示其当前行为或避免它。当代理人试图最大化它的报酬时,这个反馈循环继续。

Diagram detailing the agent-environment system in reinforcement learning

为了把它放在一个更具体的环境中,让我们想象一个真人快打的游戏,代理人是我们的战士,环境由对手和舞台组成。如果我们的战士出拳并且能够降低对手的生命值,那么我们可能会因为我们的行动而得到奖励。另一方面,如果我们的战士跑了,而对手能够踢我们并降低我们的健康水平,那么我们可能会因为我们的行动而受到惩罚。

与视频游戏交互

为了将机器学习算法与视频游戏相结合,我们利用了由 OpenAI 开发的增强学习工具 GymGym Retro 。Gym 允许我们创建前面提到的代理环境系统,而 Gym Retro 允许我们通过访问游戏中的变量和保存状态,从 Atari、Nintendo Entertainment System 和 Sega Genesis 等游戏机上模拟和运行复古游戏。

神经网络可以访问预定义的输入,每个输入都使代理执行一个动作。例如,对于世嘉创世纪控制台上的真人快打 3,神经网络只能从原始世嘉创世纪控制器上的六个按钮和方向箭头中进行选择。每个按钮都与一个特定的动作相关联(例如,“A”按钮对应一个低踢动作)。通过使用这些输入与环境交互,神经网络能够从观察和奖励中学习;最终,它能够学会如何正确应对各种情况并赢得比赛。

输入预处理

这些算法将视频游戏的每一帧作为图像输入。一个单独的关卡可能由成千上万的帧组成,而每一个单独的帧已经包含了大量的信息。因此,这个项目的一个主要方面是预处理这些图像输入,以平衡训练时间和神经网络的性能。减少计算的预处理方法有效,但是一些能提高性能的更先进的技术(不包括边缘检测)似乎对我们的模型没有帮助。

缩放输入和限制颜色

为了减少计算时间,同时保持数据的基本特征,我们缩小了许多图像的尺寸,并去掉了颜色。例如,Sega Genesis 模拟器的原始大小为 320x224 像素。我们把它缩小到一半大小,去掉了颜色。

Reducing input image size by half and removing colors

限制输入

对于每个游戏,都有我们不希望代理采取的特定动作和按钮。例如,在刺猬索尼克中,使用“向上箭头”将允许索尼克向上看,而在训练时,我们发现有些情况下只会向上看,而不会通过关卡。为了加快培训过程,我们限制了可以获得的输入。

Sonic really likes looking at those clouds…

跳帧

我们实际上忽略了一些作为输入给出的帧,因为不是所有的帧都包含重要的信息。例如,看看下面的 4 帧序列。很难区分前两帧。

Sequence of frames before applying frame skipping

通过跳过一些帧,我们能够保留足够的数据来辨别重要的特征,如运动,同时减少计算和训练时间。

Sequence of frames after applying frame skipping. Frames in yellow are used for input while frames that are crossed out are ignored.

框架堆叠

通过观察这张单一的图像,几乎不可能判断跳跃的角色正在向哪个方向移动。

通过帧堆叠,我们可以将多个帧组合成模型的单个输入。我们的模型实际上是基于一系列“堆叠在一起”的帧而不是单个帧来选择动作。这使得模型能够辨别角色移动的方向或速度。与我们的其他预处理方法不同,这项技术实际上增加了计算量,但通过帧堆叠获得的信息超过了成本。

Sequence of frames that have been skipped and stacked before being used as a single input for the neural network

背景去除

虽然我们的大部分预处理旨在减少信息以降低计算复杂度,但背景去除背后的想法是减少噪声。我们发现,一些受过训练的人工智能在达到不同背景的新水平时,表现出不同寻常的行为。

我们尝试了来自 OpenCV 库的许多不同的背景去除算法;然而,目前不存在用于去除动态背景的算法。除了去除背景之外,另一种方法是用不同的背景在不同的层次上训练人工智能

The background removal seems to be effective until the background begins scrolling

目标跟踪

在我们没有成功去除背景后,我们考虑简单地跟踪《真人快打 3》中的玩家对象和对手。不幸的是,OpenCV 库中现有的跟踪器要么将每帧的处理时间增加了 20 倍,要么无法保持对所需目标的锁定。此外,他们需要在对象上放置一个初始启动框,这需要手动选择或需要一些对象检测软件。

除了这些缺点,物体跟踪将只适用于真人快打 3,那里总是只有 2 个角色,没有其他相关的物体。在《刺猬索尼克》和《超级马里奥兄弟》中,简单地追踪主角会移除相关的环境信息,如 Goombas 或 powerups。

The object tracker first loses track of the original fighter and begins tracking the opponent. Then, it gets stuck on the light fixture in the background.

目标检测

为了克服物体跟踪器的缺点,我们决定尝试使用一个名为 YOLOv3 的物体检测库。YOLOv3 有几个版本,每个版本都有不同大小的预训练神经网络。虽然基线版本在识别真人快打的人形时工作得很好,但在单帧上运行需要大约 5 秒钟,这使得在我们当前的硬件上几乎不可能进行训练。(客观地说,我们目前的训练速度超过每秒 60 帧。)我们还尝试了 YOLOv3 的“微型”版本,它包括一个更小的神经网络,这被证明足够快;然而,由于分辨率较低,它无法始终如一地识别字符。

除了准确性较低之外,它完全无法检测出《超级马里奥兄弟》和《刺猬索尼克》中任何有用的东西,因为它没有经过训练,无法识别这两款游戏中的各种敌人和物品。由于缺乏时间,我们无法实现某种对象检测预处理,因为这需要我们的团队不仅要重新训练模型,还要找到并制作所有重要游戏对象的训练集。

边缘检测

降低噪声的另一种尝试是通过边缘检测。边缘图将灰度帧转换成二进制帧,进一步降低了输入的复杂性。然而,生成边缘图确实给每一步增加了一点开销。最初,我们的团队担心丢失了太多的细节,神经网络将无法从真人快打的对手中识别出自己,但简单的测试证明情况并非如此。当与模型结合时,这种预处理技术允许我们在《真人快打 3》上获得最佳结果。

Edge detection proved to be much more effective than we initially believed

神经网络

为了观察机器学习算法在玩视频游戏时的表现,我们使用了三个模型:来自 NEAT-Python增强拓扑的神经进化(NEAT) 、来自 OpenAI 的基线近似策略优化(PPO) ,以及来自加州大学伯克利分校、爱丁堡大学和 OpenAI 的研究人员的好奇心驱动的神经网络

我们在世嘉创世纪控制台的真人快打 3 上训练了所有这些模型。此外,我们能够在 Sega Genesis 的刺猬索尼克上训练 NEAT,我们能够在 Sega Genesis 的刺猬索尼克和任天堂娱乐系统的超级马里奥兄弟上训练好奇心驱动的神经网络。

NEAT(扩充拓扑的神经进化)

NEAT 是一个使用基因组描述个体网络的前馈网络。该算法使用适应度函数通过世代进化网络。在训练过程中,通过高分基因组之间的繁殖以及一些突变来产生后续世代。添加节点和连接的快速实现允许基因组网络在结构上适应和增长,这提供了优于固定大小网络的优势。

我们使用 NEAT 的 Python 实现在《真人快打 3》和《刺猬索尼克》上进行训练。NEAT 由一个配置文件初始化,该文件定义了常量,如输入/输出数量、突变概率和权重参数。前馈网络的输入是游戏屏幕的图像,输出是按钮按压。一个奖励函数累积起来决定每个基因组的适合度。

我们成功训练了一个整齐的网络,打败了刺猬索尼克的第一关。我们还在《真人快打 3》上对它进行了训练,但由于技术困难,无法恢复视频文件。

Full gameplay for NEAT on Sonic The Hedgehog

Lucas Thompson 在 NEAT 上的视频帮助我们编写代码,也极大地提高了我们有效训练的能力。

基线

OpenAI Baselines 库实现了各种各样的强化学习算法,基于我们在相关项目中看到的成功,我们选择使用 PPO2 模型。

在使用基线时,我们发现尽早提出一个合理的奖励函数是很重要的。我们最终不得不在项目期间多次修改我们的奖励函数,这使得当我们想要测试新方法时,很难比较模型的性能,因为奖励的比例不一致。我们发现,最好的奖励功能是奖励和惩罚几乎相等,奖励应该立即给予,而不是在一集结束时给予。当前奖励功能监控双方战士的健康和比赛胜利,当检测到变化时,立即给予奖励或惩罚。

在让奖励函数工作之后,我们想把重点放在输入的预处理上,这是我们前面讨论过的。大量预处理的目标是减少模型在 GPU 内存中的大小。我们在具有 8 GB 板载 RAM 的视频卡上训练了这个模型,并且出乎意料地容易超出可用内存。我们需要并行训练模型,以使训练时间合理,通常有 16 个环境,因此当涉及到 GPU 内存时,模型大小的任何变化都会放大 16 倍。对图像进行缩放和灰度缩放可以大幅减少输入尺寸,但是当您通过帧堆叠再次增加图像尺寸时,这些增益大多会丢失。帧堆叠的性能提升超过了空间的合理性,所以我们开始跳过帧来降低内存占用。影响模型大小的其他因素是 nsteps 变量,它控制模型优化的范围,以及 nminibatches 变量,我们认为它采用整个范围并将其分成更小的块,用于梯度下降以更新策略。增加 nsteps 会增加模型在内存中的大小,但是增加 nminibatches 会减少模型在内存中的大小;我们认为这是因为一旦小批次被处理,帧就不再存储在存储器中。

一旦模型能够适应内存,我们就开始优化超参数。我们发现 0.00005 的学习率效果很好。我们尝试了高达 0.00025 的不同值,这使得这些模型最初快速降低了它们的误差,但是它们在大约 300 万个时间步长之后明显变慢,并且在大约 1000 万个时间步长之后被具有更小学习速率的模型超过。

在我们尝试的优化中,最令人惊讶的是边缘检测带来的性能提升。在我们看来,边缘检测器似乎删除了太多的细节,但用边缘检测器训练的模型击败了我们以前的所有尝试。

我们成功地训练了我们的基线网络,以击败《真人快打 3》中的前四关。

Full gameplay for Baselines on Mortal Kombat 3. The model is the Kabal character on the left.

要查看我们 PPO2 模型的代码,请查看git lab。这个代码是基于一个由AurelianTactics开发的项目,在那里他使用 PPO 来玩魂斗罗 3。

好奇心

好奇心驱动的神经网络不是通过使用奖励函数来学习,奖励函数必须手动构建,然后进行测试,这可能是一个乏味且耗时的过程,而是通过能够正确预测给定其当前状态下其行为的结果将会发生什么来学习。这些模型具有内在的动机;他们总是试图最小化自己的预测误差。这与试图最大化一些用户定义的奖励的外部激励模型形成对比。例如,考虑一个好奇的代理玩超级马里奥兄弟的情况。代理自然会想要探索整个级别,以便通过移动和跳跃来最小化预测将会发生什么的错误,探索级别与在马里奥中完成它们是一样的。

我们必须在游戏中训练好奇心驱动的神经网络,以确保代理知道正确的输入是什么。我们还必须增加对某些游戏机显示分辨率的支持。对于如何学习特征,代码中有各种选项:像素、随机特征、变分自动编码器、逆动态特征。在研究论文中一个有趣的结果是,仅仅使用像素作为特征通常会产生最差的性能。事实上,随机特征在比较中被证明是非常有效的,并且是默认的特征学习方法。由于时间和计算的限制,我们选择在我们训练的每个游戏中使用这个默认的方法。在未来,使用其他特征学习方法并比较由此产生的代理的性能将是有趣的。

好奇心驱动的神经网络在《超级马里奥兄弟》中表现最佳,达到了第三级。另一方面,扮演刺猬索尼克的特工总是会在第一关被卡住。我们认为这是由于游戏中非常动态的背景(例如,动画瀑布,波光粼粼的水,旋转的花,滚动的云)。相比之下,《超级马里奥兄弟》中的背景基本上是静态的。不过,这个结果并不太令人意外。研究论文简要讨论了这一特殊的局限性。《真人快打 3》尽管接受训练的时间最少,但也有相对静态的背景,玩这个游戏的代理人往往可以达到第二关。

A curious agent playing Sonic the Hedgehog becomes easily distracted by the busy background. Here, the agent most likely thinks the animation of the waterfall is a result of its own actions. It then gets stuck trying to minimize its error in predicting how the waterfall will change as a result of running and jumping around.

我们成功地训练了一个好奇心驱动的网络,达到了《凡人快打 3》的第二关和《超级马里奥兄弟》的第三关,但我们无法击败《刺猬索尼克》中的任何关卡。

Full gameplay for Curiosity on Mortal Kombat 3. The model is the Shang Tsung character on the left.

Full gameplay for Curiosity on Sonic The Hedgehog

Full gameplay for Curiosity on Super Mario Bros.

我们对于好奇心驱动的神经网络的代码大部分是从最初的实现中在创造者的 GitHub 上找到的。Lucas Thompson 的 视频教程 有助于我们理解代码库。

结论

最终,预处理、边缘检测和基线的结合在《真人快打 3》上产生了最好的结果,让我们击败了前四关。NEAT 是最容易使用的;设置好之后,我们真正需要做的就是调整超参数以提高性能。基线要困难得多,因为设计一个有效的奖励函数比我们预期的更具挑战性。最后,由于缺乏文档,好奇号很难使用,但它很容易训练,因为不需要外部奖励。好奇号在效率方面的表现受到了动态背景的负面影响,但它仍然能够通过关卡取得进展。

Results for furthest level reached for each of the models on each game

我们在前面的章节中提到了一些我们遇到的挑战,但是在整个项目中,培训时间是我们最大的挑战。这是这个项目的一个瓶颈,即使我们做了预处理工作。

对于这个项目,我们能够使用真人快打 3 作为我们的控制游戏,但我们希望在未来通过包括更多的游戏和更多样化的游戏类型来扩展这一点。我们也想看看这些模型有多通用;换句话说,有没有可能有一个单一的模型可以擅长许多不同的游戏?

虽然不如我们自己玩电子游戏有趣,但我们在整个项目中学习、失败和成功都度过了一段美好的时光。

英俊的公司主管人工智能图解指南

原文:https://towardsdatascience.com/an-illustrated-guide-to-ai-for-the-handsome-corporate-executive-17f33fd97874?source=collection_archive---------27-----------------------

如何将机器学习从概念验证转移到核心组织能力

Shut up Siri, just shut up (Image credit: North By Northwest)

如今,许多公司都在机器学习方面取得进展。最近深度学习的进步和可用数据的大规模增加使图像识别和自然语言处理取得了飞跃,这使得 AI*几乎在任何地方都受到了企业的关注。ML 已经超越了人类,使公司能够处理大规模的服务请求,这是 100%人工服务台根本不可能做到的。它在从欺诈检测到医学图像分析,从机器翻译到个性化推荐等领域都有成功的应用。由于相当多的人工智能头条新闻是由 GAFA 公司制造的,所以当你开始探索人工智能在你的业务中的应用时,作为一名高管或服务经理,你很自然地会关注他们。除了遵循这种方法的明显问题——你的公司可能仍然是一个很大程度上的离线努力——还有一些较少讨论的问题我想在这篇文章中解决。

*AI =应用机器学习

Only 5 percent of artificial intelligence is actually about machines learning (source: [1])

首先,大型科技报纸标题中宣传的收益混淆了他们成功基础上的巨大事业和多年发展、人员运作、投资和失败项目。当然,这不应该成为你开始探索机器学习应用的障碍,但在建立你的第一个机器学习团队或赞助你的第一个概念证明时,记住这一点可能是有用的——ML 远未成熟,一些项目需要大量的前期投资才能在行业环境中应用。举个例子,如果我要将上面的图表转换到没有适当数据基础设施的 LSE 环境中,这大约相当于 10 个 FTE 工作两年才能接近一个基本的可扩展机器学习平台。所有这些时间和金钱只会为您购买一些基础设施(不包括模型)。一旦你的团队达到这一点,期望他们全职工作于数据管道、变更管理、操作、集成和模型开发。这对伦敦政治经济学院来说是一笔巨大的投资——根据你的抱负、规模和地理位置,在 100 万欧元到 1000 万欧元之间。包括数据基础设施(您的数据湖/护城河/沼泽/排水沟)所需的前期投资,这样一项工作的预计成本可能会很快达到数千万欧元。

We‘re bad enough at forecasting when there is a reference class to base the forecast on (source: [2]).

奇怪的是,我见过的企业中采用机器学习的最常见方法是盲目飞行(一个明显的例外是 Ronny Fehling 在空中客车对工业化人工智能的愿景;他后来转到了波士顿咨询公司。看起来,围绕人工智能的大肆宣传已经让典型的董事会成员免除了明智的项目管理和长期战略思考的责任。这是一个危险的情况,因为许多这些“人工智能无处不在”的投资直接来自每个人都在投资人工智能的事实,而不是来自可行的商业案例和发布战略。我们都知道,FOMO 就像金融市场一样,充其量也是不可预测的。随着数据被比作石油(剧透——它不是,不同的外部性),人工智能被比作电力(也不正确,许多日常工作不需要认知能力),人工智能被比作烹饪(对于从业者),我想提出一个新的类比,希望让你更好地理解人工智能的采用将在未来五十年内在全球经济中采取的轨迹:飞行。

POC for a business experiment in the bicycle industry, ca 1903 (Image credit: Wikipedia)

尽管目前人们对基于无人机的即时送货兴奋不已(让我无人机送面包圈),但人们很容易忘记,飞行用了 100 多年才成为真正的商品。即使我们在不久的将来达到这一点,预计商业航空公司在 2019 年产生的 8550 亿美元空中收入的大部分将来自运输人员——这是一种与第一家商业航空公司一样古老的商业模式。同样,当我们看机器学习时,以营业收入和股票价格衡量,对我们 21 世纪世界的主要附加值贡献大体上仍然是付费广告。这回避了一个问题,即我们是否可以期待机器学习的工业应用在未来几年快速发展,超越基于个性化的应用。很多人都在押注物联网(IoT)应用。虽然物联网确实产生了大量数据,但如果没有规模经济和适当的基础设施,该领域中 ML 应用的价值将不会超过其成本。与 POC 不同,工业规模的 ML 系统控制需要质量控制、持续维护和持续改进,如果 ML 提供的改进微不足道,这将是一个沉重的代价。也就是说,我不认为运行智能冰箱的空中交通控制塔的 ML 模拟在经济上是可行的。到目前为止,预测性维护是 ML 广泛采用的消费者领域之外的一个应用。另一方面,消费者领域的 ML 应用已经一次又一次地证明了自己。人机交互从 ML 中受益匪浅。我们正在目睹人工智能通过搜索引擎、智能助手、智能相机和自动驾驶等工具,成为这个星球上绝大多数人类与机器的主要消费者界面。

这是一个危险的情况,因为许多这些“人工智能无处不在”的投资直接来自每个人都在投资人工智能的事实,而不是来自可行的商业案例和发布战略。

回到飞行的类比,除了操作飞机的机组人员,飞机还需要地勤人员和足够的基础设施,以确保飞机飞行路线上的人员和货物与经济的其他部分相联系。换句话说,航空公司是由航空业之外更大的价值链和生态系统支撑的。ML 也是如此——它不存在于真空中。负责开发和维护模型的运营团队(数据科学家、数据工程师、机器学习经理、业务分析师等)是企业价值链和由企业应用程序、业务流程、数据基础设施和计算资源组成的更广泛的 IT 生态系统的一部分。虽然对设计和建造机场的人来说显而易见,但这些外部性在机器学习项目中经常被公然忽视。尽管设计良好的机器学习算法肯定不会损害你的成功机会,但如果没有将模型预测正确整合到内部或面向客户的业务流程中——机器学习 UI 和 UX——以及更广泛的价值链和生态系统,你的项目几乎肯定会失败。事实上,在缺乏经验证据的情况下(我知道这一点),我敢打赌,许多 ML 项目的成功或失败更多地受到公司发起人和利益相关者的影响,而不是 ML 团队本身在项目期间设法产生的任何东西。

A simple cyclical business model (image by author)

这使我想到了第二点。用机器学习创造价值往往是一个组织问题,而不是技术问题。因此,这不是机器学习实践者可以独立于组织的其他部分解决的问题。许多旨在创造商业价值的机器学习项目失败了,因为它们需要业务人员和技术人员之间的合作。这意味着,冒险进入这个勇敢的 21 世纪新数字世界的公司不仅需要采用新的和不熟悉的技术(人工智能),而且他们还需要从组织分工(和冰山风险管理)转向更灵活的由价值创造而不是业务功能绘制的组织线(见这篇麦肯锡的文章对基于平台的组织的介绍)。一旦你成功地完成了这些转变,就可以从你对机器学习的押注(投资)中获得难以置信的回报,比如客户互动的改善、成本效率和总体的惊喜。由于当今公司拥有的数字工具不再需要最直接的人与人之间的互动,任何跨职能团队都可以通过数字界面直接与客户互动,不再需要曾经代表公司的销售、人力资源或服务人员。这个逻辑既适用于主要客户是内部客户的团队(如人力资源或财务),也适用于拥有外部客户的团队(销售、服务交付等)。).

Image credit: North by Northwest

重申一下,人工智能需要嵌入到业务流程中,才能创造价值。因此,这意味着接触、改变和增强在公司 IT 环境中实现的确定性业务逻辑。坦率地说,这将导致大量的工作,以及在这些工作之上更多意想不到的工作。此外,除了对现有业务流程进行重新设计之外,人工智能驱动的运营产品还需要一个机器学习平台,以促进嵌入公司产品、业务和运营中的大量预测流程的快速开发、部署和监控。这意味着端到端的数据可追溯性、用于近实时流程的低延迟数据流,以及跨职能团队对贯穿整个组织的所有数据流的数据访问。从这个意义上说,机器学习应用与之前的自动化浪潮有很大不同。自动化认知和概率能力的引入带来了对数据驱动过程的质量控制的需求的增加。不幸的是,这需要业务利益相关者和技术专家之间更多更好的合作。

The machine learning lifecycle (image by author)

奇怪的是,公司通常会将 ML 项目成败的部分留给数据科学家。无论这位数据科学家是外部承包商还是内部员工,他或她通常都不具备处理公司政治的能力,并且通常缺乏对现有业务流程进行更改的公司授权。这导致了那些可怕的无法交付任何商业价值的 MLPOCs。受过大学和研究生教育的数据科学家应用他们在学术界学到的工作流来解决业务问题。有人在某个地方找到了一台服务器,在没有监控的情况下安排了模型,而数据科学家则继续进行下一个 MLPOC。大家都很开心(我们做了 AI!),而且什么都没有真正改变。这是一个非常黑白分明的表示,但它凸显了人工智能产业化的一个主要挑战。如果没有适当的设计和项目执行,机器学习项目就有陷入无附加值的 ML 概念证明(MLPOC)的风险,在这种情况下,高管们在 FOMO 创作 ML 项目,数据科学家应用他们在研究生院学到的知识,没有人愿意负责确保项目产生真正的 ROMLIs(机器学习投资回报)。

从这个意义上说,机器学习应用与之前的自动化浪潮有很大不同。自动化认知和概率能力的引入带来了对数据驱动过程的质量控制的需求的增加。

Life’s an adventure (image by author)

简而言之,今天被资助的机器学习努力的随意性是导致灾难的原因。最重要的是,并不是你组织中的每个人都是那种无望的乐观主义者,他们认为人工智能有潜力通过自动化日常认知任务来改善世界范围内的工作条件,从而将我们人类解放出来从事更有趣的工作。有很多人害怕自动化会接管他们的工作,害怕失去决策权,或者只是害怕改变,这导致了旷日持久的政治阴影和战壕战争,这些都减缓了机器接管世界的速度(大胆的悲伤表情符号)。人工智能从业者和消费者的长期风险是,在一系列过于慷慨的承诺和令人失望的结果之后,企业将在未来几十年继续照常运营。这是一种耻辱,因为这意味着你的客户将被迫继续生活在 20 世纪 80 年代的科技时代。总而言之,任何机器学习项目要想成功,都需要具备几个前提条件:

对于 ML 团队来说,

  • 机器学习模型可以利用的数据基础设施。
  • 用于训练机器学习模型的计算基础设施。
  • 将模型预测整合到应用中的生产途径。
  • 监控和 AB 测试基础设施,以衡量模型预测对业务和分析 KPI 的影响。

在商业方面,

  • 识别业务流程,在这些流程中,可以应用足够多的 ROMLI 来保证所做的工作:高容量、低延迟、高成本、常规认知、危险等。业务流程。
  • 围绕可以通过机器学习增强或促进的业务流程,协调跨职能利益相关方。
  • 开发机器学习模型可以操作的硬约束——认知界限。
  • 监控业务 KPI 并向 ML 团队提供(最好是基于统计的)反馈。

从上面的要点可以看出,ML 团队在这方面的工作很简单。困难的部分是调整和改变你的组织,以允许你充分利用机器学习技术进步提供的机会。这是今天大多数 ML 项目继续搁浅的地方。由于 ML 团队或其直接赞助者通常没有跨部门业务流程的授权,如果你想认真对待 ML,你需要亲自监督和指导这些项目,或者任命具有足够广泛授权的人来发现和促进现有业务流程的 ML 支持的变化,或者开发基于 ML 能力的新流程。

免责声明:我是一名自由职业的机器学习工程师,因此机器学习在组织中成功落地并为我的客户提供最大的 ROMLI(机器学习投资回报)符合我的最佳利益。吃块饼干吧。

截图来自阿尔弗雷德·希区柯克 1959 年的《西北偏北》。

泊松回归模型图解指南

原文:https://towardsdatascience.com/an-illustrated-guide-to-the-poisson-regression-model-50cccba15958?source=collection_archive---------0-----------------------

和使用 Python 的泊松回归教程

在本文中,我们将讨论以下主题:

  1. 基于计数的数据的特征:计数数据集是世界上最常见的一些数据。我们将看看是什么使基于计数的数据不同。
  2. 预测数量的回归模型:我们来详细看看泊松回归模型负二项式(NB)回归模型是另一种常用的基于计数的数据模型。我将在以后的文章中讨论这个问题。
  3. 关于泊松回归的 Python 教程:我将带你一步步学习如何使用 statsmodelsGLM 类在 Python 中创建泊松回归模型,以及如何在真实世界数据集上训练它。

在我们开始之前,有几个要点…

  • 对于关于泊松回归的 Python 教程向下滚动到本文的最后几节。
  • Python 代码的 Github 要点是这里的
  • 本文中使用的一个骑自行车者计数的真实世界数据集是这里的。****
  • 关于随机变量、泊松过程和模拟泊松过程的 Python 程序,点击这里:
    泊松过程:你需要知道的一切

现在让我们开始吧!

什么是基于计数的数据?

基于计数的数据包含以特定速率发生的事件。发生率可能会随着时间的推移或从一次观察到下一次观察而变化。以下是一些基于计数的数据示例:

Data source: Wikipedia: potentially habitable exoplanets (Image by Author)

  • 每小时通过十字路口的车辆数量,
  • 每月去诊所看病的人数,
  • 每月发现的类地行星数量。

计数数据集具有以下特征:

  • 整数数据:数据由非负整数组成:[0… ∞]普通最小二乘回归等回归技术可能不适合对这类数据建模,因为 OLSR 最适合处理实数,如-656.0、-0.00000345、13786.1 等。
  • 偏斜分布:数据可能包含大量的数据点,但只有几个值,从而使频率分布相当偏斜。例如,参见上面的直方图。
  • 稀疏性:数据可能反映了伽马射线爆发等罕见事件的发生,从而使数据变得稀疏。
  • 发生率:为了建立模型,可以假设有某个事件发生率 λ 驱动这种数据的产生。事件率可能随时间漂移。

真实世界的计数数据集

下表包含了骑自行车的人在纽约市各种桥梁上行驶的次数。从 2017 年 4 月 1 日到 2017 年 10 月 31 日每天测量计数。

Source: Bicycle Counts for East River Bridges (Data source: NYC OpenData) (Image by Author)

这是布鲁克林大桥上骑自行车的人数的时间顺序图:

Background image: The Brooklyn bridge as seen from Manhattan island

计数的回归模型

泊松回归模型负二项式回归模型是开发计数回归模型的两种流行技术。其他可能性有有序 Logit有序 Probit非线性最小二乘模型。****

回归策略

从泊松回归模型开始,并将其用作更复杂或约束更少的模型的“控制”是一个很好的实践。在他们的《计数数据的回归分析》一书中,卡梅隆和特里维迪说:

"合理的做法是估计泊松和负二项模型."

在本文中,我们将使用泊松回归模型来回归布鲁克林大桥上观察到的骑自行车的人数。

介绍泊松模型

泊松分布具有如下的概率函数。

Probability of seeing k events in time t, given λ events occurring per unit time (Image by Author)

泊松分布的期望值(平均值)为 λ。 因此,在没有其他信息的情况下,人们应该期望在任何单位时间间隔内看到 λ 事件,例如 1 小时、1 天等。对于任何区间 t ,人们都会期望看到 λt 事件

一个泊松回归模式 l 为 常数λ

如果事件速率【λ】***是恒定的,则可以简单地使用修改的均值模型来预测事件的未来计数。在这种情况下,可以将计数的所有预测值设置为该常量值 λ 。*****

下图说明了常量 λ 的场景:

Actual and predicted counts for a constant rate model (Image by Author)

以下 Python 代码用于使用泊松过程生成蓝点(过去时间步的实际计数),其中 λ=5 。橙色点(预测)都被设置为相同的值 5。

A Python program to generate event counts using a Poisson process

非常数λ 的泊松回归模型

现在我们到了有趣的部分。让我们检查一个更常见的情况,其中 λ 可以从一个观察值变化到下一个观察值。在这种情况下,我们假设 λ 的值受解释变量的向量影响,这些变量也被称为预测变量、回归变量回归变量。我们称这个回归变量矩阵为 X****

回归模型的工作是将观察到的计数 y 拟合到回归值矩阵 X

在纽约市自行车统计数据集中,回归变量是日期星期几高温低温降水量。我们还可以引入额外的回归变量,如从日期派生的日和日,并且我们可以自由删除现有的回归变量,如日期

(Image by Author)

yX 的拟合通过固定回归系数 β的向量值来实现。

在泊松回归模型中,事件计数 y 被假设为泊松分布,这意味着观察到 y 的概率是事件速率向量 λ的函数。

泊松回归模型的工作是通过一个链接函数将观察到的计数 y 拟合到回归矩阵 X ,该链接函数将速率向量 λ 表示为 1)回归系数 β 和 2)回归矩阵X的函数****

下图说明了泊松回归模型的结构。

****Scan from left to right: The structure of the Poisson regression model (Image by Author)

有什么好的链接功能 f (。)连接 λX ?事实证明,以下指数链接函数非常有效:

The exponential link function of the Poisson regression model (Image by Author)

即使当回归变量 X 或回归系数 β 为负值时,该链接函数也会保持 λ 为非负值。这是基于计数的数据的要求。

一般来说,我们有:

The exponential link function of the Poisson regression model (Image by Author)

泊松回归模型的形式规范

基于计数的数据的泊松回归模型的完整规格如下所示:

对于回归变量 x_i 行对应的 y_i 表示的数据集中第个观察值,观察计数 y_i 的概率为泊松分布,其分布如下:

Probability of observing count y_i given x_i (as per the Poisson PMF formula) (Image by Author)

其中第 I 个样本的平均速率 λ_i 由前面所示的指数链接函数给出。我们在这里重现它:

The exponential link function of the Poisson regression model (Image by Author)

一旦模型在数据集上完全训练完毕,回归系数已知,模型就可以进行预测了。为了预测与已经观察到的回归量 x_p 的输入行相对应的事件计数 y_p ,使用以下公式:

The prediction equation for the Poisson regression model (Image by Author)

所有这些都依赖于我们成功训练模型的能力,这样回归系数向量【β】就是已知的 ******

让我们看看这种培训是如何进行的。

定型泊松回归模型

训练泊松回归模型包括寻找回归系数 β 的值,这将使观察计数的向量 y 最有可能。

识别系数 β 的技术称为 M 最大值 L 似然比 E 估计(MLE)。

让我们来熟悉一下 MLE 的技巧。

理解最大似然估计

我将使用自行车计数数据集来说明 MLE 技术。看看这个数据集的前几行:

Daily counts of bicyclists on the Brooklyn bridge (Image by Author)

我们的假设是,红框中显示的骑自行车的人数来自泊松过程。因此我们可以说它们的发生概率是由泊松 PMF 给出的。以下是前 4 次发生的概率:

Probabilities of observing the bicyclist counts for the first few occurrences given corresponding regression vectors (Image by Author)

我们可以类似地计算在训练集中观察到的所有 n 计数的概率。

注意,在上述公式中,λ_1、λ_2、λ_3、…、λ_n 是使用如下链接函数计算的:**

The event rates corresponding to the counts for the first few days (Image by Author)

其中x1,x2,x3,x4为回归矩阵的前 4 行。******

训练集中整组 n 个计数 y_1,y_2,…,y_n 出现的概率就是单个计数出现的联合概率。

计数 y 为泊松分布, y_1,y_2,…,y_n 为独立随机变量,对应给出 x_1,x_2,…,x_n 。因此, y_1,y_2,…,y_n 出现的联合概率可以表示为单个概率的简单乘积。下面是整个训练集的联合概率:

The likelihood function L(β) expressed as a joint probability mass function (Image by Author)******

让我们回忆一下, λ_1,λ_2,λ_3,…,λ_n 通过回归系数 β链接到回归向量 x_1,x_2,x_3,…,x_n

β 的什么值会使给定的一组观察计数 y 最有可能?上式所示的联合概率达到最大值的是 β 的值。换句话说,就是联合概率函数 w.r.t. β 的变化率为 0 的 β 的值。换一种说法,就是对联合概率方程 w.r.t. β 进行微分并将这个微分方程设为 0 所得到的方程的解。

联合概率方程的对数*比原方程更容易微分。对数方程的解产生相同的最优值***

这个对数方程被称为对数似然函数。对于泊松回归,对数似然函数由以下等式给出:

log-likelihood function for the Poisson regression model (Image by Author)

λ_i 替换为exp(x _ Iβ))后,取前面所示的联合概率函数两边的自然对数,即可得到上述等式。***

如前所述,我们对这个对数似然方程 w.r.t. β 进行微分,并将其设置为零。这个操作给出了下面的等式:

The Poisson MLE for β is the solution to this equation (Image by Author)

解回归系数的这个方程将产生 β的最大似然估计 (MLE)******

为了求解上述方程,可以使用迭代方法,例如迭代加权最小二乘法(IRLS) 。实际上,人们不能手工解这个方程。相反,您可以使用统计软件,如 Python statsmodels 包,它会在对数据集训练泊松回归模型时为您完成所有计算。

执行泊松回归的步骤摘要

总之,下面是对基于计数的数据集执行泊松回归的步骤:

  1. 首先,确保您的数据集包含计数。一种方法是,它只包含非负的整数值,这些值表示某个时间间隔内某个事件发生的次数。在骑自行车的人数数据集中,它是每天骑自行车穿过布鲁克林大桥的人数。
  2. 找出(或猜测)会影响观察计数的回归变量。在自行车计数数据集中,回归变量为星期几、最低温度、最高温度、降水量等。**
  3. 创建一个你的回归模型将要训练的训练数据集,和一个应该放在一边的测试数据集。根据测试数据训练模型。**
  4. 使用合适的统计软件,如 Python statsmodels 包,对训练数据集配置和拟合泊松回归模型。
  5. 通过在测试数据集上运行模型来测试模型的性能,以便生成预测的计数。将它们与测试数据集中的实际计数进行比较。
  6. 使用拟合优度来确定您的模型在定型数据集上的定型程度。

如何在 Python 中进行泊松回归

让我们把所学的东西付诸实践。Python statmodels 包对泊松回归有很好的支持。

让我们使用布鲁克林大桥自行车计数数据集。您可以从 这里的 中提取数据集。

我们的目标是为观察到的骑自行车的人数建立一个泊松回归模型 y. 我们将使用训练好的模型来预测布鲁克林大桥上的骑自行车的人的每日人数,这是模型在训练期间没有看到的。

Daily count of bicyclists on the Brooklyn bridge (Image by Author)

我们将从导入所有需要的包开始。

**import pandas as pd
from patsy import dmatrices
import numpy as np
import statsmodels.api as sm
import matplotlib.pyplot as plt**

为计数数据集创建一个熊猫数据框架。

**df = pd.read_csv('nyc_bb_bicyclist_counts.csv', header=0, infer_datetime_format=True, parse_dates=[0], index_col=[0])**

我们将向矩阵 X 添加一些派生的回归变量。

**ds = df.index.to_series()df['MONTH'] = ds.dt.monthdf['DAY_OF_WEEK'] = ds.dt.dayofweekdf['DAY'] = ds.dt.day**

我们将不使用日期变量作为回归变量,因为它包含一个绝对日期值,但是我们不需要做任何特殊的事情来删除日期,因为它已经作为熊猫数据帧的索引被使用。因此它在 X 矩阵中对我们不可用。****

让我们创建训练和测试数据集。

**mask = np.random.rand(len(df)) < 0.8df_train = df[mask]df_test = df[~mask]print('Training data set length='+str(len(df_train)))print('Testing data set length='+str(len(df_test)))**

用 patsy 符号设置回归表达式。我们告诉 patsy,BB_COUNT 是我们的因变量,它取决于回归变量:DAY、DAY_OF_WEEK、MONTH、HIGH_T、LOW_T 和 PRECIP。

**expr = """BB_COUNT ~ DAY  + DAY_OF_WEEK + MONTH + HIGH_T + LOW_T + PRECIP"""**

为训练和测试数据集设置 Xy 矩阵。patsy 让这变得非常简单。

**y_train, X_train = dmatrices(expr, df_train, return_type='dataframe')y_test, X_test = dmatrices(expr, df_test, return_type='dataframe')**

使用 statsmodels GLM 类,对定型数据集定型泊松回归模型。

**poisson_training_results = sm.GLM(y_train, X_train, family=sm.families.Poisson()).fit()**

打印培训总结。

**print(poisson_training_results.summary())**

这会打印出以下内容:

Training summary for the Poisson regression model (Image by Author)

那么我们的模型表现如何呢?让我们对测试数据集做一些预测

**poisson_predictions = poisson_training_results.get_prediction(X_test)#.summary_frame() returns a pandas DataFrame
predictions_summary_frame = poisson_predictions.summary_frame()print(predictions_summary_frame)**

以下是输出的前几行:

First few rows of output from poisson_predictions.summary_frame() (Image by Author)

让我们绘制测试数据的预测计数与实际计数的对比图。

**predicted_counts=predictions_summary_frame['mean']actual_counts = y_test['BB_COUNT']fig = plt.figure()fig.suptitle('Predicted versus actual bicyclist counts on the Brooklyn bridge')predicted, = plt.plot(X_test.index, predicted_counts, 'go-', label='Predicted counts')actual, = plt.plot(X_test.index, actual_counts, 'ro-', label='Actual counts')plt.legend(handles=[predicted, actual])plt.show()**

以下是输出结果:

Predicted versus actual bicyclist counts on the Brooklyn bridge (Image by Author)

该模型似乎或多或少地跟踪实际计数的趋势,尽管在许多情况下,其预测值与实际值相差甚远

让我们绘制实际计数与预测计数的对比图。

**plt.clf()fig = plt.figure()fig.suptitle('Scatter plot of Actual versus Predicted counts')plt.scatter(x=predicted_counts, y=actual_counts, marker='.')plt.xlabel('Predicted counts')plt.ylabel('Actual counts')plt.show()**

剧情是这样的:

Scatter plot of Actual versus Predicted counts (Image by Author)

这里是使用 Python 进行泊松回归的完整源代码:

泊松回归模型的拟合优度

记住泊松分布的期望值(即均值)和方差都是 λ。大多数真实世界的数据都违反了这个相当严格的条件。

泊松回归模型失败的一个常见原因是数据不满足泊松分布强加的均值=方差标准。**

stats modelsglm results类上的 summary() 方法显示了一些有用的拟合优度统计数据,可帮助您评估泊松回归模型是否能够成功拟合训练数据。让我们看看他们的价值观:

Training summary for the Poisson regression model (Image by Author)

偏差和皮尔逊卡方的报告值非常大。给定这些值,很好的拟合实际上是不可能的。为了在某个置信水平(比如 95% (p=0.05))下定量确定拟合优度,我们在 χ2 表中查找 p=0.05 和残差自由度=163 的值。(测向残差=无观测值减去测向模型】。我们将该卡方值与观察到的统计数据进行比较,在这种情况下,是 GLMResults 中报告的偏差或皮尔逊卡方值。我们发现,在 p=0.05 且 DF 残差= 163 时,来自标准卡方表的卡方值为 193.791,远小于报告的统计值 23030 和 23300。因此,根据该测试,尽管泊松回归模型显示出对测试数据集的‘好的’视觉拟合,但它对训练数据的拟合相当差。****

结论和下一步措施

对于基于计数的数据,泊松回归模型是一个有用的起点。然后可以将其性能与其他基于计数的流行模型进行比较,例如:

  1. 一个 零膨胀泊松模型 如果您怀疑您的数据包含过多的零,即比常规泊松模型所能解释的多得多的零。
  2. 负二项回归模型 对数据不做均值=方差假设。**
  3. 广义泊松回归模型 同样适用于过度分散或分散不足的数据集。

快乐造型!

感谢阅读!我写关于数据科学的主题,重点是回归和时间序列分析。

如果你喜欢这篇文章,请关注我的Sachin Date获取关于回归和时间序列分析主题的提示、操作方法和编程建议。

费希尔线性判别式的说明性介绍

原文:https://towardsdatascience.com/an-illustrative-introduction-to-fishers-linear-discriminant-9484efee15ac?source=collection_archive---------7-----------------------

为了处理两个或更多类别的分类问题,大多数机器学习(ML)算法以相同的方式工作。

通常,他们对输入数据应用某种转换,结果是将原始输入维度减少到一个较小的数字。目标是将数据投射到一个新的空间。然后,一旦投影,该算法试图通过找到一个线性分离来分类这些点。

对于输入维数较小的问题,任务稍微容易一些。以下面的数据集为例。

假设我们要对红蓝圈进行正确的分类。

很明显,用简单的线性模型我们不会得到好的结果。没有将输入映射到其正确类别的输入和权重的线性组合。但是,如果我们可以转换数据,这样我们就可以画一条线来区分这两个类,会怎么样呢?

如果我们对两个输入特征向量求平方,就会发生这种情况。现在,一个线性模型将很容易对蓝点和红点进行分类。

然而,有时我们不知道我们应该使用哪种转换。实际上,找到最佳表示法并不是一个简单的问题。我们可以对数据进行多种转换。同样,它们中的每一个都可能产生不同的分类器(就性能而言)。

这个问题的一个解决方案是学习正确的转换。这被称为表示学习,这正是深度学习算法所做的。

神奇的是,我们不需要“猜测”哪种转换会产生数据的最佳表示。算法会解决的。

但是,请记住,无论是表示学习还是手工转换,模式都是相同的。我们需要以某种方式改变数据,以便它可以很容易地分离。

让我们退一步考虑一个更简单的问题。

我们将探索费希尔的线性判别式 (FLD)如何设法将多维数据分类到多个类别。但是在我们开始之前,请随意打开这个 Colab 笔记本并跟随。

费希尔线性判别式

看待分类问题的一种方式是通过降维的镜头。

首先,考虑两类分类问题的情况( K=2 )。蓝色和红色点在 R 。一般来说,我们可以取任意一个 D 维输入向量,并将其向下投影到 D '维。这里, D 表示原始输入尺寸,而D’是投影空间尺寸。在整篇文章中,认为D’小于 D

在投影到一维(数轴)的情况下,即D’= 1,我们可以选取一个阈值 t 在新的空间中进行分类。给定一个输入向量 x :

  • 如果预测值 y > = tx 属于 C1 类(类 1)。
  • 否则,它被归类为 C2(2 类)。

注意向量 y (预测)等于输入 x 和权重w→y=wx的线性组合

以下面的数据集为例。我们想把原来的数据维数从 D=2 减少到 D'=1 。换句话说,我们需要一个将二维向量映射到一维向量的变换 t—t(v)=ℝ→ℝ。

首先,让我们计算两个类的平均向量 m1m2

注意, N1N2 分别表示 C1 和 C2 班级的分数。现在,考虑使用类均值作为分离的度量。换句话说,我们希望将数据投影到加入 2 类平均值的向量 W 上。

值得注意的是,任何一种向更小维度的投影都可能会丢失一些信息。在这个场景中,请注意,这两个类在它们的原始空间中是明显可分的(通过一条线)。

但是,在重新投影后,数据会出现某种类别重叠,如图上的黄色椭圆和下面的直方图所示。

这就是费雪线性判别式发挥作用的地方。

Fisher 提出的想法是最大化一个函数,该函数将在投影的类均值之间给出一个大的分离,同时在每个类内给出一个小的方差,从而最小化类重叠。

换句话说,FLD 选择了最大化类别分离的投影。为此,它最大化类间方差与类内方差之比。

简而言之,为了将数据投影到一个更小的维度并避免类重叠,FLD 维护了两个属性。

  • 数据集类之间的巨大差异。
  • 每个数据集类中的微小差异。

请注意,较大的类间方差意味着预计的类平均值应尽可能远离。相反,小的类内方差具有保持投影数据点彼此更接近的效果。

为了找到具有以下属性的投影,FLD 用以下标准学习权重向量 W

如果我们替换等式(1)和(2)给出的平均向量 m1m2 以及方差 s ,我们得到等式(3)。如果我们对(3)关于 W 求导(经过一些简化),我们得到 W 的学习方程(方程 4)。

W (我们期望的变换)正比于类内协方差矩阵的逆乘以类均值的差。

正如预期的那样,结果允许用简单的阈值进行完美的分类分离。

多类 Fisher 线性判别式

我们可以将 FLD 推广到超过 K 个类别的情况。这里,我们需要类别内和类别间协方差矩阵的推广形式。****

对于类内协方差矩阵 SW ,对于每个类,取集中输入值与其转置值之间的矩阵乘法之和。等式 5 和 6。

为了估计类间协方差 SB ,对于每个类 k=1,2,3,…,K ,取局部类均值 mk 和全局类均值m外积,然后乘以类 k 中记录的数量—等式 7。

FLD 准则的最大化通过矩阵的特征分解来解决,即 SW 的逆和 SB 之间的乘法。因此,为了找到权重向量 W ,我们取对应于其最大特征值的D’特征向量(等式 8)。

换句话说,如果我们想要将我们的数据维数从 D=784 减少到 D'=2 ,那么变换向量 W 由对应于 D'=2 最大特征值的 2 个特征向量组成。这给出了 W = (N,D’)的最终形状,其中 N 是输入记录的数量,而D’是减少的特征空间维度。

构建线性判别式

到目前为止,我们仅使用 Fisher 线性判别式作为降维方法。为了真正创建判别式,我们可以在 D 维输入向量 x 上为每个类别 K 建模一个多元高斯分布,如下所示:

这里 μ (平均值)是一个 D 维向量。σ(sigma)是一个 DxD 矩阵——协方差矩阵。并且||是协方差的行列式。行列式是协方差矩阵σ拉伸或收缩空间的程度的度量。

在 Python 中,看起来是这样的。

高斯分布的参数: μσ,使用投影输入数据为每个类别 k=1,2,3,…,K 计算。我们可以使用每个类别中训练集数据点的分数来推断先验 P(Ck) 类别概率(第 11 行)。

一旦我们有了高斯参数和先验,我们就可以单独地为每个类 k=1,2,3,…,K 计算类条件密度P()x| Ck】。为此,我们首先将 D 维输入向量 x 投影到一个新的D’空间。请记住D’<D。然后,我们对每个投影点评估等式 9。最后,我们可以利用等式 10 得到每类 k=1,2,3,…,K 的后验类概率P(Ck |x)**

等式 10 在下面的得分函数的第 8 行进行评估。

然后,我们可以将输入向量 x 分配给具有最大后验概率的类别 k

对 MNIST 进行测试

使用 MNIST 作为玩具测试数据集。如果我们选择将原始输入尺寸 D=784 减少到 D'=2 ,我们可以获得大约 56% 的测试数据精度。然而,如果我们将投影空间尺寸增加到D’= 3,我们将达到接近 74% 的精确度。这两个投影也使结果特征空间更容易可视化。**

这篇文章的一些要点。

  • Fisher 的线性判别式,本质上是一种降维的技术,而不是判别式。
  • 对于二元分类,我们可以找到一个最优阈值 t 并据此对数据进行分类。
  • 对于多类数据,我们可以(1)使用高斯分布对类条件分布建模。(2)求先验类概率P(Ck),( 3)用贝叶斯求后验类概率 p(Ck|x)**
  • 为了找到投影输入数据的最佳方向,Fisher 需要监督数据。
  • 给定一个维度为 D 的数据集,我们最多可以将它向下投影到*D’等于 D-1 维度。***

本文基于模式识别与机器学习第 4.1 章。克里斯托弗·毕晓普的书。****

感谢阅读。

用 CNN 分类图像

原文:https://towardsdatascience.com/an-image-classifier-with-deep-learning-7284af97b36a?source=collection_archive---------16-----------------------

深度学习和机器学习模型与图像分类器的比较

Photo credit: Aaron Huber

让年幼的孩子整理他们的房间通常是具有挑战性的。我坚持的是脏乱,他们会坚持的是足够干净。毕竟,所有的形容词都是主观的,我希望我的孩子在我们包容的社会中尊重他人的意见。你如何定义不同的观点?实现这种区分的客观方法是使用图像分类来区分干净的房间和脏乱的房间。

这个应用程序还可以扩展到清洁服务机构或 Airbnb,尤其是超过 10%的用户投诉与肮脏和混乱的条件有关。(参见来源)

流程

构建我的应用程序的过程包括 5 个阶段:1)网络搜集 2)数据集准备 3)模型构建 4)模型测试和 5)前端烧瓶应用程序。

1。抓取网页

没有我想要的大小的数据集,所以我不得不转向网络抓取(这就是生活!)用 google_images_download 上的关键词从 google 获取图片。

对于“干净”类别,使用了“干净的卧室”、“整洁的房间”、“酒店房间”、“干净整洁”和“整理”等词。

对于“凌乱”类别,所用的词包括“杂乱”、“混乱”和“杂乱无章的房间”。

我创建了第三个有趣的类别,以迎合我的孩子为了逃避家务而离开我的借口便条的快照。(是的,惯性实际上是从很小的时候开始的。)对于这个类别/类,我使用了像“孩子的手写笔记”、“情书”、“手写笔记”等词来抓取谷歌图片。

2。数据集准备

获得超过 3,000 张图像后,确保图像的正确性非常重要。在进入每一个类别时,我仔细查看了图片,删除了 I)冲突的图片,ii)前后对比的图片,iii)对培训没有帮助的重复图片,iv)清洁剂图片,v)卡通图片,vi)文字图片,vii)公司徽标。

这个数据集的彻底清理是必不可少的。记住这个原则:垃圾进,垃圾出。

一天下来,给我留下了 600 多张“乱”和“借口”,900 多张“干净”。

3。模型构建

从机器学习开始,我使用了 8 种不同的算法。

  1. k-最近邻
  2. 高斯朴素贝叶斯
  3. 逻辑回归
  4. 支持向量分类器
  5. 决策图表
  6. 多层感知器
  7. 随机森林
  8. XGBoost

使用 F1 分数作为所有模型的评估指标,XGBoost 以 0.76 的分数表现最佳。对于那些对技术感兴趣的人来说,我将在本文中用斜体来阐述它们。如果你只对结果感兴趣,你可以跳过它们。F1 是精确度和召回率之间的和谐平衡。I)精度是所有预测阳性(包括真阳性和假阳性)中的真阳性的比率,而 ii)召回是真阳性和假阴性中的真阳性的比率。

What is the F1 score? Widget Credit: Pavan Mirla

很想知道这是否可以以一种实质性的方式得到改善,让我们使用卷积神经网络(CNN)来探索深度学习,该网络以处理图像而闻名。

CNN Architecture. Credit: Public Library of Science Data Repository

CNN 架构由许多层组成。每一层将从每一类的训练图片中提取某些特征(例如,对比度、形状、边缘、纹理)。然后,将训练好的模型应用于看不见的图片,然后使用训练好的特征元素对这些图片进行分类。

Comparison of Models with F1 score

事实上,具有 Adam 优化器和早期停止的 CNN 模型是最好的模型,以与训练好的网络相关联的新的 0.84 F1 分数击败了 XGBoost。Adam 优化器的优越性在于其自适应的学习速率,并因其相对较少的参数调整而受到青睐。以下是我的模型代码和相关 F1 分数的分类报告。

# compile & train model
# initialize # of epochs to train for, and batch size
EPOCHS = 30
BS = 128# initialize the model and optimizer 
model.compile(loss=”categorical_crossentropy”, optimizer=’adam’,metrics=[“accuracy”])# train the network
import keras
H = model.fit_generator(aug.flow(trainX, trainY, batch_size=BS),
 validation_data=(testX, testY), steps_per_epoch=len(trainX) // BS, epochs=EPOCHS,
# inject callbacks with best weights restoration
callbacks=[
 keras.callbacks.EarlyStopping(patience=8, verbose=1, restore_best_weights=True),
 keras.callbacks.ReduceLROnPlateau(factor=.5, patience=3, verbose=1),
 ])

Training and Validation accuracy with early stopping

Training and Validation loss with early stopping

Classification Report with F1 score of 0.84

“恢复最佳重量”确保模型将检索通过历元运行获得的最佳重量。

4。模型测试

用三张看不见的图片(每个班级一张)测试模型,结果如下:

Test result on an unseen excuse note image

Test result on an unseen clean room image

Test result on an unseen messy room image

更进一步说,即使我那些有创造力的孩子有一天在一张装饰过的纸上给我写了一张纸条,或者在他们的纸条上附上了一份“礼物”,这个模型仍然可以自信地把这些归类为借口。

5。前端应用

Flask App of the classifier

结论

图像分类是图像识别的一个子集,它广泛用于安全行业(面部识别)、虚拟搜索引擎(商店中的对象查找器)、医疗保健(患者的情绪检测)以及游戏和增强现实。在某种程度上,智能手机相机使所有这些进步成为可能,因为它可以轻松地创建大量图片。这个项目演示了图像分类在我们家中的应用:)

一种使用深度学习从卫星图像生成地面实况数据的图像处理工具

原文:https://towardsdatascience.com/an-image-processing-tool-to-generate-ground-truth-data-from-satellite-images-using-deep-learning-f9fd21625f6c?source=collection_archive---------12-----------------------

卫星图像的地面实况意味着在特定位置收集信息。它使卫星图像数据与地面的真实特征和材料相关联。这一信息经常用于遥感数据的校准,并将结果与地面实况进行比较。地面实况数据通常通过访问一个地点并进行一些实验来收集,如对该特定地点进行勘测,通过在不同方面进行表面观察来测量该地点的不同属性和特征,如森林、农业、水、建筑物和其他土地类别所覆盖的区域。地面真实在图像的初始监督分类中是重要的。这些数据通常用于评估卫星图像分类的性能,将图像的每个像素与相应的地面实况数据进行比较,以找到匹配。目标是最小化分割的卫星图像和地面实况信息之间的误差。目前,有许多软件和图像处理工具可以用来对卫星图像进行分类和分割,取得了很好的效果。然而,当特定地理位置的地面实况信息不可用时,问题就出现了。

不可能收集地球上所有位置的地面实况数据。因为有些地方如丘陵地带、密林等,不容易到达。人工收集地面实况信息需要大量的人力和时间。因此,卫星图像的应用,如聚类/分割/分类,仅限于地面实况信息。因此,有必要开发一些能够从卫星图像生成地面实况数据应用程序。

在本文中,我们的目标是开发一个使用深度学习技术的自动化系统,该系统可以从卫星图像本身生成地面真实数据。它不仅减少了收集这些信息所需的时间和精力,而且还生成了手动数据收集不可能得到的地理位置数据。

数据库:由于没有与卫星图像相对应的地面实况图像,在本研究中,我们使用卫星图像和相应的谷歌地图图像来训练一个模型。这个数据集包含纽约州的卫星图像和相应的谷歌地图图像,分为训练集和测试集,分别包含 1096 和 1098 个图像样本。因此,在本实验中,我们从给定的卫星图像中生成 google map 图像作为地面真实数据。图 1 显示了一个样本卫星,它的 google map 图像用于训练模型。

Figure 1: A sample satellite and it’s ground truth (google map) image.

生成对抗网络

按照这篇文章中提出的 PixtoPix GAN 架构,我们用 1096 幅卫星图像训练我们的模型。每个图像样本都带有卫星数据和相应的谷歌地图,它们被分组到源和目标列表中。GAN 的结构由两个模块组成:鉴别器和发生器。鉴别器是执行分类的卷积神经网络模型。生成器是一个使用 U-Net 架构的编码器-解码器模型。它将源图像(卫星图像)作为输入,并生成目标图像(谷歌地图图像)作为输出。生成器模型通过将图像向下采样到某个级别来编码图像,并通过使用 U-Net 架构向上采样到图像的原始大小来解码图像。点击此处了解更多关于 GAN 的详细信息。

Figure 2: Block diagram of training of GAN

由发生器模型产生的目标图像被作为鉴别器模型的输入。鉴别器模型还获取原始地面真实图像(谷歌地图图像),并预测目标图像是真实图像还是源图像的虚假翻译的可能性。发生器和鉴别器模型的框图如图 2 所示。使用 GAN 架构,我们用 30 个历元训练模型,得到训练好的模型需要大约 24 小时。

结果

结果,我们得到了卫星图像到谷歌地图图像的过渡。该系统产生给定卫星图像、相应的谷歌地图图像和预期/生成的谷歌地图图像的输出,这些图像可以被视觉分析相似性。在测试集上评估模型时的输出示例如图 3 和图 4 所示。

Figure 3: Generated ground truth image by model

Figure 4: Generated ground truth image by model

结论和未来工作

所提出的系统将卫星图像映射到其谷歌地图上,这可以被认为是地面事实。因此,它大大减少了手动收集地面实况信息所需的时间和精力。此外,开发的模型可以很容易地生成难以收集这些信息的地理位置。

所提出的模型可以扩展到从地面真实数据生成卫星图像,这可以帮助科学家更容易地研究环境变化。模型的性能可以通过用更多的历元数进一步训练来提高。

挑战挑战
1。GAN 需要大量时间和资源来训练模型。

运行“trainModel.py”从草图训练模型。若要测试生成的模型,请运行“testDBimage.py”。它将从数据库中读取测试图像,并生成预期的地面真相。你也可以从谷歌下载随机卫星图像,并使用“test_random_image.py”进行测试

感谢杰森·布朗利的精彩教程和文章,帮助我学到了很多。大部分代码都是为了他的教程。这个项目的完整代码在我的 GitHub 库中。可以随意下载修改。谢谢你的时间。祝你愉快。😃

参考文献

[1]https://machine learning mastery . com/how-to-develop-a-pix 2 pix-gan-for-image-to-image-translation/

https://github.com/junyanz/pytorch-CycleGAN-and-pix2pix

使用人工智能(AI)进行药物发现的初创公司的交互式视觉地图

原文:https://towardsdatascience.com/an-interactive-visual-map-of-startups-that-use-artificial-intelligence-ai-for-drug-discovery-e27213298c21?source=collection_archive---------21-----------------------

find link in map section for interactive map

用于药物发现的人工智能

简介:

上次我制作了一个可视地图,显示了美国所有制药公司的位置。在地图中,它显示了一些使用人工智能(AI)的传统制药公司。有许多初创公司也在利用人工智能进行药物研发。因此,我想创建一个类似的地图,展示世界各地使用人工智能进行药物发现的初创公司是如何增长的。

数据:

我发现这篇文章的标题是“141 家创业公司在药物发现中使用人工智能”。我开始刮公司名字和网站链接。现在我有了所有的网站链接,我需要从网站上收集所有的地址。

下面是抓取姓名和地址的代码。

在调查了几个网站之后,在我看来,所有的网站都彼此大相径庭。所以我不能使用 selenium 或 beautifulsoup 从联系信息中删除完整地址。由于名单不太大,我不想放弃。我只需要 2-3 个小时来收集所有的物理地址。

我手动收集了所有的数据。我在 startup 网站上找到的大部分物理地址。对于其余的物理地址,我搜索了谷歌并收集了它们。在 141 个地址中,我设法收集了 138 个。但是很少有创业公司,我只找到了他们所在的城市,而不是完整的地址。

地图:

然后我用‘Google geocoder’python 库找到了经纬度。

最后,我使用叶库创建了地图。

这里是互动地图链接

或者,您可以在浏览器中复制并粘贴以下链接

https://bit.ly/2KExnXC

如果你点击图标,它会显示创业公司的名称和网站。

这张地图清楚地显示,美国大多数初创企业位于东西海岸。美国以外也有创业公司。

所有的代码和数据都可以在我的 github 上找到

感谢阅读。请不要犹豫,在文章下面评论。

参考资料:

史密斯,S. (2017)。141 家创业公司在药物发现中使用人工智能。检索自https://blog . bench sci . com/startups-using-artificial-intelligence-in-drug-discovery

我的 linkedin

[## Yousuf Ali -研究生研究助理-德州理工大学健康科学中心| LinkedIn

孟加拉国达卡 Narayangonj ACI 有限公司产品开发官员。

www.linkedin.com](https://www.linkedin.com/in/yousuf--ali/)

有趣且直观的 AUC 和 ROC 曲线视图

原文:https://towardsdatascience.com/an-interesting-and-intuitive-view-of-auc-5f6498d87328?source=collection_archive---------15-----------------------

在学习 AUC 之前,你不需要学习 TPR,FPR 和一堆其他的东西。

AUC,或 ROC 曲线下面积,是一种广泛用于评估模型性能的指标。

网上有一堆关于 AUC 的资源。他们通常从向读者解释真阳性、敏感性、I 型、II 型错误和 FPR 等开始。他们中的许多人都很好,他们详细解释了概念,但一些概念可能会让一些没有分析背景的人感到困惑。我想在这里指出的是,一个人实际上可以在不知道所有这些专业术语的情况下学好 AUC

让我用一个简单的例子来说明如何做。

假设一家信用卡公司建立了一个风险评分模型来评估客户是否能够按时支付账单。他们拥有的数据被标记,1 表示客户不能按时付款(有风险),0 表示那些按时付款的客户。这是 20 条记录的样本的结果(假设没有重复的分数):

让我们看看如何从这 20 条记录中画出 ROC 曲线。我们先画一个正方形,左下角为(0,0),右上角为(1,1):

然后,在这 20 个记录中,我们有 5 个 1 和 15 个 0,所以我们将 y 轴除以 5,x 轴除以 15:

然后,从高分到低分,对应的标签是 1,1,0,1,0,0,…,我们把 1 换成'上',把 0 换成'右',就会得到一个新的序列:上,上,右,上,右…然后从(0,0)开始,根据这些'上'和'右'画出你的曲线。一上(或右),一招。这是 ROC 曲线。它下面的区域是 AUC。

让我们用一个完美的模型来比较一下。在一个完美的模型中,任何“1”都将比任何“0”有更高的分数。因此,从高分到低分,相应的标签将是 1,1,1,1,0,0,0,0,…并且 ROC 将是

AUC 是 1。一些观察结果:

  • 为了提高 AUC,你需要在“正确”之前出现更多的“向上”。
  • 这意味着,“1”需要在“0”之前。
  • 这意味着,模型给予目标(标签为 1 的记录)更高的分数,因此模型更好。
  • AUC 介于 0 和 1 之间。
  • AUC 是一个排名指标(重要的是得分顺序,而不是得分值本身)。

在深入研究 ROC 的其他属性之前,我想展示几个特例。

更多示例

1.得分相等。让我们稍微改变一下前面的例子,得到相同的分数。在这一组(得分 70),我们有三个 0 和一个 1。我们要做的修改是将三个“右”和一个“上”合并成一个动作。

新的 ROC 是

因此,如果所有分数相等,ROC 将正好是 x=y (AUC = 0.5)线。

2.随机猜测。当记录以随机顺序分配时,ROC 曲线将在 x=y 附近波动,AUC 在 0.5 左右。

3.逆转比分。如果我们颠倒分数顺序和最开始的例子,我们将得到一条关于点(0.5,0.5)对称于原始 ROC 曲线的新 ROC 曲线[关于线 x=y 不对称!].新的 AUC 是 1 减去原始 AUC。这就是为什么人们说当我们有一个 AUC <0.5 的模型时,我们可以执行这个分数反转技巧来获得一个更好的模型。

现在让我们看看我们还能从 ROC 曲线中提取什么信息。

性能

  1. 割线斜率越高,标记率越高(1 的数量与一个组中记录的总数之比)。在下面的示例中,选择了两个分数组,分数高的组具有较高的标记率,因此割线斜率也较高。

2.凹度。通常,由好的 ML 算法生成的结果的 ROC 曲线在整个域中是向下凹的。但是,如果不幸的是,您有一条在子区间上向上凹的曲线,您可以在该特定区间反转分数以提高性能(并且建议您还检查建模数据)。

3.高分区域/低分区域。下面的绿色方框包含高分记录的信息,橙色方框包含低分记录的信息。在绿色区域,我们希望割线斜率较大;在橙色区域,斜率越小越好。

AUC 不是我们衡量排名模型表现的唯一方式。有时,我们只关注模型在高分区域是否表现良好。

AUC 低的模型仍然有价值。例如,下面 ROC 曲线的 AUC 只有~0.64,但是它在高分记录上有很好的表现。

4.模特合奏。当我们在同一个数据集上有多个模型,并且 roc 的形状不同(有些在高分区域很好,有些在低分区域很好)时,我们通常可以通过组合模型(打包或堆叠)来找到值。

为讨厌数学和不会编码的人介绍人工智能

原文:https://towardsdatascience.com/an-intro-to-ai-for-people-that-hate-math-and-cant-code-140aa42c9f3f?source=collection_archive---------30-----------------------

这是一个关于人工智能的高级速成班,面向经理、企业主和其他非技术角色,他们希望掌握人工智能,并开始使用它来推动他们组织的价值。这不是为计算机科学家和数学家设计的。

这分为 3 个简短的部分:

  1. 为什么人工智能对商业很重要
  2. 不同类型的人工智能及其含义
  3. 机器学习究竟是如何“学习”的

让我们开始吧。

人工智能对商业意味着什么

我们将进一步了解技术,但首先你需要理解为什么你应该关心人工智能的三大原因。

1。人工智能能看到你看不到的图案

对您的车队进行维护的最佳时间是什么时候?哪些销售线索具有最高的潜在价值?公司财务中的哪些模式可能表明欺诈?

如果你给一个人工智能程序足够多的正确数据,它会告诉你。

2。AI 不像人一样思考

人工智能可以在复杂的棋盘和视频游戏中胜过人类,做出更好的投资决策(有时),甚至可以在评估法律文件质量方面击败律师。它通过比我们更理性的思考来做到这一点,并看到我们看不到的模式。

AI 一顿丰盛的午餐也不累,没有根深蒂固的偏见,也不在乎办公室政治

人工智能驱动的建议会让你对工作的任何方面都有不同的看法。

3.AI 比你想象的更容易实现

人工智能极其复杂,该领域的突破是由在计算机科学、数学和神经科学领域拥有丰富经验的团队以及大量资金推动的。

但是,他们的大部分工作已经被合成到高级库中,比如 Python 的 Keras。你(或你团队中的人)不需要成为专家,也可以通过一些教程,编写一个基本的模式识别程序来分析数据。

这需要时间来调整它,学习如何对程序输出采取行动,并适当地组织你的数据,但你不需要为此回到大学。而且,结果将远远超过投入的时间。

好吧。如果你还在这里,你可能已经意识到了人工智能的重要性,并想了解更多。是时候让变得稍微技术性一些了。

I don’t have image rights for any of the cool sci-fi renderings of AI so we’ll just go with this photo of light bulbs. Symbolism, right?

人工智能、机器学习和深度学习

有许多人工智能的子集和机器学习的变体,但这些是你可能见过使用的一些更常见的术语。

人工智能

  • 人工智能是金字塔的基础。这是一个广义的概念,机器通过某种算法来解决问题或完成任务。
  • 这听起来可能并不特别;毕竟,每个程序不都是按照某种规则运行的吗?你说得对,但让我们所知的人工智能变得“智能”的是机器能够自己创造这些算法,并在机器学习时更新这些算法,让做出更好的决策。
  • 这就是机器学习的用武之地

机器学习

  • ML 是 AI 的子集。ML 是机器用来学习 的实际 过程,所以 AI 可以做决策。
  • 在 ML 中,我们给机器大量的数据来处理和一个目标。
  • 我们通过 ML 程序运行大量数据,它确定数据中哪些特征是重要的,而无需我们告诉它做什么。

深度学习

  • DL 是 ML 的复子集。它可以将数据分成不同的类别,而无需被告知数据代表什么
  • DL 使用多层人工神经元来尝试和复制人脑的复杂性。从技术上讲,当一个网络有三层以上时,它就是“深”的(我们将在下面讨论)。
  • DL 馈入 ML,ML 馈入总体 AI

深度学习示例:

我们想要一个程序,它能告诉我们一张照片是否包含一只猫。我们会给程序提供大量的照片,并给每张照片贴上“猫”或“不是猫”的标签。

这台机器一开始会非常不准确,基本上是猜测图片中是否包含一只猫。但随着时间的推移,它会在每张标记为“猫”的照片中挑出关键特征,并将其与“非猫”照片中的特征进行比较。

在英语中,机器通过思考来“学习”,“照片中有一个白色的斑点,在它的脸中间有一个粉红色的斑点(猫的鼻子)。标有“不是猫”的照片没有那个粉红色的斑点。我要开始寻找粉红色的斑点。”

这是程序添加到算法中的一个“特征”的例子。

有了足够的照片和训练时间,它会挑出越来越多的特征。该程序将使用这些特征来确定一只猫的样子,并相当准确地决定一张照片是否包含一只猫。

AI 是如何学习的?

最后,我们将讨论机器实际上是如何学习的。我在上面提到了它,但我将在这里得到更多的颗粒。

当你创建一个机器学习程序时,你建立了一个神经网络,它应该粗略地模仿人脑中放电神经元的结构。

Source: Chrislb, Wikimedia Commons

输入是您的数据点,隐藏层是进行计算的地方,输出是最终结果:根据编程的方式,这可能是分类、建议或概率。

每个圆称为一个节点,每个垂直堆叠的节点称为一个层。这是一个浅层网络,因为它只有 3 层。但通过增加更多的隐藏层(输入和输出之间的层),网络变得“更深”,更复杂,理想情况下更准确。

上面没有显示的是每个节点的权重。节点的权重告诉网络该节点有多“重要”。每个节点被分配一个 0 到 1 之间的数字(层中节点的权重加起来为 1)。

通过对每个节点进行加权,程序决定寻找什么来做出最佳决策。在前面的例子中,它可以为“粉色斑点”分配一个高权重,以决定某个物体是否是猫。它会给“棕色头发”分配一个较低的权重,因为人类和猫可以有棕色头发。

节点的输出乘以权重,结果用于做出决策。对机器来说,低重量=低重要性。

当程序开始运行时,这些权重完全是随机的,系统很可能会非常不准确。随着你运行程序的次数越来越多,信息的流向就会发生逆转。如果你有任何错误(错过的预测),程序将改变每个节点的权重,从而改变某些特征的“重要性”。

它会一直这样做,直到程序能够达到某个较高的精确度。

包扎

你成功了!希望你现在可以离开,理解人工智能如何做决定,以及为什么它对你的业务很重要。如果您想开始实现它,请开始搜索代码示例!很有可能有人已经发布了满足您需求的开源代码。

如果这对你有帮助,并且你认为其他人也能从中获益,请快速分享。

Tensorflow 中的高级 Keras API 简介

原文:https://towardsdatascience.com/an-intro-to-high-level-keras-api-in-tensorflow-c50f6f5272de?source=collection_archive---------15-----------------------

Tensorflow 是深度学习模型生产中使用的最著名的库。它有一个非常大的令人敬畏的社区,并且在操作上有很大的灵活性。然而,Tensorflow 并不是那么用户友好,并且具有更陡峭的学习曲线。为了解决这个问题,Tensorflow 的高级 Keras API 提供了构建模块,可以更轻松地创建和训练深度学习模型。此外,Keras 模型是通过将可配置的构建模块连接在一起而形成的,几乎没有限制。这使得它更加模块化和可组合。你可以在他们的官方网站上探索。

分类

要使用高级 Keras API 进行简单分类,需要遵循的一些步骤如下:

  1. 导入所需的模块。
  2. 为 API 准备合适的数据格式。
  3. 使用 TF . Keras(tensor flow-Keras)API 构建神经网络模型并编译它。
  4. 用准备好的数据训练模型,同时尝试解决欠拟合和过拟合情况。
  5. 评估模型。
  6. 保存和恢复模型,以便在生产中使用。

导入所需的模块。

首先,需要进口 numpy 和 pandas,因为数据处理和准备需要它们。必须导入 Tensorflow API 和高层 Keras API 进行底层操作和建模。必须导入 Matplotlib 进行性能和精度等的图形分析。

*# TensorFlow and tf.keras*
**import** **tensorflow** **as** **tf**
**from** **tensorflow** **import keras**
**import** **numpy** **as** **np
import pandas as pd
import** **matplotlib.pyplot** **as** **plt
%matplotlib inline** ''' 
%matplotlib inline means with this backend, the output of plotting commands is displayed inline within frontends like the Jupyter notebook, directly below the code cell that produced it. The resulting plots will then also be stored in the notebook document.
'''

数据准备

数据准备阶段获取原始数据,使其看起来结构化,从中去除噪声,并更改数据格式和形状以适合您正在设计的模型。数据可以是不同的格式,如图像数据不同于文本数据,两者都需要不同的处理和预处理。例如,如果我们使用 mnist_fashion 数据来制作一个分类器来对服装进行分类,数据准备可以如下进行:

MNIST 时尚数据集包含 10 个类别的 70,000 幅灰度图像。这些图像以低分辨率(28×28 像素)显示了单件衣服。链接:【https://github.com/zalandoresearch/fashion-mnist

我们将使用 60,000 张图像来训练网络,并使用 10,000 张图像来评估网络学习分类图像的准确性。

加载这些数据的 Tensorflow API 显示了一些 gzip 错误。这里遵循的方法是,从 https://github.com/zalandoresearch/fashion-mnist下载原始数据集,然后按照https://pjreddie.com/projects/mnist-in-csv/将数据集转换成 CSV 格式。

**class_names = ['T-shirt/top', 'Trouser', 'Pullover', 'Dress', 'Coat', 
               'Sandal', 'Shirt', 'Sneaker', 'Bag', 'Ankle boot']****import pandas as pd
train_df = pd.read_csv('data/fashion-mnist_train.csv',sep=',')
test_df = pd.read_csv('data/fashion-mnist_test.csv', sep = ',')
train_df.head()** ''' 
we need to convert the dataframes into numpy arrays of float32 type which is the acceptable form for tensorflow and keras. 
'''
**train_data = np.array(train_df, dtype = 'float32')
test_data = np.array(test_df, dtype = 'float32')** '''
We scale the pixel values to a range of 0 to 1 before feeding to the neural network model. (presently they are from 0-255)
'''
**x_train = train_data[:,1:]/255****y_train = train_data[:,0]****x_test= test_data[:,1:]/255****y_test=test_data[:,0]**

建立神经网络模型

神经网络的基本构造块是层。图层从提供给它们的数据中提取表示。例如:

**model = keras.Sequential([
    keras.layers.Flatten(input_shape=(784,)),
    keras.layers.Dense(128, activation=tf.nn.relu),
    keras.layers.Dense(10, activation=tf.nn.softmax)
])**

该网络由一系列两层致密层组成。这些是密集连接,或完全连接的神经层。

第一密集层有 128 个节点(或神经元)。

第二层(也是最后一层)是一个 10 节点的 softmax 层,它返回一个由 10 个概率得分组成的数组,这些得分的总和为 1。每个节点包含一个分数,该分数指示当前图像属于 10 个类别之一的概率。

在模型为训练做好准备之前,它还需要一些设置。这些是在模型的编译步骤中添加的:

损失函数:衡量模型在训练过程中的精确程度。我们希望最小化这个函数,以便将模型“导向”正确的方向。

优化器:这就是模型如何根据它看到的数据和它的损失函数进行更新。

指标:用于监控培训和测试步骤。下面的例子使用了准确度,即图像被正确分类的比例。

**'''** When doing multi-class classification, categorical cross entropy loss and sparse categorical cross entropy is used a lot**.** To compare them both read [https://jovianlin.io/cat-crossentropy-vs-sparse-cat-crossentropy/](https://jovianlin.io/cat-crossentropy-vs-sparse-cat-crossentropy/)
**'''
model.compile(optimizer=tf.train.AdamOptimizer(), 
              loss='sparse_categorical_crossentropy',
              metrics=['accuracy'])**

训练模型

训练神经网络模型需要以下步骤:

  1. 将训练数据提供给模型,在本例中是 train_images 和 train_labels 数组。
  2. 模型学习将图像和标签联系起来。
  3. 我们要求模型对测试集进行预测。在本例中,是 test_images 数组。我们验证预测是否与 test_labels 数组中的标签相匹配。
**model.fit(x_train, y_train, epochs=10)
test_loss, test_acc = model.evaluate(x_test, y_test)****print('Test accuracy:', test_acc)
print('Test loss:', test_loss)****10000/10000 [==============================] - 1s 52us/step
Test accuracy: 0.8963
Test loss: 0.3374745888918638**

训练模型时的一个主要问题是过度拟合和欠拟合。通过充分的训练可以避免不合身。为了避免过度拟合,两种解决方案可以是"添加权重正则化""添加丢弃"。

添加权重调整

减轻过度拟合的一种常见方法是通过强制网络权重仅取小值来限制网络的复杂性,这使得权重值的分布更加“规则”。这被称为“权重正则化”,这是通过向网络的损失函数添加与具有大权重相关联的成本来实现的。这种成本有两种形式:

L1 正则化,其中增加的成本与权重系数的绝对值成比例(即,与所谓的权重的“L1 范数”成比例)。

L2 正则化,其中增加的成本与权重系数的值的平方成比例(即,与所谓的权重的“L2 范数”成比例)。在神经网络的上下文中,L2 正则化也称为权重衰减。不要让不同的名称迷惑你:权重衰减在数学上与 L2 正则化完全相同。

唯一需要改变的是模型架构:

**l2_model = keras.models.Sequential([
    keras.layers.Dense(16, kernel_regularizer=keras.regularizers.l2(0.001),
                       activation=tf.nn.relu, input_shape=(NUM_WORDS,)),
    keras.layers.Dense(16, kernel_regularizer=keras.regularizers.l2(0.001),
                       activation=tf.nn.relu),
    keras.layers.Dense(1, activation=tf.nn.sigmoid)
])**

添加辍学

Dropout 是神经网络最有效和最常用的正则化技术之一,由 Hinton 和他在多伦多大学的学生开发。

应用于一个层的丢弃包括在训练期间随机“丢弃”(即设置为零)该层的一些输出特征。假设在训练期间,给定的层通常会返回给定输入样本的向量[0.2,0.5,1.3,0.8,1.1];在应用丢弃后,该向量将具有随机分布的几个零条目,例如[0,0.5,1.3,0,1.1]。

“丢失率”是被归零的特征的分数;通常设置在 0.2 到 0.5 之间。在测试时,没有单元被丢弃,相反,层的输出值会按与丢弃率相等的因子按比例缩小,以平衡比训练时更多的单元处于活动状态这一事实。

这里,唯一需要改变的是模型架构。

**dpt_model = keras.models.Sequential([
    keras.layers.Dense(16, activation=tf.nn.relu, input_shape=(NUM_WORDS,)),
    keras.layers.Dropout(0.5),
    keras.layers.Dense(16, activation=tf.nn.relu),
    keras.layers.Dropout(0.5),
    keras.layers.Dense(1, activation=tf.nn.sigmoid)
])**

模型评估

有许多度量来评估分类、回归、聚类等。这里我们将用准确度来衡量分类。(精度、召回率、F-measure 和准确度是分类器性能测量的主要使用指标)。

**test_loss, test_acc = model.evaluate(x_test, y_test)****print('Test accuracy:', test_acc)
print('Test loss:', test_loss)****10000/10000 [==============================] - 1s 52us/step
Test accuracy: 0.8963
Test loss: 0.3374745888918638**

我们还可以看到当模型被训练时,指标是如何变化的。为此,需要保存模型历史,并绘制图表来显示训练进行的趋势。

**history = model.fit(train_data, train_labels,
                    epochs=50,
                    batch_size=512,
                    validation_split=0.2)****acc = history.history['acc']
val_acc = history.history['val_acc']
loss = history.history['loss']
val_loss = history.history['val_loss']****epochs = range(1, len(acc) + 1)****plt.plot(epochs, acc, 'bo', label='Training Acc')
plt.plot(epochs, val_acc, 'b', label='Validation Acc')
plt.title('Training and validation Acc')
plt.xlabel('Epochs')
plt.ylabel('Acc')
plt.legend()****plt.show()**

模型保存和恢复

可以使用 tf.keras.Model API 在 Tensorflow 中保存和恢复模型。

**model.compile(optimizer=tf.train.AdamOptimizer(), 
              loss='sparse_categorical_crossentropy',
              metrics=['accuracy'])** # Save weights to a TensorFlow Checkpoint file
**model.save_weights('./weights/my_model')**
# Restore the model's state,
# this requires a model with the same architecture.
**model.load_weights('./weights/my_model')**'''It also can be saved in keras HDF5 format'''
# Save weights to a HDF5 file
**model.save_weights('my_model.h5', save_format='h5')**# Restore the model's state
**model.load_weights('my_model.h5')****#The model arch can also be saved to a json file**# Serialize a model to JSON format
**json_string = model.to_json()
json_string** #Then it can be restored like below
**latest_model = tf.keras.models.model_from_json(json_string)**

还可以为动态模型保存创建检查点,以便操作不会因训练时的一些中间错误而丢失。

您可以在我的 git hub repo 上了解更多信息。

[## sambit9238/Tensorflow_Guide

通过在 GitHub 上创建帐户,为 sambit9238/Tensorflow_Guide 开发做出贡献。

github.com](https://github.com/sambit9238/Tensorflow_Guide)

内核介绍

原文:https://towardsdatascience.com/an-intro-to-kernels-9ff6c6a6a8dc?source=collection_archive---------9-----------------------

Mathematical tricks

内核是神奇的。

不完全是,但是他们看起来很喜欢。它们是一种数学“技巧”,允许我们不需要对数据进行技术转换就可以更快地进行某些计算。在机器学习中,它们在分类模型中用于将我们的数据分成组。对相似数据进行分组的最简单的方法是用直线,但这并不总是可行的。有时,我们的数据是以这样一种方式组织的,用一条直线将它们分开是不可能的。

那么当我们有不可线性分离的数据时,我们能做什么呢?一个解决方案是投影我们的数据。这可以通过为我们的数据创建一个新的维度(或特征)来实现,这样我们的数据可以变得更加独立。

将我们的数据映射到一个更高维的空间是通过一个我们称之为 phi (𝜙).)的函数来完成的

将数据映射到更高维度空间的问题在于,它在计算上可能是昂贵的。映射函数𝜙必须应用于每个数据点,然后我们仍然必须使用包含的新功能对数据进行计算。当处理大量数据和添加许多新功能时,计算成本会呈指数级增长。

对我们来说幸运的是,内核的出现扭转了局面。由于我们只需要数据点的内积来计算支持向量机的决策障碍,这是一种常见的分类模型,因此内核允许我们跳过将数据映射到更高维空间的过程,直接计算内积。数学上,核函数的定义是:

Definition of a kernel

其中 xy 是独立的数据点,𝜙是将我们的数据映射到更高维空间的东西,两端的尖括号意味着你取整个语句的内积。

为了被认为是内核,函数必须满足一些要求。

  • 函数需要是连续的,这意味着在其定义域中不能有任何缺失点
  • 它必须是对称的,这意味着 K(x,y) = K(y,x)
  • 它具有正半定性。这意味着核是具有非负特征值的对称矩阵。

有几十种核用于各种不同的问题,所以让我们来看看机器学习中最常见的三种核,线性核、多项式核和径向基函数核。

线性核

也称为“非内核”,线性内核是所有内核中最简单的。从技术上讲,当使用这个内核时,数据不会被投影到更高的维度上,所以它只是带有可选常数项 cxy 的内积。

Linear kernel equation

线性核的好处是它非常简单,只有常数项 c 作为参数。线性核通常用于具有大量特征的数据集,因为增加这些数据集的维度并不一定提高可分性。文本分类就是这类数据集的典型例子。

多项式核

与线性核不同,多项式核确实涉及到从更高维度空间取内积。多项式核可以表示为

Polynomial kernel equation

其中三个参数是𝛼、 cd 。最常用的度数( d )是 2,因为更大的度数会导致过度拟合。多项式核通常用于自然语言处理问题。

让我们看一个例子。让我们设定𝛼=1, c =1/2, d=2,使这个例子成为二次型。

正如我们所见,这个内核相当于𝜙(x)**【𝜙】(y)*的内积,其中𝜙函数的每个元素都表示变量的不同幂。如果我们使用𝜙函数,我们将需要评估六个特征( x,x,1/2,y,y,1/2 )。内核省去了我们创建四个新特性的麻烦,只留给我们评估 xy.*

径向基函数核

径向基函数(RBF)核是支持向量机中最常用的核。它被定义为

Radial basis function kernel equation

其中,𝛾是一个自由参数,用于衡量两点之间的相互影响程度。与着眼于额外维度的多项式核不同,RBF 扩展到无限多个维度。这是由于指数的膨胀。为了使人信服,让我们设定𝛾 = 1/2 并扩展指数。

从这里, exp(x,y) 可以使用泰勒级数近似展开成无限维。这看起来像

这意味着两个向量的点积可以表示为

所以我们可以看到,一个 RBF 核等价于两个数据点的内积,这两个数据点有无限多个维度。我们现在可以明白为什么 RBF 如此受欢迎了。

我希望这篇博客能帮助你更好地理解内核。如果你还有问题,我推荐这篇论文和以下来源:

* [## 核方法

在机器学习中,核方法是一类用于模式分析的算法,其最著名的成员是核方法

en.wikipedia.org](https://en.wikipedia.org/wiki/Kernel_method)*

Apache、PySpark 和 Dataframe 转换简介

原文:https://towardsdatascience.com/an-introduction-to-apache-pyspark-and-dataframe-transformations-2a6d4229f0e3?source=collection_archive---------5-----------------------

掌握大数据分析的全面指南

Picture from Unsplash

简介:大数据问题

Apache 是作为数据分析的新引擎和编程模型出现的。它的起源可以追溯到 2009 年,它在最近几年变得如此重要的主要原因是由于经济因素的变化,这些因素强调了计算机应用程序和硬件。

从历史上看,计算机的能力只会随着时间的推移而增长。每年,新的处理器都能够更快地执行操作,运行在其上的应用程序也自动变得更快。

所有这一切在 2005 年发生了变化,当时散热的限制导致从提高单个处理器的速度转向探索 CPU 内核的并行化。这意味着应用程序和运行它们的代码也必须改变。所有这些都为 Apache Spark 等新模型奠定了基础。

此外,传感器和存储单元的成本仅在过去几年有所下降。如今收集和储存大量信息是完全不可能的。

有如此多的数据可用,处理和分析数据的方式也必须彻底改变,通过在计算机集群上进行大规模并行计算。这些集群能够同时协同组合这些计算机的能力,并使处理数据处理等昂贵的计算任务变得更加容易。

这就是 Apache Spark 发挥作用的地方。

什么是 Apache Spark

如伟大的著作《火花——权威指南》所述:

“Apache Spark 是一个统一的计算引擎和一组用于在计算机集群上进行并行数据处理的库”

如今,Apache Spark 是最流行的大数据处理开源引擎。主要原因是:

  • 它支持广泛使用的编程语言,如:Python、Scala、Java 和 r。
  • 它支持 SQL 任务。
  • 它支持数据流。
  • 它有机器学习和深度学习的库。
  • 它可以在单台机器上运行,也可以在一群计算机上运行。

下面是一个示意图,展示了 Spark 生态系统中可用的不同库。

Figure by the Author

如何设置和运行 Apache Spark

在这一系列文章中,我们将重点关注 Apache Spark Python 的库 PySpark。如前所述,Spark 既可以在本地运行,也可以在计算机集群中运行。有几种方法可以配置我们的机器在本地运行 Spark,但是不在本文的讨论范围之内。

使用 PsyPark 并释放其 inmense 处理能力的最简单、最快速的方法之一是使用免费网站 Databricks,具体来说就是使用它的社区版。

要开始,我们只需访问:

[## 尝试数据块

无限集群,可扩展至任何规模的作业调度程序,为生产管道执行作业完全交互式…

databricks.com](https://databricks.com/try-databricks)

并选择其社区版:

然后,我们必须创造和说明。

运行临时集群

一旦我们创建了一个帐户,为了能够开始工作,我们应该创建一个临时集群。

由于是免费版本,这些集群的默认内存为 6 Gb,每个集群可以运行 6 个小时。为了开发工业项目或使用数据管道,建议使用 premiun 平台。

但是对于这些教程来说,社区版已经足够了。

添加数据

为了添加要使用的数据:

  • 单击数据选项卡
  • 然后添加数据

您可以使用其他用户上传的可用数据,也可以使用从您的计算机上传的数据。

完成后,我们可以在笔记本中创建一个表格,这样我们就都设置好了!

Pyspark 应用和分区

为了理解 Apache Spark 如何工作,我们应该讨论 Spark 应用程序的核心组件:驱动程序、执行器和集群管理器。

下面是一个 Spark 应用程序架构的示意图:

Figure by the Author

驾驶员

该驱动程序位于计算机集群的一个节点中,并执行三个主要任务:

  1. 保存关于 Spark 应用程序的信息
  2. 响应输入,例如用户的程序
  3. 分析、分配和安排执行者要完成的任务。

实施者

执行者是实际执行驱动程序分配的工作的人。他们做两件事:

  1. 执行分配给他们的代码。
  2. 向驱动程序报告计算的状态。

集群管理器

集群管理器负责:

  1. 控制物理计算机
  2. 将资源分配给 Spark 应用

可以有几个 Spark 应用程序同时在同一个集群上运行,所有这些应用程序都将由集群管理器管理。

PySpark 数据帧

Apache Spark 使用几个数据抽象,每个抽象都有一个特定的接口。最常见的抽象是:

  • 数据集
  • 数据帧
  • SQL 表
  • 弹性分布式数据集

在本系列中,我们将重点关注在 Apache Spark 中表示和存储数据的最常见的单元 Dataframes。

数据帧是具有行和列的数据表,理解它们最接近的类比是具有带标签的列的电子表格。

数据帧的一个重要特征是它们的模式。数据帧的模式是一个列表,其中包含列名和每列存储的数据类型。

数据帧的其他相关属性是它们不位于一台简单的计算机中,事实上它们可以被分割到数百台机器中。这是因为优化了信息处理,并且当数据太大而不适合单台机器时。

Apache 分区

如前所述,执行器执行驱动程序分配的工作,并且它们以并行方式执行,为了能够做到这一点,将数据火花分割到不同的分区。

这些分区是位于群集内单台计算机中的行的集合。当我们谈论 Dataframe 的分区时,我们谈论的是数据如何分布在我们集群上的所有机器上。

大多数情况下,我们不会明确指定如何在集群中进行分区,但通过我们的代码,我们将传输数据的高级转换,Spark 将自行意识到哪种方式是执行这些分区的最佳方式。总是寻求获得最大的处理效率。

执行这些操作的低级 API 超出了本系列的范围。

数据框架转换

首先,我们必须明白,转换是我们指定对数据帧进行的修改。

这些转换是以一种高级的方式指定的,并且直到我们明确地调用一个动作时才会被执行。

这种工作方式叫懒评,目的是提高效率。当我们要求进行转换时,Spark 会设计一个计划来优化执行这些任务,直到最后一分钟我们要求一个动作(如。显示()或。收集())

苹果股价

现在,我们将探讨一些最常见的操作和转换。我们将从 2010 年到 2016 年研究苹果股价的数据。我们将执行一些探索性的数据分析、数据转换、处理缺失值并执行分组和聚合。

导入数据框架

要初始化和显示数据帧,代码如下:

**# File location and type**
file_location = "/FileStore/tables/appl_stock.csv"
file_type = "csv"# CSV options
infer_schema = "true"
first_row_is_header = "true"
delimiter = ","**# The applied options are for CSV files. For other file types, these will be ignored.**
df = spark.read.format(file_type) \
  .option("inferSchema", infer_schema) \
  .option("header", first_row_is_header) \
  .option("sep", delimiter) \
  .load(file_location)**# Display Dataframe**
display(df)

获取数据框架的模式

数据帧的模式是数据结构的描述,它是 StructField 对象的集合,并提供关于数据帧中数据类型的信息。

显示数据帧的模式非常简单:

**# Display Dataframe's Schema** df.printSchema()

执行过滤和转换

为了过滤我们的数据,只获取那些收盘价低于$500 的行,我们可以运行下面一行代码:

**# Filter data usign pyspark**
df.filter(" Close < 500").show())

我们还可以过滤以仅获取某些列:

**# Filter data by columns**
df.filter("Close < 500").select(['Open', 'Close']).show()

要按一列过滤并显示另一列,我们将使用。选择()方法。

**# Filter by one column and show other**
df.filter(df['Close'] < 500).select('Volume').show()

要按多个条件过滤:

**# Filter by multiple conditions: closing price < $200 and opening price > $200**
df.filter( (df['Close'] < 200) & (df['Open'] > 200) ).show()

获取数据的统计汇总

与 Pandas 等其他库类似,我们可以通过简单地运行。describe()方法。

**# Display Statistic Summary**
df.describe().show()

添加和重命名列

要向 dataframe 添加新列,我们将使用。withColumn()方法如下。

**# Display Dataframe with new column**
df.withColumn('Doubled Adj Close', df['Adj Close']*2).select('Adj Close', 'Doubled Adj Close').show()

要重命名现有的列,我们将使用。withColumnRenamed()方法。

**# Display Dataframe with renamed column**
df.withColumnRenamed('Adj Close', 'Adjusted Close Price').show()

分组和聚合数据

现在,我们将对我们的数据进行一些整理和汇总,以获得有意义的见解。但是首先,我们应该导入一些库

**# Import relevant libraries**
from pyspark.sql.functions import dayofmonth,hour,dayofyear,weekofyear,month,year,format_number,date_format,mean, date_format, datediff, to_date, lit

现在,让我们创建一个新列,每行包含年份:

**# To know th average closing price per year**
new_df = df.withColumn('Year', year(df['Date']))
new_df.show()

现在,让我们按最近创建的“年度”列进行分组,并按每年的最高、最低和平均价格进行聚合,以获得对价格状态和演变的有意义的见解。

**# Group and aggregate data**
new_df.groupBy('Year').agg(f.max('Close').alias('Max Close'), f.min('Close').alias('Min Close'), f.mean('Close').alias('Average Close')).orderBy('Year').show()

我们已经实现了我们的目标!然而,我们仍然有一些非常难读的数据。事实上,我们有比我们需要的更多的小数。

考虑到我们正在处理数百美元的价格,超过两位小数并不能为我们提供相关信息。

因此,让我们利用这一优势,学习如何格式化结果,以显示我们想要的小数位数。

格式化我们的数据

为了格式化我们的数据,我们将使用 format_number()函数,如下所示:

**# Import relevant functions**
from pyspark.sql.functions import forman_number, col**# Select the appropiate columns to format** cols **=** ['Max Close', 'Min Close', 'Average Close']**# Format the columns** formatted_df = new_df.select('Year', *[format_number(col(col_name), 2).name(col_name) for col_name in cols])

用户定义的函数

现在让我们学习如何将我们定义的函数应用到我们的数据帧中。我们将在本例中使用它来获取一个列,其中记录了每行的月份。

**# Import relevant functions**
from pyspark.sql.functions import date_format, datediff, to_date, lit, UserDefinedFunction, month
from pyspark.sql.types import StringType
from pyspark.sql import functions as F**# Create month list** month_lst = ['January', 'Feburary', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']**# Define the function** udf = UserDefinedFunction(lambda x: month_lst[int(x%12) - 1], StringType())**# Add column to df with the number of the month of the year** df = df.withColumn('moy_number', month(df.Date))**# Apply function and generate a column with the name of the month of the year** df = df.withColumn('moy_name', udf("moy_number"))

成功!

结论

在本文中,我们讨论了:

  • Apache Spark 的基础
  • 我们对它的重要性和运作方式有了直觉
  • 使用 PySpark 和 Dataframes 执行分析操作

在接下来的文章中,我们将学习如何在 PySpark 中应用机器学习,并将这些知识应用到一些项目中。敬请期待!

最后的话

如果你喜欢这篇文章,那么你可以看看我关于数据科学和机器学习的其他文章 这里

如果你想了解更多关于机器学习、数据科学和人工智能的知识 请在 Medium 上关注我,敬请关注我的下一篇帖子!

注意力入门

原文:https://towardsdatascience.com/an-introduction-to-attention-transformers-and-bert-part-1-da0e838c7cda?source=collection_archive---------1-----------------------

为什么和什么

我们最大的困惑来源是七足动物的“书写”它看起来根本不像是在写作;它看起来更像是一堆复杂的图形设计。这些语标没有排成一排,或者一个螺旋,或者任何线性的样式。相反,Flapper 或 Raspberry 会根据需要将尽可能多的徽标粘在一起,形成一个巨大的聚合体,从而写出一个句子。

姜峯楠的中篇小说《你生命的故事》中的这几行也许能很好地说明基于注意力的架构与普通 RNNs 的顺序性质有何不同。

让我们快速地看一下普通的 RNNs 和用于任务排序的编码器-解码器变体,了解这些设计有什么缺点,并看看注意力机制如何解决它们。

Fig 1: Vanilla RNN example

一个普通 RNN 的基本前提是一个接一个地解析输入序列中的每一项,并在每一步中不断更新它的“隐藏状态”向量,如图 1图 1 所示。每一步末尾的这个隐藏向量被理解为表示所有先前输入的上下文。换句话说,最后一个隐藏状态表示整个序列的上下文。

在序列到序列的翻译任务中,这个代表上下文的产生隐藏状态的 RNN 被认为是一个编码器,最终的隐藏状态向量,在图 2 的中被称为“上下文”,被馈入另一个称为解码器的序列产生 RNN。

但是,这种连续的处理本质是重要的还是让我们处于劣势?有些语言的词序并不重要,比如波兰语和匈牙利语。或者甚至在英语中,我们可以根据我们想要强调的内容改变词序。有时甚至在实际应用中,比如在诊断预测模型中处理患者的病史时,事件间的关系甚至比实际事件序列本身更重要。

直观地说,这种严格的处理顺序可能类似于平面二维图像,即从矩阵转换为矢量,并使用普通的前馈网络来处理它。与在矩阵表示中保持自然空间关系的 CNN 架构相比,它的效率要低得多(当然,与在图像中不同,我们不知道是否存在正确的顺序或者该顺序是什么。原来如此!).这种严格的顺序性处理也许是 的第一个缺点

Fig 2: RNNs in Seq to Seq Encoder Decoder model

这就是 LSTMs 和 GRUs 通过各种细胞水平的创新(如遗忘门、重置门、更新门等)提供仅携带相关信息从一个步骤到下一个步骤的方法的巨大帮助。双向 RNNs 提供了一种机制,不仅可以查看先前的输入,还可以查看随后的输入,然后在某个时间步长生成输出。这样的发展解决了“严格顺序”的问题,但是并没有完全解决下一个挑战。

输入序列长度(即 NLP 中的句子长度)越长,隐藏向量捕获上下文就越困难(由 Cho 等人在此提出的解释性假设,可以在 Koehn 和 Knowles 在此的论文中找到性能下降的实验证明)。这个缺点直觉上是有道理的;对同一向量进行的更新越多,早期输入和更新丢失的可能性就越大(如图 3 所示)。

Fig 3: Context becomes weak with longer sentences

我们如何解决这个问题?也许如果我们不再使用最后一个隐藏状态作为整个句子的代理,而是建立一个消耗所有隐藏状态的架构,那么我们就不必处理弱化的上下文。这就是“注意力”机制的作用。Bahdanau 等人在这篇论文中介绍了这一点。

Fig 4: Using all hidden states, not just the last one

在提出的模型中,每个生成的输出字不仅仅是最终隐藏状态的函数,而是所有隐藏状态的函数。而且,这不仅仅是一个简单的合并所有隐藏状态的操作——如果是的话,那么我们仍然给每个输出步骤相同的上下文,所以它必须是不同的!它不是简单的连接或点积,而是“注意”操作,对于每个解码器输出步骤,产生代表所有编码器隐藏状态的不同向量,但是对不同的编码器隐藏状态给予不同的权重。

Fig 5: From paper by Bahdanau et al.

输出步骤的不同上下文向量是注意力权重和所有输入隐藏状态的和积。每个单一输出的注意力权重将是不同的,因此加权隐藏向量的总和对于每个输出步骤是不同的。

Fig 6: Based on paper by Bahdanau et al.

请记住,“关注”的精神更多的是关注每个输出步骤的各种输入的能力,而不是关注其他方面,如使用的对齐函数、所涉及的 RNN 的性质等。因此,您可能会遇到上述内容的其他变体。

就这一点而言,虽然这种解决方案似乎解决了单个上下文向量的问题,但它使模型变得非常大。当您试图为每个输出步骤准备一个单独的上下文向量时,会涉及到大量的计算。

此外,还有另外一个问题,这个问题的计算复杂度没有被这个解决方案引入,但是甚至在基本的 RNN 中也存在。给定操作的顺序性质,如果输入序列的长度为“n”,则需要“n”个顺序操作来达到最终的隐藏状态(即计算 h1、h2 等,直到 hn)。我们不能并行执行这些操作,因为 h1 是计算 h2 的先决条件。序列中并行性的缺乏也不能通过在训练批次中添加更多样本来弥补,因为加载和优化不同样本的权重会增加内存需求,这将限制批次中可以使用的样本数量。**

解决其中一些问题需要我们看看注意力的一些其他变体,随后它将引导我们探索变压器模型。我打算在另一篇文章中写这些,希望很快。

自动驾驶汽车介绍

原文:https://towardsdatascience.com/an-introduction-to-autonomous-vehicles-91d61ff81a40?source=collection_archive---------9-----------------------

对自动驾驶汽车的大致了解。

Lyft’s self-driving car [Source]

每年,T2 大约有 125 万人死于交通事故。这相当于每天 3287 人死亡!作为一个刚刚学会开车的青少年,这是一个萦绕在我脑海深处的可怕事实。除此之外,我们还不得不忍受数量惊人的交通,这对大多数人来说只是制造了不必要的挫折。

这让我开始思考……有没有另一种方法可以复制人类的驾驶,但要比人类好 20 倍?

这是我发现自动驾驶汽车的地方。

自动驾驶汽车是如何工作的?

对于自动驾驶汽车(SDC),目标是能够像人类司机一样驾驶汽车。唯一的问题是座位后面没有司机。

Caption this on a highway with no driver! [Source]

听起来很吓人,对吧?

你可能想知道,在做如此复杂的事情时,计算机(或者在这种情况下,汽车)是如何接近人类智能的?要回答这个问题,我们需要了解构成 SDC 的五个组成部分:

  1. 计算机视觉
  2. 传感器融合
  3. 本地化
  4. 路径规划
  5. 控制

如果你不懂那些术语,不要担心!目前,解决这个问题的一个好方法是把 SDC 想象成人类。

计算机视觉

像人类司机一样,我们需要能够看到我们周围的环境,无论是看前方的交通还是阅读路标,视觉都是🔑。

同样,计算机视觉是汽车如何看到它的环境

在 SDC 的计算机视觉中,目标是能够识别汽车附近的物体。我们通过使用一种叫做(卷积神经网络)的图像分类网络来做到这一点。

SDC being able to identify cars in front of them. [Source]

传感器融合

让我们回过头来想想一个人类司机。

假设司机被困在拥挤的交通中。司机通过分析环境知道这一点。

这相当于传感器融合的思想:能够以详细的方式理解环境。因为一辆 SDC 上装备了一堆传感器,我们可以获取所有必要的数据并融合它们来为我们的汽车提供更丰富的图表,因此得名传感器融合

Generating a detailed environment using LiDAR [Source]

本地化

酷酷。这就是我们目前对 SDC 的了解:

  • 它能看见
  • 它知道它的环境

但是,难道你不认为确切知道你在哪里也很重要吗?就像如果你知道 Chick-fil-a 就在街区附近,那不是很有用吗?在 SDC,我们希望能够找出我们的车在现实世界中的位置,这样我们就可以更好地决定如何从 A 点到达 b 点

这就是事情变得复杂的地方,需要复杂的数学算法。现在,只要把定位想象成你手机上的 GPS。

路径规划

很好,现在我们更新后的列表如下所示:

  • 它能看见
  • 它知道它的环境
  • 它知道自己的位置

下一步是计划旅程。以我们的人类司机为例。在整个乘车过程中,司机可能在考虑要避开的特定街道和预计到达时间。这也正是 SDC 人所做的。

它不断地问,“我怎样才能以可能的最佳方式从 A 点到达 B 点?”。

控制

一旦我们找到了路径,汽车所要做的就是能够操控方向盘。唯一的挑战是以类似人类的方式驾驶汽车(例如只是不是自动的),这需要大量的练习。

[Source]

当前应用

有很多公司像 Waymo(谷歌公司)、优步和 Lyft 都在 SDC 大肆宣传,但距离我们达到第五级自动驾驶(无人驾驶,接近 100%准确)还有很长的路要走。

目前,最接近的公司是 Waymo,它的 SDC 行驶了超过 1000 万英里。那大概是 10 辈子的驾驶!

No driver! [Source]

然而,SDC 的未来仍然是一个讨论的话题,最终将取决于人们是否决定在 SDC 变得广泛可用时信任他。

TL;博士

在谷歌和优步等公司的引领下,自动驾驶汽车为下一代交通工具带来了光明的未来。无人驾驶汽车背后的主要组件如下:

  • 计算机视觉(汽车如何看到)
  • 传感器融合(汽车如何理解其环境)
  • 定位(汽车如何知道其位置)
  • 路径规划(汽车如何思考关于最优路线)
  • 控制(汽车如何操纵车轮)

资源

  • 优步了解更多关于 SDC 的信息
  • 了解更多关于激光雷达(在 SDCs 中非常重要)

如果你喜欢我的文章或者学到了新的东西,请务必:

  • 通过 LinkedIn 与我联系
  • 发送一些反馈(我总是乐于接受建议!)

贝叶斯推理导论

原文:https://towardsdatascience.com/an-introduction-to-bayesian-inference-e6186cfc87bc?source=collection_archive---------11-----------------------

和马尔可夫链蒙特卡罗

前言:下面的帖子旨在介绍一些数学知识。它假设您对统计学有一定的了解。虽然包括数学,但我绝不是专家。我努力学习概率编程的基础知识,希望这能帮助其他人理解这个世界。如果您发现任何错误,请留下评论并帮助我们学习。干杯!

在数据科学中,我们通常对理解数据是如何产生的感兴趣,主要是因为它允许我们回答关于新的和/或不完整的观察的问题。更具体地说,我们希望对观察数据中的输入影响输出数据的过程和程度进行建模。但是对于任何给定的数据集,有无限多种可能的模型结构可以合理地解释数据集是如何生成的。但是并不是所有的模型结构都是一样的——也就是说,基于我们对世界如何运作的假设,某些模型结构比其他模型结构更现实。由建模者选择最能描述他们所观察的世界的一个。

目标:找到最能解释数据集 D 如何生成的模型 M

即使我们已经选择了我们对世界的影响的假设(即模型结构),模型结构本身到目前为止还是抽象的。例如,我们可能认为预测我吃冰淇淋概率的模型是合适的,如果我们设置它,使日期和我的位置影响温度,从而影响我狼吞虎咽黑巧克力冰淇淋(最好的一种)的机会。但这只是给出了模型结构。理想情况下,我们希望有一个函数,可以为给定日期和地点的任何可能的冰淇淋结果分配概率。为了做到这一点,我们还需要知道每一个输入对模型的每一层有多大的影响——这些是由模型参数 θ捕获的。

I love gelato.

修改后的目标:对于包含我们对世界结构的假设的给定模型结构 M (即我们认为数据是通过其产生的影响过程),如果观察到的数据 D 是在这个选择的模型下产生的,那么模型的参数 θ 的值是多少?

换句话说,我们可能感兴趣的是找到 θ 的值,这些值最大化了在给定 X s 的情况下观察到 y s 的可能性(换句话说:最大化了观察到的数据 D 的可能性)。这被称为最大似然估计。

回到意式冰淇淋:想象你记录了我每天在哪里,我是否吃意式冰淇淋(奇怪,但也许我的医生担心我吃了太多的意式冰淇淋)。最大似然估计器将输出使似然函数最大化的θs。似然函数是我们观察到的 y s(我的冰淇淋消耗量)和 X s(日期和我的位置)的概率,如果这些 y s 确实是由那些 θ s 和那些 X s 生成的。最大化似然性给了我们看起来最能解释数据的 θ s 组合。

通常,我们试图搜索模型参数值的每一个组合,并计算具有该组特定模型参数值的模型生成我们的观察数据的概率。当然,在大多数实际情况下,搜索 θ 的每个组合是不可能的,所以在传统的机器学习中,我们用梯度下降等算法来优化这种搜索,这些算法根据当前值的组合在解释观察到的数据方面的表现来选择接下来要测试的 θ 的哪些值。然后,我们选择并报告最大化数据可能性的 θ 组合。

这种方法的一个问题是,我们报告的是 θ s 的单一组合作为我们的最佳估计值,但是看到这份报告的其他人不会知道我们对每个报告的参数值有多大的把握。这是一个问题,因为观察到的数据几乎总是真实总体的样本,并且本质上是有噪声的,不管我们收集了多少数据;我们永远不应该对模型参数的任何点估计有 100%的把握。考虑一下,如果我们观察到一个不同的或有限的人口样本(例如,如果我只记得记录我 75%的时间里的冰淇淋消费量,或者只有当我在纽约的时候,会怎么样?),我们报告的 θ s 会发生剧烈变化还是最小变化?知道了每个 θ 值的可信区间,就嵌入了这样的信息,即基于我们看到的数据,我们认为我们对给定模型参数的估计有多有代表性,这通常可能代表真实物理现象的影响。我们也很少知道关于我吃冰淇淋的知识会如何影响某个温度或我在某个城市的概率(即反向推断)。

贝叶斯推理

为了解决这些问题,我想介绍一下贝叶斯推理,贝叶斯法则是我们的口头禅:

Eqn 1: Bayes Rule

让我们看看如何将它应用到我们的目标中。回想一下,给定我们观察到的数据:P_M ( θ | D),在我们选择的模型结构下,知道参数值 θ 的概率分布是理想的。将此代入贝叶斯法则:

Eqn 2

Eqn 3

我们现在可以将等式 2 改写为:

Eqn 4

如果我们选择 θ 的值来测试我们预先选择的模型,计算 P_M ( D | θ) 真的很容易,因为我们知道这个建模函数的所有输入/输出/参数(回想一下这被称为似然性), 我们还知道先验 P( θ) ,因为它代表了我们对特定 θ 的信念(例如,对于看似公平的硬币, θ 很可能是以 0.5 为中心的法线,根据我们对硬币公平程度的信念,我们可能会增加或减少该法线的方差)。 对于选定的 θ ,计算 EQN 4 的分子非常简单。

问我们每一个可能的 θ 的数量,我们很快意识到我们在传统的机器学习中遇到了同样的问题:我们无法对每一个 θ 进行采样!换句话说,EQN 4 的分母几乎无法计算。

MCMC

开发马尔可夫链蒙特卡罗(MCMC)技术是为了智能地采样 θ s,而不是直接对每个可能的 θ 的似然性和先验性求和。这些技术背后的主要思想类似于我们在传统机器学习中看到的 θ 更新技术:我们根据我们对当前一组 θ 值的可能性的评估,用一组新的 θ 值进行“更新”。这里最大的不同是,我们是取样而不是更新——换句话说,我们对我们探索过的价值观的历史感兴趣。这很重要,因为我们不再只是对知道每个参数的单个最佳估计感兴趣(这是我们在梯度下降中所做的),而是对知道每个参数的“好”估计的集合以及它们的可能性有多大感兴趣。(即给定 Dθ 的概率分布)。

让我们深入研究 MCMC 算法的高级概述以及它们在这里工作的原因。MCMC 关心跟踪两件事:

θ_current: 单个 θ 我们目前感兴趣的
trace_θ :所有 θ_current 的列表

MCMC 首先选择一个随机初始值 θ :

θ_ current =θ_ 0
trace θ=[θ 0】

并计算似然和先验(即等式 4 的分子)。创建 MCMC 的目的是,尽管分母在所有的 θ 选择中保持不变,但我们不能直接计算分母中的和,所以我们暂时把它放在一边。在这一点上,我们不知道我们选择的 θ_0 是否是一个好的选择。相反,我们选择一个提议 θ_1 (在这一点上,认为它被神奇地选择了,但我们很快就会回到那个问题上)如果它在 EQN 4 中产生一个更大的分子,我们可以同意它是对 θ 的更好选择。这是因为在 EQN 4 中分母是不变的,不管我们选择还是θ 来代入 EQN 4。既然我们知道 θ_1 更好,让我们把它加到我们的迹中,更新我们当前的 θ ,并计算似然和先验(即 EQN 4 的分子):

θ_ current =θ_ 1
trace θ=[θ 0,θ_ 1】

我们现在可以选择一个新的 θ_2 来提出(目前仍是一个神奇的过程),如果它不能很好地解释数据(即,它产生了等式 4 的一个较小的分子),那么我们这次不会立即接受它,而是将它接受到我们的 θ_currenttrace_θ 的概率𝛼:中

Eqn 5

之所以这样,是因为我们可以推论出 θ_2 只有𝛼和 θ_current 一样好。这意味着在我们的采样历史中,我们应该期望我们采样的次数 θ_2 是我们采样的次数 θ_current 的𝛼的一个因子:

Eqn 6

在这种情况下,经过充分的采样后,您应该会有一种直觉,即我们将会探索大量的 θ 值,并将它们保存在跟踪变量中,其频率与 θ 值相对于其他θ值解释数据的程度成比例,这正是我们感兴趣的分布

最后,我们回到如何生成好的建议 θ s 的问题。如果我们没有方法并在 θ 的所有可能值中随机选择 θ s 来建议,我们将拒绝太多的样本(考虑到 θ 的真实密度可能是相对窄分布的)。相反,我们从建议分布q(θ_ proposed |θ_ current)中得出θs。例如,我们可以选择使 q 成为具有固定方差和平均值 θ_current 的正态分布。

这是最流行的 MCMC 算法之一 Metropolis-Hastings (MH)的本质。我们通过以下方式将其纳入我们的𝛼接受率:

Eqn 7

如果我们选择对称建议分布(如正态分布),则:

Eqn 8

由此可见,𝛼_ = 𝛼.这叫做随机漫步 MH 算法,你会得到这样的图:

Image 1

左图是“intercept_mu”参数的 KDE 图(本质上是一个平滑的直方图),右图是每个采样链随时间变化的轨迹。我们可以推断,虽然参数(轨迹的模式,也称为地图)最可能的值是 0.16,但参数的可信区间可能在 0.1 和 0.21 之间。

附录:

  • 为了更直观地解释这个过程,请看这段视频
  • 大多数帮助你进行 MCMC 的软件包通常会运行 3 个或更多的轨迹(也称为“链”),它们具有不同的随机初始化,以确保链是“收敛的”。这很重要,因为聚合链表明你的马尔可夫链已经稳定。
  • 我通常会考虑老化期,它会丢弃最初的几千个样本,这些样本可能取决于θ的随机初始化
  • 先验的选择对抽样结果有影响。不要选择太窄的先验(因为你的偏见会妨碍对参数空间的正确探索,你的链将无法收敛)或太宽的先验(称为无信息先验,你收敛的机会也会减少,因为你会花太多时间拒绝无用的样本)。
  • 我通常使用曲线的模式或均值来报告最可能的值,并使用 HPD(最高后验密度)区间来建立可信区间。

大数据、Apache Spark 和 RDDs 简介

原文:https://towardsdatascience.com/an-introduction-to-big-data-apache-spark-and-rdds-975ef4d91be2?source=collection_archive---------8-----------------------

Spark 架构如何优化以处理大型数据集的基本方法

Photo by NASA on Unsplash

我们每天总共产生超过 2.5 万亿字节的数据。

yelp 评论、广告点击或地理坐标——只要你说得出,我们的数字足迹就可能在那里。从社交媒体平台上的数百万内容创作者到源源不断的交易行项目,我们的世界一直在以指数速度产生数据。它们的大小从 0.7 MB 的 twitter 帖子到 100 多 PB 的优步地理交通洞察

Current big data systems are processing datasets in the Petabytes range

随着这一趋势,重要的是,我们有能力捕捉它,解释它,并基于它做出“数据驱动的决策”。但为了让我们真正获得这些见解,数据科学家围绕大数据以及如何处理如此庞大的信息创建了一个完整的领域。

特别是,大数据需要更强大的计算工具,而不仅仅是标准的 excel 回归,甚至是你可能熟悉的 python 熊猫。特别是在处理企业级生产级数据集或考虑为任何具有数据播放功能的初创公司进行扩展时,大数据平台是管理和分析您所有大数据需求的核心。其中一个平台 Apache Spark 已经成为处理大数据的事实平台,并继续成为学术界和行业中数据专家使用最多的平台。本文旨在将 Spark 的核心概念分解成简单明了的描述。

Spark 处理大数据

让我们从 Apache Spark 网站开始——Spark 是一个“用于大数据处理的统一分析引擎”从高层次来说,它是一个计算框架,允许我们:

  1. 加载/接收大量实时数据(流)
  2. 转换/清理大量数据(SQL 操作)
  3. 对大量数据运行 ML 分析技术(机器学习)
  4. 处理大量数据的图形网络(图形处理)

看到模式了吗?处理大数据的各种计算功能。我们用 Python、R、Scala 和 Java 为 Apache Spark 编写代码,脚本通常运行在支持这些大型计算的平台上。

A Big Number of Big Machines process Big Data

这些运行 Spark 的平台通常是基于云的(微软 Azure、AWS、谷歌云等。)并写在与云环境相连的笔记本上。这些笔记本电脑由联网的计算机集群支持,可以高效地处理大型数据集,这是您单独的笔记本电脑或 PC 无法处理的。(更多关于如何以后)

RDD 作为火花的基本抽象

Apache Spark 通过一种称为弹性分布式数据集(RDD)的抽象来处理这些海量数据。你会经常听到这个词,因为它是 Spark 强大的数据处理引擎的基础。

从高层次上讲,RDD 是一种逻辑结构,它允许我们以我们熟悉的传统表格格式可视化数据,并在数据集上运行必要的 SQL 查询。它的核心是一个 java 对象,有内置的方法(如 RDD_example.map()RDD_example.filter() 等)。)允许我们操作传入的原始数据。RDD 仅仅是一个抽象,负责处理(存储&转换)我们传入的数据。

然而,在幕后,RDD 通过对数据子集进行分区来有效地处理大数据,这些子集可以在各个节点上并行地在上操作,并且每个分区都有副本以防止数据丢失。下面是一个用 RDD 表示数据的具体例子:

示例:让我们给 Spark 100GB 的数据:

假设在这个设置中我们有 5 个工作节点可用。Spark 认识到将所有 100 GB 分配给一个工作节点而让其他四个空着是低效的。相反,它选择将这个原始数据集划分到工作节点上,以平均分配工作负载。Spark 决定将数据划分为 100 个分区(从技术上讲,分区数量是您首先设置的参数),每个分区有不同的 GB。

现在,节点#1 获得第一个 20 GB,节点#2 获得 21–40gb,节点#3 获得 41–60gb,依此类推。

但是并不是所有的数据都是同等地创建的——有些数据可能比其他数据运行得更快,而有些数据可能过于繁重,以至于会导致节点崩溃。

Spark 决定为节点#1 提供 21–40gb 和 41–60gb 的副本,为节点#2 提供 41–60gb 和 61–80gb 的副本,依此类推。

因此,虽然每个工作节点主要负责其原始的 20 GB,但它也存储其他 GB 分区的副本。因此,Spark 有效地将数据划分到节点上,这样工作节点可以并行计算数据,同时防止空闲节点。也就是说,如果一个工作者节点提前完成了它的计算,它可以从另一个工作者节点(可能很慢或者已经崩溃)那里“拾起空闲”并支持另一个 GB 分区的计算。

从示例中,我们可以看到以下几点:

  1. 数据具有弹性 —通过存储数据的多个副本,每个副本存储在不同的节点中,我们可以避免在一个或多个节点发生故障的罕见情况下丢失数据。
  2. 数据是分布式的 —很明显,在最初的 100GB 数据中,我们已经跨多个节点对数据进行了分区或分片。这使得每个节点处理的数据更少,从而提高了整体运行速度。
  3. 数据是一个数据集 —它是一个保存数据的数据结构。在表功能中,它可以被格式化为具有索引的命名列,但是除了被分区之外,它也可以没有正式的结构组织。当它以 DataFrame 对象的形式使用内置方法时,可以为这种特殊的数据集提供更丰富的优化。

这就产生了弹性分布式数据集的名称。当然,这个过程还存在更多的细微差别,但是上面的例子试图说明 Spark 使用 rdd 的效率的一个简化的思考过程。

PySpark 中 rdd 的 4 行代码

RDD_example = sc.parallelize([1,2,3])
o = RDD _ example . filter(lambda I:I % 2)。map(lambda I:I * 2)
result = o . collect()
print(结果)

(输出:2,6)

注意,使用并行化方法的第一行,我们从传入的整数列表中创建 RDD。可以把并行化想象成这样——创建 RDD,这样我们就可以并行处理数据。

在我们创建的 RDD 上,我们对该对象应用了两个额外的方法,这两个方法仍然返回 RDD 对象。过滤器和映射都是 MapReduce 框架的一部分,接受各自的匿名函数。在这种情况下,我们过滤 RDD 以包含奇数的元素,然后将加倍函数映射到这些相应的元素。

惰性评估和 Dag

在这一点上,RDD 的方法似乎与我们在 CS 入门课程中看到的方法相同。那么,为什么我们要费这么大的劲来过滤一个函数并把它映射到一个列表上呢?来评价一下 Spark 如何懒懒地计算

上面的例子,在我们调用 collect 的最后一行,简洁地显示了 spark 转换动作之间的区别。在这里,我们可以深入了解——的转变。过滤器()和。先前的 map()没有被实际执行,而是被放入执行 map 中,以便稍后被动作激活。的。collect()操作方法实际上用于执行整个代码序列,并开始跨节点的计算。

The local environment execution plan as a Directed Acyclic Graph (DAG) https://spark.apache.org/docs/latest/cluster-overview.html

转换在本地环境中创建的执行计划存储在一个有向无环图(DAG)中。与中一样,计算的步骤遵循一个连续的方向,永远不会循环回自身。

长话短说,转换方法是返回放入 DAG 的 RDD 的 RDD 方法。动作方法通常是启动 Spark 引擎进行计算的最终操作。转换在本地环境中添加 DAG,并且在动作调用时,DAG 被发送到主驱动程序上的主 Spark 解释器。

大局

在 Spark 如何运行以及 RDD 如何融入框架的更大范围内,下图抓住了中央驱动程序如何在工作节点之间分布的核心。

https://spark.apache.org/docs/latest/cluster-overview.html

我们称之为初始的 sc 对象或 SparkContext。parallelize()方法是 Apache Spark 的内置功能,我们可以将其视为主驱动程序的一部分。这个火花上下文对象是我们创建的,或者是给予我们的,这样我们就有能力创建 RDD。从那里,主驱动程序从您的 PySpark 脚本接收 DAG 执行计划,序列化代码(例如,转换成位和字节),并将各自的分区发送到它们通过 API 调用接收的工作节点。然后,每个工人执行从 DAG 分配给他们的操作。这提升了 Spark 并行计算和高效处理大数据的能力。

fast.ai 中使用迁移学习的计算机视觉导论——飞机分类

原文:https://towardsdatascience.com/an-introduction-to-computer-vision-using-transfer-learning-in-fast-ai-aircraft-classification-a2685d266ac?source=collection_archive---------5-----------------------

使用 fastai 和 pytorch 的图像分类简介

介绍

我来 fast.ai 派对有点晚了,不过有句名言是这么说的,

迟做比不做好

这不是最伟大的格言,但对我来说很管用。

2018 年 11 月,我开始探索用于深度学习的 fast.ai 库,这是通过杰瑞米·霍华德同名的奇妙 MOOC 实现的,我想在一些数据集上对该库进行实验,以获得良好的感受。我还从我的朋友 Aayush Agrawal博客文章中获得了灵感,这篇文章是关于使用转移学习通过叶子图像检测植物疾病的

fast.ai 是一个 Python 深度学习库,位于脸书深度学习 PyTorch 框架之上。在这篇文章中,我们看看如何使用迁移学习对 9 个飞机模型进行分类,数据集是我通过从互联网下载 9 个飞机模型的图像手动构建的,如下所示:

Airbus A320 — Airbus A340 — Airbus A350

Airbus A380 — Boeing 737 — Boeing 747

Boeing 757 — Boeing 777 — Boeing 787

从小我就一直对飞机很着迷。也有一段时间,我梦想成为一名飞行员——但我猜这些梦想从未实现过(看到我在那里做了什么吗?)——所以我决定把这种魅力带进我的深度学习探索中。现在让我们深入 Python 代码,看看所有这些是如何展开的:

导入必要的模块

让我们从导入计算机视觉问题所需的模块开始:

from fastai.vision import *

可能会有一群 Pythonistas 等着向我扔鸡蛋,因为我使用了上面的import *,但这几乎是这篇文章所需要的。这个库包含了很多功能,随着我们对数据探索的深入,您将会意识到它的易用性。

探索数据

我们的图像数据集作为.jpg文件存储在 9 个不同的文件夹中,每个文件夹都带有文件夹中包含的图像的飞机模型名称。我们使用ImageDataBunch.from_folder()函数来加载图像,并根据读取图像的文件夹的名称给图像分配标签。

我们首先声明文件夹所在的路径:

这就是我们加载这些图像所需要做的一切。显然这是一个对编码者友好的库。

上面的.normalize(imagenet_stats)方法用于根据 ImageNet 数据集的 RGB 通道的统计数据来标准化数据集。

现在我们已经加载了数据集,让我们看一看它是什么样子的:

data.show_batch(rows=3, figsize=(7,8))

我看没问题。让我们看看什么是图像类、类的数量以及训练集和测试集的大小:

data.classes —我们的数据集中有哪些类别的飞机?

['airbus_a320',
  'airbus_a340',
  'airbus_a350',
  'airbus_a380',
  'boeing_737',
  'boeing_747',
  'boeing_757',
  'boeing_777_300',
  'boeing_787']

data.c —我们的数据集中有多少个类?

9

len(data.train_ds) —我们的训练数据集有多大?

2473

len(data.valid_ds) —我们的验证数据集有多大?

618

因此,我们在训练集中有 2473 幅图像,在测试集中有 618 幅图像(约 20%),如上面的ImageDataBunch.from_folder()函数所定义。

训练模型

我们现在使用预训练的 ResNet50 卷积神经网络模型,并使用迁移学习来仅学习网络的最后一层的权重。

为什么要转学?因为使用迁移学习,你从一个现有的(经过训练的)用于图像识别的神经网络开始,然后在这里或那里稍微调整一下,为你的特定用例训练一个模型。我们为什么要这么做?训练一个合理的神经网络将意味着需要大约 300,000 个图像样本,并且为了实现真正良好的性能,我们将需要至少一百万个图像。在我们的例子中,我们的训练集中有大约 2500 幅图像——如果我们从头开始训练神经网络,你有一个猜测来决定这是否足够。

我们使用create_cnn()函数来加载预训练的 ResNet50 网络,该网络是在来自 ImageNet 数据库的大约一百万张图像上训练的。

现在,让我们拟合 4 个时期的一个周期,看看我们的模型在该数据集上的表现如何:

learn.fit_one_cycle(4)

为什么只有 4 个纪元?我想尝试和基准我的第一次尝试与调整,我会在一段时间内,使一个合理的比较。通过 4 个时期,并且没有对我们的模型进行调整,我们已经成功地实现了(?)大约 32%的错误率(这相当于 68%的准确度)。这有多好?当我们进一步阅读时,我们会找到这个问题的答案。

让我们看看我们的模型预测有什么问题:

interp = ClassificationInterpretation.from_learner(learn)interp.plot_top_losses(8)

上面图像中的热图描绘了图像中激活网络的区域——更简单地说,这些是图像中帮助网络识别类别的区域(在上面的案例中不是很有帮助,因为损失是最高的)。关于这方面的更多信息,本文给出了一个很好的演示。

一个突出的事实是,当它被输入到模型中时,大多数图像被裁剪成正方形( n x n 像素)。这是因为目前,GPU 输入只能是正方形图像。对于我们的用例来说,这是一个潜在的警告,因为帮助识别飞机的主要组件之一是它的鼻子,它在大多数图像中被裁剪掉,因此我们的模型没有足够的信息来学习。

为了克服这一点,现在让我们把我们的图像挤压成正方形,而不是裁剪它们。可以把它想象成从图像的两边施加压力,使它看起来有点扭曲,但保留了图像的组成部分,而没有裁剪它。为此,我们对我们的ImageDataBunch.from_folder()函数做了一点小小的改变。最初,我们将size参数设置为值 450,这意味着图像将被裁剪为450 x 450图像。让我们对该参数进行如下修改:

我们现在已经将size 的值从450改为**(450,450)**。这种变化虽然不明显,但会将图像压缩到上述相同的尺寸:

data_squished.show_batch(rows=3, figsize=(7,8))

Images loaded with size = (450,450), with images squished but the aircraft noses are retained

这里的区别是显而易见的,与我们最初加载的图像相比,图像较宽的一端(大多数情况下,鼻子)被剪掉了:

Images loaded at the beginning of the post (size = 450), thus cropping the noses

现在让我们通过用新图像重新训练模型来创建另一个学习者:

learn2 = cnn_learner(data_squished, 
                     models.resnet50,       
                     metrics=error_rate)

现在让我们用 4 个时期来拟合我们的模型(一个时期意味着我们的模型扫描我们的数据一次——时期的数量越多,它在每次扫描中学习的就越多)

learn2.fit_one_cycle(4)

这个结果是 21%的错误率,比我们之前 32%的错误率有了相当大的改善。现在,让我们尝试通过微调来改进我们的模型:

让我们暂时保存模型(权重):

learn2.save('aircraft_classification_stg1')

深度学习模型中最重要的参数之一是学习速率。选择正确的学习率很重要,我们可以使用一个漂亮的函数— lr_finder()来找到一个非常好的学习率,供我们的模型学习,而不是随机猜测或多次试错。这个函数是 Leslie Smith 的论文中关于调整神经网络超参数的一个实现,所以读一下吧。

在我们运行lr_find()之前,我们可以解冻整个网络。我发现在运行lr_find()之前解冻网络能让我得到更好的结果。unfreeze()使我们能够更新整个网络的权重。理想情况下,我们希望而不是大幅度更新早期层的权重,但是小的变化(由低学习率定义)以及随着我们在各层之间移动而逐渐增加学习率可能会导致更好的结果。

learn2.unfreeze()
learn2.lr_find()

lr_find()本质上是用线性递增的学习率来训练模型,学习率通常在 10e-7 到 1 之间。运行后,我们绘制了损失与学习率的关系图,如下所示:

learn2.recorder.plot()

我们可以选择我们的学习速率,使它低于损失开始显著上升的速率。在上图中,1e-4 似乎是最后一层组的合理学习速率。

我们可以通过选择学习率的范围来将学习率分布在网络的各层,其中最大学习率将是 1e-4(来自上图),最小学习率(将应用于第一学习组)可以是最大学习率的十分之一,在这种情况下将是 1e-5。

为了训练整个网络,我们首先需要 解冻 网络——这是我们在运行lr_find()之前做的事情,所以我们不必再做一遍。

现在让我们用 8 个时期来拟合我们的模型的一个周期——阅读更多关于fit_one_cycle的内容,这是一篇关于这个主题的很棒的文章。

learn2.fit_one_cycle(8, max_lr=slice(1e-5,1e-4))

通过以上步骤,我们已经将错误率降低到了约 4% —不错!我们最初的错误率是 32%,这是一个很大的进步!

现在让我们看看我们的混淆矩阵,看看我们的模型在哪里给出了错误的预测:

interp = ClassificationInterpretation.from_learner(learn2)
interp.plot_confusion_matrix()

从混淆矩阵来看,看起来模型预测飞机是波音 787,而实际上它是另一个模型。让我们看看损失最大的例子:

interp.plot_top_losses(10, figsize = (20,20))

我们可以让我们的模型通过一些预测——例如,第四张图片只是一个引擎,我不认为我给模型提供了足够的放大引擎图像来准确区分飞机引擎。第七张图片是飞机前部的放大图,公平地说,这很难区分不同的飞机,特别是对于一个我们没有调整太多的模型。上图中的热图显示了图像的激活层。

结论

在没有对我们的模型进行深入调整的情况下,我们能够获得接近 97%的准确率。我们可以做大量的实验来进一步了解是否可以提高精度,例如增加历元的数量、多次运行单个历元周期、更多的数据扩充技术等。这篇文章的目的是说明 fastai 库的易用性和速度,以及它只需很少的调整就可以实现的最先进的结果,以及迁移学习在开发最先进的图像识别模型方面令人难以置信的能力。fast.ai 的人们正在不断开发这个库,它将激励人们更多地了解人工智能及其在建设更美好世界中的非凡用例。

这个项目的代码可以在我的 Github 档案中找到

卷积神经网络导论

原文:https://towardsdatascience.com/an-introduction-to-convolutional-neural-networks-bdf692352c7?source=collection_archive---------10-----------------------

一个简单的指南,介绍什么是 CNN,它们如何工作,以及如何用 Python 从头开始构建一个 CNN。

在过去的几年里,关于卷积神经网络(CNN)有很多讨论,特别是因为它们如何彻底改变了计算机视觉领域。在这篇文章中,我们将基于神经网络的基本背景知识和探索什么是 CNN,了解它们如何工作,并从头开始用 Python 构建一个真实的 CNNs】(仅使用 numpy )。

这篇文章假设只有神经网络的基础知识。我的神经网络介绍涵盖了你需要知道的一切,所以你可能想先读一下。

准备好了吗?让我们跳进来。

这篇文章的格式在 victorzhou.com 的原帖中看起来最好。

1.动机

CNN 的一个经典用例是执行图像分类,例如,查看宠物的图像并判断它是猫还是狗。这是一个看似简单的任务— 为什么不用普通的神经网络呢?

好问题。

原因 1:图像很大

现在用于计算机视觉问题的图像通常是 224x224 或更大。想象一下,构建一个神经网络来处理 224x224 彩色图像:包括图像中的 3 个颜色通道(RGB ),得出 224 x 224 x 3 = 150,528 输入特征!在这样的网络中,一个典型的隐藏层可能有 1024 个节点,因此我们必须为第一层训练 150,528 x 1024 =1.5 亿个以上的权重。我们的网络将会非常庞大,几乎无法训练。

我们也不需要那么多重量。图像的好处是我们知道像素在它们的邻居的上下文中最有用。图像中的物体由小的局部特征组成,比如眼睛的圆形虹膜或者一张纸的方形角。第一个隐藏层的每一个节点都要看每一个像素是不是显得很浪费?

原因 2:立场可以改变

如果你训练一个网络来检测狗,你会希望它能够检测一只狗,不管它出现在图像的什么地方。想象一下,训练一个对某个狗图像工作良好的网络,然后给它输入同一图像的稍微偏移的版本。狗不会激活同样的神经元,所以网络会做出完全不同的反应!

我们很快就会看到 CNN 如何帮助我们缓解这些问题。

2.资料组

在本帖中,我们将解决“你好,世界!”计算机视觉的: MNIST 手写数字分类问题。很简单:给定一个图像,将其归类为一个数字。

MNIST 数据集中的每幅图像都是 28x28,包含一个居中的灰度数字。

说实话,一个普通的神经网络实际上可以很好地解决这个问题。您可以将每个图像视为一个 28 x 28 = 784 维的向量,将其输入到一个 784 维的输入层,堆叠几个隐藏层,最后得到一个包含 10 个节点的输出层,每个节点对应一个数字。

这只会起作用,因为 MNIST 数据集包含以为中心图像,所以我们不会遇到前面提到的大小或移动的问题。然而,在这篇文章的整个过程中请记住,大多数现实世界的图像分类问题并不容易。

足够的积累。让我们进入 CNN!

3.回旋

什么是卷积神经网络?

它们基本上只是使用卷积层的神经网络,也称为 Conv 层,基于卷积的数学运算。Conv 图层由一组滤镜组成,你可以把它们想象成 2d 数字矩阵。这是一个 3x3 滤波器的例子:

A 3x3 filter

我们可以使用输入图像和滤波器,通过将滤波器与输入图像卷积来产生输出图像。这包括

  1. 将滤镜覆盖在图像顶部的某个位置。
  2. 在滤波器中的值和它们在图像中的相应值之间执行逐元素乘法
  3. 对所有元素的乘积求和。该总和是输出图像中目标像素的输出值。
  4. 对所有位置重复。

边注:我们(以及许多 CNN 实现)在技术上实际上使用 互相关 来代替这里的卷积,但它们做的几乎是同样的事情。我不会在这篇文章中深入讨论这种差异,因为它并不重要,但是如果你好奇的话,可以随意查看。

这个 4 步描述有点抽象,所以让我们来做一个例子。考虑一下这个小小的 4x4 灰度图像和这个 3x3 滤镜:

A 4x4 image (left) and a 3x3 filter (right)

图像中的数字代表像素强度,其中 0 代表黑色,255 代表白色。我们将卷积输入图像和滤波器,以产生 2x2 输出图像:

A 2x2 output image

首先,让我们在图像的左上角覆盖我们的过滤器:

Step 1: Overlay the filter (right) on top of the image (left)

接下来,我们在重叠的图像值和滤波器值之间执行逐元素乘法。以下是结果,从左上角开始,向右,然后向下:

Step 2: Performing element-wise multiplication.

接下来,我们总结所有的结果。这很简单:62–33 =29

最后,我们将结果放在输出图像的目标像素中。因为我们的过滤器覆盖在输入图像的左上角,所以我们的目标像素是输出图像的左上角像素:

我们做同样的事情来生成输出图像的其余部分:

3.1 这有什么用?

让我们缩小一下,从更高的层面来看这个问题。用滤波器卷积图像有什么作用?我们可以从我们一直使用的示例 3x3 滤波器开始,它通常被称为垂直 Sobel 滤波器:

下面是垂直索贝尔滤波器的一个例子:

An image convolved with the vertical Sobel filter

类似地,还有一个水平 Sobel 滤波器:

An image convolved with the horizontal Sobel filter

看到发生了什么吗?索贝尔滤波器是边缘检测器。垂直 Sobel 滤波器检测垂直边缘,水平 Sobel 滤波器检测水平边缘。输出图像现在很容易解释:输出图像中的亮像素(具有高值的像素)表示原始图像中有很强的边缘。

你能看出为什么边缘检测图像可能比原始图像更有用吗?回想一下我们的 MNIST 手写数字分类问题。例如,在 MNIST 上训练的 CNN 可能通过使用边缘检测过滤器并检查图像中心附近的两个突出的垂直边缘来寻找数字 1。一般来说,卷积帮助我们寻找特定的局部图像特征(如边缘),我们可以在网络中稍后使用。

3.2 填充

还记得之前用 3×3 滤波器卷积 4×4 输入图像以产生 2×2 输出图像吗?很多时候,我们更希望输出图像和输入图像大小相同。为此,我们在图像周围添加零,这样我们可以在更多的地方覆盖过滤器。3x3 滤镜需要 1 个像素的填充:

A 4x4 input convolved with a 3x3 filter to produce a 4x4 output using same padding

这被称为“相同”填充,因为输入和输出具有相同的尺寸。不使用任何填充,这是我们在这篇文章中一直在做并将继续做的,有时被称为“有效”填充

3.3 Conv 层

现在我们知道了图像卷积的工作原理以及它为什么有用,让我们看看它在 CNN 中的实际应用。如前所述,CNN 包括 conv 层,它使用一组过滤器将输入图像转换为输出图像。conv 层的主要参数是它拥有的滤镜数量。

对于我们的 MNIST CNN,我们将使用一个带有 8 个过滤器的小 conv 层作为我们网络的初始层。这意味着它会将 28x28 的输入图像转换成 26x26x8 的输出音量:

提醒:输出是 26x26x8,而不是 28x28x8,因为我们使用了 有效填充 ,将输入的宽度和高度减少了 2。

conv 层中的 8 个过滤器中的每一个都产生 26x26 的输出,所以堆叠在一起它们构成了 26x26x8 的体积。这一切的发生都是因为 3 x 3(滤镜大小)x 8(滤镜数量)= 只有 72 个权重

3.4 实现卷积

是时候将我们所学的内容转化为代码了!我们将实现一个 conv 层的前馈部分,它负责将滤波器与输入图像进行卷积,以产生输出体积。为简单起见,我们假设滤波器始终为 3x3(这是不正确的,5x5 和 7x7 滤波器也很常见)。

让我们开始实现一个 conv 图层类:

Conv3x3类只有一个参数:过滤器的数量。在构造函数中,我们存储过滤器的数量,并使用 NumPy 的 randn() 方法初始化一个随机过滤器数组。

注意:在初始化期间潜水 9 比你想象的更重要。如果初始值太大或太小,训练网络将无效。要了解更多信息,请阅读关于 Xavier 初始化

接下来,实际卷积:

iterate_regions()是一个助手生成器方法,为我们生成所有有效的 3x3 图像区域。这将有助于稍后实现该类的向后部分。

第 26 行实际上执行卷积。让我们来分解一下:

  • 我们有im_region,一个包含相关图像区域的 3x3 数组。
  • 我们有self.filters,一个三维阵列。
  • 我们做到了,它使用 numpy 的广播特性对两个数组进行元素相乘。结果是一个与self.filters维度相同的 3d 数组。
  • 我们 np.sum() 使用上一步的结果,产生一个长度为num_filters的 1d 数组,其中每个元素包含相应滤波器的卷积结果。

对输出中的每个像素执行上述序列,直到我们获得最终的输出量!让我们测试一下我们的代码:

目前看来不错。

注意:在我们的 *Conv3x3* 实现中,为了简单起见,我们假设输入是一个2dnumpy 数组,因为我们的 MNIST 图像就是这样存储的。这对我们有用,因为我们把它作为网络的第一层,但是大多数 CNN 有更多的 Conv 层。如果我们要构建一个需要多次使用 *Conv3x3* 的更大的网络,我们必须让输入成为一个3dnumpy 数组。

4.联营

图像中的相邻像素往往具有相似的值,因此 conv 图层通常也会为输出中的相邻像素产生相似的值。因此,conv 层输出中包含的大部分信息都是冗余的。例如,如果我们使用边缘检测滤波器,并在某个位置找到一个强边缘,那么我们也有可能在与原始位置偏移 1 个像素的位置找到相对强的边缘。不过,这些都是一样的边缘!我们没有发现任何新东西。

池层解决了这个问题。它们所做的只是通过(你猜对了)值汇集到输入中来减小输入的大小。池化通常通过简单的操作来完成,如maxminaverage。这是一个最大池层的示例,池大小为 2:

Max Pooling (pool size 2) on a 4x4 image to produce a 2x2 output

为了执行 max 池,我们以 2x2 块遍历输入图像(因为池大小= 2)并将 max 值放入输出图像的相应像素。就是这样!

池化将输入的宽度和高度除以池大小。对于我们的 MNIST CNN,我们将在最初的 conv 图层后放置一个池大小为 2 的最大池图层。池层将 26x26x8 的输入转换为 13x13x8 的输出:

4.1 实施联营

我们将实现一个MaxPool2类,方法与上一节中的 conv 类相同:

这个类的工作方式类似于我们之前实现的Conv3x3类。关键的一行是第 30 行:为了从给定的图像区域中找到最大值,我们使用了 np.amax() ,numpy 的 array max 方法。我们设置它是因为我们只想最大化前两个维度,高度和宽度,而不是第三个维度num_filters

来测试一下吧!

我们的 MNIST CNN 开始团结起来了!

5.Softmax

为了完善我们的 CNN,我们需要赋予它实际预测的能力。我们将通过使用多类分类问题的标准最终层来做到这一点:Softmax 层,一个使用 Softmax 函数激活的全连接(密集)层。

提醒:全连接层的每个节点都连接到前一层的每个输出。如果你需要复习,我们在我的 神经网络介绍 中使用了全连接层。

如果你之前没有听说过 Softmax,那么在继续之前,请阅读我的soft max快速介绍。

5.1 用法

我们将使用一个有 10 个节点的 softmax 层,每个节点代表一个数字,作为 CNN 的最后一层。图层中的每个节点都将连接到每个输入。应用 softmax 变换后,概率最高的节点代表的数字将是 CNN 的输出!

5.2 交叉熵损失

你可能会对自己说,为什么要费心将输出转换成概率呢?产值最高的不会一直概率最高吗?如果你做了,那你就完全正确。我们实际上不需要使用 softmax 来预测一个数字——我们可以从网络中选择输出最高的数字!

softmax 真正做的是帮助我们量化我们对自己预测的确信程度,这在训练和评估我们的 CNN 时很有用。更具体地说,使用 softmax 让我们使用交叉熵损失,它考虑了我们对每个预测的确信程度。我们是这样计算交叉熵损失的:

其中 c 是正确的类别(在我们的例子中是正确的数字), pc 是类别 c 的预测概率, ln自然对数。一如既往,损失越低越好。例如,在最好的情况下,我们会

在更现实的情况下,我们可能会

在这篇文章的后面,我们将再次看到交叉熵损失,所以请记住这一点!

5.3 实施 Softmax

现在你已经知道该怎么做了——让我们实现一个Softmax层类:

这里没什么太复杂的。几个亮点:

  • 我们 flatten() 输入使其更容易处理,因为我们不再需要它的形状。
  • np.dot()inputself.weights逐元素相乘,然后对结果求和。
  • np.exp() 计算用于 Softmax 的指数。

我们现在已经完成了 CNN 的整个转发过程!综合起来看:

运行cnn.py会产生类似于下面的输出:

MNIST CNN initialized!
[Step 100] Past 100 steps: Average Loss 2.302 | Accuracy: 11%
[Step 200] Past 100 steps: Average Loss 2.302 | Accuracy: 8%
[Step 300] Past 100 steps: Average Loss 2.302 | Accuracy: 3%
[Step 400] Past 100 steps: Average Loss 2.302 | Accuracy: 12%

这是有道理的:通过随机权重初始化,你会认为 CNN 只是随机猜测。随机猜测将产生 10%的准确度(因为有 10 个类别)和交叉熵损失 ln(0.1)=2.302,这就是我们得到的结果!

想自己尝试或修改这段代码吗? 在浏览器中运行本 CNNGithub 上也有。

6.结论

CNN 的介绍到此结束!在本帖中,我们

  • 为什么 CNN 可能对某些问题更有用,比如图像分类。
  • 介绍了 MNIST 手写数字数据集。
  • 了解了 Conv 图层,它将滤镜与图像进行卷积,以产生更有用的输出。
  • 谈到了池层,它可以帮助修剪一切,但最有用的功能。
  • 实现了一个 Softmax 层,这样我们就可以使用交叉熵损失

还有很多我们还没有涉及的,比如如何实际训练一个 CNN。我的下一篇文章将深入训练 CNN ,包括导出渐变和实现反向投影,敬请关注!

如果你渴望看到一个训练有素的 CNN 在工作:这个例子 Keras CNN 在 MNIST 训练达到 99.25% 的准确率。CNN 很厉害!

原载于https://victorzhou.com

卷积神经网络导论

原文:https://towardsdatascience.com/an-introduction-to-convolutional-neural-networks-eb0b60b58fd7?source=collection_archive---------0-----------------------

描述什么是卷积神经网络,它们如何工作,如何使用,以及为什么它们如此强大

卷积神经网络(CNN)是一种具有一个或多个卷积层的神经网络,主要用于图像处理、分类、分割以及其他自相关数据。

卷积本质上是在输入上滑动滤波器。考虑卷积的一个有用的方法是引用 Prasad Samarakoon 博士的话:“卷积可以被认为是“观察一个函数的周围环境,以更好/准确地预测其结果”。"

与其一次查看整个图像来寻找某些特征,不如查看图像的较小部分会更有效。

CNN 的常见用途

CNN 最常见的用途是图像分类,例如识别包含道路的卫星图像或对手写字母和数字进行分类。还有其他相当主流的任务,如图像分割和信号处理,CNN 在这些方面表现良好。

CNN 已经被用于自然语言处理(NLP)和语音识别中的理解,尽管对于 NLP 经常使用递归神经网络(RNNs)。

CNN 也可以被实现为 U-Net 架构,其本质上是两个几乎镜像的 CNN,导致 CNN 的架构可以呈现为 U 形。u-net 用于输出需要与输入大小相似的场合,例如分割和图像改善。

除了图像处理,CNN 还有其他有趣的用途

CNN 架构越来越多不同且有趣的用途正在被发现。非图像应用的一个例子是 Lex Flagel 等人的“卷积神经网络在群体遗传推断中的不合理有效性”。这用于执行选择性扫描,寻找基因流,推断群体大小变化,推断重组率。

有一些研究人员,比如 T2 量子生物学实验室的 Gerald Quon 教授,使用 CNN 作为单细胞基因组学的生殖模型来识别疾病。

CNN 也在天体物理学中被用于解释射电望远镜数据,以预测代表数据的可能的视觉图像。

Deepmind 的 WaveNet 是一个用于生成合成语音的 CNN 模型,用作谷歌助手的语音合成器的基础。

卷积核

每个卷积层包含一系列称为卷积核的滤波器。过滤器是一个整数矩阵,用于输入像素值的子集,大小与内核相同。每个像素乘以内核中的相应值,然后将结果相加得到单个值,为简单起见,在输出通道/特征图中表示网格单元,如像素。

这些是线性变换,每个卷积都是一种仿射函数。

在计算机视觉中,输入通常是 3 通道 RGB 图像。为简单起见,如果我们取一个具有一个通道(二维矩阵)和一个 3×3 卷积核(二维矩阵)的灰度图像。内核遍历输入的数字矩阵,逐列水平移动,滑动/扫描包含图像像素值的矩阵的第一行。然后内核垂直向下移动到后续行。注意,过滤器可以一次跨越一个或几个像素,这将在下面进一步详述。

在其他非视觉应用中,一维卷积可以在输入矩阵上垂直滑动。

从卷积核创建特征图

下图显示了卷积核的操作。

A stride one 3x3 convolutional kernel acting on a 8x8 input image, outputting an 8x8 filter/channel. Source: https://www.researchgate.net/figure/a-Illustration-of-the-operation-principle-of-the-convolution-kernel-convolutional-layer_fig2_309487032

下面是一个精彩演示的可视化,展示了内核扫描输入矩阵中的值。

Kernel scanning over the values in the input matrix. Source: Otavio Good: excerpt https://www.youtube.com/watch?v=f0t-OCG79-U from https://www.youtube.com/watch?v=Oqm9vsf_hvU

填料

为了处理边缘像素,有几种方法:

  • 丢失边缘像素
  • 用零值像素填充
  • 反射填充

反射填充是目前最好的方法,卷积核处理边缘像素所需的像素数被添加到外部,从图像边缘复制像素。对于 3x3 内核,需要在外部周围添加一个像素,对于 7x7 内核,则需要在外部周围反射三个像素。每条边周围添加的像素是尺寸,减半并向下取整。

传统上,在许多研究论文中,边缘像素被忽略,这丢失了一小部分数据,并且如果有许多深卷积层,这变得更糟。出于这个原因,我无法找到现有的图表来轻松传达这里的一些要点,而不会误导和混淆步幅 1 卷积和步幅 2 卷积。

使用填充时,宽度为 w、高度为 h 的输入的输出将为宽度为 w、高度为 h(与使用单个输入通道的输入相同),假设内核一次跨越一个像素。

使用多个内核创建多个通道/特征图

当在一个卷积层中应用多个卷积核时,会创建许多通道/特征图,每个卷积核一个。下图显示了正在创建的通道/特征地图。

Visualisation of channels/feature maps created from a layer of convolutional kernels. Source: Otavio Good: excerpt https://www.youtube.com/watch?v=f0t-OCG79-U from https://www.youtube.com/watch?v=Oqm9vsf_hvU

RGB 3 通道输入

大多数图像处理需要对具有三个通道的 RGB 图像进行操作。RGB 图像是数字的三维阵列,也称为秩三张量。

当处理三通道 RGB 图像时,通常会使用一个卷积核,它是一个三维数组/秩为 3 的数字张量。卷积核的大小通常为 3x3x 3——卷积核就像一个立方体。

通常至少有三个卷积核,以便每个卷积核可以充当不同的滤波器,以从每个颜色通道获得洞察力。

卷积核作为一个组构成一个四维阵列,也称为秩 4 张量。当维度高于三个维度时,即使不是不可能,也是很难想象的。在这种情况下,把它想象成一个三维立方体的列表。

过滤器以同样的方式在输入数据中移动,滑动或大步跨过行,然后向下移动列并大步跨过行,直到到达右下角:

3x3x3 convolutional kernel acting on a 3 channel input. Source: https://machinethink.net/images/vggnet-convolutional-neural-network-iphone/ConvolutionKernel@2x.png

在填充和步长为 1 的情况下,来自宽度 x、高度 y 和深度 3 的输入的输出将是宽度 x、高度 y 和深度 1,因为立方体从每个步长产生单个求和输出值。例如,对于 3×64×64 的输入(例如 64×64 的 RGB 三通道图像),则一个内核以 1 为步长填充边缘像素,将输出 64×64 的通道/特征图(一个通道)。

值得注意的是,输入通常是标准化的,这将在下面进一步详述。

大步

通常使用跨距 2 卷积而不是跨距 1 卷积,其中卷积核一次跨越 2 个像素,例如我们的 3×3 核将从位置(1,1)开始,然后跨距到(1,3),然后到 1,5)等等,与跨距为 1 的卷积核相比,输出通道/特征图的大小减半。

使用填充,来自宽度为 w、高度为 h、深度为 3 的输入的输出将是宽度为 w/2、高度为 h/2、深度为 1 的上限,因为内核从每个步幅输出单个求和输出。

例如,对于 3×64×64 的输入(例如 64×64 的 RGB 三通道图像),一个内核采取两个步长并填充边缘像素,将产生 32×32 的通道/特征图。

许多内核

在 CNN 模型中,通常有三个以上的卷积核,一个卷积层中有 16 个甚至 64 个核是常见的。

这些不同的卷积核各自充当不同的滤波器,创建代表不同事物的通道/特征图。例如,内核可以过滤顶部边缘、底部边缘、对角线等等。在更深层次的网络中,这些内核可以过滤动物的特征,如眼睛或鸟的翅膀。

卷积核的数量越多,通道/特征图的数量就越多,数据量也越大,这就需要更多的内存。根据上述示例,步长 2 卷积有助于减少内存使用,因为步长 2 卷积的输出通道的宽度和高度是输入通道的一半。这假设使用了反射填充,否则它可能会稍微小一些。

stride 2 的几个卷积层的示例

对于具有三个通道和 16 个 3x3x3 内核的 64 像素方形输入,我们的卷积层将具有:

输入:64×64×3
卷积核:16×3×3×3(四维张量)
卷积核的输出/激活:16×32×32(16 个通道/32×32 的特征图)

网络然后可以应用批量标准化来减少学习时间和减少过度拟合,更多细节如下。此外,通常应用诸如 RELU 的非线性激活函数,以允许网络更好地逼近,下面有更多细节。

通常有几层 stride 2 卷积,创建越来越多的通道/特征图。以上一层的例子为例:

输入 : 16x32x32
卷积核 : 64x3x3x3
卷积核的输出/激活 : 64x16x16 (64 通道 16x16 的特征图)

然后,在应用 ReLU 和批量标准化(见下文)之后,应用另一个跨距 2 卷积:

输入:64×16×16
卷积核:128×3×3×3
卷积核的输出/激活:128×8×8(8×8 的 128 通道/特征图)。

分类

例如,如果一幅图像属于 42 个类别中的一个,并且网络的目标是预测该图像属于哪个类别。

根据上述输出为 128×8×8 的例子,首先取秩 3 张量的平均池。平均池是每个通道的平均,在这个例子中,每个 8×8 矩阵被平均成一个数字,具有 128 个通道/特征图。这创建了 128 个数字,一个大小为 1x128 的向量。

下一层是 128×42 权重的矩阵或秩 2 张量。输入的 1×128 矩阵乘以 128×42 矩阵(点积),产生 1×42 向量。42 个网格单元/向量元素中的每一个的激活程度是预测与该向量元素所代表的分类的匹配程度。Softmax 作为激活函数应用,然后 argmax 选择元素最高值。

整流线性单元

整流线性单元被用作非线性激活函数。一个 ReLU 表示如果值小于零,就向上舍入到零。

标准化

标准化是减去平均值并除以标准差的过程。它将数据的范围转换为-1 和 1 之间,使数据使用相同的比例,有时称为最小-最大比例。

通常对输入特征进行归一化,通过移除平均值和缩放至单位方差来标准化数据。输入要素以零为中心并且具有相同数量级的方差通常很重要。

对于一些数据,如图像,数据被缩放,使其范围在 0 和 1 之间,最简单的是将像素值除以 255。

这也允许训练过程更快地找到最佳参数。

批量标准化

批量规格化的好处在于,有助于使网络输出更稳定的预测,通过规格化减少过度拟合,并将训练速度提高一个数量级。

批次标准化是在当前批次的范围激活层内进行标准化的过程,减去批次激活的平均值并除以批次激活的标准偏差。

这是必要的,因为即使在标准化输入之后,由于一些激活可能更高,这可能导致后续层行为异常并使网络更不稳定。

由于批量归一化已经缩放并移动了激活输出,下一层中的权重将不再是最优的。随机梯度下降(SGD)将取消标准化,因为它将最小化损失函数。

为了防止这种效应,可以向每层添加两个可训练参数,以允许 SGD 对输出进行反规格化。这些参数是平均参数“β”和标准偏差参数“γ”。批量归一化为每个激活输出设置这两个权重,以允许归一化被反转来获得原始输入,这通过避免必须更新其他权重来避免影响网络的稳定性。

为什么 CNN 如此强大

简单来说,一个足够大的 CNN 可以解决任何可以解决的问题。

在许多不同的图像处理任务中表现出色的著名 CNN 架构有 VGG 模型(K. Simonyan 和 A. Zisserman)、ResNet 模型(明凯何等人)和谷歌盗梦空间模型(克里斯蒂安塞格迪等人)。这些模型有数百万个可训练的参数。

VGG-16 Network Architecture. Source: https://neurohive.io/wp-content/uploads/2018/11/vgg16-1-e1542731207177.png

通用逼近定理

通用逼近定理本质上陈述了如果一个问题可以被解决,那么它可以通过深度神经网络来解决,给定足够的仿射函数层与非线性函数层。本质上,一堆线性函数后跟非线性函数可以解决任何可以解决的问题。

实际上,在实施中,这可以是许多矩阵乘法,足够大的矩阵后接 RELU,堆叠在一起,这些具有数学属性,能够以任意高的精度求解任意复杂的数学函数,假设您有时间和资源来训练它。

这是否会给神经网络理解是一个有争议的话题,特别是由认知科学家。论点是,无论你对一个问题的语法和语义理解得多好,你永远也不会理解它。这基本上是塞尔的中国房间论点的基础。有些人会说,如果你能很好地逼近问题的解决方案,与理解问题没有区别,这有什么关系吗?

Fastai 课程

我要感谢 Fastai 团队,他们的课程帮助巩固了我的深度学习和 CNN 知识,为进一步学习和理解提供了一个极好的起点。

降维引论

原文:https://towardsdatascience.com/an-introduction-to-dimenstionality-reduction-8c7d1c80737d?source=collection_archive---------10-----------------------

降维如何使您的数据集更易于管理

高维数据集是所有数据科学中最大的挑战之一。挑战很简单。机器学习算法要求数据集是密集的,以便做出准确的预测。随着维度越来越多,数据空间变得极其庞大。巨大的数据空间需要极大的数据集来维持密度。这一挑战可能会导致模型预测不准确(例如,我描述了 k-nearest neighbors 算法如何在 k -Nearest Neighbors 和维数灾难中的高维数据空间中变得无用),或者数据集太大,计算机无法合理处理。

幸运的是,数据科学家已经找到了解决这个问题的方法。这叫降维。降维的本质很简单:你搜索数据集,寻找暗示数据集沿着不同于你最初假设的维度运行的趋势,然后你相应地转换你的数据。通过这种方式,您可以减少数据集中的维数。

降维是如何工作的?

降维的工作原理是识别数据集中真正重要的维度。一旦确定了真正重要的维度,您就可以转换数据集,以便沿着这些维度而不是最初显示的维度来表示这些点。

让我们用一个例子来讨论这个问题。在 k-最近邻居和维度的诅咒中,我给出了一个有点半开玩笑的花园侏儒分界线的例子。在这个例子中,假设你正在研究一个城市中花园侏儒的位置,并绘制它们。你首先确定城市中每个花园侏儒的纬度和经度,然后将它们绘制成二维图表。这两个维度是南北向和东西向,以距离城市中心的英里数表示。这是一种非常合理的呈现数据的方式,并且只有两个维度就足够了。

然而,假装你是一个完美主义者,希望用尽可能少的维度来呈现数据。你还会注意到,出于某种奇怪的原因,花园侏儒们从城市的东北角到城市的西南角形成了一条近乎完美的直线。数据集不是花园 gnome 位置的云,而是一条线。注意到这一点,你意识到你可以根据东北-西南方向离市中心的距离来绘制每个花园侏儒的位置。这种表示只需要一维。

下一步是执行转换。你需要沿着新的轴计算每个点离城市中心的距离,并声明你的新数据集。新的距离可以用代数方法计算。完成后,可以绘制出最终的剖面图,以一维方式显示您的数据集。

这个过程是什么样的?

我们将使用前面的花园 Gnome 分界线的例子来完成这个过程。我将使用 pandas 和 numpy 的功能,用 python 来完成所有这些工作。关于如何使用这些工具的详细说明,我强烈推荐阅读 Wes McKinney 的 Python for Data Analysis(韦斯是熊猫的创造者,所以你可以打赌他知道他在说什么。我将使用 python 包 bokeh 生成图。关于这个包的有用介绍可以在用散景进行数据可视化的实践中找到。

我在一个名为 GardenGnomeLocations 的熊猫数据框架中构建了我的数据集。它有一个包含 31 个条目的索引,以及代表每个花园侏儒在南北轴和东西轴上的位置的列。这些列被命名为“南北(mi)”和“东西(mi)”。

图 1 展示了原始数据集,显示了城市中每个花园侏儒沿南北和东西轴的位置。每个圆圈代表一个花园侏儒相对于市中心的位置。请注意数据中呈现的上述趋势;出于某种神秘的原因,花园侏儒的位置是一条从城市东北角到城市西南角的直线。

Figure 1: Location of Each Garden Gnome in the City Using the North-South and East-West Axes

一旦注意到这种趋势,很明显花园侏儒的位置确实可以用一个单一的维度,一个单一的轴来呈现。我们可以利用这些知识创建一个新的轴,东北-西南轴(或者,我喜欢称之为花园侏儒分界线)。然后,数据可以在一个维度上显示,即沿该轴到市中心的距离。

为了执行这种转换,我们在每个数据点上使用勾股定理。为了计算每个花园侏儒沿新轴到市中心的距离,我们需要使用 for 循环、pandas.loc 函数、math.sqrt 函数和一些代数表达式。计算新距离并将其添加到数据框中的“距离(mi)”列的代码如下:

for i in GardenGnomeLocations.index: GardenGnomeLocations.loc[i, 'Distance (mi)'] =      math.sqrt(GardenGnomeLocations.loc[i, 'NorthSouth (mi)'] ** 2 + GardenGnomeLocations.loc[i, 'EastWest (mi)'] ** 2) if GardenGnomeLocations.loc[i, 'NorthSouth (mi)'] < 0: GardenGnomeLocations.loc[i, 'Distance (mi)'] = -1 * GardenGnomeLocations.loc[i, 'Distance (mi)']

代码块顶部的 for 循环告诉脚本对 GardenGnomeLocations 数据帧中的每一行执行此计算,并使用变量 I 跟踪它在数据帧中的位置。第二行执行实际的计算,并将数据存储在 dataframe 中的适当位置。您会注意到,这个等式归结为 c = sqrt(a + b),这是勾股定理的常见形式。第一个术语 GardenGnomeLocations.loc[i,' Distance (mi)']告诉 python 我们将要计算的值应该放在 GardenGnomeLocations 数据帧中' Distance (mi)'列的第 I 行。等式的另一边使用“南北(mi)”和“东西(mi)”列中的相应数据来计算结果。请记住,勾股定理只会返回距离的绝对值。为了克服这一点,我们添加了最后两行代码。第一个确定原始数据点的值是正还是负。如果原始值为负,则第二个函数将距离乘以-1,使其为负。

绘制这些数据的结果如图 2 所示。数据看起来非常相似,因为这个图是二维的,但是注意这里的轴。图 2 显示了每个侏儒的位置,而不是用南北轴和东西轴来表示,而是用离市中心的距离来表示。在一维空间。

Figure 2: Location of Each Garden Gnome in the City Using the Distance

这种缩减到一个维度的做法使得数据集更容易使用。需要更少的点来确保数据集足够密集以返回准确的预测。更少的数据点意味着相同质量结果的计算时间减少。一些算法,如 k-最近邻算法,比使用更高的维度更有可能返回有用的结果。

然而,这种转变确实增加了解释数据的难度。最初,数据很容易理解;每个数据点都用我们常用的术语表示花园侏儒的位置。我们可以确定南北距离,东西距离,并简单的使用。现在,我们离市中心有一段距离,但数据并没有明确指出方向。为了理解这些数据,我们必须保留所有先前的数据集和算法。通过这种方式,我们可以在以后将新轴的数据转换回原始轴,这样就可以很容易地理解和使用它。

真的这么简单吗?

不幸的是,没有。事情没那么简单。这是一个过于简化、有些滑稽的例子,旨在演示基本概念。在现实中,没有一个数据集会像这个数据集那样沿着一条完美的直线运行,也不可能简单地使用勾股定理来转换数据。真实的数据集看起来更像隐藏着模糊趋势的数据云,您需要使用一种称为主成分分析的技术来转换数据。这项技术超出了这篇介绍性文章的范围,但是乔尔·格罗出色地演示了如何从零开始在数据科学中实现它。

包装它

高维数据集给数据科学家带来了严峻的挑战。随着维度数量的增加,数据空间也在增加。随着越来越多维度的加入,空间变得异常巨大。这种巨大的空间使得大多数机器学习算法很难发挥作用,因为数据集中的差距呈现出模型无法匹配的区域。一些算法,如k-最近邻算法,特别敏感,因为它们要求数据点在每个维度的T5 接近,这在有多个维度时变得非常罕见。

维度问题的明显解决方案是更大的数据集。这可以用来保持数据密度;然而,非常大的数据空间需要非常大的数据集。这些数据集可能会变得太大,超过计算机执行必要计算的能力。在这种情况下,解决方案是应用降维。

降维是指注意到数据点与最初使用的数据点沿不同的轴对齐,并转换数据集以沿这些轴呈现它们。我们用遍布整个城市的花园侏儒的例子来证明这一点。最初,它们被绘制在直观的南北轴和东西轴上。然而,在检查了这些数据后,很明显它们是沿着一条从城市东北角到西南角的独立轴线排列的。翻译数据集相应地将数据集从一维减少到二维。虽然这是一个小例子,但原理可以应用于更大的数据集。

数据科学家的离散化技术介绍

原文:https://towardsdatascience.com/an-introduction-to-discretization-in-data-science-55ef8c9775a2?source=collection_archive---------5-----------------------

Photo by Kevin Ku from Pexels

特征工程:要学习的 4 种离散化技术。

离散化是我们将连续变量、模型或函数转换成离散形式的过程。我们通过创建一组连续的区间(或箱)来做到这一点,这些区间跨越了我们期望的变量/模型/函数的范围。

连续数据 测得的, 离散数据**是算出的。

|| I ||为什么离散化很重要

有连续数据的数学问题有无穷多个自由度。由于我们的计算不可能永远进行下去,所以这样的问题必然要求有限的自由度。出于多种原因,数据科学家需要使用离散化。Kaggle 上的许多顶级贡献使用离散化,原因如下:

Photo by Ryoji Iwata on Unsplash

符合问题陈述

通常,将连续数据(如体重)划分并存储到有意义的类别或组中会更容易理解。比如我们可以把一个连续变量,体重,分成以下几组来存储:
100 磅以下 (轻),140–160 磅之间 (中),200 磅以上 (重)

如果我们看不到属于同一权重类别的变量之间的客观差异,我们将认为该结构是有用的。
在我们的例子中,85 磅
和 56 磅的重量传达了相同的信息(物体很轻)。因此,如果数据符合问题陈述,离散化有助于使我们的数据更容易理解。

Photo by William Daigneault on Unsplash

解释特征

由于具有无限的自由度,连续特征与目标变量关联的机会较小,并且可能具有复杂的非线性关系。因此,可能更难解释这样的函数。在离散化变量之后,可以解释对应于目标的组。

Photo by Franck V. on Unsplash

与模型/方法不兼容

某些模型可能与连续数据不兼容,例如,替代决策树模型(如随机森林模型)不适合连续特征。

特征工程方法,例如任何基于熵的方法可能无法处理连续数据,因此我们将离散化变量以处理不同的模型和方法。

Photo by Mariano Werneck on Unsplash

信噪比

当我们离散化一个模型时,我们将它拟合到箱中,并减少数据中小波动的影响。通常,我们会将微小的波动视为噪声。我们可以通过离散化来减少这种噪声。这是“平滑”的过程,其中每个箱平滑波动,从而减少数据中的噪声。

|| II ||离散化方法

  • 无监督:
    —等宽
    —等频
    — K 均值
  • 监督:
    —决策树

|| III ||等宽离散化

将所有可能的值分成“ N 个仓,每个仓具有相同的宽度。间隔宽度的公式:

*Width =(最大值-最小值)/ N 其中 N 是仓或区间的数量。

在 python 上,您可能希望导入以下内容进行离散化:

*from sklearn.preprocessing import KBinsDiscretizer
from feature_engine.discretisers import EqualWidthDiscretiser*

按照以下方式设置等宽离散化器:

*discretizer = EqualWidthDiscretiser(bins=10, variables = ['var1', 'var2'])#OR discretizer = KBinsDiscretizer(n_bins=10, encode='ordinal', strategy='uniform')*
  • 相等的宽度不会改善值的分布
  • 它可以处理异常值
  • 可以与分类编码结合使用

|| IV ||等频离散化

将所有可能的值分成数量为“ N 的箱,每个箱具有相同数量的观察值。区间可以对应于分位数值。

在 python 上,您可能希望导入以下内容进行离散化:

*from sklearn.preprocessing import KBinsDiscretizer
from feature_engine.discretisers import EqualFrequencyDiscretiser*

按照以下方式设置等频离散化器:

*discretizer = KBinsDiscretizer(n_bins=10, encode='ordinal', strategy='quantile')#OR discretizer = EqualFrequencyDiscretiser(q=10, variables = ['var1', 'var2'])*
  • 相等的频率确实提高了值的分布
  • 它可以处理异常值
  • 可以与分类编码结合使用

| | V | | K-均值离散化

我们将 K 均值聚类应用于连续变量,从而将其划分为离散的组或聚类。

在 python 上,您可能希望导入以下内容以使用 K-means 进行离散化:

*from sklearn.preprocessing import KBinsDiscretizer*

按照以下方式设置 K 均值离散化器:

*discretizer = KBinsDiscretizer(n_bins=5, encode='ordinal', strategy='kmeans')*
  • K-Means 并不能提高价值传播
  • 它可以处理异常值,但是可能存在质心偏差。
  • 可以与分类编码结合使用

|| VI ||决策树离散化

我们使用决策树来确定箱的最佳数量。当模型做出决定时,它为每个节点分配一个观察值。然后,这些观察结果被分类为变量的离散输出。

在 python 上,您可能希望导入以下内容以使用决策树进行离散化:

*from sklearn.model_selection import train_test_split
from feature_engine.discretisers import DecisionTreeDiscretiser*

您的离散化器应按以下方式设置:

*# cross-validation number (cv)
# how to evaluate model performance (scoring)
# the variables we want to discretise (variables)
# whether it is a target for regression or classification
# and the grid with the parameters we want to testtreeDisc = DecisionTreeDiscretiser(cv=10, scoring='accuracy',
                                   variables=['var1', 'var2'],
                                   regression=False,
                                   param_grid={'max_depth': [1,2,3],
'min_samples_leaf':[10,4]})*
  • 决策树不能提高价值分布
  • 它可以很好地处理异常值,因为树对于异常值是健壮的。
  • 创建单调的关系

|| VII ||下一步

离散化变量后,您可以执行以下任一操作:

  • 构建决策树算法并直接使用离散化的输出作为箱的数量。决策树可以发现离散化变量和目标变量之间的非线性关系。
  • 使用线性模型,而箱与目标变量没有线性关系。通过将箱子视为具有某种编码的类别来改进模型。

感谢你的阅读!

关注我,了解更多关于数据科学的内容。

梯度下降导论

原文:https://towardsdatascience.com/an-introduction-to-gradient-descent-c9cca5739307?source=collection_archive---------6-----------------------

机器学习和深度学习之旅

从理论到实践,在数据集上实现批量梯度下降、小批量梯度下降和随机梯度下降

本博客将涵盖以下问题和主题:

1.什么是渐变?

2.什么是梯度下降?

3.三种常见的梯度下降

4.用 Python 实现

1。梯度

梯度是一个向量,它与一个函数相切,并指向该函数最大增长的方向。梯度在局部最大值或最小值处为零,因为没有单一的增加方向。在数学中,梯度被定义为函数的每个输入变量的偏导数。例如,我们有一个函数:

函数的图形如下所示,我们可以看到函数的最小值是(0,0)。

在这种情况下,梯度的 x 分量是相对于 x 的偏导数,梯度的 y 分量是相对于 y 的偏导数。上述函数的梯度为:

如果我们想找到在点(1,2)处增加函数最多的方向,我们可以将(1,2)代入上面的公式,得到:

2。梯度下降

由于梯度是指向函数最大增量的向量,负梯度是指向函数最大减量的向量。因此,我们可以通过向负梯度方向迭代移动一点来最小化一个函数。这就是梯度下降的逻辑。

给定一个起点:

我们可以构建一个迭代过程:

上式中的参数α被称为学习率,它在大多数情况下是一个小常数,范围从 0 到 1。迭代过程不会停止,直到它收敛。以前面的例子为例,我们已经知道梯度是:

因此,梯度下降的迭代过程可以写成:

那么我们可以得到:

最后,假设α小于 1,那么我们可以得到:

结论与我们在上图中观察到的一样。

解释梯度下降的另一种直观方式是在函数的上下文中考虑下面的三维图形。我们的目标是从右上角的山移动到左下角的深蓝色的海。箭头代表从任何给定点开始的最陡下降方向(负梯度)——尽可能快地降低函数的方向。”[3]

Image Source: https://ml-cheatsheet.readthedocs.io/en/latest/gradient_descent.html

在机器学习中,我们更关注代价函数和参数之间的关系,而不是因变量和自变量。机器学习中梯度下降的一般思想是迭代地调整参数,以便最小化成本函数。

Image Source: https://saugatbhattarai.com.np/what-is-gradient-descent-in-machine-learning/

在某些情况下,我们可以应用封闭形式的方程来直接计算最适合模型训练数据集的参数。例如,为了最小化线性回归的 MSE,参数可以写成:

然而,在其他情况下,我们没有封闭形式的方程,如逻辑回归。因此,应用类似梯度下降的迭代优化方法。

梯度下降中的一个重要参数是学习率,它决定了每一步的大小。当学习率太大时,梯度下降可能会跳过山谷,到达另一边。这将导致成本函数发散。另一方面,当学习率太小时,算法需要很长时间才能收敛。因此,在梯度下降开始之前,需要适当的学习速率。

Image Source: https://towardsdatascience.com/gradient-descent-in-a-nutshell-eaf8c18212f0

归一化对梯度下降起着重要作用。如果特征没有被归一化,则具有大规模的特征将在更新中占主导地位,因此该算法将生成之字形学习路径。要达到最小值需要很多不必要的步骤和更长的时间。在所有特征被归一化之后,成本函数是更接近球形的形状。梯度下降算法直接走向最小值。执行标准化的一种方法是减去平均值并除以标准偏差。也可以直接在 Scikit-Learn 中应用 StandardScaler 函数。

Image Source: https://www.jeremyjordan.me/batch-normalization/

3。三种典型的梯度下降

我们将研究在机器学习中广泛使用的梯度下降的几种变体:批量梯度下降、小批量梯度下降和随机梯度下降。

批量梯度下降

批量梯度下降在每一步都使用整批训练数据。它计算每条记录的误差,并取平均值来确定梯度。分批梯度下降法的优点是计算效率更高,产生稳定的学习路径,更容易收敛。但是,当训练集很大时,批量梯度下降需要更长的时间。

随机梯度下降

在另一种极端情况下,随机梯度下降法在每一步只从训练集中选取一个实例,并只根据该单个记录更新梯度。随机梯度下降的优点是算法在每次迭代时都快得多,这弥补了批量梯度下降的局限性。然而,与批量梯度下降相比,该算法产生的学习路径不太规则和稳定。成本函数不是平滑递减,而是上下跳动。经过多轮迭代后,算法可能会找到一个好的参数,但最终结果不一定是全局最优的。

小批量梯度下降

小批量梯度下降结合了批量和随机梯度下降的概念。在每一步,该算法基于训练集的子集而不是完整数据集或仅一个记录来计算梯度。小批量梯度下降法的优点是算法在计算过程中可以利用矩阵运算,并且代价函数比随机梯度下降法下降得更平稳。

Image Source: https://towardsdatascience.com/gradient-descent-algorithm-and-its-variants-10f652806a3

4。用 Python 实现

在这一部分中,我将使用著名的数据集 iris 来展示梯度体面如何在逻辑回归中工作。

首先,导入包。

*from sklearn import datasets
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.lines as mlines*

接下来,加载数据。注意,为了简单起见,我只选择 2 种虹膜。

# Load data
iris = datasets.load_iris()
X=iris.data[0:99,:2]
y=iris.target[0:99]# Plot the training points
x_min, x_max = X[:, 0].min() - .5, X[:, 0].max() + .5
y_min, y_max = X[:, 1].min() - .5, X[:, 1].max() + .5plt.figure(2, figsize=(8, 6))
plt.clf()plt.scatter(X[:, 0], X[:, 1], c=y, cmap=plt.cm.Set1,edgecolor='k')
plt.xlabel('Sepal length')
plt.ylabel('Sepal width')
plt.xlim(x_min, x_max)
plt.ylim(y_min, y_max)

批量梯度下降

# Function for batch gradient decent    
def Batch_GD (Learning_Rate,num_iterations,X,y):
    #Step 1: Initial Parameter
    N=len(X)
    w=np.zeros((X.shape[1],1))
    b=0
    costs=[]
    # Starting Loop
    for i in range(num_iterations):
        #Step 2: Apply Sigmoid Function and get y prediction
        Z=np.dot(w.T,X.T)+b
        y_pred=1/(1+1/np.exp(Z))

        #Step 3: Calculate Loss Function
        cost=-(1/N)*np.sum(y*np.log(y_pred)+(1-y)*np.log(1-y_pred))

        #Step 4: Calculate Gradient
        dw=1/N*np.dot(X.T,(y_pred-y).T)
        db=1/N*np.sum(y_pred-y)

        #Step 5: Update w & b
        w = w - Learning_Rate * dw
        b = b - Learning_Rate * db

        # Records cost
        if i % 1000 == 0:
            costs.append(cost)
            #print(cost)
    return(w,b,costs)# Run a function
Result_BatchGD=Batch_GD(Learning_Rate=0.01,num_iterations=100000,X=X,y=y)

随机梯度下降

# Function for Stochastic Gradient Descent       
def Stochastic_GD (Learning_Rate,num_iterations,X,y):
    # Step 1: Initial Parameter
    N=len(X)
    w=np.zeros((X.shape[1],1))
    b=0
    costs=[]
    # Starting two layer of loops
    for i in range(num_iterations):
        for j in range(N):
            # Choose 1 record
            XX=X[j,:]
            yy=y[j]
            # Step 2: Apply Sigmoid Function and get y prediction
            Z=np.dot(w.T,XX.T)+b
            y_pred=1/(1+1/np.exp(Z))
            #Step 3: Calculate Loss Function
            cost=-(yy*np.log(y_pred)+(1-yy)*np.log(1-y_pred))
            #Step 4: Calculate Gradient
            dw=np.multiply(XX,(y_pred-yy)).reshape((2,1))
            db=y_pred-yy
            #Step 5: Update w & b
            w = w - Learning_Rate * dw
            b = b - Learning_Rate * db

        #Step 6: Calculate Loss Function       
        Z_full=np.dot(w.T,X.T)+b
        y_pred_full=1/(1+1/np.exp(Z_full))
        cost=-(1/N)*np.sum(y*np.log(y_pred_full)+(1-y)*np.log(1-y_pred_full))
        #Records cost
        if i % 100 == 0:
            costs.append(cost)
            #print(cost)

    return(w,b,costs)# Run a function
Result_Stoc_GD=Stochastic_GD(Learning_Rate=0.01,num_iterations=2000,X=X,y=y)

小批量梯度下降

# Function for mini batch Gradient Descent
def Minibatch_GD (Learning_Rate,num_iterations,X,y,Minibatch):
    # Part 1: Mini Batch 
    np.random.seed(1000)
    N=len(X)
    mini_batches=[]

    #Step 1: Shuffle (X,y)
    permutation=list(np.random.permutation(N))
    shuffled_X=X[permutation,:]
    shuffled_y=y[permutation]

    #Step 2: Partition
    num_complete_minibatches=int(np.floor(N/Minibatch))

    for i in range(num_complete_minibatches):
        mini_batch_X=shuffled_X[i*Minibatch:(i+1)*Minibatch,:]
        mini_batch_y=shuffled_y[i*Minibatch:(i+1)*Minibatch]

        mini_batch = (mini_batch_X, mini_batch_y)
        mini_batches.append(mini_batch)

    if N % Minibatch !=0:
        mini_batch_X=shuffled_X[N-Minibatch:N,:]
        mini_batch_y=shuffled_y[N-Minibatch:N]

        mini_batch = (mini_batch_X, mini_batch_y)
        mini_batches.append(mini_batch)

    # Part 2: Gradient Descent
    w=np.zeros((X.shape[1],1))
    b=0
    costs=[]

    for i in range(num_iterations):
        for j in range(num_complete_minibatches+1):
            #Select Minibatch
            XX=mini_batches[j][0]
            yy=mini_batches[j][1]
            #Step 2: Apply Sigmoid Function and get y prediction
            Z=np.dot(w.T,XX.T)+b
            y_pred=1/(1+1/np.exp(Z))

            #Step 3: Calculate Gradient
            dw=1/Minibatch*np.dot(XX.T,(y_pred-yy).T)
            db=1/Minibatch*np.sum(y_pred-yy)
            #Step 4: Update w & b
            w = w - Learning_Rate * dw
            b = b - Learning_Rate * db

        #Step 5: Calculate Loss Function       
        Z_full=np.dot(w.T,X.T)+b
        y_pred_full=1/(1+1/np.exp(Z_full))
        cost=-(1/N)*np.sum(y*np.log(y_pred_full)+(1-y)*np.log(1-y_pred_full))

        if i % 1000 ==0:
            costs.append(cost)
            #print(cost)

    return(w,b,costs)# Run a function
Result_MiniGD=Minibatch_GD(Learning_Rate=0.01,num_iterations=100000,X=X,y=y,Minibatch=50)

可视化结果

# Plot linear classification
fig, ax = plt.subplots()
ax.scatter(X[:, 0], X[:, 1], c=y, cmap=plt.cm.Set1,edgecolor='k')
line_B_GD=mlines.Line2D([0,7],[-0.5527,4.1577],color='red')
line_Mini_GD=mlines.Line2D([0,7],[-0.56185,4.1674],color='blue')
line_Sto_GD=mlines.Line2D([0,7],[-0.5488,4.1828],color='green')
ax.add_line(line_B_GD)
ax.add_line(line_Mini_GD)
ax.add_line(line_Sto_GD)
ax.set_xlabel('Sepal length')
plt.show()

从上图可以看出,三种梯度下降产生了相似的线性决策边界。

总结

在这篇文章中,你学到了很多关于梯度下降的知识。你现在知道了梯度背后的基本数学,并且理解了算法是如何在幕后工作的。第二,你了解了为什么学习速率和规范化对算法的成功如此重要。最后,您了解了最常见的梯度下降类型以及如何在 python 中实现这些算法。这些知识使你能够更好地理解机器学习和深度学习。你可以点击以下链接阅读更多博客:

[## 机器学习和深度学习之旅

这一系列博客将从理论和实现两个方面对深度学习进行介绍。

medium.com](https://medium.com/@songyangdetang_41589/table-of-contents-689c8af0c731)

参考

[1] Aurélien Géron,使用 Scikit-Learn & TensorFlow 进行机器学习,2018 年

[2]伊恩·古德费勒,约舒阿·本吉奥,亚伦·库维尔,(2017) 深度学习

[3]https://ml-cheat sheet . readthedocs . io/en/latest/gradient _ descent . html

图形数据库简介

原文:https://towardsdatascience.com/an-introduction-to-graph-databases-cd81a0d5aa12?source=collection_archive---------11-----------------------

用 Neo4j 建模高度相关的数据

在过去的几年里,我们看到了数据库中新范例的激增。以前,以微软的 SQLServer 或 Oracles MySQL 为代表的关系数据库管理系统(RDBMS)一直是那些寻找数据库的人的事实上的路线。我谈到了这样做的原因,并在我的早期作品中看到了一些更新的或者重新发现的替代方案;在这篇文章中,我将深入探讨其中的一个,图形数据库,探索它们能做什么,并展示一些它们闪光的用例。

什么是图?

图形数据库,顾名思义,以图形的形式组织数据,基于图论的数学原理。从根本上说,我们可以把一个图看作是节点和边的集合。节点通常表示实体,边用于表示这些实体之间的关系。就数据库而言,这一点对我们非常有用,因为节点可以保存描述实体的数据,但是边也可以保存描述关系的性质和细节的数据。这些数据可能和关系类型一样简单,也可能更详细。

让我们看一个示例图,看看它是什么样子的。

A simple ‘movie’ graph

在这个图表中,我们可以看到我们描述了许多不同类型的实体。我们有“人”,他们有典型的属性,如姓名和性别,还有“电影”,他们有一个标题,上映日期和预算。这些在图中用气泡表示。

连接气泡给出图形结构的是边。这些描述了链接节点之间的关系;例如,我们可以看到由安东尼和约瑟夫·鲁索执导的《复仇者联盟 4:终局之战》,他还执导了《美国队长:冬日战士》,而最后一部由小罗伯特·唐尼主演。

图的一个重要方面是它们天生是弱模式化的,或者说是无模式的。这意味着久而久之,我们希望扩展图形以容纳不同类型的实体和数据,我们可以简单地创建描述它们的节点,而不破坏我们已经拥有的或必须对数据库进行复杂的模式更改。

例如,下图显示了用“字符”类型扩展的上述 MCU 图,以及“出现在”和“播放”关系。

Extended example MCU graph

现在我们有了数据和建模的关系,我们可以开始查看可以用来从图表中提取信息的查询类型。除了简单和常见的“查找所有导演”或“查找小罗伯特·唐尼主演的所有电影的总预算”之外,我们还可以基于关系计算更复杂的数据集。例如,我们可以很快找到所有由约瑟夫和安东尼·罗素执导、小罗伯特·唐尼出演钢铁侠的电影。显然,我们可以构建一个模式,允许我们在其他形式的数据库中做同样的事情,包括传统的 RDBMS 然而,当我们看 Neo4j 时,我们会看到它在图形数据库中既简单又快速。这些是典型的使用案例,其中图形数据库是一个很好的选择。

输入 Neo4j

eo4j 是卓越的图形数据库引擎,提供 ACID 事务和本地图形数据存储和处理。它既有免费使用的开源版本,也有商业企业许可版本。开源版本仅支持单节点,而企业版同时支持集群和热备份支持。两个版本都支持 Cypher 查询语言,该语言旨在使用“ASCII-art”风格的语法,使图形数据的存储和查询尽可能简单和合理。

在 Neo4j 中构建我们的 MCU 示例

首先,假设你有运行的 Neo4j,或者你正在使用他们提供的在线沙盒,我们需要创建我们的图表。我们有几个选择,我们可以通过使用一系列离散的 Cypher 操作(反映应用程序如何在数据库中创建数据)来创建数据,我们可以使用 Cypher 从 CSV 或 JSON 等文件中加载数据,或者我们可以使用 Neo4j 的内置 ETL 功能从 JDBC 连接的 RDBMS 中加载数据。

让我们快速地看一下 couple,首先使用文件导入来创建我们看到的第一个例子中显示的数据。

首先,我们需要 CSV 文件中的图表数据,你可以在我的 GitHub 中找到一组数据。我们可以从 GitHub 直接使用这些,使用下面的密码导入它们并构建我们的初始图。请注意,您需要单独运行每个命令。

首先,我们根据每种类型的 CSV 文件为人物和电影创建节点。然后,我们加载定义关系的 CSV,并通过匹配节点来创建合适的关系。最后,因为id字段只需要从非关系文件中构建关系,所以我们将它从节点中移除。这对于图数据库来说是一件关键的事情——因为关系是一等公民,我们不再需要担心 id 来创建外键了(耶!).

现在我们已经有了初始数据,让我们运行一些 Cypher 操作,将它扩展到第二个例子中显示的完整图形。首先,我们可以运行下面的代码来创建我们的第一个角色

CREATE (character:Character {name: "iron man"})

然后我们可以把他和一些关系联系起来:

MATCH (person:Person {name: "robert downey jnr"}), (character:Character {name: "iron man"}) CREATE (person)-[:played]->(character)

MATCH (character:Character {name: "iron man"}), (movie:Movie {name: "avengers endgame"}) CREATE (character)-[:appeared_in]->(movie)

一旦我们做到了这一点,我们就可以使用 Neo4j 的内置浏览器来查询图表,并检查我们有什么

A small part of the MCU in Neo4j

运行一些查询

现在我们已经构建了我们的图表,让我们来看看我们可以使用 Cypher 创建的一些查询来探索它。您可以在 Neo4j 提供的浏览器中直接运行这些来查看结果。

首先,让我们看看我们能找到什么关于复仇者联盟的结局

MATCH (m:Movie {name: "avengers endgame"}) RETURN m

这将返回图形中所有类型为 Movie、名称为“avengers endgame”的节点。在传统的 RDBMS 中,这很可能是一个SELECT * FROM t WHERE x = y风格的查询。

现在让我们看看更复杂的东西,让我们找到约瑟夫·罗素执导的所有电影

MATCH m=(p:Person {name: “joseph russo"})-[r:Directed]->() RETURN m

该查询将返回美国队长冬季士兵和复仇者联盟 Engame。同样,我们可以在 RDBMS 中使用带有外键的三个表来建模,然后创建一个 Select 语句来连接它们。然而,就性能而言,这些类型的查询是 Neo4j 优于关系数据库的地方;由于 Neo4j 将关系有效地存储为指针,因此与 RDBMS 采用的连接算法相比,跟随它们是一个微不足道的操作。语法通常也比由多种类型的连接组成的 SQL 语句更明显,我们不必担心外键

让我们用这个理论来运行一个更复杂的查询,更深入地研究人和电影之间的关系。下面的代码返回了我们的图表摘录,显示了由 Joseph Russo 导演并由小罗伯特·唐尼主演的电影

MATCH m=(director:Person {name: “joseph russo"})-[r.Directed]->(movie:Movie)<-[a:ActedIn]-(actor:Person {name: "robert downey jnr"}) RETURN director, movie, actor

正如您所看到的,我们现在正在基于关系构建非常复杂的查询,同样没有复杂的连接或外键。

如果我们想要执行聚合,例如查找上面返回的电影的总预算,我们稍微修改一下查询,如下所示

MATCH m=(director:Person {name: “joseph russo"})-[r.Directed]->(movie:Movie)<-[a:ActedIn]-(actor:Person {name: "robert downey jnr"}) RETURN SUM(movie.budget)

更复杂的关系

到目前为止,我们已经看到了非常简单的关系,它们仅仅定义了关系的性质。Neo4j 允许我们更进一步,向关系中添加数据;我们将构建一个新的图形来映射 MCU 中的战斗,看看这是如何工作的。

A whole mess of characters fighting each other

我们上面的新图描绘了一些 MCU 英雄和恶棍,以及他们在三部电影中史诗般的电影大战。节点代表角色,并且有一种类型表示他们是“英雄”还是“恶棍”,关系显示这些角色在哪里互相争斗。在这个例子中,打架关系还包括附加数据来表示打架发生在哪部电影中。鉴于 MCU 中的 smack downs 数量,这已经是一个非常复杂的图形,但我们可以使用 Cypher 开始解码。

首先,让我们使用这些额外的数据来查找在《复仇者联盟:无限战争》中与灭霸战斗的每个人的名字

MATCH (hero:Character)-[:fought {film: "avengers infinity war"}]->(villain:Character {name: "thanos"}) RETURN hero.name

如果我们运行这个,我们会得到四个名字:钢铁侠,美国队长,视觉和黑寡妇。让我们现在找出谁在游戏中与灭霸战斗,而不是在无限战争中

Match (hero:Character)-[:fought {film: "avengers infinity war"}]->(villain:Character {name: "thanos"}), (hero2:Character)-[:fought {film: "avengers endgame"]->(villain:Character {name:"thanos"}) WITH COLLECT (distinct hero.name) AS AIWheros, COLLECT (distinct hero2.name) as AEheros RETURN [x in AEheros WHERE NOT (x in AIWheros)]

运行这个,我们会发现蚁人只在最后阶段与灭霸战斗过。我们通过使用与之前基本相同的查询在《无限战争》和《残局》电影中构建一个英雄集合,然后返回他们的交集来计算。

通过在我们的关系上添加元数据,我们可以使用 Chypher 开始理解高度复杂的图形。

结论

我们从看一点图论开始,以及它如何驱动一类我们可以在我们的解决方案中使用的 NoSQL 数据库。

然后我们看了一下 Neo4j,我们如何使用它来创建数据图表,然后构建查询来从数据中获取信息和意义,尤其是关系。

我们已经看到,对于某些类型的问题,图数据库是一个非常强大的工具,虽然我们可以用更传统的数据库引擎来解决它们,但图数据库提供了一个更加优化的解决方案。

图论导论

原文:https://towardsdatascience.com/an-introduction-to-graph-theory-24b41746fabe?source=collection_archive---------35-----------------------

在深入图论之前,我们需要理解机器学习中的数据结构和网络。网络是一种有用的数据结构,用于映射从驾驶方向到社交网络的一系列应用。

网络是另一种表示数据的方式,你还没有完全调查。简单地说,它们包含由边(线)连接的节点(圆)。

节点代表一个对象,这些对象之间的关系是它们之间的边。

分析

我们首先要分析网络路径搜索算法。寻找两个节点之间的最短路径是创建距离度量的基本概念,然后可以使用该距离度量进行更高级的分析。将欧几里得距离和 KNN 视为距离度量。绘制节点和边的示例可以是地图应用程序,如谷歌地图、苹果地图、Waze 或优步,它们也是路径搜索算法的自然应用程序。这些应用程序通常希望找到从 A 到 b 的最短距离。

找到路径后,我们要研究节点和边的属性。中心性是一个关键概念,它有助于确定哪些节点对网络最有影响力,或者在连接网络中占据关键位置。

集团和聚类是在你的个体中心性分析完成后,研究更大的结构。您将使用集团和集群的概念来将网络细分为更小的组。这种方法的自然应用包括将社交网络分组或对语言/书籍等项目进行分类。

结果

您不仅能够识别行业趋势或产品中的客户受欢迎程度,绘图还可以用于推动推荐系统!通过您的分析,您可以发现客户之间的趋势和购买相似性,然后您可以建立一个推荐器来提高购买力。我可以是人口统计学上的或者行为学上的。了解这一点,你就能有效地向客户推荐产品。

这里有一些例子

1。映射

2。社会网络分析(SNA)是通过使用网络和图论来调查社会结构的过程

3。互联网网络

更多图片图论有助于理解:

https://towardsdatascience.com/graph-theory-132122ac38f2

JSON 简介

原文:https://towardsdatascience.com/an-introduction-to-json-c9acb464f43e?source=collection_archive---------8-----------------------

完全的初学者指南

Created by Katerina Limpitsouni

如果你对数据科学或软件工程或任何相关领域感兴趣,你可能会遇到“JSON”这个术语,如果你是新手,你可能会感到困惑。在这篇文章中,我将尝试在没有任何先验知识的情况下介绍 JSON,并用简单的例子解释 JSON 的概念。让我们开始吧。

JSON 是什么?

Created by Katerina Limpitsouni

JSON 代表 JavaScript 对象符号。不要被行话冲昏了头脑,理解和使用起来其实很简单。正如单词“notation”可能暗示的那样, JSON 只是一种独立于平台的表示数据的方式——这只是意味着它有点像数据的 PDF(在不同平台如移动、桌面和 web 上是一样的)。JSON 格式是由道格拉斯·克洛克福特指定的,文件扩展名是。json

因此,数据的 PDF 跨平台传输,并保持表示和存储的一致性。如今它被广泛使用,因此在数据科学和软件工程领域至关重要。

为什么是 JSON?

Created by Katerina Limpitsouni

JSON 听起来很酷,但背后的动机或目的是什么?

如上所述,JSON 独立于平台,是每天交换大量数据的计算机之间数据传输格式的主要选择之一。

JSON 的替代品是 XML(可扩展标记语言),但 JSON 在许多方面更好。虽然两者都是人类可读和机器可读的,但 JSON 更容易阅读,计算机处理起来也更快。此外,JSON 是用 JavaScript 解析器(内置于大多数 web 浏览器中)处理(或解析)的,而 XML 需要一个单独的 XML 解析器。这就是“JavaScirpt”在“JSON”中发挥作用的地方

你可以在这里和这里阅读更多关于的区别。

如何 JSON?

Created by Katerina Limpitsouni

在理解了什么是 JSON 及其背后的基本原理之后,现在可以开始编写一些 JSON 代码了。JSON 的语法与 JavaScript 非常相似,所以如果你以前有过 JavaScript 的经验,应该会很熟悉。

让我们通过一个例子来理解 JSON 的编写。假设你是你所在街区的领导,并且维护着一个所有人的数据库。考虑一个场景,当 Jodhn Appleseed 先生搬到你家附近时。您可能希望存储像他的名、姓、出生日期、婚姻状况等信息。这个就用 JSON 吧!

当你写 JSON 的时候,你本质上是一个撮合者!是的,真的!但你匹配的不是人,而是数据。在 JSON 中,数据存储为键-值对——每个数据项都有一个键,通过这个键可以修改、添加或删除数据项。

让我们从添加名字和姓氏开始:

{
    "first name":"John",
    "last name":"Appleseed"
}

正如您所注意到的,左列中的值是键(“名字”、“姓氏”),右列中的值是各自的值(“John”、“Appleseed”)。冒号将它们分开。用双引号括起来的值是字符串类型,这基本上意味着它们应该是文本,而不是引用其他内容(例如,数字、文件另一部分中的变量等)。).

注意,在 JSON 中,所有的键都必须是字符串,所以必须用双引号括起来。此外,除了最后一个键-值对,每个键-值对后面都有一个逗号,表示正在记录一个新项目。

现在,让我们加上他的年龄:

{
    "first name":"John",
    "last name":"Appleseed",
    "age":30
}

请注意,数字 30 没有双引号。直观地说,这种数据的数据类型是数,,因此你可以对它们进行数学运算(当你检索信息时)。在 JSON 中,这种数据类型(数字)可以采用任何数值——十进制、整数或任何其他类型。请注意,当我在“Appleseed”下面添加另一个项目时,我是如何在它后面添加一个逗号的。

让我们现在做一些有趣的事情。让我们试着添加他的房子,这将有它的地址,所有者信息和城市。但是我们如何为 John 将这些东西添加到 JSON 文件中呢?像所有者信息这样的东西是房子的属性,而不是 John 的属性,所以直接将这些信息添加到 John 的 JSON 文件中是没有意义的。不用担心,JSON 有一个有趣的数据类型来处理这个问题!

在 JSON 中,值也可以是对象(也是键值对)。这个对象就像另一个 JSON 文件——用花括号括起来,包含键值对,只是它在我们原始的 JSON 文件中,而不是有自己的文件。

{
    "first name" : "John",
    "last name" : "Appleseed",
    "age" : 30, 
    "house" : { 
            "address":{
                "house no":22,
                "street":"College Ave East",
                "city":"Singapore",
            },
            "owner":"John Appleseed"
            "market price($)":5000.00
    }
}

您可能注意到,房子是一个对象,它包含关键字地址所有者市场价格地址中的数据也是一个对象,包含关键字门牌号街道城市。因此,可以在对象中嵌套对象,这样可以更清晰地表示数据,如上所示。

现在,让我们添加他的朋友的信息。我们可以通过添加“朋友 1”和名字,“朋友 2”和名字等等来做到这一点,但是这很快就会变得很无聊。JSON 提供了一种有效存储这些信息的数据类型,称为数组。它是项目的有序集合,可以是任何数据类型。

假设他有三个朋友:查尔斯、马克和达伦。我们的 JSON 文件现在看起来像这样:

{
    "first name":"John",
    "last name":"Appleseed",
    "age":30, 
    "house" : { 
            "address":{
                "house no":22,
                "street":"College Ave East",
                "city":"Singapore",
            },
            "owner":"John Appleseed"
            "market price($)":5000.00
    },
    "friends":[
        "Charles",
        "Mark",
        "Darren"
     ]
}

请注意,数组用方括号括起来,除了最后一项,我们将每一项都写在一个新行中,后跟一个逗号。新的一行不是必需的,但是它有助于提高代码的可读性。

最后,让我们加上他的婚姻状况。我们可以做类似于"married":"yes"的事情,但是 JSON 为所有二分法选择提供了一种特殊的数据类型:布尔值。它只能有两个值:真或假。直觉上,不可能两者同时。假设约翰是个单身汉。让我们将这最后一条信息添加到我们的文件中!我们的文件现在看起来像这样:

Final JSON File for John Appleseed

并且,您已经熟悉了 JSON。在本文中,我们了解了 JSON 是什么,它为什么有用,以及如何使用 JSON。在此过程中,我们学习了 JSON 数据类型(字符串、数字、数组、对象和布尔)。

上面的文件是 GitHub 的要点,你可以点击这个链接来下载这个文件,并使用它,添加更多的信息或为新人制作 JSON 文件。你可以检查你的代码是否是有效的 JSON,也可以用这个工具格式化它。

我希望这篇文章能帮助您了解 JSON。回复这个故事,让我知道你的旅程如何。

逻辑回归导论

原文:https://towardsdatascience.com/an-introduction-to-logistic-regression-8136ad65da2e?source=collection_archive---------10-----------------------

机器学习和深度学习之旅

逻辑回归从理论到实践的深度探讨

本博客将涵盖五个主题和问题:

1.什么是逻辑回归?

2.为什么不用线性回归?

3.最大似然估计

4.逻辑回归的梯度下降

5.用 Python 实现逻辑回归

  1. 什么是逻辑回归?

Logistic 回归是一种传统而经典的统计模型,在学术界和工业界得到了广泛的应用。与用于预测数值响应的线性回归不同,逻辑回归用于解决分类问题。例如,当一个人向银行申请贷款时,银行感兴趣的是这个申请人将来是否会违约?(默认或非默认)

一种解决方案是直接对申请人的未来状态进行预测,如感知器,这是 SVM 和神经网络的基础。请阅读我在感知器上的博客:

[## 感知器算法简介

从理论到实践,学习感知机的基本原则,并在数据集上实现它与随机…

towardsdatascience.com](/an-introduction-to-perceptron-algorithm-40f2ab4e2099)

另一种解决方案,如逻辑回归,是对申请人违约的概率进行预测。由于概率的性质,预测将落在[0,1]内。凭经验,如果预测概率大于或等于 0.5,那么我们可以给这个申请人贴上‘违约’的标签;如果预测概率小于 0.5,那么我们可以将该申请人标记为“不违约”。但是线性回归的范围是从负无穷大到正无穷大,而不是在[0,1]中。然后引入 sigmoid 函数来解决这个问题。sigmoid 函数的表达式为:

sigmoid 函数给出了一条 S 形曲线,当它的自变量非常正或非常负时,它会饱和。花点时间记下这个公式。我们将在最大可能估计中应用它。

sigmoid 函数的图形:

Sigmoid 函数有许多特性,包括:

在逻辑回归中,我们可以写成:

函数的导数如下所示,将用于计算成本函数的梯度。

2。为什么不用线性回归?

《统计学习导论》直接解释了为什么使用逻辑回归而不是线性回归来解决分类问题。首先,线性回归的范围是负无穷大到正无穷大,超出了[0,1]的边界。如果线性回归和逻辑回归都对概率进行预测,线性模型甚至会产生负面的预测,而逻辑回归不存在这样的问题。见下图。

Figures Source: Gareth James, Daniela Witten, Trevor Hastie, Robert Tibshirani, 2017, An Introduction to Statistical Learning

线性回归的另一个问题是线性模型的预测总是基数的而不是名义的。即使在某些情况下,响应的值确实采用了自然排序,例如坏、中性和好。看起来坏和中性的差距和中性和好的差距是一样的,所以把坏、中性和好相应地编码成 1、2、3 是合理的。然而,没有自然或直接的方法将名义响应转换成数字响应。

3。最大似然估计(MLE)

从全部人口中抽取一个样本。该记录遵循伯努利分布。

在这个公式中, y 是 1 或 0 的指标, p 是事件发生的概率。

如果总共有 N 条记录呢,概率是多少?简而言之,假设每条记录都是独立且同分布的( I.I.D ),我们可以一起计算 N 条记录的概率。

然后取两边的对数,我们就可以得到对数似然。

注意,在公式中, p 是需要估计的参数(概率),等于:

在统计学中,最大似然估计(MLE)被广泛用于获得分布的参数。在这个范例中,最大化对数似然等于最小化成本函数 J 。它是凸优化中的一个对偶问题。成本函数 J 如下:

本节展示了 MLE 和成本函数之间的关系,以及 sigmoid 函数是如何嵌入 MLE 的。下一个问题是如何计算 p 并进一步计算 w 以最小化成本函数。

4。逻辑回归的梯度下降

与具有封闭形式解决方案的线性回归不同,梯度下降应用于逻辑回归。梯度下降的一般思想是反复调整参数 wb 以最小化成本函数。有三种典型的梯度下降法,包括批量梯度下降法、小批量梯度下降法和随机梯度下降法。在这个博客中,批量渐变体面使用。

Figure Source: https://saugatbhattarai.com.np/what-is-gradient-descent-in-machine-learning/

成本函数 J 的梯度为:

在第一部分中应用 sigmoid 函数的导数,然后我们可以得到:

初始值被分配给w;然后通过学习率*代价函数的梯度迭代更新 w 。该算法不会停止,直到它收敛。

梯度下降请看我的博客:

[## 梯度下降导论

本博客将涵盖以下问题和主题:

towardsdatascience.com](/an-introduction-to-gradient-descent-c9cca5739307)

5。用 Python 实现逻辑回归

在这一部分中,我将使用众所周知的数据 iris 来展示梯度体面如何工作以及逻辑回归如何处理分类问题。

首先,导入包

from sklearn import datasets
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.lines as mlines

接下来,加载数据。为简单起见,我只选择 2 种虹膜。

# Load data
iris = datasets.load_iris()
X=iris.data[0:99,:2]
y=iris.target[0:99]# Plot the training points
x_min, x_max = X[:, 0].min() - .5, X[:, 0].max() + .5
y_min, y_max = X[:, 1].min() - .5, X[:, 1].max() + .5
plt.figure(2, figsize=(8, 6))

梯度下降的伪代码

 1\. Initialize the parameters
Repeat {
   2\. Make a prediction on y
   3\. Calculate cost function
   4\. Get gradient for cost function
   5\. Update parameters
 }

梯度下降代码

#Step 1: Initial Model Parameter
Learning_Rate=0.01
num_iterations=100000
N=len(X)
w=np.zeros((2,1))
b=0
costs=[]for i in range(num_iterations):
  #Step 2: Apply sigmoid Function and get y prediction
    Z=np.dot(w.T,X.T)+b
    y_pred=1/(1+1/np.exp(Z)) #Step 3: Calculate Cost Function
    cost=-(1/N)*np.sum(y*np.log(y_pred)+(1-y)*np.log(1-y_pred)) #Step 4: Calculate Gradient
    dw=1/N*np.dot(X.T,(y_pred-y).T)
    db=1/N*np.sum(y_pred-y) #Step 5: Update w & b
    w = w - Learning_Rate*dw
    b = b - Learning_Rate*db
   #Records cost
    if i%100==0:
    costs.append(cost)
    print(cost)

可视化成本函数随时间的变化

# Plot cost function
Epoch=pd.DataFrame(list(range(100,100001,100)))
Cost=pd.DataFrame(costs)
Cost_data=pd.concat([Epoch, Cost], axis=1)
Cost_data.columns=['Epoch','Cost']
plt.scatter(Cost_data['Epoch'], Cost_data['Cost'])
plt.xlabel('Epoch')
plt.ylabel('Cost')

从上图中,我们可以看到,起初成本急剧下降;经过 40000 轮迭代,变得稳定。

可视化线性分类

# Plot linear classification
fig, ax = plt.subplots()
ax.scatter(X[:, 0], X[:, 1], c=y, cmap=plt.cm.Set1,edgecolor='k')
line=mlines.Line2D([3.701,7],[2,4.1034],color='red')
ax.add_line(line)
ax.set_xlabel('Sepal length')
ax.set_ylabel('Sepal width')
plt.show()

上图中的红线是 logistic 回归的决策边界。因为虹膜数据只包含二维,所以判定边界是一条线。在某些情况下,当存在 3 个或更多维时,决策边界将是超平面。

总结

在这篇博客中,我从理论到实践解释了逻辑回归。希望你看完这篇博客后对逻辑回归有更好的理解。如果您对其他博客感兴趣,请点击以下链接:

[## 机器学习和深度学习之旅

这一系列博客将从理论和实现两个方面对深度学习进行介绍。

medium.com](https://medium.com/@songyangdetang_41589/table-of-contents-689c8af0c731)

参考

[1]伊恩·古德菲勒,约舒阿·本吉奥,亚伦·库维尔,(2017) 深度学习

[2] Gareth James,Daniela Witten,Trevor Hastie,Robert Tibshirani,(2017) 统计学习介绍

https://en.wikipedia.org/wiki/Gradient_descent

NLP 介绍和提高游戏水平的 5 个技巧

原文:https://towardsdatascience.com/an-introduction-to-nlp-and-5-tips-for-raising-your-game-639636188ddf?source=collection_archive---------21-----------------------

Source: pexels — free stock images

我开始时就想知道的事情😅

对于那些在数据科学、机器学习和/或人工智能领域工作的人来说,NLP 可能是最令人兴奋的工作领域之一。

NLP 代表自然语言处理,是关于计算机和人类语言之间的互动。能够处理和分析大量自然语言数据的编程算法。

潜在的目标可能会有所不同,但总体目标是得出关于人类行为的结论……我们写作时的意图,我们写作时的想法或感觉,我们所写的项目的类别,以及一些其他东西,如聊天机器人,客户的市场细分,找到元素之间的重复和相似之处,虚拟助手(如 Siri 或 Alexa)以及更多东西。

尽管如此,NLP 作为一门学科出现的时间并不长,只是在 1960 年,艾伦·图灵发表了一篇名为“计算机器和智能”的文章,提出了现在所谓的“图灵测试”。这篇论文提出了“机器会思考吗?”这项测试证明了一台机器能够表现出与人类同等的智能行为。运行测试需要三个参与者,其中玩家 C(评估者)的任务是尝试确定哪个玩家(A 或 B)是计算机,哪个是人。

The Japanese robot Pepper, made by Aldebaran Robotics

然后,评估者将判断人类和机器之间的自然语言对话,这些对话旨在产生类似人类的反应,并知道对话中的两个伙伴之一是机器。对话将被限制在纯文本频道,结果不取决于机器对问题给出正确答案的能力,而只取决于它的答案与人类给出的答案有多相似。如果在测试结束时,评估者不能可靠地将机器与人区分开来,那么机器就被认为通过了测试。

从那里开始,在过去的几年里,这个领域已经有了指数级的发展,从使用一组规则的手工编码系统,到更复杂的统计 NLP。在这种背景下,一些公司正在这个领域做一些非常令人兴奋的事情。例如,如果你是安卓用户,你可能会熟悉快捷键,这是一个使用文本预测的初创公司,旨在提高用户写作的准确性、流畅性和速度。Swiftkey 从我们的书写中学习,预测最喜欢的单词、表情符号甚至表情。另一家初创公司signal 1,将手语转换成文本。帮助失聪的人与不懂手语的人交流。

事实是,现在使用 Python、Tensorflow、Keras 等开源库的扩展,使得 NLP 变得可访问,每天都有越来越多的企业在使用它。他们中的一些人雇佣了专门从事该主题的其他公司,但其他一些人雇佣了数据科学家和数据分析师,以便构建自己的解决方案。

如果你是这种情况,不管你是公司的人还是数据专家,在接下来的文章中,我将介绍一些我在 NLP 工作时学到的东西。幸运的是,所有这些都是基于错误的提示!所以希望你能提前避开它们,不要像我一样:)

1.找到适合您的矢量化类型

在 NLP 中,通常,在许多许多(可能更多)的数据清理之后,魔术开始于称为矢量化的东西。这种工具、技术,或者你想怎么称呼它,取一堆文本,通常称为文档,并根据每个文档中出现的单词将它们转换成向量。举以下例子:

作者使用来自https://www.oreilly.com的图片创建的示例

在上面的例子中,我们使用了一种叫做计数矢量器或单词袋的工具。这种矢量化通常会丢弃文本中的语法、顺序和结构。这是一个很好的选择,因为它可以跟踪文档中出现的所有单词,以及它们简单的处理方式,只需计数就可以理解,并让我们清楚地了解最重要的单词。然而,它提出了两个主要问题:

  • 数据稀疏:当统计整个文档中的所有出现时,我们可以很容易地以一个由充满零的向量组成的矩阵结束,因为当然,每个文档将只包含少量的所有可能的单词。我们稍后会详细讨论这一点。
  • 未来本身:计数矢量器输出一个固定大小的矩阵,其中包含当前文档中出现的所有单词(或某些频率的单词)。如果我们将来收到更多的文档,而我们不知道可能找到的单词,这可能会是一个问题。
  • 棘手的文档:如果我们有一个文档,其中一个特定的单词出现了很多次,以至于它看起来是所有文档中最常见的单词,而不是一个单词在一个文档中出现了很多次,会发生什么?

为了解决第一个问题和第二个问题,我们可以使用一个散列向量化,它将一组文本文档转换成一个用散列技巧计算的出现矩阵。每个单词都被映射到一个特征,使用哈希函数将它转换成一个数字。如果我们在文本中再次遇到该单词,它将被转换为相同的哈希,这样我们就可以统计单词的出现次数,而无需在内存中保留字典。这个技巧的主要缺点是不可能计算逆变换,因此我们丢失了重要特征对应的单词的信息。

为了解决上面提到的第三个问题,我们可以使用术语频率-逆文档频率(tf-idf)矢量器。tf-idf 分数告诉我们哪些单词在文档之间最有区别。在一个文档中出现很多但在很多文档中没有出现的单词包含很大的辨别能力。逆文档频率是对单词提供多少信息的度量,即该术语在所有文档中是常见的还是罕见的。增强特定文档的高度专用术语,同时抑制大多数文档的通用术语。

Sklearn 实现了所有这三种类型的矢量化:

2.个性化停用词,并注意数据中的语言

在进行任何类型的矢量化时,使用停用词是获得可靠结果的关键步骤。向我们的算法传递一个停用词列表,我们告诉它:‘如果你发现任何停用词,请忽略所有这些词……我不想让它们出现在我的输出矩阵中’。Skelarn 包含了一个默认的停用词列表供我们使用,只需将单词“english”传递给“stop_words”超参数即可。但是,有几个限制:

  • 它仅包括像“和”、“the”、“him”这样的基本词,这些词被假定为在表示文本内容时不提供信息,并且可以被移除以避免它们被解释为用于预测的信号。但是,例如,如果您正在处理从租赁代理网站上搜集的房屋描述,您可能会想要删除所有与房产描述本身无关的词语。像“机会”、“报价”、“惊人”、“太棒了”、“现在”之类的词
  • 对我来说,作为一个说西班牙语的人和用那种语言处理机器学习问题的人,最大的缺点是:它只有英语版本

因此,无论您是想丰富英语的默认单词列表以改善您的输出矩阵,还是想在其他一些语言中使用列表,您都可以通过使用超参数' stop_words '向 Sklearn 的算法传递个性化的停用词列表。顺便说一句,这里有一个 GitHub 库,里面有很多不同语言的列表。

在进入下一点之前,请记住,有时你根本不想使用任何停用词。例如,如果你在处理数字,甚至 Sklearn 中默认的英文停用词列表也包括从 0 到 9 的所有单个数字。所以对你来说,问问自己是否正在处理一个需要停用词的 NLP 问题是很重要的。

3.使用词干分析器对相似的单词进行“分组”

文本规范化是将含义基本相同但略有不同的单词版本转换为相同特征的过程。在某些情况下,考虑一个可能的单词的所有可能的变体可能是明智的,但是无论您是使用英语还是任何其他语言,有时您还会希望对文档进行某种预处理,以便以相同的方式表示具有相同含义的单词。例如,consultant、consulting、consult、consultant 和 consultants 都可以表示为“顾问”。有关更多示例,请参见下表:

Source: https://www.wolfram.com — Generate and verify stemmed words

为此,我们可以使用词干。词干分析器从单词中去掉词缀,只留下单词词干。幸运的是,Python 的 NLTK 库包含了几个健壮的词干分析器。如果您想将特定语言词干分析器或其他工具集成到矢量器算法中,可以使用以下代码:

spanish_stemmer = SpanishStemmer()classStemmedCountVectorizerSP(CountVectorizer):
def build_analyzer(self):
analyzer = super(StemmedCountVectorizerSP,self).build_analyzer()return lambda doc: ([spanish_stemmer.stem(w) for w in analyzer(doc)])

对于使用 HashingVectorizer 或 TfidfVectorizer,您可以很容易地更改这一点,只需更改赋予该类的算法。

4.避免使用熊猫数据框

这条建议简单明了:如果你在一个 NLP 项目中工作,有超过 5-10,000 行的数据,避免使用数据帧。仅仅使用 Pandas 对大量文档进行矢量化就会返回一个巨大的矩阵,这使得处理非常缓慢,而且很多时候,自然语言处理项目涉及到测量距离等内容,这往往非常缓慢,因为它需要将元素相互比较。尽管我本人是熊猫数据帧的忠实用户,但对于这类东西,我会推荐使用 Numpy 数组或稀疏矩阵。

还有。记住,你总是可以通过使用。toarray()'函数,反之亦然,从数组到稀疏矩阵使用:

from scipy import sparsemy_sparse_matrix = sparse.csr_matrix(my_array)

顺便说一下,如果你在处理时间问题,记住你可以使用下面的方法来为你的代码计时:

start = time.time()whatever_you_want_to_timeend = time.time()print(end — start)

5.数据稀疏:使你的输出矩阵可用

如前所述,使用 NLP 时最大的问题之一是数据稀疏问题…以成千上万列充满零的矩阵结束,这使得我们无法在以后应用某些东西。以下是我过去处理这个问题的一些技巧:

  • 使用超参数‘max _ features’使用 TfidfVectorizer 或 CountVectorizer 时。例如,您可以打印出文档中的单词频率,然后为它们设置一个阈值。假设你设置了一个 50 的阈值,你的数据语料库由 100 个单词组成。在查看单词频率后,20 个单词出现的次数少于 50 次。因此,您设置 max_features=80,您就可以开始了。如果 max_features 设置为 None,则在转换过程中会考虑整个语料库。否则,如果你传递 5 个给 max_features,那就意味着用文本文档中最常用的 5 个单词创建一个特征矩阵。
  • 在哈希矢量器中设置多个‘n _ features’。该超参数设置输出矩阵中特征/列的数量。特征数量少容易造成哈希碰撞,数量多会造成线性学习器系数维数较大。这个数字取决于你和你需要什么。
  • 使用降维。像主成分分析这样的技术将具有成千上万列的输出矩阵分成一个更小的集合,捕捉原始矩阵的方差可能是一个好主意。只要分析一下这种维数减少对你最终结果的影响有多大,检查一下它是否真的有用,并且选择要使用的维数。

我真的真的希望我学到的这些知识能对你的 NLP 项目有所帮助。将来会有更多关于 NLP 的故事,但是如果你喜欢这个故事,不要忘记看看我最近的一些文章,比如如何将你的数据分成训练集和测试集以确保代表性、s 数据科学中的生存偏差以及在云中使用集群以 4 个简单步骤完成数据科学项目。在我的中型档案中可以找到所有这些以及更多信息。

还有如果你想直接在你的邮箱里收到我的最新文章,只需 订阅我的简讯 😃

感谢阅读!

— — — — — — — — — — — —

特别提及我在整个故事中使用的以下资源:

https://blog . ventureradar . com/2015/09/22/top-5-companies-innovating-with-natural-language-processing/

https://en.wikipedia.org/wiki/Natural_language_processingT21

https://en.wikipedia.org/wiki/Turing_test

https://www . Forbes . com/sites/bernardmarr/2019/06/03/5-amazing-examples-of-natural-language-processing-NLP-in-practice/# 365 b 59901 b30

https://www . oreilly . com/library/view/applied-text-analysis/9781491963036/ch04 . html

https://stack overflow . com/questions/46118910/scikit-learn-vectorizer-max-features

Python 中的熊猫介绍

原文:https://towardsdatascience.com/an-introduction-to-pandas-in-python-b06d2dd51aba?source=collection_archive---------15-----------------------

No, this blog post isn’t about the panda bear. Sorry to disappoint. Source.

pandas github 官方知识库中的自述文件将 pandas 描述为“一个 Python 包,它提供了快速、灵活和富有表现力的数据结构,旨在使处理“关系”或“标签”数据变得既简单又直观。它旨在成为用 Python 进行实际的、真实世界的数据分析的基础高级构建块。此外,它还有一个更广泛的目标,那就是成为任何语言中最强大、最灵活的开源数据分析/操作工具。它已经在朝着这个目标前进。”

The pandas library is a powerful Python data analysis toolkit. Source.

熊猫的背景

根据维基百科,pandas 是“一个为 Python 编程语言编写的软件库,用于数据操作和分析。”听起来很棒,不是吗?但是它真正的含义是什么,熊猫对一个数据科学家来说有什么用途和用处呢?在这篇博文中,我将详细介绍熊猫的一些用途,并举例说明。这是对熊猫图书馆及其功能的简要介绍,而不是包罗万象的深入探讨。更多详细信息,请看熊猫 github 知识库这里,或者熊猫官方文档这里

Wes McKinney — the godfather of pandas. Source.

它最初是由韦斯·麦金尼于 2008 年在 AQR 资本管理公司工作时开发的。他能够说服 AQR 允许他开源该库,这不仅允许,而且鼓励全球的数据科学家免费使用它,为官方知识库做出贡献,提供错误报告和修复,文档改进,增强,并提供改进软件的想法。

熊猫入门

一旦你安装了熊猫,第一步就是导入它。你可以在这里找到更多关于安装熊猫的信息。下面是熊猫常用的快捷方式。虽然您不需要使用别名来导入 pandas,但是使用别名会有所帮助,这样您就可以使用 pd.command,而不是每次需要调用方法或属性时都键入 pandas.command。

import pandas as pd

导入库后,让我们导入一个数据集,这样我们就可以开始研究 pandas 及其功能。我们将使用“R 中应用的统计学习介绍”在线版本中的数据集,该数据集可以在这里找到。

Pandas 能够读取几种不同类型的存储数据,包括 CSV(逗号分隔值)、tsv(制表符分隔值)、JSONs (JavaScript 对象符号、HTML(超文本标记语言)等。对于我们的示例,我们将使用 CSV 并以这种方式读入数据。

auto = pd.read_csv('[http://faculty.marshall.usc.edu/gareth-james/ISL/Auto.csv'](http://faculty.marshall.usc.edu/gareth-james/ISL/Auto.csv'))

在上面的代码块中,我们读入了 CSV 文件,并将其保存为变量“auto”。单引号中的链接是我们的绝对文件路径——或者文件实际存储的位置。如果我们的文件存储在本地,我们也可以传入一个相对文件路径,这给了我们相对于目录中当前位置的目标文件

序列和数据帧的区别

在 pandas 中,我们有两个主要的数据结构可以探索。第一个是数据帧,第二个是系列。那么这两者有什么不同呢?

DataFrame 是一个包含行和列索引的二维数组。

系列是带有索引的一维数值数组。

如果基于这些一句话的解释还不清楚这两者之间的区别,希望下面的图片有所帮助。

A Series, on the left, and a DataFrame on the right. Image taken from General Assembly’s “Intro to Pandas” lesson.

如果看起来左边的图片也存在于右边的图片中,那你就对了!其中数据帧是整个数据集,包括所有行和列——系列实质上是该数据帧中的一列。在 pandas 中创建这两个数据结构是一个相当简单的过程,如下所示。

pd.DataFrame(data = [
['NJ', 'Towaco', 'Square'], 
['CA', 'San Francisco', 'Oval'], 
['TX', 'Austin', 'Triangle'], 
['MD', 'Baltimore', 'Square'], 
['OH', 'Columbus', 'Hexagon'], 
['IL', 'Chicago', 'Circle']
],
             columns = ['State', 'City', 'Shape'])pd.Series(data=['NJ', 'CA', 'TX', 'MD', 'OH', 'IL'])* Side Note: Python is able to make use of "white space" so the code is easier to read - hence the new lines and spacing.

上面的代码将创建我们在上面的图片中看到的数据帧系列。传入数据对于创建数据帧系列是必要的,以便它们不为空。有额外的参数可以传递到每个参数中,但是对于我们的目的来说,我们只需要传递的参数。有关这些附加参数作用的更多信息,请查看关于数据帧系列的文档。

探索性数据分析的一些有用的方法和性质

任何优秀的数据科学家在探索数据时应该做的第一件事就是探索数据。实现这一点的最好(也是最容易的)方法之一是查看前几行数据。默认情况下,调用.head()方法将显示数据帧的前五行,并包含列标题。您可以通过在括号中输入一个数字来修改显示的行数,这将改变显示的行数。

auto.head()

A look at the first five rows of our dataset.

同样,我们也可以看看数据集的最后几行。默认情况下,.tail()方法将显示数据帧的最后五行。类似于.head(),我们可以向我们的方法传递一个数字来修改显示多少行。让我们看一下我们的数据帧的最后三行,只是为了给你一个我们如何修改.tail()的感觉。

auto.tail(3)

A look at the last three rows of our dataset.

除了查看前几行或后几行之外,查看数据集中有多少行和列可能会有所帮助。让我们看看.shape的房产。

auto.shape

The shape of our dataset, in rows and columns.

这里,我们的数据集有 397 行和 9 列。根据我们对数据集的.head().tail()的观察,我们看到我们的数据集从索引 0 开始,一直运行到索引 396,确认我们总共有 397 行。但是,我们可能不想只看有多少行,而是想看看我们的数据集中有多少值丢失了。为此,我们可以调用.isnull()方法。

The first five rows of our dataframe when .isnull() is called.

在上图中,为了图片的缘故,我捕获了前 5 行,但是您可以通过调用.isnull().head()来获得同样有限的数据集。熊猫和 python 最酷的一点是它允许你堆叠方法和属性。.isnull()所做的是为每个值返回一个布尔项,并告诉我们它是否缺失(为 null,或 True),或者它是否不缺失(非 null,或 False)。

查看空值的另一种方式是在我们的.isnull()方法上堆叠另一个方法。如果我们看一下.isnull().sum(),我们将会看到在我们的每一列中有多少空值。

auto.isnull().sum()

How many null values are in each column?

幸运的是,上面的列都没有空值——所以我们不必担心删除空值,或者填充空值

另一个可能对我们有用的有用信息是查看我们的数据集中有什么类型的数据。为此,我们可以使用.dtypes属性。这将为我们提供每一列中包含的数据类型的快照。

auto.dtypes

A look at our datatypes within our DataFrame

在这里,我们可以看到我们有浮点数(带小数位的数字)、整数(整数)和对象(字符串)。

如果我们想快速总结一下到目前为止我们已经看过的所有信息,我们可以调用的一个特别有用的方法是.info(),它基本上汇总了我们到目前为止已经探索过的所有内容!

auto.info()

.info() shows us just about everything we’ve covered so far.

在这里,我们可以看到我们的auto变量的类型是什么(pandas . core . frame . data frame)——它是一个数据帧!RangeIndex 告诉我们总共有多少条目,从索引 0 到索引 396,Data columns 告诉我们总共有多少列——在本例中有 9 列。每个单独的列向我们显示有多少条目,多少是空的,以及特定列的类型。在底部,dtypes 显示了我们有哪些数据类型,以及每种类型有多少。最后,内存使用情况向我们显示了数据帧实际使用了多少内存。

希望您已经发现这是对 pandas 的快速介绍,它的一些方法和属性,它有助于向您展示为什么 pandas 在查看和分析数据集时如此有用。虽然这只是对熊猫及其方法和属性的一个非常基本的介绍,但希望我能有机会深入了解熊猫,帮助澄清一些被忽略的东西。如果你喜欢这篇博文,请记得查看所有关于熊猫的文档,看看它对你有多有用!

感知器算法简介

原文:https://towardsdatascience.com/an-introduction-to-perceptron-algorithm-40f2ab4e2099?source=collection_archive---------9-----------------------

机器学习和深度学习之旅

从理论到实践,学习感知器的基本原理,并用随机梯度下降法实现算法

本博客将涵盖以下问题和主题

1.什么是感知器?

2.感知器的随机梯度下降

3.用 Python 实现

1。什么是感知器?

感知器在 20 世纪 80 年代为神经网络模型奠定了基础。该算法由弗兰克·罗森布拉特开发,并被封装在 1962 年发表的论文“神经动力学原理:感知机和大脑机制理论”中。当时,罗森布拉特的工作受到马文·明克斯和西蒙·派珀特的批评,认为神经网络有缺陷,只能解决线性分离问题。然而,这种限制只出现在单层神经网络中。

感知器可以用来解决两类分类问题。算法的一般形式可以写成:

非线性激活标志功能是:

而逻辑回归是针对事件发生或不发生的概率,所以目标值的范围是[0,1]。感知器对第一类使用更方便的目标值 t=+1,对第二类使用 t=-1。因此,该算法不提供概率输出,也不处理 K>2 分类问题。另一个限制来自于该算法只能处理固定基函数的线性组合的事实。

2。感知器的随机梯度下降

根据前面的两个公式,如果记录分类正确,则:

否则,

因此,为了最小化感知器的成本函数,我们可以写出:

m 表示错误分类记录的集合。

通过偏导数,我们可以得到成本函数的梯度:

与逻辑回归可以应用批量梯度下降、小批量梯度下降和随机梯度下降来计算参数不同,感知器只能使用随机梯度下降。我们需要初始化参数 wb ,然后随机选择一条错误分类的记录,使用随机梯度下降迭代更新参数 wb ,直到所有记录都被正确分类:

注意学习率 a 的范围是从 0 到 1。

例如,我们有 3 条记录, 、Y1 = (3,3)、Y2 = (4,3)、Y3 = (1,1) 、T3。 Y1Y2 标注为+1Y3标注为-1。假设初始参数都是 0。因此,所有的点都将被归类为 1 类。

随机梯度下降循环通过所有训练数据。在第一轮中,通过应用前两个公式, Y1Y2 可以被正确分类。但是 Y3 会被误分类。假设学习率等于 1,通过应用上面所示的梯度下降,我们可以得到:

那么线性分类器可以写成:

即 1 轮梯度下降迭代。

上表显示了感知器的随机梯度下降的整个过程。如果一条记录被正确分类,那么权重向量 wb 保持不变;否则,我们在 y=1 时将向量 x 加到当前权重向量上,并且在 y=-1 时从当前权重向量 w 中减去向量。请注意,最后 3 列是预测值,错误分类的记录以红色突出显示。如果我们反复执行梯度下降,在第 7 轮中,所有 3 个记录都被正确标记。那么算法就会停止。线性分类器的最终公式为:

请注意,这种算法总是存在收敛问题。当数据可分时,有多种解,选择哪种解取决于起始值。当数据不可分时,算法不会收敛。有关详细信息,请参见下面参考资料中的相应段落。

3。用 Python 实现

*from sklearn import datasets
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.lines as mlinesnp.random.seed(10)# Load data
iris=datasets.load_iris()
X = iris.data[0:99,:2]
y = iris.target[0:99]*

首先,加载虹膜数据。

*# Plot figure
plt.plot(X[:50, 0], X[:50, 1], 'bo', color='blue', label='0')
plt.plot(X[50:99, 0], X[50:99, 1], 'bo', color='orange', label='1')
plt.xlabel('sepal length')
plt.ylabel('sepal width')
plt.legend()*

然后可视化数据

*# Update y into -1 and 1
y=np.array([1 if i==1 else -1 for i in y])*

y=0 更新为 y=-1

*#################################
# Gradient Descent
################################## Initialize parameters
w=np.ones((X.shape[1],1));
b=1;
learning_rate=0.1;
Round=0;
All_Correct=False;# Start Gradient Descent
while not All_Correct:
    misclassified_count=0
    for i in range(X.shape[0]):
        XX=X[i,]
        yy=y[i]
        if yy * (np.dot(w.T,XX.T)+b)<0:
            w+=learning_rate * np.dot(XX,yy).reshape(2,1)
            b+=learning_rate * yy misclassified_count +=1 if misclassified_count==0:
        All_Correct=True
    else:
        All_Correct=False
    Round += 1
    print(Round)print(w)
print(b)*

应用随机梯度下降后,我们得到 w=(7.9,-10.07)b=-12.39

*x_points = np.linspace(4,7,10)
y_ = -(w[0]*x_points + b)/w[1]
plt.plot(x_points, y_)plt.plot(X[:50, 0], X[:50, 1], 'bo', color='blue', label='0')
plt.plot(X[50:99, 0], X[50:99, 1], 'bo', color='orange', label='1')
plt.xlabel('sepal length')
plt.ylabel('sepal width')
plt.legend()*

上图显示了感知器的最终结果。我们可以看到,线性分类器(蓝线)可以正确地分类所有训练数据集。在这种情况下,虹膜数据集仅包含 2 维,因此决策边界是一条线。在数据集包含 3 个或更多维度的情况下,决策边界将是超平面。

结论

在这篇博客中,我解释了感知器背后的理论和数学,将该算法与逻辑回归进行了比较,并最终用 Python 实现了该算法。希望看完这篇博客,你能对这个算法有更好的理解。如果您对其他博客感兴趣,请点击以下链接:

* [## 机器学习和深度学习之旅

这一系列博客将从理论和实现两个方面对深度学习进行介绍。

medium.com](https://medium.com/@songyangdetang_41589/table-of-contents-689c8af0c731)

参考

[1] Christopher M. Bishop,(2009),模式识别与机器学习

[2]特雷弗·哈斯蒂,罗伯特·蒂布拉尼,杰罗姆·弗里德曼,(2008),*《统计学习的要素》**

初学者递归神经网络入门

原文:https://towardsdatascience.com/an-introduction-to-recurrent-neural-networks-for-beginners-664d717adbd?source=collection_archive---------8-----------------------

关于 rnn 是什么、它们如何工作以及如何用 Python 从头开始构建一个 rnn 的简单介绍。

递归神经网络(RNNs)是一种专门处理序列的神经网络。由于它们在处理文本方面的有效性,它们经常被用于自然语言处理 (NLP)任务。在这篇文章中,我们将探索什么是 rnn,了解它们是如何工作的,并从头开始用 Python 构建一个真正的 RNNs】(仅使用 numpy )。

本帖假设具备神经网络的基础知识。我的神经网络介绍涵盖了你需要知道的一切,所以我建议你先读一下。

让我们开始吧!

1.为什么

普通神经网络(以及CNN)的一个问题是,它们只能处理预先确定的大小:它们接受固定大小的输入并产生固定大小的输出。rnn 是有用的,因为它们让我们有可变长度序列作为输入和输出。下面是几个 rnn 的例子:

Inputs are red, the RNN itself is green, and outputs are blue. Source: Andrej Karpathy

这种处理序列的能力使得 RNNs 非常有用。例如:

  • 机器翻译(例如谷歌翻译)是通过“多对多”的 rnn 完成的。原始文本序列被输入到一个 RNN,然后产生翻译文本作为输出。
  • 情感分析(例如这是正面还是负面评论?)通常是用“多对一”RNNs 完成的。待分析的文本被输入 RNN,然后产生一个单一的输出分类(例如这是一个正面评价)。

在这篇文章的后面,我们将从头开始构建一个“多对一”的 RNN 来执行基本的情感分析。

注意:我推荐在 victorzhou.com 阅读这篇文章的其余部分——许多数学格式在那里看起来更好。

2.怎么做

让我们考虑一个输入为 x_0x_ 1、… x_n 的“多对多”RNN,它想要产生输出 y_ 0、 y_ 1、… y_n 。这些 x_i 和 y_i 是向量,并且可以具有任意维数。

RNNs 通过迭代更新隐藏状态 h 来工作,隐藏状态 h 是也可以具有任意维度的向量。在任何给定的步骤 t,

  1. 使用前一个隐藏状态 h_{t-1}和下一个输入 x_t 来计算下一个隐藏状态 h_t。
  2. 使用 h_t 计算下一个输出 y_t。

A many to many RNN

下面是 RNN 循环 : 的原因,它对每一步使用相同的权重。更具体地说,典型的普通 RNN 仅使用 3 组砝码进行计算:

  • Wxh ,用于所有 x_t → h_t 环节。
  • Whh ,用于所有 h_{t-1} → h_t 环节。
  • Why ,用于所有 h_t → y_t 环节。

对于我们的 RNN,我们还将使用两个偏差:

  • b_h,计算 h_t 时添加。
  • b_y,计算 y_t 时添加。

我们将权重表示为矩阵和偏差表示为向量。这三个重量和两个偏差组成了整个 RNN!

以下是将所有东西放在一起的方程式:

Don’t skim over these equations. Stop and stare at this for a minute. Also, remember that the weights are matrices and the other variables are vectors.

使用矩阵乘法应用所有权重,并将偏差添加到结果乘积中。然后,我们使用 tanh 作为第一个方程的激活函数(但是也可以使用类似 sigmoid 的其他激活)。

不知道什么是激活函数?看我的 神经网络导论 像我提到的。说真的。

3.问题是

让我们把手弄脏吧!我们将从头实现一个 RNN 来执行一个简单的情感分析任务:确定给定的文本字符串是正面的还是负面的。

以下是我为这篇文章收集的小型数据集中的一些样本:

4.这个计划

由于这是一个分类问题,我们将使用“多对一”RNN。这类似于我们之前讨论的“多对多”RNN,但是它只使用最终隐藏状态来产生一个输出 y :

A many to one RNN

每个 x_i 将是一个向量,代表文本中的一个单词。输出 y 将是一个包含两个数字的向量,一个代表正,另一个代表负。我们将应用 Softmax 将这些值转化为概率,并最终在正/负之间做出决定。

让我们开始建设我们的 RNN 吧!

5.预处理

我前面提到的数据集由两个 Python 字典组成:

True = Positive, False = Negative

我们必须做一些预处理,以便将数据转换成可用的格式。首先,我们将为数据中存在的所有单词构建一个词汇表:

vocab现在拥有在至少一个训练文本中出现的所有单词的列表。接下来,我们将分配一个整数索引来表示我们的 vocab 中的每个单词。

我们现在可以用相应的整数索引来表示任何给定的单词!这是必要的,因为 rnn 不能理解单词——我们必须给它们数字。

最后,回想一下,我们的 RNN 的每个输入 x_i 是一个向量。我们将使用 单热点 向量,它包含除了一个 1 之外的所有 0。每个独热向量中的“1”将在该字的相应整数索引处为

由于我们的词汇表中有 18 个唯一的单词,每个 x_i 将是一个 18 维的一个热点向量。

稍后我们将使用createInputs()来创建向量输入,以传递给我们的 RNN。

6.前进阶段

是时候开始实施我们的 RNN 了!我们首先初始化 RNN 需要的 3 个权重和 2 个偏差:

Note: We’re dividing by 1000 to reduce the initial variance of our weights. This is not the best way to initialize weights, but it’s simple and works for this post.

我们使用 np.random.randn() 从标准正态分布初始化我们的权重。

接下来,让我们实施我们的 RNN 的向前传球。还记得我们之前看到的这两个方程吗?

下面是这些相同的等式被写入代码:

很简单,对吧?注意,在第一步中,我们将 h 初始化为零向量,因为在这一点上没有先前的 h 可以使用。

让我们试一试:

Need a refresher on Softmax? Read my quick explanation of Softmax.

我们的 RNN 可以工作,但还不是很有用。让我们改变这一点…

喜欢这个介绍吗?订阅我的时事通讯以获得关于像这样的新机器学习帖子的通知。

7.倒退阶段

为了训练我们的 RNN,我们首先需要一个损失函数。我们将使用交叉熵损失,它通常与 Softmax 成对出现。我们是这样计算的:

哪里是我们 RNN 对正确类的预测概率(正或负)。例如,如果阳性文本被我们的 RNN 预测为 90%阳性,损失为:

想要更长的解释吗?阅读我的卷积神经网络(CNN)入门的 交叉熵损失 章节。

现在我们有一个损失,我们将使用梯度下降来训练我们的 RNN,以尽量减少损失。这意味着是时候导出一些梯度了!

⚠️ 以下章节假设了多变量微积分的基础知识。如果你愿意,你可以跳过它,但我建议即使你不太明白,也要略读一下。我们将在获得结果的同时逐步编写代码,即使是表面的理解也会有所帮助。

如果你想要一些额外的背景知识,我推荐你先阅读我的神经网络介绍中的 训练神经网络 部分。另外,这篇文章的所有代码都在Github上,所以如果你愿意的话,你可以跟着一起看。

准备好了吗?开始了。

7.1 定义

首先,一些定义:

  • 让 y 代表 RNN 的原始输出。
  • p 代表最终概率: p =softmax( y )。
  • c 指代某个文本样本的真实标签,也称为“正确”类。
  • L 为交叉熵损失:L= ln(p _ c)。
  • WxhWhhWhy 为我们 RNN 中的 3 个重量矩阵。
  • 设 b_h 和 b_y 是 RNN 中的两个偏置向量。

7.2 设置

接下来,我们需要编辑我们的前向阶段,以缓存一些数据供后向阶段使用。同时,我们也将为我们的逆向阶段设置框架。看起来是这样的:

对我们为什么要进行缓存感到好奇吗?阅读我的 CNN 入门 培训概述 中我的解释,其中我们做了同样的事情。

7.3 渐变

数学时间到了!我们先从计算∂ L /∂ y 开始。我们知道:

我将把∂ L /∂ y 使用链式法则的实际推导过程留给你们作为练习😉但是结果很好:

例如,如果我们有 p =[0.2,0.2,0.6]并且正确的类是 c =0,那么我们将得到∂l/∂y=[0.8,0.2,0.6]。这也很容易转化成代码:

很好。接下来,让我们来看看为什么渐变,它们只是用来把最终的隐藏状态变成 RNN 的输出。我们有:

其中 h_n 是最终隐藏状态。因此,

同样的,

我们现在可以开始实现backprop()

提醒:我们在 forward() 中更早的创造了 self.last_hs

最后,我们需要 WhhWxh 和 b_h 的梯度,它们在 RNN 的每个步骤中都要用到。我们有:

因为改变 Wxh 每影响一次 h_t,都影响 y 最终 L 。为了完全计算出 Wxh 的梯度,我们需要通过反向传播所有时间步长,这就是所谓的通过时间 (BPTT)反向传播:

Backpropagation Through Time

Wxh 用于所有 x_t → h_t 前向链路,因此我们必须反向传播回那些链路中的每一个。

一旦我们到达给定的步骤 t ,我们需要计算∂ h_t/Wxh :

tanh的衍生产品众所周知:

我们像往常一样使用链式法则:

同样的,

我们最不需要的就是∂ y/h_t 我们可以递归计算:

我们将从最后一个隐藏状态开始实现 BPTT,并向后工作,所以当我们想要计算∂y/h _ t时,我们已经有了∂y/h _ { t+1 }!例外是最后一个隐藏状态 h_n:

我们现在拥有了最终实现 BPTT 和完成backprop()所需的一切:

需要注意一些事情:

  • 为了方便起见,我们将∂l/y**∂y/h*合并为∂ L/h
  • 我们一直在更新一个d_h变量,它保存了最近的∂l/∂h _ { t+1 },我们需要它来计算∂ L/ht
  • 完成 BPTT 后,我们 np.clip() 梯度值低于-1 或高于 1。这有助于缓解爆炸梯度问题,即梯度由于有许多相乘项而变得非常大。爆炸或消失的梯度对于普通的 rnn 来说是一个很大的问题——更复杂的 rnn,如lstm通常能够更好地处理它们。
  • 一旦计算出所有梯度,我们使用梯度下降更新权重和偏差。

我们做到了!我们的 RNN 完成了。

8.高潮

我们期待已久的时刻终于到来了——让我们测试一下我们的 RNN 吧!

首先,我们将编写一个助手函数,用我们的 RNN 处理数据:

现在,我们可以编写训练循环:

运行main.py应该会输出如下内容:

--- Epoch 100
Train:  Loss 0.688 | Accuracy: 0.517
Test:   Loss 0.700 | Accuracy: 0.500
--- Epoch 200
Train:  Loss 0.680 | Accuracy: 0.552
Test:   Loss 0.717 | Accuracy: 0.450
--- Epoch 300
Train:  Loss 0.593 | Accuracy: 0.655
Test:   Loss 0.657 | Accuracy: 0.650
--- Epoch 400
Train:  Loss 0.401 | Accuracy: 0.810
Test:   Loss 0.689 | Accuracy: 0.650
--- Epoch 500
Train:  Loss 0.312 | Accuracy: 0.862
Test:   Loss 0.693 | Accuracy: 0.550
--- Epoch 600
Train:  Loss 0.148 | Accuracy: 0.914
Test:   Loss 0.404 | Accuracy: 0.800
--- Epoch 700
Train:  Loss 0.008 | Accuracy: 1.000
Test:   Loss 0.016 | Accuracy: 1.000
--- Epoch 800
Train:  Loss 0.004 | Accuracy: 1.000
Test:   Loss 0.007 | Accuracy: 1.000
--- Epoch 900
Train:  Loss 0.002 | Accuracy: 1.000
Test:   Loss 0.004 | Accuracy: 1.000
--- Epoch 1000
Train:  Loss 0.002 | Accuracy: 1.000
Test:   Loss 0.003 | Accuracy: 1.000

对我们自己造的 RNN 来说还不错。💯

想自己尝试或修改这段代码吗? 在你的浏览器中运行这个 RNNGithub 上也有。

9.结束了

就是这样!在这篇文章中,我们完成了递归神经网络的演练,包括它们是什么,它们如何工作,它们为什么有用,如何训练它们,以及如何实现一个。但是,您还可以做更多的事情:

  • 了解一下长短期记忆 (LSTM)网络,一个更强大、更受欢迎的 RNN 架构,或者了解一下门控循环单元 (GRUs),一个众所周知的 LSTM 变种。
  • 使用合适的 ML 库,如 TensorflowKerasPyTorch ,尝试更大/更好的 rnn。
  • 阅读关于双向 RNNs 的内容,该过程向前和向后排序,以便输出层可以获得更多信息。
  • 尝试像 GloVeWord2Vec 这样的单词嵌入,可以用来将单词转化为更有用的矢量表示。
  • 查看自然语言工具包 (NLTK),这是一个用于处理人类语言数据的流行 Python 库。

我写了很多关于机器学习的文章,所以订阅我的时事通讯如果你有兴趣从我这里获得未来的 ML 内容。

感谢阅读!

原载于https://victorzhou.com

使用 Python 的正则表达式简介

原文:https://towardsdatascience.com/an-introduction-to-regex-using-python-aac26fd9daf4?source=collection_archive---------15-----------------------

Photo by the author

你甚至需要学习正则表达式吗?

根据维基百科,正则表达式是定义搜索模式的一系列字符。换句话说:是字母、数字和符号的组合,我们可以用来在更大的文本中搜索内容:)

在技术领域,关于程序员必须学习正则表达式的讨论在 Stackoverflow、Quora 和许多其他类似的网站上随处可见:

是的,其中一些问题是最近才出现的,主要是因为一些新的工具和编程语言使得间接处理 Regex 变得容易,而没有真正处理围绕它的所有混乱。但是,上面最后一个问题是七年前的了!在 Stackoverflow 还有其他更老的。所以你可以看到关于正则表达式及其强制性的讨论已经持续了一段时间😅。

事实上,大约 11 年前,Stack Overflow 的联合创始人杰夫·阿特伍德(Jeff Atwood)在他的博客“编码恐怖”中写了一篇文章,名为“T10 正则表达式:现在你有两个问题 T11”,这是他在三年后写的另一篇文章,名为“T12”。如果你这么喜欢正则表达式,为什么不与它们结婚呢?好吧…我会的!'

在这一点上,如果你在想这样的事情,那就太公平了:

  • 这种正则表达式的东西显然太复杂了…可能不值得
  • 好吧,那么杰夫·阿特伍德是个疯子……这肯定是雷杰克斯的错

但是等等,在你离开之前,让我告诉你,尽管这是真的,但是 regex 是复杂和令人困惑的,很可能它是值得争论的。效用和复杂性之间的二元性,或者说爱与恨之间的二元性,正是杰夫·阿特伍德在他的第二个故事中试图表达的。事实上,甚至在他最近出版的书的开头,阿特伍德就引用了杰米·扎温斯基在 1997 年说的话:

有些人,当遇到问题时,会想“我知道,我会用正则表达式。”现在他们有两个问题。

关于他自己对正则表达式的思考方式,他还声明如下:

正则表达式摇滚。它们绝对应该是每个现代编码者工具箱中的关键部分。(Jamie 想说的是:正则表达式本身并不是邪恶的,而是过度使用正则表达式是邪恶的。我完全同意。正则表达式就像一种特别辣的辣酱——只有在适当的时候才能适度使用。你应该尝试用正则表达式解决你遇到的每一个问题吗?哦,不

Hell Fire Detroid [https://heatonist.com/] image retouched

所以最后,很多问题和答案。同一个杰夫·阿特伍德显然学会了同时讨厌和喜欢正则表达式。是不是值得学的东西?我来快速总结一下我通过 Stackoverflow 和 Quora 看的所有回答:

  • 这是必须学习的东西吗?不
  • 我要每天甚至每周使用它吗?可能不会
  • 对你来说,知道和理解它是一个重要的工具吗?是
  • 对于某些任务来说,它是否非常高效和有用?肯定是的
  • 我需要完全了解它的每一个细节吗?可能不会

当然,很多人会不同意上面的一些答案,但现实是,现在我们有谷歌,我们在编码时可能会遇到的每个问题都有很多答案。到目前为止,每次我不得不使用正则表达式时,没有一次我对如何写东西没有疑问。有时,我不得不承认,即使是最基本的东西,不用一会儿就从我的脑海中抹去了。

这就是为什么这个故事的想法是涵盖正则表达式的主要和基本的东西。因此,您可以从一些实际应用程序开始,检查正则表达式并不是那么可怕(当您有一个合适的指南并且 google 触手可及时😅).

Python 和 Jupyter 笔记本中的 Regex

我们的想法是实践下面的例子和工具,所以首先,我们需要知道如何在 Python 中使用 regex。但是,请注意,使用 regex 并不一定需要 Python 或 Jupyter 笔记本。它甚至可以通过终端和其他几种语言使用。不幸的是,并不是所有的程序、命令和编程语言都使用相同的正则表达式,但它们都非常相似。

让我们从导入库开始:

import re

一旦我们这样做了,从任何给定的字符串开始,有两种使用正则表达式的主要方法:

text = ‘those THAT tilt that That 8’
  1. 仅使用 re.findall 函数
In: re.findall(r’[Tt]h[^i][st]’, text)Out: [‘thos’, ‘that’, ‘That’]

2.使用重新编译:

In: pattern = re.compile(r’[Tt]h[^i][st]’)In: re.findall(pattern, text)Out: [‘thos’, ‘that’, ‘That’]

为什么这个模式从我们的字符串中返回单词‘thos’、‘That’和‘That’?不要担心,我们将在下一节解释这一点🙂。

主要实用程序和语法

在接下来的段落中,我们将学习正则表达式中一些最基本的东西。如果您已经熟悉 regex,那么您可能不会得到任何新的东西。但除此之外,它确实值得一读。

包括常规字符串:在 Python 中我们通常称为字符串的字符在 regex 世界中被称为‘文字’。然而,尽管如此,使用它们没有任何区别。诸如 a、g、t、r、m 或偶数之类的字符可以包括在任何特殊考虑之内。例如,如果我们想在前面的文本中搜索字母“t ”,我们可以这样做:

In: re.findall(r’[t]’,text)Out: [‘t’, ‘t’, ‘t’, ‘t’, ‘t’, ‘t’] #check by yourself if we had 6 lower case ‘t’s in our text

提示:注意仅仅通过指示文字,regex 是区分大小写的!

使用字符类:这个实用程序指示 regex 在一个组中搜索一个或另一个字符。该组将在方括号中指定。举以下例子:

In: re.findall(r’[tT]’,text)Out: [‘t’, ‘T’, ‘T’, ‘t’, ‘t’, ‘t’, ‘t’, ‘T’, ‘t’]

现在我们找到了文本中所有的 t,大写和小写都有。然而,这并不是更为正统的做法。在 Python 中有一种更好的方法:

In: In : pattern = re.compile(r’t’, flags=re.IGNORECASE)In: re.findall(pattern, text)Out: [‘t’, ‘T’, ‘T’, ‘t’, ‘t’, ‘t’, ‘t’, ‘T’, ‘t’]

请注意,字符类也可以使用范围。事实上,这就是它们如此受欢迎的原因!例如,这就是我们如何匹配“a”和“z”之间的任何小写字母:

In: re.findall(r’[a-z]’,text)Out: [‘t’, ‘h’, ‘o’, ‘s’, ‘e’, ‘t’, ‘i’, ‘l’, ‘t’, ‘t’, ‘h’, ‘a’, ‘t’, ‘h’, ‘a’, ‘t’]

否定语法:对于我们到目前为止看到的任何情况,以及对于 regex 中的任何其他表达式,您可以通过以下方式使用'^'字符来使用否定:

In: re.findall(r’[^a-zA-Z]’,text)Out: [‘ ‘, ‘ ‘, ‘ ‘, ‘ ‘, ‘ ‘, ‘8’]

在上面的例子中,我们只返回空格和字符串中的唯一数字,因为我们排除了' a '和' a '之间的任何字母,包括小写和大写。

在进入下一个实用程序之前,不知道您是否意识到了,但是我们已经看到了足够多的内容,可以理解我们最初的例子了!让我们重温一下:

text = ‘those THAT tilt that That 8’In: re.findall(r’[Tt]h[^i][st]’, text)Out: [‘thos’, ‘that’, ‘That’]

把它分成几部分,我们可以看到:

  • 首先,我们对匹配“T”或“T”的任何内容使用一个类范围
  • 之后,我们会指出任何后面有“h”的东西
  • 后来,我们用否定来表示任何后面没有“我”的东西
  • 最后,任何以 and 's 或 a 't 结尾的单词

注意单词“那些”是如何在“s”处被截断的,因为我们没有在那里进一步指定任何东西。

快捷键和特殊字符

如果您以前看过正则表达式,那么它可能会引起您对反斜线数量的注意。这样做有一个很好的理由:regex 包含了很多快捷方式,所以你不必用大量的字符编写永恒的表达式。一开始你可能不会记住所有的代码(或者可能只有我在不得不使用它们的时候才会努力记住一些小代码?😂),但将它们放在触手可及的地方会很方便:

\w —匹配单词字符(包括数字和下划线)

\W —匹配\W 不匹配的内容—非单词字符

\d —匹配所有数字字符—数字为[0–9]

\D —匹配所有非数字字符

\s —匹配空白(包括制表符)

\S —匹配非空白

\n —匹配新行

\r —匹配回车

\t —匹配制表符

所有这些都可以在字符类中和/或与否定一起使用。让我们看一些例子:

# Get everything but blank spacesIn: re.findall(r’[\w]’,text)Out: [‘t’, ‘h’, ‘o’, ‘s’, ‘e’, ‘T’, ‘H’, ‘A’, ‘T’, ‘t’, ‘i’, ‘l’, ‘t’, ‘t’, ‘h’, ‘a’, ‘t’, ‘T’, ‘h’, ‘a’, ‘t’, ‘8’]

— —

# Get only blank spacesIn: re.findall(r’[\W]’,text)Out: [‘ ‘, ‘ ‘, ‘ ‘, ‘ ‘, ‘ ‘]

— —

# Match all that’s NOT a non-digit characters → all characters that are not lettersIn: re.findall(r’[^\D]’,text)Out: [‘8’]

— —

# Match word characters and white spaces → everything but the eightIn: re.findall(r’[\D\s]’,text)Out: [‘t’, ‘h’, ‘o’, ‘s’, ‘e’, ‘ ‘, ‘T’, ‘H’, ‘A’, ‘T’, ‘ ‘, ‘t’, ‘i’, ‘l’, ‘t’, ‘ ‘, ‘t’, ‘h’, ‘a’, ‘t’, ‘ ‘,‘T’, ‘h’, ‘a’, ‘t’, ‘ ‘]

嗯,我想这足以理解捷径是如何工作的了,对吗?在这篇文章中我们将看到的最后一件事是为了包含特殊字符,我们必须再次用反斜杠对它们进行转义。

特殊正则表达式字符包括:

. \ + * ? [ ^ ] $ ( ) { } = ! < > | : -

量词

这是一个简单的基本工具,但也是一个必要的工具。它帮助您匹配您想要返回多少个字符来匹配您的表达式:

  • —零个或多个
  • —一个或多个
    ?—零个或一个
    {n} —正好是‘n’个数字
    {n,} —匹配‘n’个或更多个出现
    {n,m} —在‘n’和‘m’之间

嗯,我认为这足以让你开始学习正则表达式,并让你对这个故事着迷。将来,我会再写关于正则表达式的文章,我们会看到更多的中级/高级工具和语法。然而,如果你有足够的兴趣继续阅读,我建议你继续阅读以下内容:

  • 分组和采集
  • 间隔
  • 向前看和向后看

最后,一个非常好的继续阅读的来源是:https://www.regular-expressions.info/

如果你喜欢这个故事,别忘了看看我最近的一些文章,比如:

我的中等档案中可以找到所有这些以及更多信息。还有如果你想直接在你的邮箱里收到我的最新文章,只需 订阅我的简讯 😃

中号见!

注意:对于这个故事,我使用了来自伦敦大会的数据科学沉浸式课程的内容。

介绍 Spark GraphFrame,并举例分析维基百科链接图

原文:https://towardsdatascience.com/an-introduction-to-spark-graphframe-with-examples-analyzing-the-wikipedia-link-graph-67e58c20a107?source=collection_archive---------7-----------------------

Spark GraphFrame 是一个非常强大的工具,用于使用大型图形数据执行分布式计算。本文介绍了 GraphFrame 抽象,并展示了如何利用它来分析维基百科文章之间的链接所形成的图形。

Spark GraphFrame 是使用分布式计算处理大型图形的强大抽象。它提供了大量常见的图形算法,包括标签传播PageRank 。此外,它为实现复杂的图形算法提供了基础,包括用于图形处理的 Pregel 范例的健壮实现。任何对处理大型图表感兴趣的人都应该学习如何应用这个强大的工具。

在本文中,我将向您介绍 GraphFrame 的基本知识,并通过几个例子演示如何使用这个工具。这些例子考虑了维基百科文章之间的链接图,我演示了如何利用 GraphFrame 抽象来分析这个图。

请注意,本文中的例子构建了一些更基本的 Spark 概念,如数据帧。此外,它使用基本的 Scala 代码来演示算法。这里只展示了小而简单的例子,因此人们不需要非常熟悉这些概念就可以了解 GraphFrame 抽象的强大功能。

让我们开始考虑如何创建一个 GraphFrame。我将首先在一个基本的 Spark RDD 中介绍维基百科链接数据。这个 RDD 的每个元素都是一个单独的维基百科文章页面,用下面的 Scala 类表示。

请注意,每个链接都是另一个页面的标题。即,每个页面都知道它通过标题链接到的所有其他页面。

我们从一个包含 19,093,693 个维基百科文章页面的 RDD pages开始。由此,我们生成两个 Spark 数据帧,一个由顶点(即页面节点)组成,另一个由有向边组成。

请注意,此图中有 206,181,091 条有向边。

接下来,我们使用这两个数据帧创建一个 GraphFrame。

这就是我们访问这个强大的抽象所要做的一切。我们现在可以开始使用一些内置的图形算法来分析维基百科的链接图。

让我们从计算一些简单的东西开始:拥有最多出站链接的维基百科页面。为此,我们可以使用 GraphFrame 方法outDegrees,这是一个计算的数据帧,对应于每个顶点的出站边的数量。由于这是一个数据框架,我们可以使用orderBy方法和limit来选择前 10 名。

这给出了以下结果。

有趣的是,我们可以看到许多特殊的“维基百科:”前缀页面的出站链接数最高。

接下来,让我们考虑每个页面的入站边的数量,并使用相应的 GraphFrame 方法inDegrees找到前 10 个链接到的页面。

我们可以看到,包括国家和城市在内的位置是与页面链接最多的位置。

现在让我们探索一些更复杂的图形计算。让我们考虑一下链接最多的文章“美国”,并在链接图中找到在到达“美国”时必须遵循的链接数量方面离这篇文章最远的其他文章。

为此,我们可以使用 GraphFrame 方法,shortestPaths,它获取一组地标顶点,并返回图中每个顶点到每个地标顶点的路径长度。

有趣的是,就最短路径长度而言,只有三篇文章距离“美国”文章整整 10 个链接。

让我们更进一步,计算每个路径长度的页数。即,从“美国”移除了多少维基百科文章的 1 个链接,移除了多少 2 个链接,等等。

(注意,我使用的是数据块笔记本的内置display功能。我将在以后的文章中更多地谈论使用 Databricks 的乐趣。)

在这里,我们可以看到有数百万个页面从“美国”文章中删除了 2 到 4 个链接。也有极少数的文章删除了六个或更多的链接。此外,路径长度为-1 表示文章与“United States”的文章没有任何联系,大约有一百万个页面符合这个标准。

最后,如果不展示使用 GraphFrame 执行 PageRank 算法是多么容易,那么它的演示就是不完整的。

前 10 篇文章的页面排名是:

“美国”拥有最高的顶点排名并不奇怪,因为我们知道它是链接最多的文章。

我希望这些例子有助于让您相信 GraphFrame 是对大型图形执行分布式计算的强大抽象。我希望在未来的文章中分享更多更高级的概念,包括如何使用 GraphFrame 的 Pregel 计算范式实现自定义图形算法。

更新:如果你觉得本文中的 Scala 例子很有趣,并且想了解这种强大的编程语言的更多信息,你可以看看我的文章,通过计算机程序例子的结构和解释快速学习 Scala 的基础知识(第 1 部分)

SQL:简介

原文:https://towardsdatascience.com/an-introduction-to-sql-4c9eb27995df?source=collection_archive---------12-----------------------

通过示例学习 SQL 的基础知识

SQL 代表结构化查询语言,它主要用于关系数据库。它是您可以用来与数据库通信和检索数据的语言。尽管已经有了标准化的尝试,但是你经常会发现不同关系数据库之间的差异。然而,大多数基本陈述在所有这些方面都是相同的。

一些最流行的付费关系数据库包括 Microsoft SQL Server、Oracle 和 Sybase。然而,也有许多免费的 SQL 数据库。MySQL、PostgreSQL 和 SQLite 就是这样的例子。在本文中,我们将使用 SQLite 来介绍 SQL。

Photo by Shahadat Shemul on Unsplash

为什么要学习 SQL

学习 SQL 是一件非常有用的事情,可以帮助你与数据库进行交互。这样,您可以轻松快速地处理大型数据集。很多分析工作都在寻找具备 SQL 知识的候选人。如果你想离开 excel,它也非常适合数据分析。

建立

在我们继续学习 SQL 示例之前,我将解释如何建立自己的 SQLite 数据库,以便您可以了解我们所学的内容。你需要做的第一件事是安装一个 SQLite 浏览器

安装并运行它之后,您应该能够看到以下内容:

SQLite Browser

要创建一个新的数据库,您只需点击“新建数据库”并选择一个保存位置。然后,您可以继续创建任何包含数据的表。

如果您想使用 Python 将数据传输到数据库,请查看我以前的文章:

[## 用 Python 从 Excel 到数据库

了解如何使用 Python 进行快速数据分析

medium.com](https://medium.com/financeexplained/from-excel-to-databases-with-python-c6f70bdc509b)

桌子

当谈到关系数据库时,你有一个表的概念。你可以把一个表想象成一个数据的集合;或者,如果您熟悉 excel,您可以将其视为 Excel 工作表。

每个表都有一个名称和一个已定义的结构。让我们看一个例子。下面的 Excel 工作表,可以变成 SQL 表。

Excel Worksheet on the left and a db table on the right

为了创建表,我们需要运行一个 SQL 命令:

CREATE TABLE "Trade" (
 "TradeId" INTEGER,
 "TradeType" TEXT,
 "Notional" NUMERIC,
 "NotionalCurrency" TEXT,
 PRIMARY KEY("TradeId")
);

正如您所看到的,SQL 倾向于以一个动作词开始,后面是您想要操作的表。一旦我们创建了表,我们需要插入数据。我们可以通过以下命令来实现:

INSERT INTO "Trade" (
 "TradeId",
 "TradeType",
 "Notional",
 "NotionalCurrency"
)
VALUES
 ("672932","CDS","100000","GBP"),
 ("739393","Equity", "20000", "USD"),
 ("812033", "Bond", "50000", "EUR");

Photo by Mathew Schwartz on Unsplash

从数据库中检索数据

大多数情况下,数据库会被建立起来,您需要做的就是从数据库中查询数据。假设您需要查看表交易下的所有数据,您需要做的就是:

SELECT * FROM Trade

语句中的*表示您希望看到所有列。但是,如果您只想查看其中的两列,则必须显式选择它们:

SELECT TradeId, TradeType FROM Trade

限制返回的数据

然而,有时您并不知道该表下有多少数据,您首先要做的就是确定数据看起来像什么。因此,您可能希望将返回的数据限制在前 5 个条目中。你可以通过跑步做到这一点

SELECT * FROM Trade
LIMIT 5

在其他 SQL 版本中,如 MS Server 和 Sybase,这可以通过运行以下命令来实现:

SELECT TOP 5 * from Trade

找出表格中有多少行

在运行 SELECT 语句之前,您可能想知道将返回多少条记录;因此,您想知道表中有多少行。您可以通过运行以下命令找到答案:

SELECT COUNT(*) FROM Trade

给予:

跨表工作

一旦在不同的表中有了数据,您可能会决定要查看来自两个不同表的信息。方法是通过一个叫做 JOIN 的操作。让我们探索一下这是如何工作的。

表格和数据设置

假设您有一个名为 Trades 的表和一个名为 FX 的表,如下所示:

它是由以下人员编写的:

CREATE TABLE "FX" (
 "FROMCcy" TEXT,
 "TOCcy" TEXT,
 "RATE" NUMERIC,
 PRIMARY KEY("FROMCcy","TOCcy")
);
INSERT INTO "FX" (
 "FROMCcy",
 "TOCcy",
 "RATE"
)
VALUES
 ("GBP","USD","1.27"),
 ("EUR","USD", "1.13"),
 ("EUR", "CHF", "1.1"),
 ("JPY", "CHF", "0.0091");

如何将这两个数据集结合在一起?

SQL 联接的类型

有许多不同类型的连接;每一个都给你一种不同的方式将数据整合在一起。下图对此进行了最好的描述:

Compliments of reddit.com

左连接

左连接允许您查看出现在左表中的所有数据,或者您在连接中提到的第一个表,以及来自右表的任何匹配数据。

让我们看一个例子,我们想知道将我们的交易转换成美元所需的汇率。

SELECT * FROM Trade t
LEFT JOIN FX f ON f.FROMCcy = t.NotionalCurrency and f.TOCcy = 'USD'

请注意我是如何在特定属性(货币和名义货币)上定义贸易和外汇之间的左连接的,同时我将结果集限制为货币美元。

您可能已经注意到,第二行没有任何关于 FX 的信息;它回来时一片空白。这是因为,它在“右”表中找不到任何东西,而左连接允许显示来自交易的所有信息。

右连接

让我们看看当我们把左连接改为右连接时会发生什么。(注意:在大多数 SQL 客户机中,右连接就是简单的连接)。

SELECT * FROM Trade t
JOIN FX f ON f.FROMCcy = t.NotionalCurrency and f.TOCcy = 'USD'

导致:

如您所见,只返回了两行。其原因是因为从“右”表中只找到两个匹配。

其他类型的联接包括完全外部联接和交叉联接。

将两组结果放在一起

有时,您可能决定将两个不同的结果集放在一起。例如,假设你有两组结果,CDS:

SELECT * FROM Trade t
LEFT JOIN FX f ON f.FROMCcy = t.NotionalCurrency and f.TOCcy = 'USD'
WHERE TradeType = 'CDS'

然后是一组结果键:

SELECT * FROM Trade t
LEFT JOIN FX f ON f.FROMCcy = t.NotionalCurrency and f.TOCcy = 'USD'
WHERE TradeType = 'Bond'

显然,如果我们想把它们放在一起,我们可以把等号改成 In 语句

SELECT * FROM Trade t
LEFT JOIN FX f ON f.FROMCcy = t.NotionalCurrency and f.TOCcy = 'USD'
WHERE TradeType IN ('Bond', 'CDS')

但是,假设这两个查询完全不同,我们可以使用 UNION 操作:

SELECT * FROM Trade t
LEFT JOIN FX f ON f.FROMCcy = t.NotionalCurrency and f.TOCcy = 'USD'
WHERE TradeType = 'Bond'
UNION
SELECT * FROM Trade t
LEFT JOIN FX f ON f.FROMCcy = t.NotionalCurrency and f.TOCcy = 'USD'
WHERE TradeType = 'CDS'

只要两个结果查询返回相同的属性,您就可以联合它们。

Photo by Vincent Botta on Unsplash

聚合函数

最后,在介绍 SQL 时,您需要知道的最后一件事是聚合函数,特别是 GROUP BY 语句。

让我们看一个简单的例子。假设您想知道我们的交易表中所有交易类型的总和:

SELECT t.TradeType,sum(Notional* RATE) as 'NotionalUSD' FROM Trade t
LEFT JOIN FX f ON f.FROMCcy = t.NotionalCurrency and f.TOCcy = 'USD'
GROUP BY TradeType

注意,我们在 SELECT 和 group GROUP BY 语句中都指定了 TradeType。股权再次回到空白,因为它乘以名义美元与'零'从左边加入外汇汇率。

至此,您应该可以开始使用 SQL 了。

奇异值分解及其广泛应用简介

原文:https://towardsdatascience.com/an-introduction-to-svd-and-its-widely-used-applications-f5b8f19cb6cb?source=collection_archive---------14-----------------------

如果您在数据科学领域(或与之接近),即使您没有使用过 SVD,您也可能已经听过一千遍了。无论是对于 PCA(主成分分析)还是推荐算法,SVD 都是一种强大的技术,目前广泛应用于许多模型中——我们将描述它是什么,并展示它如何在一些关键方法中使用。

注意:我们不讨论代码部分,只讨论理论。

什么是 SVD?

SVD 的意思是奇异值分解。维数为 n×d 的矩阵 X 的 SVD 由下式给出:

其中:

  • UV 为直角正交;

  • D 为尺寸 d×n 的对角线

一些附加说明:

  • D 不一定是正方形
  • 矩阵的奇异值分解可以在对任何矩阵进行
  • 奇异值分解不同于矩阵的特征值分解

我们来定义一个矩阵的特征值分解。首先,对于一个矩阵 X 它存在当且仅当 X 是平方的并且特征向量在矩阵维数空间中形成一个基。如果是这种情况,那么可以写:

其中 P 是特征向量的矩阵,D eltaX 的特征值的对角矩阵——这里 D elta 是平方。

在某种意义上, SVD 是特征值分解的推广,因为它可以应用于任何矩阵。

主成分分析中使用的奇异值分解

PCA 表示主成分分析。给定一个输入矩阵 X ,它包括寻找作为原始坐标的线性组合的分量 p_i :

以这样的方式:

  • 分量为正交 ( E[p_ip_j]=0 )
  • 组件以这样的方式排序,即P1解释了最大的方差百分比,而p2解释了第二大的方差百分比(这一点没有被P1解释)等等。

我们这里假设 X 归一化(每个特征E(X _ I)= 0**Var(X _ I)= 1)。

可以看出,分量 p 由下式给出

其中γ是对 X 的方差-协方差矩阵进行特征值分解时找到的矩阵。注意,这是可能的,因为方差-协方差矩阵是对称的,并且任何对称矩阵都有特征值分解。还要注意的是, Gamma 的正交性意味着

还要注意,因为 E(x)=0E(p)=0 。和

其中 D elta 是按降序排列的 X 的方差-协方差矩阵的特征值的矩阵。这里要记住的关键是X 的主成分是通过使用方差-协方差矩阵的特征向量的线性变换得到的。

一旦我们有了组件,我们可以通过只保留顶部的 k ( k 是任意的)组件来减少我们的数据。

但是我们真的需要计算这个特征值分解吗?

不要!这就是 SVD 的用武之地。实际上,使用上面的 SVD 公式,方差-协方差矩阵的特征向量由 X 的 SVD 的矩阵 U 给出。并且特征值是来自 X 的 SVD 的奇异值的平方。

因此我们可以使用 SVD 来执行 PCA ,并且保持 X 的顶部 k 奇异值近似给定的顶部 k 主分量。

在一些常见情况下,通过 SVD 进行 PCA 在数值上比通过方差-协方差矩阵的特征值分解更有效(计算方差-协方差矩阵需要一些额外的时间)。

矩阵补全中使用的奇异值分解

对于大多数推荐算法,输入矩阵非常稀疏,矩阵分解方法是关键,因为空间需要“减少”到一个更小的潜在空间。奇异值分解在其中起着核心作用。

一般的矩阵分解问题表述为

在约束条件下,M 的秩小于或等于任意整数 r 。人们可以证明这个问题的

在哪里

并且 D_r 是通过仅保留第一个 r 奇异值而从 D 构建的。

人们可以注意到,当矩阵 X 有缺失值时,我们不容易解决上述问题。有几种方法可以解决这个问题。其中之一是从一个初始解开始,通过做 SVDs 迭代,直到收敛。我们不会在这里讨论这些方法的细节,但是底线是 SVD 也可以用于矩阵补全,因为它涉及到矩阵分解。

自助法简介

原文:https://towardsdatascience.com/an-introduction-to-the-bootstrap-method-58bcb51b4d60?source=collection_archive---------0-----------------------

关于 bootstrap 方法、动机及其工作原理的探讨

Bootstrap 是一种强大的基于计算机的统计推断方法,它不依赖于太多的假设。我第一次应用自举方法是在一个 A/B 测试项目中。当时我就像是使用了一种强大的魔法,仅仅从一个样本数据就形成了一个抽样分布。我的统计推断不需要公式。不仅如此,事实上,它还广泛应用于其他统计推断如置信区间、回归模型,甚至机器学习领域。这使我通过一些关于 bootstrap 的研究,用比我的理论数理统计课更实际的知识来补充统计推断知识。

本文主要介绍 Bootstrap 的核心概念及其应用。但是一些嵌入代码将被用作说明的概念。我们将介绍 bootstrap 重采样方法,然后说明 Bradley Efron(1979)提出 Bootstrap 的动机,并说明 Bootstrap 的一般思想。

相关基础知识

事实上,bootstrap 背后的思想包含了太多需要关注的统计主题。然而,这是一个回顾一些统计推断概念的好机会!相关的统计概念包括:

  • 基础微积分和函数的概念
  • 均值、方差和标准差
  • 分布函数和概率密度函数
  • 抽样分布
  • 中心极限理论、大数定律和依概率收敛
  • 统计泛函、经验分布函数和插入原理

具备以上一些基础知识将有助于获得 bootstrap 背后的基本概念。有些想法可能会涉及到高级统计,但我会用一种简单的方式,而不是非常正式的数学表达式来说明基本的想法,尽可能简单。如果你想了解更多关于这些概念的知识,文章末尾会提供一些链接。

自助抽样方法

bootstrap 的基本思想是在样本数据上对总体参数 θ (如总体均值)的一个估计(如样本均值)进行推断。它是一种重采样方法,通过从具有相同样本大小 n 的现有样本数据中独立地进行替换采样,并在这些重采样数据之间执行推理。

通常,引导包括以下步骤:

  1. 样本量为 n 的总体样本。
  2. 从原始样本数据中抽取一个样本,替换为大小为 n 的,复制 B 次,每个重新抽样的样本称为一个 Bootstrap 样本,总共有 B 个 Bootstrap 样本。
  3. 评估每个 Bootstrap 样本的 θ统计量,总共会有 θ 的 B 估计。
  4. 用这些最佳 Bootstrap 统计数据构建一个抽样分布,并使用它进行进一步的统计推断,例如:
  • 估计 θ的统计标准误差。
  • 获得 θ 的置信区间。

我们可以看到,我们通过对现有样本进行重新采样来生成新的数据点,并根据这些新的数据点做出推断。

【bootstrap 如何工作以及为什么工作?

在本文中,我将这个大问题分成三个部分:

  1. Efron 推出 bootstrap 的最初动机是什么?
  2. 为什么使用模拟技术?换句话说,如何通过重采样找到统计量的估计方差?
  3. 我们需要从原始样品中抽取一个样品并替换的主要想法是什么?

一、初始动机——估计者的标准误差

bootstrap 技术的核心思想是借助现代计算机能力进行某种统计推断。当 Efron 引入该方法时,它特别受到统计推断领域中评估者的准确性的激励。通常,估计标准误差是批判性思考统计估计准确性的第一步。

现在,为了说明 bootstrap 是如何工作的以及估计量的标准误差是如何起重要作用的,让我们从一个简单的例子开始。

情景案例

想象一下,你想总结 100 名学生每天在你的实验室拿起智能手机的次数。很难像人口普查那样统计整个实验室的皮卡数量。取而代之的是,你可以做一个在线调查,这个调查还提供了一个计数应用程序。在接下来的几天里,你会收到 30 名学生的回复,告知他们在某一天的接送次数。你计算了这 30 个拾音器的平均值,得到拾音器的估计值为 228.06 倍。

Codes for this case, just feel free to check out.

在统计学领域,上述过程称为点估计。我们想知道的是整个实验室中皮卡的真实数量。我们没有人口普查数据,我们能做的只是通过一个基于观察样本的估计器来评估人口参数,然后得到一个估计值作为对实验室中智能手机平均使用情况的评估。

  • 估计量/统计量:计算估计量的规则在这种情况下是样本平均值,通常表示为
  • 总体参数:总体的数字汇总。在这种情况下,是我们实验室每天接听电话的平均时间,通常表示为 μ

一个关键问题是——这个估算结果有多准确?

由于,实际上 X̄ = μ 发生 的情况几乎不会发生。 因此 除了报告点估计值外,还应给出一些关于精度的指示。衡量准确性的常用标准是估计值的标准误差。

标准误差

估计量的标准误差是它的标准偏差。它告诉我们你的样本估计值偏离实际参数的程度。如果标准误差本身涉及未知参数,我们使用估计标准误差* 通过用参数的估计值替换未知参数。*

我们举个例子。在我们的例子中,我们的估计量是样本均值,对于样本均值(而且几乎只有一个!),我们有一个简单的公式很容易获得它的标准误差。

然而,在现实世界中,总体的标准差 σ 总是未知的,因此最常见的度量是 估计标准差、 使用样本标准差 S 作为总体的估计标准差:

在我们的例子中,我们有 30 个样本,样本均值为 228.06,样本标准差为 166.97,因此我们的估计样本均值的标准差为166.97//√30 = 30.48。

统计推断中的标准误差

现在我们已经得到了我们的估计标准误差。如何在统计推断中使用标准误差?我们用一个简单的例子来说明。

粗略地说,如果一个估计量具有正态分布或近似正态分布,那么我们期望我们的估计在大约 68%的时间里与其期望值相差不到一个标准误差,在大约 95%的时间里相差不到两个标准误差。

在我们的例子中,回想一下我们收集的样本是 30 个响应样本,这在经验法则中是足够大的,中心极限定理告诉我们 X̄的抽样分布是非常接近正态分布。结合估计的标准误差,我们可以得到:

我们有理由相信,学生每天在我们实验室拿起智能手机的平均次数 μ的真实值,位于 X̄的大约 2 个标准误差之内,即(228.06-2×30.48,228.06+2×30.48) = (167.1,289.02)。

统计世界中的理想与现实

我们已经做出了统计推断。然而,这一推论是如何顺利进行的是在一些严格的假设下。

让我们回忆一下到目前为止我们可能用过的假设或经典定理:

  • 我们的样本均值的标准差可以很容易地估计,我们使用样本的标准差作为估计量,并通过一个简单的公式来获得估计的标准差。
  • 我们假设我们知道或者能够估计估计者的总体。在我们的例子中是近似的正态分布。

然而,在我们的现实世界中,有时很难满足如上的假设或定理:

  • 很难知道关于人口或人口分布的信息。
  • 一般来说,估计值的标准误差很难估计。很多时候,没有像样本均值的标准差这样精确的公式。如果现在,我们要对智能手机拾音器的中值做一个推断,样本中值的标准误差是多少?

这就是 bootstrap 解决这类问题的原因。当这些假设被违反时,或者当不存在估计标准误差的公式时,bootstrap 是强有力的选择。

二。关于引导程序的说明****

为了说明主要概念,下面的解释将发展一些数学定义和外延,这是一种非正式的,以提供更多的直觉和理解。

1.初始场景

假设我们要估计我们的统计量的标准误差来作出一个关于总体参数的推断,如用于构造相应的置信区间(就像我们以前所做的一样!).并且:

  • 我们对人口一无所知。
  • 没有精确的公式来估计统计的标准误差。****

设X1,X2,…,Xn 是分布函数为 F 的总体 P 中的随机样本。M = g(X1,X2,…,Xn) ,是我们感兴趣的参数的统计量,意味着统计量是样本数据 X1,X2,…,Xn 的函数。我们想知道的是M方差**,记为 Var(M)。****

  • 首先,由于我们对总体一无所知,我们无法确定 Var(M) 的值,这需要已知总体的参数,所以我们需要估计 Var(M) 的估计标准差表示为、* EST_Var(M)。(还记得样本均值的估计标准差吗?)***
  • 第二,在现实世界中,除了样本均值之外,我们总是没有一个简单的公式来计算 EST_Var(M) 。

这就导致我们需要近似EST _ Var(M) 如何?在回答这个问题之前,让我们先介绍一种常见的实用方法是模拟,假设我们知道 P** 。**

2.模拟

先说模拟的思路。借助计算机获得有关统计抽样分布的信息是很有用的。但是它有一个重要的假设——假设我们知道人口

现在,假设 X1,X2,…,Xn 是来自总体的随机样本,并假设 M= g(X1,X2,…,Xn)是感兴趣的统计量,我们可以通过如下模拟来近似统计量 M 的均值和方差:**

  1. 从 P 中抽取大小为 n 的随机样本。
  2. 计算样本的统计数据。
  3. 流程 1 重复 B 次。和 2,并得到 B 统计量。
  4. 得到这些 B 统计量的平均值方差

这个模拟为什么会起作用? 从一个经典定理开始, 大数定律 :

  • 当 B → ∞ 时,这些 B 统计值的平均值收敛到统计值的真实平均值 M

并通过大数定律和几个与依概率收敛有关的定理:

  • 当 B → ∞ 时,这些 B 统计量的样本方差收敛于统计量 M 的真实方差。

借助计算机,我们可以使 B 尽可能大,以逼近统计量 M 的抽样分布。

下面是在前面的电话拾音案例中模拟的示例 Python 代码。我使用 B=100000,样本平均值的模拟平均值和标准误差非常接近最后两个单元格中的理论结果。请随意退房。

Example codes for simulation applied with the previous phone-picks case start from cell [10].

3.经验分布函数和插入原理

我们已经学会了模拟的概念。现在,我们是否可以通过模拟的方式近似EST _ Var(M)?不幸的是,要做上面的模拟,我们需要知道人口 P 的信息。事实是,我们对 p 一无所知。为了解决这个问题,采用了 bootstrap 方法中最重要的组件之一:

经验分布函数逼近总体分布函数,应用插入原理得到** Var(M)的估计值——即插入估计量。**

(1)经验分布函数

经验分布函数(EDF) 的思想是从现有数据集构建分布函数(CDF)。EDF 通常非常接近 CDF,特别是对于大样本量。事实上,在实际中,这是一种估计随机变量 CDF 的常用而有用的方法。

EDF 是一个离散分布,它给每个数据点赋予相等的权重(即,它给原始 n 个观测值中的每一个赋予 1/ n 的概率),并形成一个累积分布函数,该函数是一个阶跃函数,在每个 n 数据点上跳跃 1/ n

(2)统计功能

Bootstrap 使用 EDF 作为人口 CDF 的估计值然而,我们知道 EDF 是一种累积分布函数(CDF)。为了应用 EDF 作为我们统计 M** 、的估计量,我们需要将 M 的形式作为 CDF 类型的函数,甚至感兴趣的参数也要有一些基线。要做到这一点,一个常见的方法是称为统计泛函的概念。粗略地说,统计泛函是分布函数的任何函数。让我们举个例子:**

假设我们对人口的参数感兴趣。在统计领域,总有这样一种情况,感兴趣的参数是分布函数的函数,这些被称为统计泛函。下面列出了总体平均值 E(X)是一个统计函数:

从上面我们可以看出,总体 E(X)的均值也可以表示为总体的 CDF 的一个形式 F —** 这是的一个统计泛函。当然,这个表达式可以应用于均值以外的任何函数,比如方差。**

统计函数可以看作是描述总体特征的量。F 的均值、方差、中位数、分位数是总体的特征。因此,使用统计泛函,我们有一个更严格的方法来定义人口参数的概念。因此,我们可以说,我们的统计量 M 可以是:M=g(F),用人口 CDF F。

(3)插件原理= EDF +统计泛函

我们已经使我们的统计量 is M = g(X1,X2,…,Xn)=g(F)成为一个统计函数形式。但是,我们不知道 F。所以我们必须为 F“插入”一个估计量,“到”我们的 M=g(F),以便使这个 M 可以被评估。

叫做插件原理。一般来说,插入原理是一种通过评估相同的泛函,从总体分布中估计统计泛函的方法,但是使用基于样本的经验分布。该估计被称为感兴趣的总体参数的插件估计。例如,总体分布的中值可以由样本的经验分布的中值来近似。这里的经验分布是由样本形成的,因为我们不知道人口。简单来说:

  • 如果我们感兴趣的参数,比如θ,具有统计函数形式θ=g(F),其中 F 是总体 CDF。
  • θ=g(F)的插入式估计量定义为θ_hat=g(F_hat):

  • 从上式可以看出,我们将θ_hat 和 F_hat“代入”未知的θ和 F,这里的 F_hat 纯粹是由样本数据估计的。
  • 注意,θ和θ_hat 都是由同一个函数 g(.).

下面举个刻薄的例子,我们可以看到 g(。)表示平均值,即所有数据点的平均值,它也适用于样本平均值。这里的 F_hat 是作为 f 的估计量的样本形式。我们说样本均值是总体均值的插入估计量。(更明确的结果将很快提供。)

那么,F_hat 是什么?还记得 bootstrap 使用经验分布函数(EDF)作为人口 CDF 的估计值吗?事实上,EDF 也是一种常用的估计器,广泛应用于 F_hat 的插入式原理中。

让我们看看,如果我们将 EDF 插入其中,我们的估计器 M = g(X1,X2,…,Xn)=g(F)会是什么样子。

  • 设感兴趣的统计量是 M=g(X1,X2,…,Xn)= g(F)来自一个总体 CDF F
  • 我们不知道 F,所以我们为 M 建立一个插入式估计量,M 变成 M_hat= g(F_hat)。让我们重写 M_hat 如下:

我们知道 EDF 是一个离散分布,通过概率质量函数 PMF 将概率 1/ n 分配给 n 个观测值中的每一个,因此据此,M_hat 变为:

据此,对于我们的均值例子,我们可以发现均值的插入估计量 μ 就是样本均值:

因此,我们通过插入原理,对 M=g(F)作出估计,比如说 M_hat=g(F_hat)。记住,我们要找出的是 Var(M),我们用 Var(M_hat)来逼近 Var(M)。但是一般情况下,除了样本均值,Var(M_hat)没有精确的公式!它引导我们应用一个模拟。

(4)自助方差估计

快到最后一步了!让我们用插件原理概念来刷新整个过程。

我们的目标是估计我们的估计量 M 的 方差,也就是 Var(M)。 自举原理如下:

  1. 我们不知道人口P 与 CDF 表示为 F,所以 bootstrap 使用经验分布函数(EDF)作为 F 的估计值。****
  2. 使用我们现有的样本数据形成一个 EDF 作为估计人口。
  3. 应用插入原理使 M=g(F)可以用 EDF 计算。因此,M=g(F)成为M_hat= g(F_hat) 它是带 EDF 的插入式估计器— F_hat。
  4. 模拟近似为** Var(M_hat)**

回想一下,要进行原始版本的模拟,我们需要从总体中抽取一个样本数据,从中获得一个统计量 M=g(F ),并将该过程重复 B 次,然后获得这些 B 统计量的方差,以逼近统计量的真实方差。

因此,要在步骤 4 中进行模拟,我们需要:

  1. EDF 中提取样本数据。
  2. 获得一个插件统计 M_hat= g(F_hat)。
  3. 重复两个程序 B 次。
  4. 得到这些 B 统计量的方差,来逼近插件统计量的真实方差。(这是一个容易混淆的部分。)

什么是模拟?其实就是我们在本文开头提到的 bootstrap 抽样过程!****

这里两个问题(我保证这是最后两个!):

  1. 在步骤 1 中,从 EDF 中提取看起来如何?
  2. 这个模拟是如何工作的?

EDF 的图纸看起来怎么样?

我们知道 EDF 从现有样本数据 X1,…,Xn 构建 CDF,根据定义,它在每个样本数据点放置质量 1/n。因此,从 EDF 中抽取一个随机样本,可以看作是从我们现有的样本数据 X1,…,Xn 中抽取 n 个观察值,并进行替换。这就是为什么如上所示,使用替换对引导样本进行采样。****

模拟是如何工作的?

插件估计量 M_hat=g(F_hat)的方差就是 bootstrap 模拟想要模拟的。在模拟的开始,我们从现有的样本数据 X1,…,Xn 中得出替换的观察值。让我们将这些重采样数据表示为 X1,…,Xn。现在,让我们再次将 bootstrap 模拟与我们的原始模拟版本进行比较。

Var(M=g(F))的原始模拟过程:

****Original Simulation Version- Approximate EST_Var(M|F) with known F**Let X1, X2, … , Xn be a random sample from a population *P* and assume *M*= g(X1, X2, …, Xn) is the statistic of interest, we could approximate variance of statistic *M* by simulation as follows:1\. Draw random sample with size n from P.
2\. Compute statistic for the sample.
3\. Replicate B times for process 1\. and 2 and get B statistics.
4\. Get the variance for these B statistics.**

Same with previous Simulation part for simulating Var(M).

Var(M_hat=g(F_hat))的自举模拟

****Bootstrap Simulation Version- Approximate Var(M_hat|F_hat) with EDF**Now let X1, X2, … , Xn be a random sample from a population *P with CDF F,* and assume *M*= g(X1, X2, …, Xn ;F) is the statistic of interest. But we don't know F, so we:1.Form a EDF from the existing sample data by draw observations with replacement from our existing sample data X1, …, Xn. These are denote as X1*, X2*, …, Xn*. We call this is a bootstrap sample.2.Compute statistic *M_hat*= g(X1*, X2*, …, Xn* ;F_hat) for the bootstrap sample.3\. Replicate B times for steps 2 and 3, and get B statistics M_hat.4\. Get the variance for these B statistics to approximate the **Var(M_hat)**.**

Simulating for Var(M_hat).

你对上述流程熟悉吗?其实和我们之前说的 bootstrap 抽样法的过程是一样的!

三。引导程序的工作原理是什么?

最后,让我们看看我们的模拟将如何工作。我们从这个 bootstrap 模拟中得到的近似值是针对 Var(M_hat)** 的,但我们真正关心的是 Var(M_hat)能否逼近 Var(M)。所以这里有两个问题:**

  1. 将 bootstrap 方差模拟结果,即 S ,**能很好地近似为 Var(M_hat)?**
  2. Var(M _ hat)能近似为 Var(M)吗?

为了回答这个问题,让我们用一个图表来说明这两种类型的模拟误差:

  1. 从 bootstrap 方差估计中,我们将得到 Var(M_hat)的估计—Var(M)的插入估计。而大数定律告诉我们,如果我们的模拟次数 B 足够大,bootstrap 方差估计 S,是 Var(M_hat)的一个很好的近似。幸运的是,借助计算机,我们可以随心所欲地得到一个更大的 B。所以这个模拟误差可以很小。
  2. M_hat 的方差,是 M 相对于真实 f 的方差的插入式估计。是 Var(M _ hat;f _ hat)Var(M;F) ?换句话说,插入式估计量是否与感兴趣的估计量非常接近?这是我们真正关心的关键点。事实上,插入估计量的渐近性质这一主题属于高级数理统计范畴。但是让我们解释一下主要的问题和想法。
  • 首先,我们知道如果样本量很大,比如说 F_hat → F,经验分布将很好地收敛到真实分布函数。
  • 第二,如果 F_hat → F,并且如果是对应的统计函数 g(。)是一个平滑度条件,那么 g(F_hat) → g(F)。在我们的例子中,统计函数 g(。)是方差,满足所需的连续性条件。因此,这解释了为什么 bootstrap 方差是估计量 m 的真实方差的良好估计。**

一般来说,一些泛函上的光滑条件很难验证。幸运的是,大多数常见的统计函数,如均值、方差或矩,都满足所需的连续性条件。它规定自举是可行的。当然,尽可能使原始样本量不要太小。

以下是我的自举样本代码的皮卡情况下,觉得自由检查。

自举概述

让我们用下图回顾一下 bootstrap 的主要思想!

到目前为止,我知道有大量的统计概念并不容易。但是理解一个方法背后的基本概念可以让我们在应用它的时候有一个正确的方向。毕竟,Bootstrap 已经被应用到更广泛的实际案例中,从基础部分开始学习更有建设性。感谢阅读到目前为止,希望这篇文章有所帮助!如果我有任何错误,请留下您的评论:)!

参考

Efron 的最有帮助的书,有更一般的 Bootstrap 的概念和它如何连接到统计推断。

也是一本有用的书,从 EDF 到 Bootstrap 方法

其他书籍:

经验分布函数和插入原理

其他材料

朴素贝叶斯算法简介

原文:https://towardsdatascience.com/an-introduction-to-the-naive-bayes-algorithm-be3bd692273e?source=collection_archive---------8-----------------------

大多数垃圾邮件过滤器背后的算法是如何工作的

朴素贝叶斯算法是数据科学领域中一个非常常见的工具。它也可能是最受欢迎的,因为它是世界上大多数垃圾邮件过滤器背后的大脑。这个算法的基础很简单:它根据对一个相关事物的了解来计算一个事物的概率。

由于这种算法也是世界上大多数垃圾邮件过滤器的基础,我将提供这方面的例子。在讨论垃圾邮件过滤器时,朴素贝叶斯的基础是,它根据对电子邮件的了解来计算电子邮件是垃圾邮件的可能性。那么,垃圾邮件过滤器有哪些方法可以识别一封电子邮件是垃圾邮件呢?

一些潜在的指标包括:

  • 它提到了一个“尼日利亚王子”(特别是如果所说的尼日利亚王子给你钱)。
  • 主题行包括短语“热门本地单身”(不幸的是,这也可能是垃圾邮件)。
  • 它包括紧急行动呼吁,如“您确认收到此消息很重要”或“此机会只会持续有限的时间。”

请注意,这些例子都不能保证它是垃圾邮件,天真的模型也不认为它能保证这一点。然而,我想我们都同意,包含这些例子的电子邮件比其他邮件更有可能是垃圾邮件。

我如何阅读统计符号?

在我们深入研究朴素贝叶斯算法如何工作的细节之前,重温一下统计符号是很重要的。朴素贝叶斯作为一种统计模型,终究只能用统计学的语言来真正理解。有几个重要的符号需要理解。它们是:

  • P(S)表示某事(S)的概率(P);
  • P(S | T)表示已知一件事(T)的情况下,某件事(S)发生的概率(P);
  • P(S T)表示已知某事(T)不为真时,某事(S)的概率(P)。

这些工具是朴素贝叶斯模型的基础。本质上,朴素贝叶斯计算的是,给定我们所知道的使用上述符号表达的情况的信息,某事为真的概率。

朴素贝叶斯算法是如何工作的?

朴素贝叶斯模型将几个不同的计算概率相乘,以确定某事为真或为假的概率。这也许可以通过一个例子得到最好的理解。假设您正在创建一个垃圾邮件过滤器,从尼日利亚王子发送的邮件开始。为此,您可以从一个非常简单的朴素贝叶斯模型开始,该模型根据包含短语“尼日利亚王子”的电子邮件是垃圾邮件的概率和包含短语“尼日利亚王子”的电子邮件是而不是垃圾邮件的概率来计算给定电子邮件是垃圾邮件的几率。该模型将具有以下形式:

P(S | N) = P(N | S) / (P(N | S) + P(N S))

用简单的英语写,根据我们的“尼日利亚王子”过滤器,电子邮件是垃圾邮件的概率等于包含短语“尼日利亚王子”的电子邮件是垃圾邮件的概率除以包含短语“尼日利亚王子”的电子邮件是垃圾邮件的概率加上包含短语“尼日利亚王子”的电子邮件不是垃圾邮件的概率之和。

为了使用这个模型,你需要知道所有这些概率。这叫做训练你的模型,这个过程的描述可以在如何在多个模型中选择中找到。在这个例子中,假设您的训练数据显示了以下内容:

  • 90%包含“尼日利亚王子”的电子邮件都是垃圾邮件,而且
  • 只有 2%包含“尼日利亚王子”的邮件不是垃圾邮件。

在这种情况下,我们的朴素贝叶斯模型表明,任何包含短语“尼日利亚王子”的电子邮件

0.9 / (0.9 + 0.01) = 0.989

换句话说,它说包含短语“尼日利亚王子”的电子邮件应该在 98.9%的情况下被垃圾邮件过滤器删除。更进一步,每次都删除它是相当安全的…

这种模式如何扩展?

显然,上面介绍的垃圾邮件过滤器太简单了,没有用。这是因为一个非常具体的原因:它只有一个单一的过滤器检查一个单一的短语。世界上的垃圾短信种类很多,很多都和尼日利亚王子无关。为了使这个模型有用,它必须能够捕捉所有这些不同的场景。

幸运的是,当应用多个不同的过滤器时,朴素贝叶斯模型继续以相同的方式工作。它只是将不同过滤器的概率相乘。因此,如果我们扩展我们的模型,以包括上面列出的三个不同的例子(“尼日利亚王子”、“热门的当地单身人士”和“确认收到此消息很重要”),它看起来会像下面这样:

P(S) = P(S | N) * P(S | H) * P(S | I)

P(S | N) = P(N | S) / (P(N | S) + P(N S))

P(S | H) = P(H | S) / (P(H | S) + P(H S))

P(S | I) = P(I | S) / (P(I | S) + P(I S))

注意,在上面的等式中,我用 H 来表示“热门本地单曲”,用“I”来表示“确认收到这条消息很重要。”

为了计算一封包含所有三个可疑短语的电子邮件的概率,我们需要知道与这三个短语相关的概率。这也是通过将模型训练成训练数据集来完成的,其简要介绍可以在如何在多个模型之间进行选择中找到。假设训练数据集中的数据显示:

  • 70%包含短语“热门本地单身”的电子邮件是垃圾邮件,
  • 20%包含“热门本地单身”这句话的邮件不是垃圾邮件(可能那些用户有 Tinder 账号),
  • 50%包含“确认收到此邮件很重要”这句话的电子邮件是垃圾邮件,并且
  • 30%包含“确认收到此邮件很重要”这句话的电子邮件不是垃圾邮件。

从前面的例子中我们已经知道 P(S | N)是 0.989,所以我们不需要重新分析它。

执行计算以确定包含所有三个短语的电子邮件是垃圾邮件的概率,得到:

P(S | H) = 0.7 / (0.7 + 0.2) = 0.778

P(S | I) = 0.5 / (0.5 + 0.3) = 0.625

P(S) = 0.989 * 0.778 * 0.625 = 0.481

这表明,假设训练数据集实际上包含了我在这个例子中编造的概率,包含这三个短语的电子邮件有 48.1%的几率是垃圾邮件。这是相当惊人的低,但也证明了重要的一点

为什么这个概率这么低?

朴素贝叶斯模型依赖于模型中的每一个概率。全部都是。因此,如果过滤器中使用的任何概率较低,模型预测的最终概率也会较低。如果存在过滤器显示包含短语的电子邮件是垃圾邮件的可能性为 0%的任何情况,这尤其成问题。例如,如果训练数据集中包含短语“爱你的,妈妈”的 0 条消息是垃圾邮件,那么模型将永远不会将带有该短语的消息标记为垃圾邮件。所有的尼日利亚王子都可以把这句话加到他们的电子邮件中,突然之间,模型就无法捕捉到他们中的任何一个了!

为了克服这一挑战,朴素贝叶斯模型通常使用伪计数,人为地夸大带有该短语的邮件是垃圾邮件的百分比。进行计算时,伪计数值通常用 k 表示。在计算包含“爱你的,妈妈”(表示为“L”)的邮件是垃圾邮件的几率时,它采用以下形式:

P(S | L) = (k +包含 L 的垃圾邮件数量)/ (2*k +垃圾邮件总数)

分子中有 k 会人为增加包含 L 的垃圾邮件的数量,分母中有 2k 会人为增加垃圾邮件的总数。由于分母中的 k 项是分子中的两倍,这意味着伪计数自然会将概率拉向 50%。注意避免将 k 设置得太大,以至于淹没了实际的数据集,并且所有项的概率约为 50%。

作为工作原理的示例,让我们使用以下假设来计算包含短语“爱你的,妈妈”的电子邮件是垃圾邮件的概率:

  • 总共 42 封垃圾邮件中有 0 封包含该短语,并且
  • k 被设置为 4。

那么包含短语“爱你的,妈妈”的电子邮件变成:

P(S | L) = (4 + 0) / (2 * 4 + 42)

P(S | L) = 0.08

这个伪计数将我们的过滤器报告的概率从 0%增加到 8%,降低了检查包含该短语的电子邮件时出现假阴性的可能性。

提醒一句

我们还没有讨论的一件事是,为什么这个算法被称为“朴素贝叶斯”贝叶斯部分自然来自于它基于贝叶斯统计的事实。不幸的是,天真的部分是承认这是一个非常天真的模型。也就是说,这个模型假设在计算中使用的键之间没有任何关系。

有时候这个假设成立。包含“尼日利亚王子”这句话的邮件比其他邮件包含“桌子”这个词的可能性大还是小?大概没啥关系吧。或者,一个特别爱出风头的电子邮件人,喜欢说“确认收到这条信息很重要”,也提到冰淇淋的可能性有多大?这很难说——也许那个人没有理由提到冰淇淋,也许他们正在寻找资金来帮助他们开办一家冰淇淋商店。

但是还有其他时候这个假设不成立。我相信你能想出很多例子,一个单词的出现使得其他单词也更有可能出现。我相信你可以想出一些例子,说明这些单词的组合使得给定的电子邮件更有可能是垃圾邮件。

为了抓住这种假设的危险,我将使用 Joel Grus 的书从头开始的数据科学中的一个例子。他以兜售“廉价伟哥”或“正宗劳力士”的垃圾邮件为例。相关联的垃圾邮件过滤器正在寻找单词“伟哥”和“劳力士”

他在书中假设,包含“伟哥”一词的垃圾短信有 50%是垃圾短信,包含“劳力士”一词的垃圾短信有 50%是垃圾短信。然后,他计算出垃圾邮件同时包含“伟哥”和“劳力士”的几率是 0.5 * 0.5 = 0.25。这显然是荒谬的,也是朴素贝叶斯模型的弱点之一。

测试模型

这一弱点使得在信任朴素贝叶斯分类模型之前测试它们的性能变得极其重要。模型测试是模型开发过程中非常重要的一部分,本质上是指使用模型预测已知的数据集,并将模型预测与已知结果进行比较。表现好的模型会匹配已知结果,表现差的模型不会。你可以在如何在多个模型中选择中找到更多关于测试模型的信息。

在朴素贝叶斯模型的情况下,通常通过计算四个参数来进行测试:

  • “真阳性”的数量,或者模型正确预测某事为的情况;
  • “假阳性”的数量,或者模型错误地预测某事为的情况;
  • “真否定”的数量,或模型正确预测某事为的情况;和
  • “假阴性”的数量,或者模型错误地预测某事为的情况。

改进模型的方法

当开发你的第一个朴素贝叶斯模型时,你可能会测试你的模型,发现它非常不准确。这是开发数据科学模型的标准部分。因此,有一个不同事物的列表来尝试提高模型的质量是非常有帮助的。这里有一些想法:

  • 使用短过滤器:你的模型中非常详细的过滤器不会产生有用的结果,因为它们太严格了。它们不会出现在足够多的不同电子邮件中来提供有价值的过滤器。基于这一点,我们示例中的过滤器“确认收到此邮件很重要”是一个糟糕的过滤器。可能有很多很多电子邮件包含这个意图,但很少会包含这个具体的句子。通过使用非常短的过滤器而不是完整的消息,可以避免这个问题。一些可能的例子包括“接收”、“确认接收”和“这很重要”
  • 使用重复的单词:有可能一次使用的单词并不意味着一封邮件是垃圾邮件,但是重复使用的单词就意味着是垃圾邮件。这在试图推销产品的垃圾邮件中很常见,因为他们反复使用这个词,以确保这个词一直在你的脑海中。例如,一封非常友好的电子邮件可能会使用“增强”这个词,而一封推销“男性增强”的电子邮件可能会一遍又一遍地使用这个词。为了避免这个问题,您可以创建一个字典来跟踪每个过滤术语在电子邮件中出现的次数。然后加入一个限制,这样,如果某个过滤条件出现的次数多于该过滤条件,而不是仅出现一次,则只考虑该过滤条件。
  • 添加一个词干分析器函数:我们到目前为止讨论的例子都不知道一些最差的和另一些相似。例如,“更好”和“最好”非常相似,但是显示为两个完全不同的过滤器。词干分析器功能可以识别这些相似之处,并将它们组合成一个过滤器。这是一件很难从头开始做的事情,大多数人使用搬运工斯特梅尔帮助。
  • 使用非基于单词的过滤器:本文中的所有过滤器都基于单词和短语。但是这没有理由成为你模型中的一个限制。考虑使用其他过滤器。如果您添加了一种搜索不同类型图像的方法会怎么样?还是数字?或者电子邮件地址?

履行

提供朴素贝叶斯模型的详细实现超出了本文的范围;然而,那些寻求更多信息的人应该考虑从头开始查看数据科学中提供的文档。它提供了非常详细的实现,包括我们在这里讨论的所有不同计算的实际 Python 代码。

包装它

朴素贝叶斯算法是垃圾邮件过滤器等应用程序中常用的分类算法。它通过计算某件事是或不是基于其他可用知识的事实的概率来运作。当在垃圾邮件过滤器中使用时,这通常采取识别包含特定单词的电子邮件是否是垃圾邮件的形式。这些概率可以相乘,允许模型使用多个不同的过滤器来确定总概率。

将多个过滤器组合在一起存在基于单个过滤器具有 0 概率而返回假阴性的风险。这通常通过包含伪计数来克服。伪计数人为地将正结果和负结果相加,将正结果概率为 0 的过滤器改变为结果概率非常低的过滤器。这种解决方案可以防止过滤器获得肯定结果的可能性为零,并避免使结果立即无效。

请记住,这个算法的名称包含“幼稚”一词是有原因的。它假设没有一个过滤器以任何方式彼此相关。这是一个巨大的假设,任何知道语言如何运作的人都会相信。同时,这个模型无论如何都表现得很好,只要记住这个限制就可以使用。

模型在首次开发时并不总是表现良好。这是开发模型的一个简单现实。在模型测试失败后,改进过滤器的一些方法包括:1)使用短的、有针对性的过滤器;2)使过滤器基于重复的单词,而不是单词的单个实例;3)添加词干分析器功能以识别常用词;以及 4)使用基于事物而不是单词的过滤器。

关系数据库简介

原文:https://towardsdatascience.com/an-introduction-to-the-relational-database-820e0ab62123?source=collection_archive---------35-----------------------

作为一名数据科学家,您工作的很大一部分是获取您需要操作的数据。在许多公司中,这些数据将存储在一个或多个关系数据库中。本文的目标是介绍关系数据库——什么是关系数据库以及为什么它们在历史上如此受欢迎。

不同类型的数据

重要的是要理解有不同类型的数据,每种数据都适用于不同的存储机制。一个常见且重要的特征是区分 结构化非结构化 数据。

结构化数据是非常适合电子表格的东西。想象大量带有一致标签的小块信息。例如,地址就是结构化数据。大多数美国地址由相同的五个字段组成——街道地址、第二个地址字段(例如,邮政信箱)、城市、州和邮政编码。

非结构化数据是一种你更可能存储在 Word 或 Google doc 中的信息。一篇论文,一份电话记录,一本书的内容。非结构化数据并没有真正分解成可以有效分离或查询的一致的小信息块(与地址相反,您可能希望检索给定城市、州或邮政编码内的所有地址)。

还有半结构化数据——结构化和非结构化数据的混合。如果你去看医生,他们可能会问你的名、姓、体重和身高。这些都是适合电子表格的结构化信息。但也可能有一个大的“注释”字段,其中包含描述医生对您症状的观察的非结构化文本。

在实践中,当您获得更多的非结构化数据时,您可以将它们转换成半结构化数据。如果我只写一篇论文,我可能会以非结构化格式存储,比如 Google doc。如果我负责审查和评分 100 篇论文,我可能会将它们视为半结构化数据,其中包含名、姓、系、提交日期和年级等结构化信息,然后是一个指向提交的 PDF 的链接,以保存论文本身的非结构化文本。

它从一个文本文件开始

在微型计算机的早期,如果你想把信息存储到磁盘上,你会把它写到一个文本文件中,或者如果你雄心勃勃,某种更有效的二进制存储格式。实际上,每当你编写一个软件时,你都是在从头开始设计你自己的存储机制。如果你只是想保存非结构化的数据,这是相当容易的。当它改变的时候把它写到一个文件中,当你想取回它的时候从文件中读取它。

当你想处理结构化的数据时,问题就出现了。您可以先写出列名,然后以逗号或制表符分隔的格式保存信息。但是,如果您想要检索数据的子集(比如生活在加利福尼亚的所有学生的地址),这是低效的,因为您必须通读文件中的每一条记录才能找到您想要的记录。

例如,如果您有一个 20,000 名学生的列表,并且想要检索居住在加利福尼亚的 500 名学生,您必须获取所有 20,000 名学生,并且只丢弃不在加利福尼亚的学生。这使得检索操作非常缓慢,尤其是对于大型数据集。这就像有一个装满学生档案的文件柜,不得不取出并放回每一个,只是为了找到哪些人住在某个特定的州。

移动到表格

改善这种情况的一种方法是将信息存储在二维表格中——想象一个 Excel 电子表格——列名在顶部,数据在下面的行中。这本身并没有太大的改善,但它让我们能够添加索引,它们会带来很大的不同。

添加索引

在关系数据库中,你会得到表和索引。索引允许你说“我关心基于这个字段的值获取信息,让它更快”。它们通过在硬盘上保存附加信息(“指针”)来工作,根据给定字段的值指向记录,并根据索引字段的值快速检索信息。

例如,如果您按城市索引邮寄地址列表,数据库在保存每个新地址时会多花一点时间,因为它必须写入索引。但是,这将使“检索旧金山的所有地址”更快。实际上,我们是在用写性能的一点损失(保存一个东西需要多长时间)换取读性能的显著提高(返回一组记录需要多长时间)。

对于读的次数比写的次数多的数据来说,这是一个特别好的权衡。例如,优化《纽约时报》上一篇文章的读取性能要比优化写入性能重要得多,因为任何给定的故事都只更新几次(假设有一些编辑/更正),但会被读取数十万次。

尽管索引在大多数关系数据库介绍中并不突出,但它实际上是使这种数据库如此强大和高性能的原因。

消除重复

“关系型”数据库的名称来源于拥有多个相关表的想法。这是 Ted Codd 1970 年在 IBM 工作时写的支持这种方法的理论论文。如果你有几分钟的时间,它值得一读。作为一名数据科学家,养成阅读研究论文的习惯将对你大有裨益,其中的数学非常简单!

假设我们想为一所当地社区大学创建一个课程及其相关教材的数据库,以方便学生查找和订购他们需要的书籍。它可能看起来像这样:

你注意到表中的重复了吗?最明显的是,每本书的教授姓名和课程名称都是重复的。首先,这浪费了硬盘空间。这在现在没什么大不了的,但在 1970 年你付钱的时候,这是一个真正的考虑因素!

更重要的是出错的风险。编程中有一个重要的原则叫做“干”——或者不要重复自己。这个想法是,如果你在多个地方写相同的代码,在某个时间点你很可能改变代码,并且可能忘记在其中一个地方改变它。数据也是如此。首先,您可能在最初输入数据时输入错误。更重要的是,如果数据在未来发生变化(也许您改变了教授课程的教授),您可能会忘记更新其中的一行,这会使学生感到困惑,因为他们不知道哪个教授将成为他们的讲师!

关系数据库通过支持多个相关的表来解决这个问题。在这种情况下,我们可以为课程创建一个表,为书籍创建另一个表,并使用惟一的标识符来“连接”这些表。

您可以看到,在这种情况下,我们为索引使用了一个自动递增的整数。这只是一种奇特的说法,即给定列的 ID 从“1”开始,每增加一条新记录就增加 1。

ID 不需要自动递增或者是整数——它们只需要是唯一的。同一表中的任何两行都不能有相同的“主键”值,主键是数据库用来唯一标识该表中的行的字段。在这种情况下,它是我们调用的字段。

你会看到在这个表中,我们有一个与这个表相关联的字段,所以前三本书可以“加入”到 id 为 1 的课程中——“Ruby 简介”这样,如果我们必须更新与课程相关联的教授,我们只需更新课程表中的一行即可。

这就是关系数据库的核心——使用多个“相关”表来减少重复。

对数据库进行反规范化

只是为了涵盖您可能遇到的边缘情况,我们还需要理解如何考虑关系数据库的反规范化。

通过跨相关表分割信息来减少重复的一个挑战是,这会影响性能。一般来说,数据分割的表越多,检索的时间就越长。对于大多数应用程序来说,这是一个完全可以接受的折衷,在给定查询速度的基础上优化数据的质量和一致性,但有时这样的查询不够快。在这种情况下,您可能会有意决定对数据库进行一点非规范化处理。

例如,如果我需要显示用户在一个流行网站上发表的评论,我将有一个存储评论的表和一个存储评论人信息的表。但是我可能还会在 comments 表中存储一个用户名的副本,这样我就不必为每次检索注释时连接两个表而付出性能代价。

对于一个高流量的网站,这可能不是一个坏的交易。这将有意义地提高一个普通请求(显示文章评论)的性能,并且数据出错的风险相当有限,因为人们通常不会经常更改他们的名字!

包装它

因此,总而言之,关系数据库特别擅长存储和检索结构化数据。相关表允许您减少重复和不一致数据的风险,索引允许您有效地检索数据子集和/或基于一个或多个“字段”对数据进行排序

最初发表于【https://flatironschool.com】

使用 R 和 Python 的介绍

原文:https://towardsdatascience.com/an-introduction-to-working-with-r-and-python-1c51fac0b16f?source=collection_archive---------9-----------------------

T 他的文章旨在介绍如何在 Python 中使用 R

Image by Mitchell Luo

当我还是一名大学生时,统计学课程(生存分析、多变量分析等)是在 r 中教授的。然而,由于我希望学习数据科学,所以我选择了 Python,因为它对我来说似乎很“怪异”。

由于只使用 Python,我偶然发现需要实现一些统计技术,如离群值的 Grubb 检验、模拟的马尔可夫链蒙特卡罗或合成数据的贝叶斯网络。因此,本文旨在作为一篇介绍性的指南,将 R 融入到您作为 Python 数据科学家的工作流程中。如果您想作为一名 R 数据科学家将 Python 集成到您的工作流程中,reticulate 包很有用,请查看[1]。

rpy2

我们选择 rpy2 框架,其他选项有 pyRservepypeR ,因为它运行嵌入式 R。换句话说,它允许 Python 和 R 对象之间通过 rpy2.robjects 进行通信,稍后我们将看到一个将 pandas 数据帧转换为 R 数据帧的特定示例。如果您在以下任何步骤中遇到困难,请阅读官方文档或参考资料。

我们将介绍在 Python 中开始使用 R 的三个步骤。最后,我们将做一个实际的例子,并涵盖 rpy2 包允许您处理的更多功能。

  1. 安装 R 包。
  2. 从 r 导入包和函数。
  3. 将 pandas 数据帧转换为 R 数据帧,反之亦然。
  4. 实际例子(运行贝叶斯网络)。

但是首先,我们应该安装 rpy2 软件包。

# Jupyter Notebook option
!pip install rpy2
# Terminal option
pip install rpy2

1.安装 R 包

在 R 中,安装包是通过从 CRAN mirrors 下载然后在本地安装来实现的。与 Python 模块类似,可以安装并加载包。

# Choosing a CRAN Mirror
import rpy2.robjects.packages as rpackages
utils = rpackages.importr('utils')
utils.chooseCRANmirror(ind=1)# Installing required packages
from rpy2.robjects.vectors import StrVector
packages = ('bnlearn',...,'other desired packages')
utils.install_packages(StrVector(packages))

通过在chosseCRANmirror中选择ind = 1,我们保证自动重定向到离我们位置最近的服务器。现在,我们将讨论第二步。**

2.导入包和函数

这里,我们将导入在实际例子中执行贝叶斯网络所需的库和函数。

***# Import packages
from rpy2.robjects.packages import importr
base, bnlearn = importr('base'), importr('bnlearn')# Import Functions
bn_fit, rbn = bnlearn.bn_fit, bnlearn.rbn
hpc, rsmax2, tabu = bnlearn.hpc, bnlearn.rsmax2, bnlearn.tabu***

为了导入任何函数,在每个包的字典中查看“rpy2”键是很方便的,例如,在我们运行的 bnlearn 上查看可导入的函数:

***bnlearn.__dict__['_rpy2r']Output:
...
...
'bn_boot': 'bn.boot',
  'bn_cv': 'bn.cv',
  'bn_cv_algorithm': 'bn.cv.algorithm',
  'bn_cv_structure': 'bn.cv.structure',
  'bn_fit': 'bn.fit',
  'bn_fit_backend': 'bn.fit.backend',
  'bn_fit_backend_continuous': 'bn.fit.backend.continuous',
...
...***

有关如何导入函数 checkout [4]或[5]的更多信息。

3.将 pandas 数据帧转换为 R 数据帧,反之亦然

就我个人而言,我认为这个功能允许您将可伸缩性(python)与统计工具(R)结合起来。举一个个人的例子,当我使用多处理 python 库实现并行计算时,除了 statsmodels Python 包的函数之外,我还想尝试 forecast R 库中的auto.arima()函数来进行预测。因此,robjects.conversion允许人们融合两种编程语言的精华。

***# Allow conversion
import rpy2.robjects as ro
from rpy2.objects import pandas2ri
pandas2ri.activate()# Convert to R dataframe
r_dt = ro.conversion.py2rpy(dt) # dt is a pd.DataFrame object# Convert back to pandas DataFrame        
pd_dt = ro.conversion.rpy2py(r_dt)***

当激活熊猫转换(pandas2ri.activate())时,许多 R 到熊猫的转换将自动完成。然而,对于显式转换,我们调用py2rpyrpy2py函数。

4.贝叶斯网络的实际例子

除了蒙特卡罗方法,贝叶斯网络也是模拟数据的一种选择。然而,到目前为止,Python 中还没有可用于此任务的库。因此,我选择了 bnlearn 包,它可以学习贝叶斯网络的图形结构,并从中进行推理。

在下面的例子中,我们使用混合算法(rsmax2)来学习网络的结构,因为它允许我们使用基于约束和基于分数的算法的任意组合。然而,根据问题的性质,你应该选择正确的启发式算法,可用算法的完整列表见[7]。一旦网络被学习,我们用rbn函数从贝叶斯网络中模拟 n 个随机样本。最后,我们执行一个 try-except 结构来处理特定类型的错误。

***r_imputados = robjects.conversion.py2rpy(imputados)                

try:   
    # Learn structure of Network
    structure = rsmax2(data, restrict = 'hpc', maximize = 'tabu')       

    fitted = bn_fit(structure, data = data, method = "mle")                                               

    # Generate n number of observations
    r_sim = rbn(fitted, n = 10)

except rpy2.rinterface_lib.embedded.RRuntimeError:
    print("Error while running R methods")***

当我们不希望函数失败或做一些意想不到的事情时,就会发生 RunTimeError 。在这种情况下,我们捕获这个错误是因为这是一种在出错时通知用户这不是另一种错误的方式(完整的异常参见[9])。作为一个例子,我得到了在运行rsmax2 函数时没有找到hybrid.pc.filter hybrid.pc.filter 的错误。

更多功能

使用 rpy2 低级接口和高级接口,您可以做更多的事情。例如,您可以用 R 调用 python 函数,让我们看看如何通过共轭梯度法找到四维 Colville 函数的最小值。

*****from** **rpy2.robjects.vectors** **import** FloatVector
**from** **rpy2.robjects.packages** **import** importr
**import** **rpy2.rinterface** **as** **ri** stats = importr('stats')

*# Colville f: R^4 ---> R*
**def** Colville(x):
    x1, x2, x3, x4 = x[0], x[1], x[2], x[3]

    **return**   100*(x1**2-x2)**2 + (x1-1)**2+(x3-1)**2 + 90*(x3**2-x4)**2 + 10.1*((x2-1)**2 + (x4-1)**2) + 19.8*(x2-1)*(x4-1)

*# Expose function to R*
Colville = ri.rternalize(Colville)

*# Initial point*
init_point = FloatVector((3, 3, 3, 3))

*# Optimization Function*
res = stats.optim(init_point, Colville, method = c("CG"))***

参考文献:

[1]马特·布朗。“使用 reticulate 包从 R 运行 Python 代码”。r 酒吧。网址:https://r studio-pubs-static . S3 . amazonaws . com/407460 _ 396 f 867 ce 3494d 479 FD 700960879 e22c . html

[2] Ajay Ohri。“结合使用 Python 和 r: 3 种主要方法”。KDnuggets。网址:https://www . kdnugges . com/2015/12/using-python-r-together . html

**[3] Rpy2 官方文档。网址:【https://rpy2.github.io/doc/latest/html/index.html **

[4]https://stack overflow . com/questions/59462337/importing-any-function-from-an-r-package-into-python/59462338 # 59462338

[5]https://stack overflow . com/questions/49776568/calling-functions-from-in-r-packages-in-python-using-importr

[6]https://stack overflow . com/questions/47306899/how-do-I-catch-an-rpy 2-rinter face-rruntimeerror-in-python

[7]bn 学习官方文档。http://www . bn learn . com/documentation/man/structure . learning . html

[8]丹尼尔·厄姆。“贝叶斯网络与 bnlearn 包的例子”。网址:http://gradient descending . com/Bayesian-network-example-with-the-bn learn-package/

[9] Python 3.8 内置异常。URL:https://docs . python . org/3.8/library/exceptions . html # runtime error

[10]罗伯特,克里斯蒂安;卡塞拉,乔治。介绍蒙特卡罗方法。2010

[11] Nagarajan,Radhakrishnan 马可·斯库塔里;太棒了,索菲。贝叶斯网络。2013

嵌入的直观解释

原文:https://towardsdatascience.com/an-intuitive-explanation-of-embeds-558844e4798?source=collection_archive---------35-----------------------

大多数 GDL 技术忽略了网络的语义。嵌入也旨在表示语义关系。

介绍

在前面的故事中,我们讨论了几种从不同角度解决节点表示问题的 GDL 技术。我们从名为 DeepWalk 的直推式方法开始,接着是 GraphSAGE 归纳方法。在上一篇文章中,我们讨论了 NeoDTI 从异构图中学习特定于任务的节点嵌入。你可以在下面找到这个故事。

[## NeoDTI 的直观解释

NeoDTI 是一种用于异构网络上链路预测的特定任务节点嵌入学习算法。

towardsdatascience.com](/an-intuitive-explanation-of-neodti-e1859d178031)

在这个故事中,我们将用嵌入[1]来结束 GDL 方法系列。嵌入目标是大多数 GDL 模型的常见缺陷。虽然现有方法可以有效地反映节点嵌入中基于邻域的相似性,但它们不足以嵌入更高级别的语义,如子类(人是人的子类)关系。这种语义在 DBPedia 和 FreeBase 等知识图(KG)中很常见,应该与节点嵌入一起表示。

KG 不同于我们到目前为止分析过的网络,它包含了语义上更丰富的信息。除了这些类的成员之外,kg 通常还包含类、层次结构及其交互。例如,一个包含人物和电视连续剧的 KG 将包括人物和电视连续剧的分类,而我们到目前为止看到的网络仅代表这些类的成员之间的交互。下面我们可以看到这样一个 KG。

A KG to represent interactions between people and TV Series

在显示的 KG 中,实线表示主演的一个人和电视剧之间的关系,而虚线表示可以出演一个阶层间的关系。我们总是可以添加更多的关系类型,比如 canWatch,可以在这两个类之间创建或者引入新的类,比如 Movies。如果我们使用了 HN,我们将只有成员之间的链接,没有类层次,没有类间的交互。

请注意,虽然 kg 看起来像 HNs,但我们不能在 HN 中表示职业等级。一个 KG 类就像一个超节点包含一组节点并与其他类交互,而不是一个简单的节点与不同类型的节点交互。以这种方式,kg 是具有丰富语义的非常强大和可扩展的表示方案。KGs 中丰富的语义不能用常规的 HN 嵌入技术(如 NeoDTI)有效地嵌入到空间中。嵌入目标就是这个问题。

使...嵌入

EmbedS 是作为一种本体感知的图嵌入方法提出的,旨在以几何方式表示高级语义。嵌入了 RDFS 格式的作品,这是一种在网络中表示语义的标记方案。为了这个研究的目的,他们定义了五个谓词(或关系)作为类型、子类、子属性、域范围。目标是学习属性表示,以及类和节点表示。

为了表示节点,他们随机创建 N 维向量,并在优化过程中更新它们,与之前的工作类似。另一方面,它们定义区域来通过一个 N 维向量和一个半径 r 来表示类。属性也用区域表示,其中中心用两个 N 维向量和一个半径 r 表示。类似于节点向量,类和属性中心及其半径在优化期间被更新。因此,财产和阶级区域随着时间的推移而扩大和缩小。

现在我们将解释将用于更新模型参数的损失函数背后的直觉。EmbedS 使用一个两部分损失函数,将它们相加以获得总损失。第一部分被定义为反映节点之间的邻域信息。换句话说,当两个节点的嵌入可用于恢复这些节点之间的交互(或链路、边)时,第一部分被最小化,类似于 NeoDTI 方法。

在损失函数的第二部分,目标是保持由上面列出的五个谓词定义的关系。嵌入基于谓词本身、类和节点将成本与每个谓词类型相关联。因为节点是点,而类和属性是区域,所以我们有两种不同的丢失情况。我们可以计算一个点和一个区域之间或者两个区域之间的损耗。

为了计算点和区域之间的损失,我们计算节点和区域中心之间的 L2 距离,然后减去区域的半径。为了计算区域到区域的成本,我们计算中心之间的 L2 距离,然后减去半径之和。下面我们可以看到一个图,显示了节点和类之间的开销,其中开销用红线显示。

Cost computation from between an entity and a class. [1]

为了最小化这样的损失函数,必须调整参数以满足谓词,而不仅仅是邻域关系。在优化过程中,每个类和谓词的半径将被更新,以最小化损失和中心。例如,我们期望的结果是,如果类 x 是类 y子类,那么 x 的区域在y的区域内。因此,类的层次结构反映在几何空间中。这同样适用于其他谓词。

因此,高层语义反映在空间和嵌入是本体感知的。

结论

嵌入是在网络中表示更丰富的语义的一个步骤,这是大多数 GDL 技术所缺少的。用区域来表示类和谓词,而不是空间中的点,这是一种可以进一步研究的新方法。然而,定义的损失函数需要特定于谓词的工程,这对于大型网络来说可能难以实现。此外,EmbedS 目前还没有经过广泛的测试,其跨任务的性能也值得怀疑。

参考

[1] 嵌入纸张。

GraphSAGE 的直观解释

原文:https://towardsdatascience.com/an-intuitive-explanation-of-graphsage-6df9437ee64f?source=collection_archive---------6-----------------------

归纳学习在动态数据集中很有用。这里我们讨论一个关于图的归纳学习算法。

介绍

在之前的故事中,我们谈到了 DeepWalk,一种学习节点表示的算法。如果不熟悉 DeepWalk,可以查一下之前的故事。

[## 对 DeepWalk 的直观解释

网络上的机器学习有明显的优势。在这个故事中,我们讨论 DeepWalk 来学习节点嵌入。

medium.com](https://medium.com/analytics-vidhya/an-intuitive-explanation-of-deepwalk-84177f7f2b72)

DeepWalk 是一种直推式算法,这意味着,它需要整个图都可以用来学习节点的嵌入。因此,当一个新节点被添加到现有节点时,需要重新运行它来为新节点生成嵌入。

在这个故事中,我们介绍了 GraphSAGE[1],一种适用于动态图的表示学习技术。GraphSAGE 能够预测新节点的嵌入,而不需要重新训练过程。为此,GraphSAGE 学习了聚合器函数,该函数可以在给定新节点的特征和邻域的情况下诱导新节点的嵌入。这叫做归纳学习。

我们可以将 GraphSAGE 分为三个主要部分,即上下文构建、信息聚合、损失函数。下面我们分别描述各个部分。

语境建构

与 word2vec 和 DeepWalk 类似,GraphSAGE 也有一个基于上下文的相似性假设。

GraphSAGE 假设位于相同邻域的节点应该具有相似的嵌入。

与 DeepWalk 类似,上下文的定义是参数化的。该算法具有控制邻域深度的参数 K 。如果 K 为 1,则只有相邻节点被认为是相似的。如果 K 为 2,则距离为 2 的节点也会出现在相同的邻域中。

注意, k = 2 意味着距离为 4 的节点可以通过中间的节点影响彼此的嵌入。因此,增加步行长度会在节点之间引入不期望的信息共享。K太大甚至会导致所有节点都有相同的嵌入!

Neighborhood exploration and information sharing in GraphSAGE. [1]

信息聚合

定义了邻居之后,现在我们需要邻居之间的信息共享程序。聚合函数或聚合器接受一个邻域作为输入,并将每个邻域的嵌入与权重相结合,以创建一个邻域嵌入。换句话说,它们聚集了来自节点邻居的信息。根据函数,聚合器权重可以是学习的,也可以是固定的。

为了学习聚合器的嵌入,我们首先初始化所有节点到节点特性的嵌入。依次地,对于直到 K,的每个邻域深度,我们用聚合器函数为每个节点创建邻域嵌入,并将其与节点的现有嵌入连接。我们通过神经网络层传递连接的向量来更新节点嵌入。当每个节点被处理时,我们归一化嵌入以具有单位范数。伪代码可以在下面找到。

Pseudocode of GraphSAGE algorithm. [1]

学习聚合器函数来生成节点嵌入而不是学习嵌入本身的优点是归纳性。

当聚集器权重被学习时,一个看不见的节点的嵌入可以从它的特征和邻域中产生。

结果,当新的节点被引入到图中时,聚合器消除了重新训练的必要性。请注意,这在社交网络、web、引用网络等等中相当普遍。

损失函数

到目前为止,我们已经描述了生成节点嵌入的过程。然而,为了学习聚合器和嵌入的权重,我们需要一个可微分的损失函数。基于我们的直觉,我们希望相邻节点具有相似的嵌入,独立节点具有较远的嵌入向量。下面的函数用两项满足这两个条件。

Loss function of GraphSAGE. [1]

这里 uv 是两个邻居,计算的损失为 u 。第一项促进了我们所期望的最大化 uv 嵌入的相似性。在第二项中,我们有一个变量 Q 它是负样本的数量,是从负样本分布中抽取的负样本。在这种情况下,负样本意味着非邻居节点。这个术语试图将这两个节点的嵌入分开。最后, σ 通常用于表示 sigmoid 函数。

请注意,这是一个无监督的损失函数,可以在没有标签的情况下最小化。要在受监督的上下文中使用 GraphSAGE,我们有两种选择。我们可以首先学习节点嵌入,然后学习嵌入和标签之间的映射,或者我们可以在损失函数中添加监督损失项,并采用端到端的学习过程。这种灵活性很有价值。

关于聚合器的更多信息

GraphSAGE 的归纳性归功于它的聚合函数。我们可以定义各种参数或非参数的聚合器。作为一个非参数函数,我们可以使用简单的平均。换句话说,我们可以平均邻域中所有节点的嵌入来构造邻域嵌入。

参数函数可以是 LSTM 单元。然而,LSTM 细胞是为顺序操作而设计的,并且有记忆。因此,邻居被馈送到 LSTM 的顺序会影响邻居嵌入,尽管没有明显的顺序。为了缓解这种情况,可以将节点的随机排列提供给 LSTM。当损失函数最小化时,LSTM 参数将被学习。

另一个可学习的聚合器是一个单层神经网络,后面跟一个最大池算子。为了做到这一点,我们从一个非线性层传递每个邻居的嵌入,并对它们的结果应用元素式的最大值运算。在本文中,通过实验证明该功能是最有前途的功能。

虽然可以设计更复杂的聚合器,但简单是可取的,因为聚合器会显著影响训练时间。理想的聚合器应该是简单的、可学习的和对称的。换句话说,它应该学会如何聚合邻居嵌入,并且对邻居顺序漠不关心,同时不产生巨大的训练开销。

结论

GraphSAGE 是一种归纳表示学习算法,对于随时间增长的图形尤其有用。与转导技术相比,使用 GraphSAGE 为新节点创建嵌入要快得多。此外,GraphSAGE 不会因速度而影响性能。在需要节点分类、节点聚类和跨图泛化的三个不同数据集上进行了测试,结果优于现有解决方案。

如今,GraphSAGE 已经扩展到异构网络,并且有了新的归纳方法。然而,GraphSAGE 在归纳图表示学习中发挥了开拓性和影响力的作用。

参考

[1] Hamilton,Will,之桃·英,Jure Leskovec。"大型图上的归纳表示学习."神经信息处理系统的进展。2017.

假设检验和 P 值的直观解释

原文:https://towardsdatascience.com/an-intuitive-explanation-of-hypothesis-testing-and-p-values-8391db2c90f?source=collection_archive---------4-----------------------

几年前,我在一家水果和蔬菜供应链公司做了第一份统计方面的自由职业。根据质量控制人员的随机抽样,来自农民的产品在送往超市之前,每天 24 小时都要经过质量控制。

在一年比一年的质量报告比较中,他们注意到今年的质量比前一年差,在 1 到 10 的范围内大约是 0.5 分。

然后我进来了,我要回答的问题是:

0.5 的差异是真正的差异吗?

在没有任何统计学背景的情况下,这个问题可能显得有些怪异。但是不要担心:本文的目标是向您展示如何使用假设检验(也称为统计推断)来回答这个问题。

这是一个数字游戏:1 个不同苹果的影响

想象一下,你正在检查一个苹果是好是坏,从一个很大的苹果盒子里随机选择一些苹果。

在下图中,我们可以清楚地看到样本大小对测量的影响:对于小样本,一个不同苹果的影响非常大,而样本越大,一个苹果的影响就越小。

The impact of 1 different apple depends on the sample size

理解样本大小的影响是理解假设检验的第一个基础。我们可以开始争论,2 个苹果上的 0.5,将是 1 个苹果的差别:很可能发生。但是在 100 个苹果中,0.5 将代表 50 个苹果的差异:一个非常强的差异!

在小样本上,0.5 不是很大的差异,但在大样本上 0.5 就是很大的差异。

样本应该有多大:假设检验和作为答案的意义

有不同的方法来解决这个问题,但在这篇文章中,我将进入统计推断,或假设检验来解决这个问题。

假设检验是一组统计方法,用于确定观察数据样本是否可用于接受或拒绝预先定义的假设。假设检验应用于许多领域,主要是在研究领域,但也是在线营销的一个关键方法(AB 检验)。

数学家们发展了假设检验,这样就有了一个特定的程序来寻找真理。

假设检验只允许验证假设,不允许发展假设。

在一盒 100 个苹果(称之为群体)中,我们取 8 个苹果的样本。今年的 8 个苹果样本中有 5 个烂苹果(62%),去年的 8 个苹果样本中有 4 个烂苹果(50%)。我们想用假设检验来确定今年 100 个苹果的盒子里烂苹果的百分比是否比去年大。

假设检验是人口测量的数学替代方法。多亏了它的计算,我们可以将小样本的测量结果推广到大样本人群。这样就避免了很多工作。

Mathematician found out how to generalize a conclusion on a sample into a conclusion of a population

这个数学解决方案从陈述一个明确的研究假设开始。不幸的是,只有当我们已经知道要测试什么的时候,数学才起作用。对于勘探,存在其他类型的方法。

研究假设我们的例子: 今年烂苹果的人口百分比大于去年烂苹果的人口百分比

实际假设检验

假设检验的数学方法使得在样本测量结果和观察数量之间达到一种有根据的平衡。输出是一个 P 值。

这些计算通过使用分布:对于几乎每一种可以想象的情况,一些数学家已经找到了描述预期结果的数学规律。

对于像我们的烂苹果(烂 vs 没烂)这样的是/否问题,抛硬币法则是适用的。这是数学定律最基本的例子:正面 50%,反面 50%

虽然非常简单,但这可以用一个一般的数学分布来表示,它告诉我们观察到的概率,例如,10 次抛硬币中有 7 次正面朝上。这被称为二项式分布,可以这样绘制:

Binomial distribution with 10 coin flips

对于这篇文章,我将远离沉重的数学,但重要的是要认识到,我们可以使用数学公式来估计某个百分比是接近还是远离预期的百分比。

在本文的最后,我会给出许多不同情况下最常用的假设检验公式的列表,以及如何实现它们的进一步阅读。但是首先,我解释一下假设检验的解释。这对于每个假设检验都是一样的。

假设检验的输出称为 P 值

在假设检验之后,在观察值和样本量之间进行数学平衡。在计算结束时,存在的每一个假设检验将输出一个标准化的分数,该分数允许对结果进行比较,即使数学不完全相同。

P 值是制定假设检验结果的标准方法,对每一个可能的检验都以同样的方式解释。

P 值是一个介于 0 和 1 之间的分数,它告诉我们样本观察值和假设值之间的差异是否显著不同。0.05 是它的参考值。

当 P 值小于 0.05 时,差异显著 当 P 值大于 0.05 时,差异不显著

例 1: 我们做 10 次抛硬币。
我们的假设:我们预计有 5 个头。
我们的结果:我们得到 6 个头。
我们的 P 值计算输出 0.518,比 0.05 大
我们的结论:差异不显著。 我们的解释:结果是符合的假设。

例 2: 我们做 10 次抛硬币。我们的假设:我们期待 5 个头。我们的结果:我们得到 10 个头。
我们的 P 值计算输出 0.0,比 0.05 小
我们的结论:差异是显著的。我们的解释是:结果与假设不符。

例三: 我们测试 10 个苹果。我们的假设:我们期待 1 个烂苹果。我们的结果:我们得到一个烂苹果。
我们的 P 值计算输出 1.0,比 0.05 大 我们的结论:差异不显著。 我们的解读:结果是符合的假设。

例 4: 我们测试 10 个苹果。
我们的假设:我们预期 1 个烂苹果。我们的结果:我们得到了 5 个烂苹果。
我们的 P 值计算输出 0.0114,比 0.05 小
我们的结论:差异是显著的。
我们的解释:结果是不符合假设。

结论和进一步阅读

在本文中,我对统计干扰或假设检验背后的一般框架给出了直观的解释。我希望您现在对何时使用假设检验以及它为什么有用有了更好的了解。

我没有进入任何数学解释,也没有进入不同测试的任何细节。在下表中,我列出了一些非常常见的假设检验,建议进一步阅读。

List with Alternative Hypotheses (= Research Hypotheses) for a number of common hypothesis tests.

我希望这篇文章对你有用,并祝你在假设检验的旅途中好运!

NeoDTI 的直观解释

原文:https://towardsdatascience.com/an-intuitive-explanation-of-neodti-e1859d178031?source=collection_archive---------25-----------------------

NeoDTI 是一种用于异构网络上链路预测的特定任务节点嵌入学习算法。

介绍

在本系列之前的故事中,我们已经讨论了 DeepWalk 和 GraphSAGE。他们两个都被提出来学习具有单个实体和单个链路类型的网络中的节点表示,即同质网络。如果你不知道这些方法,你可以查看以前的故事。

[## GraphSAGE 的直观解释

归纳学习在动态数据集中很有用。这里我们讨论一个关于图的归纳学习算法。

towardsdatascience.com](/an-intuitive-explanation-of-graphsage-6df9437ee64f)

在这个故事中,我们将解释 NeoDTI [1],它有一个不同的视角。NeoDTI 在两个方面不同于 DeepWalk 和 GraphSAGE。首先,NeoDTI 能够在异构网络上操作,即具有多个链路和实体类型的网络。其次,与 DeepWalk 和 GraphSAGE 不同,NeoDTI 学习特定于任务的节点嵌入,而不是通用的节点嵌入。以这种方式,NeoDTI 嵌入专用于一项任务,即链路预测。

NeoDTI 被提议利用异构数据进行药物-靶标相互作用(DTI)预测任务。在 DTI 任务中,每种药物和靶标用一个节点表示,如果已知两个节点相互作用,则这两个节点是相邻的。因此,关联预测对应于预测药物和蛋白质是否相互作用。下面我们可以看到一个玩具异构网络,由三种药物和四个目标组成。

A drug-target network with three drugs and four targets.

虽然 NeoDTI 是针对 DTI 提出的,但是异构网络上的链路预测是一个跨域问题。例如,考虑用户和故事被表示为节点的中型网络。在这个网络中,用户之间的边表示跟随者关系,而用户和故事之间的边表示鼓掌。在这种情况下,链接预测任务可以用于向用户推荐朋友或故事。

Medium network with users and stories.

媒体网络的例子突出强调了 NeoDTI 的可推广性。然而,在故事的其余部分,我们将坚持 DTI 预测任务,以符合原始论文。我们将分三步描述 NeoDTI,即邻域整合、节点嵌入更新和边重构学习。

邻里整合

NeoDTI 在一个有四个实体和十二个关系的网络上工作。实体是药物、目标、疾病和副作用,而关系包含这些实体的相互作用、关联和相似性。每个关系都用二元边来表示。邻域整合旨在整合节点邻域内的多方面信息,并将其反映在节点的嵌入中。

尽管这个想法与 DeepWalk 和 GraphSAGE 非常相似,但 NeoDTI 遵循了不同的策略。与以前的方法不同,NeoDTI 不通过图遍历来探索节点的邻域,而是将所有相邻节点视为邻域。对于邻域中的每个实体类型,NeoDTI 通过非线性神经网络层传递每个相邻节点,并对它们的和应用规格化器,以获得实体类型特定的邻域嵌入。为了组合来自不同实体类型的信息,NeoDTI 应用求和并获得结果邻域嵌入。下面我们可以看到节点的邻域积分方程

Information aggregation from the neighborhood in NeoDTI [1].

在这个等式中, u 是具有边类型 rv 的相邻节点,并且 f ⁰(u) 是检索 u 的初始嵌入向量的函数。 Wᵣbᵣ 是边缘类型特定的神经网络权重, σ 是非线性激活函数。神经网络前的系数是基于节点度的归一化器。最后, aᵥ 是得到的邻域嵌入。

节点嵌入更新

已经为节点 v 构造了邻域嵌入,是时候将它与v’s自身嵌入结合起来了。为此,NeoDTI 将 v ( f ⁰ (v) )的初始嵌入与邻域嵌入( aᵥ )连接起来。与上一步类似,连接的向量通过另一个非线性神经网络层,然后归一化为单位长度,以获得更新的节点嵌入( f (v) )。在下面的等式中, Wb 表示该步骤中神经网络的权重。

Node embedding update rule in NeoDTI [1].

理论上,更新步骤可以重复几次,以创建更多的嵌入。然而,在实践中,使用单个更新步骤就足以获得相当好的预测。

边缘重构学习

在前面的步骤中,我们定义了使用异构邻域信息创建节点嵌入的必要过程。现在是时候定义一个损失函数来实现学习了。NeoDTI 使用损失函数来促进边缘重建。换句话说,NeoDTI 旨在从节点嵌入中重建初始网络的边。

下面我们看到损失公式,其中 GᵣHᵣ 是边缘类型特定的投影矩阵和 s(e)uv 之间的边缘的权重。为了创建负样本,NeoDTI 对不相邻的节点进行采样,并在训练期间将它们作为输入提供。

The loss function used for edge reconstruction in NeoDTI [1].

现在让我们解释损失函数。为了将损耗降至最低,求和中的项应尽可能接近 0。因此, s(e) 必定等于 f (u)ᵀ Gᵣ Hᵣᵀ f (v) 。由于f(u)ᵀgᵣhᵣᵀf(v)】是基于节点嵌入和投影矩阵的重构项,因此嵌入被学习,使得边被重构。

与旨在最大化相似节点之间的嵌入相似性的 DeepWalk 和 GraphSAGE 相反,NeoDTI 嵌入被学习用于边缘重建。这就是它们具有特定任务的原因。

有了这个公式,重建项可以用来对 NeoDTI 的预测进行采样。为了预测药物 u 和目标 v 是否相互作用,我们使用学习的药物和目标投影矩阵f(u)f (v)来计算重建项。结果是对 uv 之间的边权重的 NeoDTI 预测。

讨论

NeoDTI 是一种端到端的学习方法,用于学习特定于任务的节点嵌入。嵌入创建和损失函数步骤都是完全可微的,并且所有权重和嵌入都可以通过梯度下降来学习。这个端到端过程的结果嵌入被优化用于边缘重建,即链路预测。因此,面对链路预测精度的提高,学习嵌入的可推广性被牺牲了。下面我们可以在一张图中看到 NeoDTI 的工作流程。

The workflow of NeoDTI [1].

此外,尽管 NeoDTI 在二值边上运行,但它也适用于加权边。在这个问题中, s(e) 被当作一个二进制项,但可以用实值权重来代替。在这种情况下,权重应该表示节点之间的连接强度,并且训练目标将是恢复连接强度。

结论

NeoDTI 是用于异构网络上的链路预测任务的有价值的方法。论文表明,集成异构信息提高了模型性能。因此,网络可以很容易地用新的实体和关系类型来扩展,以包含更多的信息。这就是使用异构网络的力量。

此外,与首先学习节点嵌入并将其用于链路预测的多步骤方法相比,使用端到端方法导致了准确性的提高。通过异构数据和端到端学习,NeoDTI 在 DTI 任务中产生了 SOTA 结果。然而,应该注意的是,NeoDTI 也可以应用于不同的领域。

参考

[1] NeoDTI 论文

[2] NeoDTI Github

随机森林和额外树分类器的直观解释

原文:https://towardsdatascience.com/an-intuitive-explanation-of-random-forest-and-extra-trees-classifiers-8507ac21d54b?source=collection_archive---------6-----------------------

利用群众的智慧来提高绩效

Photo by Aperture Vintage on Unsplash

目的:本文的目的是让读者对随机森林多余树量词有一个直观的了解。

材料和方法:我们将使用包含描述三种花的特征的 Iris 数据集。总共有 150 个实例,每个实例包含四个特征,并标有一种花。我们将调查并报告决策树、随机森林和额外树的准确性。

硬件:我们在配备 8 GB 1600 MHz DDR3、带 2 个 CPUs @ 2.9 Ghz 的 Inter(R)Core(TM) i7 和英特尔 HD Graphics 4000 卡的苹果工作站上训练和评估我们的模型。让我们踢一些尾巴。

注意:如果您是从零开始,我建议您按照这篇文章安装所有必要的库。最后,假设读者熟悉 Python、Pandas、Scikit-learn 和决策树。关于 Scikit-learn 决策树的详细解释可以在这里找到。

一个树桩对 1000 个树桩

假设我们有一个弱学习器,一个准确率略好于随机决策的分类器,分类准确率为 51 %。这可能是一个决策树桩,一个深度设置为 1 的决策树分类器。在第一个例子中,它似乎不应该麻烦这样一个弱分类器;然而,如果我们考虑将 1000 个略有不同的决策树桩(系综)放在一起,每个都有 51 %的准确性来做出我们的最终预测,会怎么样呢?直观地,我们可以看到,平均来说,510 个分类器会正确地分类一个测试用例,而 490 个会错误地分类。如果我们收集每个分类器的硬票,我们可以看到平均会有大约 20 个以上的正确预测;因此,我们的系综将趋向于具有高于 51 %的准确度。让我们在实践中看到这一点。

在这里,我们将构建一个决策树桩,并将其预测性能与 1000 个决策树桩进行比较。决策树的集合是使用 sci kit-learnbagging classifier创建的。决策树桩和集成将在包含四个特征和三个类别的 Iris 数据集上训练。数据被随机分割以创建训练和测试集。

每个决策树桩将根据以下标准构建:

  1. 训练集中可用的所有数据都用于构建每个树桩。
  2. 为了形成根节点或任何节点,通过搜索所有可用特征来确定最佳分割。
  3. 决策树桩的最大深度是 1。

首先,我们导入将用于本文的所有库。

Script 1 — Importing the libraries.

然后,我们加载数据,分割数据,训练并比较单个树桩和整体。结果被打印到控制台。

Script 2— Stump vs Ensemble of 1000 Stumps

The accuracy of the stump is 55.0 %
The accuracy of the ensemble is 55.0 %

结果表明,1000 个决策树桩的集合获得了 55 %的准确率,表明它们并不比单个决策树桩好。发生了什么事?为什么我们没有得到更好的结果?我们基本上创造了 1000 个完全相同的决策树桩。这就像我们问一个人 1000 次他们最喜欢的食物是什么,毫不奇怪,得到了 1000 次相同的答案。

随机森林分类器

在上一节中,我们了解到在我们的系综中有 1000 个相同的决策树桩就像有一个决策树桩。因此,我们将改变构建每个树桩的标准,以引入变化。

每个决策树桩将根据以下标准构建:

  1. 将通过用替换对训练集进行随机采样来创建引导。引导的大小被设置为等于训练集的大小。
  2. 为了形成根节点或任何节点,通过在大小为 sqrt(特征数量)的随机选择的特征的子集中进行搜索来确定最佳分割。在我们的例子中,每个决策树桩被允许检查四个特征中的两个。
  3. 决策树桩的最大深度是 1。

我们刚刚描述的是创建随机森林的标准。但是,随机森林使用深度为 1 或更大的决策树。术语 random 来源于我们对训练集进行随机采样的事实,因为我们有一个树的集合,所以很自然地称之为森林——因此称为随机森林。为了构建树中的根节点或任何节点,选择特征的随机子集。对于这些选定的特征中的每一个,该算法搜索最佳切割点,以确定给定特征的分割。然后,从随机选择的子集产生最纯粹分裂的特征被用于创建根节点。树增长到深度 1,并且对树中的所有其他节点重复相同的过程,直到达到树的期望深度。最后,需要注意的是,每棵树都是使用不同的 bootstrap 单独构建的,这会在树之间引入差异。因此,每棵树都会犯不同的错误,当组合在一起时,可以建立一个强大的分类器。如果你被所有的术语搞糊涂了,阅读这篇文章,它用一段话解释了我刚刚描述的大部分内容。

Script 3 — Stump vs Random Forest. Notice how in line 5, we set splitter = “best” and in line 9 bootstrap = True. Your results may slightly vary since we did not fixed the seeds in the stump.

The accuracy of the stump is 55.0 %
The accuracy of the Random Forest is 95.0 %

什么?!因此,通过简单地引入变量,我们能够获得 95 %的准确率。换句话说,低精度的决策树桩被用来建造森林。通过在 bootstraps 上构建树桩,在树桩之间引入了变化-通过使用替换对训练集进行采样来创建,并允许树桩仅搜索随机选择的特征子集来分割根节点。单独地,每个树桩将获得低精度。然而,当在合奏中使用时,我们发现它们的准确性直线上升!朋友们,这就是通常所说的群体智慧。

为了让它深入人心,我们可以使用弱分类器作为集成的基础,以获得高性能的集成。

额外的树分类器

与随机森林分类器类似,我们有额外的树分类器,也称为极度随机树。为了在整体中引入更多的变化,我们将改变构建树的方式。

每个决策树桩将根据以下标准构建:

  1. 训练集中可用的所有数据都用于构建每个树桩。
  2. 为了形成根节点或任何节点,通过在大小为 sqrt(特征数量)的随机选择的特征的子集中进行搜索来确定最佳分割。每个选定特征的分割是随机选择的。
  3. 决策树桩的最大深度是 1。

注意,在额外的树分类器中,特征和分裂是随机选择的;因此,“极度随机化的树”。由于额外树分类器中的每个特征都是随机选择分裂的,因此它的计算开销比随机森林要少。

Script 4— Stump vs Extra Trees. Notice how in line 5 splitter = “random” and the bootstrap is set to false in line 9. Your results may slightly vary since we did not fixed the seeds in the stump.

The accuracy of the stump is 55.0 %
The accuracy of the Extra Trees is 95.0 %

额外树分类器的表现类似于随机森林。但是,我想提一下性能差异。即:决策树表现为高方差,随机森林表现为中方差,额外树表现为低方差。

结束语

如果您已经阅读完本文,现在您应该了解集成方法的强大功能,并且知道随机森林和额外树分类器是如何构建的。我想提一下,你不应该使用 Bagging 分类器来构建你的随机森林或额外树木分类器。这两个分类器的更有效版本已经内置到 Scikit-learn 中。

集成方法不限于将弱学习者作为它们的基本估计器。例如,您可以为给定的任务确定最佳的三个分类器,并使用 Scikit-learn 投票分类器来形成一个集成。您可以优化集合的权重,并使用它们进行预测。假设您已经对分类器进行了微调,并且所有分类器都具有相似的性能,那么投票分类器将比它们中的任何一个都有优势。为了缩小要使用的分类器的搜索范围,您可以阅读这篇讨论使用 Scikit-learn 进行模型设计和选择的文章。

你可以在 LinkedIn 上找到我,或者访问我的个人博客

[## 弗兰克·塞瓦洛斯

图表

www.frank-ceballos.com](https://www.frank-ceballos.com/) [## Frank Ceballos -威斯康星医学院博士后| LinkedIn

我是威斯康星医学院的博士后研究员,在那里我分析高维复杂的临床数据…

www.linkedin.com](https://www.linkedin.com/in/frank-ceballos/)

对辍学的直观解释

原文:https://towardsdatascience.com/an-intuitive-explanation-to-dropout-749c7fb5395c?source=collection_archive---------13-----------------------

深度学习

以及如何用它来对抗过度拟合

Photo by ray sangga kusuma on Unsplash

什么是过度拟合?

训练神经网络很棘手。人们应该注意,他的模型足够好,可以从现有数据中学习,也足够好,可以推广到看不见的数据。缺乏一个通用的模型主要是因为一个叫做过度拟合的问题。

简而言之,过度拟合意味着模型在初始训练数据上达到非常高的精度,而在新出现的数据上达到非常低的精度。这就像老师总是在考试中给出同样的问题。他们的学生很容易得到高分,因为他们只是简单地记住了答案。因此,高分在这里不是一个好的衡量标准。另一个危险的后果是,学生们甚至懒得再学习这门学科了。

针对过拟合有很多技巧, 辍学 就是其中之一。在本文中,我们将发现辍学背后的直觉是什么,它是如何在神经网络中使用的,以及最终如何在 Keras 中实现它。

辍学背后的直觉

考虑一个由参与者、一组观众和节目主持人组成的电视节目。该节目的工作原理如下:

  1. 在游戏开始时,主持人随机选择一部未看过的电影作为事件的主要目标。
  2. 在每一个阶段,主持人展示所选电影的短片,
  3. 然后问了一个关于电影到目前为止的事件的问题。
  4. 每个观众都会给出一个答案,
  5. 参与者必须从观众中选择一个答案。
  6. 如果答案正确,参与者和从观众中选出的人将各获得 50 美元。
  7. 如果答案是错的,他们都要付 100 美元。

假设参与者注意到一个观众总是给出正确的答案。随着时间的推移,参与者将与此人建立信任,并会忽略其他人给出的答案。

这种策略存在一些问题。受信任的人可能在游戏的早期阶段对问题分类很好,但在游戏的后期阶段对问题分类很差。如果只有一个人(或一小组人)总是被选中,其他观众会感到被冷落,不再关心播放的视频剪辑。这样——在以后的阶段——被信任的人将不再有帮助,而停止关注的其他观众将已经失去正确回答事件的顺序。所以,只靠一个人是不好的,肯定会损失很多钱。

你认为我们如何解决这个问题?一个聪明的策略是总是给别人机会。通过这种方式,参与者将了解每位听众的优势,并根据问题类别知道该问哪一位。另外,这样每个人都会一直觉得有责任,有义务去关注。

神经网络中的辍学

你可能会问这跟神经网络有什么关系?好吧,让我们考虑以下网络…

A Simple Neural Network Example

我们可以认为输入层(绿色)是主持人提出的问题,隐藏层(蓝色)中的每个神经元是观众中的一个人,输出层(红色)是一个选定观众的选择答案。如果输出层发现某个特定的神经元总是给出最佳答案,它可能会忽略其他的,而把所有的权重都给这个神经元。

基于我们之前的分析,我们选择禁止一些神经元回答,而给其他神经元机会。这样我们就会达到平衡,迫使所有神经元学习。这就是辍学的概念,从技术上讲,它的工作原理如下:

  1. 我们指定一个退出率,它代表要退出的神经元的百分比(例如,20%的神经元)
  2. 在每个阶段,我们根据预先定义的百分比移除随机神经元。
  3. 我们根据剩余神经元的结果组合来计算最终输出。

使用这种技术,所有神经元都有机会投票,并且必须正确回答,以减少模型损失。

这是一个神经网络在辍学前后的例子。

Image source: Deep Learning for Computer Vision

喀拉斯辍学

在 Keras 申请退学比你想象的要简单。你所要做的就是导入并创建一个新的 Dropout layer 对象,然后将其添加到网络结构中的相关位置。

from keras import models, layersmodel = models.Sequential()
model.add(layers.Dense(32))
model.add(layers.Dropout(0.5))
model.add(layers.Dense(1))

通常,在全连接的密集层之后、输出之前添加漏失层,漏失率= 0.5 (50%)。一些最近的方法在卷积层或递归层的激活函数之后应用丢弃,丢弃率=0.2 (20%)。

最后的想法

在这篇文章中,我介绍了辍学,这是一种解决训练中过度适应问题的有趣方法。尽管如此,辍学背后的概念非常简单,当训练你的模型时,它会带来很大的改进。我试图让解释尽可能简单。所以,如果你有任何问题,请随时留下你的评论。

如果你喜欢这篇文章,请点击“鼓掌”按钮,我将不胜感激👏所以可能会传染给他人。也可以在 推特脸书上关注我直接发邮件给我 或者在LinkedIn上找到我。**

高斯过程直观指南

原文:https://towardsdatascience.com/an-intuitive-guide-to-gaussian-processes-ec2f0b45c71d?source=collection_archive---------2-----------------------

一个不受重视的算法的数学解释

高斯过程是回归和分类的强大算法。他们最大的实际优势是可以对自己的不确定性给出一个可靠的估计。在这篇没有数学的高水平文章结束时,我的目标是让你对高斯过程有一个直观的认识,以及是什么让它们在其他算法中独一无二。

内容:

  • 回顾机器学习
  • 如何应对不确定性
  • 简而言之贝叶斯推理
  • 高斯过程

什么是机器学习?

机器学习是类固醇上的线性回归。

机器学习是使用我们拥有的数据(称为训练数据)来学习一个函数,我们可以用它来预测我们还没有的数据。最简单的例子是线性回归,我们学习直线的斜率和截距,这样我们就可以从点的水平位置预测点的垂直位置。如下所示,训练数据为蓝色点,学习的功能为红色线。

Left: linear regression. Right: steroids. Together: machine learning.

机器学习在几个方面是线性回归的扩展。首先,现代 ML 处理更复杂的数据,而不是像线性回归那样学习一个函数来计算另一个数,我们可能会处理不同的输入和输出,例如:

  • 房屋的价格(输出)取决于其位置、房间数量等……(输入)
  • 基于图像(输入)中像素的强度和颜色的图像(输出)的内容
  • 根据围棋(输入)棋盘的状态,最好移动(输出)
  • 基于低分辨率图像(输入)的高分辨率图像(输出)

Clockwise from top left: Figure 1 from the AlphaGo paper, figure 12 from Ledig et al, samples from ImageNet, image from the Zillow house price prediction competition.

其次,现代 ML 使用更强大的方法来提取模式,深度学习只是其中的一种。高斯过程是这些方法中的另一种,它们的主要区别是它们与不确定性的关系。

思考不确定性

不确定性可以表示为一组可能的结果及其各自的可能性,称为概率分布

我们周围的世界充满了不确定性——我们不知道我们的通勤需要多长时间,也不知道明天中午的天气如何。一些不确定性是由于我们缺乏知识,不管我们有多少知识,这是这个世界固有的。既然我们无法完全消除宇宙中的不确定性,我们最好有一个好的方法来处理它。概率分布正是如此,事实证明这是理解高斯过程的关键。

概率分布最明显的例子是掷出一个公平的六面骰子的结果,即任何特定面的概率为六分之一。

这是一个离散概率分布的例子,因为有有限数量的可能结果。在离散的情况下,概率分布仅仅是一系列可能的结果和它们发生的几率。在许多真实世界的场景中,连续的概率分布更合适,因为结果可以是任何实数,下一节将探讨一个例子。

另一个稍后会有用的关键概念是从概率分布中采样。这意味着从一组可能的结果到一个真实的结果——在这个例子中是掷骰子。

贝叶斯推理

贝叶斯推理可能是一个令人生畏的短语,但它可以归结为一种基于我们观察到的证据来更新我们对世界的信念的方法。在贝叶斯推理中,我们对世界的信念通常表示为概率分布,而贝叶斯法则告诉我们如何更新这些概率分布。

贝叶斯统计为我们提供了基于新数据更新信念(用概率分布表示)的工具

让我们来看一个贝叶斯推理的说明性例子——我们将根据一些证据来调整我们对巴拉克·奥巴马身高的看法。

让我们考虑一下,我们从来没有听说过巴拉克·奥巴马(请原谅),或者至少我们不知道他的身高。然而,我们知道他是一个居住在美国的男性。因此,在看到任何证据之前,我们对奥巴马身高的信念(用贝叶斯术语来说,这是我们的先验信念)应该只是美国男性的身高分布。

现在让我们假装维基百科不存在,这样我们就不能只查奥巴马的身高,而是观察一些照片形式的证据。

我们更新的信念(贝叶斯术语中的后验)看起来像这样。

Blue: updated belief. Red: old belief

我们可以看到奥巴马肯定高于平均水平,略高于其他几位世界领导人,但是我们不能确定具体有多高。显示的概率分布仍然反映了奥巴马是平均身高,而照片中的其他人都非常矮的小概率。

什么是高斯过程?

现在我们知道了如何用数字值来表示不确定性,比如高度或掷骰子的结果,我们准备学习什么是高斯过程。

高斯过程是可能函数的概率分布。

由于高斯过程让我们描述函数的概率分布,我们可以使用贝叶斯规则通过观察训练数据来更新我们的函数分布。

为了加强这种直觉,我将使用高斯过程运行一个贝叶斯推理的例子,这个例子与上一节中的例子完全相似。我们不是根据照片来更新我们对奥巴马身高的信念,而是根据一个未知函数的样本来更新我们对该函数的信念。

我们关于未知函数的先验信念如下图所示。右边是我们的高斯过程的平均值和标准差——我们对函数没有任何了解,所以我们的平均值的最佳猜测是在实数的中间,即 0。

左边的每一行都是函数分布的样本,我们知识的缺乏反映在展示的各种可能的函数和不同的函数形状上。从高斯过程中采样就像掷骰子,但每次你得到的是不同的函数,并且有无限多种可能的函数。

我们将观察未知函数在不同点的输出,而不是观察奥巴马的一些照片。对于高斯过程,我们的证据 是训练数据

现在我们已经看到了一些证据,让我们使用贝叶斯规则来更新我们对函数的信念,以获得后验高斯过程,也就是我们对我们试图拟合的函数的更新信念。

类似于奥巴马可能高度的狭窄分布,你可以看到一个更狭窄的函数分布。更新的高斯过程被限制为适合我们的训练数据的可能函数-我们的函数的平均值截取所有训练点,每个采样函数也是如此。我们还可以看到,标准差远离我们的训练数据,这反映了我们对这些领域知识的缺乏。

GPs 的优点和缺点

高斯过程知道他们不知道的。

这听起来很简单,但是许多(如果不是大多数的话)ML 方法并不具备这一点。一个关键的好处是,拟合 GP 的不确定性随着训练数据的增加而增加,这是 GPs 植根于概率和贝叶斯推理的直接结果。

Subset of the images from the Classifier comparison page on the scikit-learn docs.

上面我们可以看到在一个简单的分离蓝点和红点的任务中通过不同的方法学习到的分类函数。请注意,两种常用且强大的方法在远离训练数据的情况下保持了其预测的高度确定性——这可能与对立 示例现象有关,其中强大的分类器出于奇怪的原因给出了非常错误的预测。高斯过程的这一特性与身份验证和安全关键用途特别相关,因为您希望完全确定您的模型输出是有充分理由的。

高斯过程让你结合专家知识。

当你使用 GP 来建模你的问题时,你可以通过选择内核来塑造你的先验信念(对这些的完整解释超出了本文的范围)。

这可以让你以多种不同的方式塑造你的拟合函数。你们中善于观察的人可能一直在想,在给定上述不确定性属性的情况下,高斯过程如何能够超越其训练数据进行推广。答案是,GPs 的泛化特性几乎完全取决于核的选择。

高斯过程计算量很大。

高斯过程是一种非参数方法。参数化方法将有关训练数据的知识提炼为一组数字。对于线性回归,这只是两个数字,斜率和截距,而其他方法,如神经网络,可能有几十万个。这意味着在他们被训练之后,进行预测的成本只取决于参数的数量。

然而,由于高斯过程是非参数的(尽管核超参数模糊了图像),它们需要在每次进行预测时考虑整个训练数据。这不仅意味着训练数据必须在推断时保存,还意味着预测的计算成本成比例(立方!)与训练样本数。

高斯过程的未来

高斯过程的世界在可预见的时间内仍将令人兴奋,因为正在进行的研究将它们的概率优势引入到目前由深度学习主导的问题中——稀疏迷你批处理高斯过程增加了它们对大型数据集的可扩展性,而深度卷积高斯过程使高维和图像数据触手可及。注意这个空间。

一个直观的二项分布的真实例子,以及如何在 R

原文:https://towardsdatascience.com/an-intuitive-real-life-example-of-a-binomial-distribution-and-how-to-simulate-it-in-r-d72367fbc0fa?source=collection_archive---------1-----------------------

Photo by Daria Nepriakhina on Unsplash

学一次,天天用

从计算机器学习模型分类精度到测试新的癌症疗法,二项分布无处不在。

学习。这是关于成功和失败的。

什么是二项式分布,为什么它们如此有用?

当我们重复一组事件,比如 10 次抛硬币,并且一组事件中的每个事件都有两种可能的结果(正面或反面)时,想想二项分布。这里的每个事件都被称为伯努利试验。

双入二项分布是指通常被描述为成功 成功的两种结果。一个“是”或者“不是”。

概率分布通常用于预测未来事件,并且通常基于看起来很糟糕的数学公式。但是,这里也有美好的东西。例如,特定的二项式分布数学函数可用于预测具有两种结果的任何现实生活事件的结果。

Photo by Ibrahim Rifath on Unsplash

让我们从一个简单的例子开始。

这为什么有意思?

例如,玩硬币,两种可能性是正面(成功)或反面(不成功)。假设你有 50 次抛硬币的机会。我们可以尽可能多次重复这个集合,并记录每次重复中我们获得正面(成功)的次数。

如果把结果画出来,我们会得到一个概率分布图。如果你重复的次数足够多,你会接近一个二项式概率分布曲线。我们一会儿就做这个。但是,首先生成数据来绘制我们的图。

我们可以用 R 来生成数据。我们将从一组重复的 50 次硬币投掷 100000 次中产生随机数据,并记录每次重复的成功次数。

rbinom()函数可以生成给定数量的重复(这里是 100.000)组(50 次抛硬币)的实验。它需要 3 个参数。

**rbinom(n** = number of repetitions = 100.000,
       **size** = sample size = 50, 
       **p** = the probability of success (chance of throwing heads is       0.5)**)**

这个概率分布图怎么用?

二项式概率分布帮助我们理解罕见事件的可能性,并设定可能的预期范围。

上面的图说明了如果我们随机投掷硬币 50 次,我们将很可能获得 20 到 30 次成功(正面),而在 50 次尝试中获得超过 35 次成功(正面)的事件是非常不可能的。红色条表示有 35 个或更多机头的器械组。

r 代码可以用来找到准确的概率。我们来比较一下得到 25 个、35 个甚至 49 个以上人头的概率。您可以将 rbinom 与 mean function 结合起来,找出具有选定结果的事件的百分比。

# Probability of getting 25 or more heads
mean(rbinom(100000, 50, .5) >= 25)0.5555# Probability of getting 35 or more heads
mean(rbinom(100000, 50, .5) >= 35)0.00341# Probability of getting 49 or more heads
mean(rbinom(100000, 50, .5) >= 49)0

我们发现投掷 49 个或更多人头的概率为 0。但是从技术上来说,它是 375 万亿分之一乘以 1 ⁴⁹)+(1/ ⁵⁰))).

那么这些都有什么用呢?

你可以用你使用二项分布预测掷硬币结果的能力来打动你的朋友,但是让我们看看它们在现实生活中的其他应用。

机器学习模型的表现。

你建立了一个二进制输出的机器学习模型。比方说准确率 90%的肝癌病理图像识别算法。你测试了 100 个病人,你想知道你 95%的置信区间?或者你的新结果显示你的模型正确检测到的病人不到 70 个。可能吗?或者你应该重新开始优化你的参数?

Photo by Sharon McCutcheon on Unsplash

对治疗有反应的患者人数

比方说,你有一种新的癌症疗法,有 10%的可能性治愈病人。有 500 名病人服用了这种药物。预计康复病人人数为 50 人。但是在你的试验中有 75 个病人有反应。这是出于偶然还是有重大影响?或者你应该开始寻找潜在的因素,如果治疗或患者群体有什么问题的话?

想象一下医院急救站。

你是一名医院经理,你想正确组织不同工作日的员工人数。你知道在给定的时间内,因为酒精中毒而被送进急救站的病人总数。您可以分析一周中每天的患者人数分布。很可能在周末你会遇到更多这样的情况,你需要更多的员工。

其他行业也是如此。他们可以使用二项式分布来计算需求的变化,并据此制定计划。

如果你运行的是网络服务器。

通过确定流量较高的时间,您可以更好地分配资源。

我们可以通过二项式分布回答的其他一些问题有:

对调查问题回答“是”的人数。
一个赛季一支球队会赢多少场比赛?
选举中候选人的票数。
生产运行中的缺陷产品数量。

二项分布是常见的,他们有许多现实生活中的应用。

当单个事件有两个以上的结果时,我们可以将二项式分布扩展为多项分布。

例如,当滚动骰子或分析人群中眼睛颜色类型(黑色、蓝色、绿色等)的分布时,有 6 种结果。当涉及多类别事件的分布时,考虑一下多项式分布。

如果观察值的数量(n)很大,我们可以将多项式绘制视为一系列二项式绘制 (Gentle,2003 年,第 198-199 页)。例如,在掷骰子时,6 个类别可以被认为是 6 个不同二项式试验的组合(得到 1、2、3 等等)。

如果你仅仅通过阅读这些还不能被说服,我将通过增加试验次数来模拟多项式事件的形状是如何变化的。

Multinomial trial approaches a binomial distribution

让我们用一些真实的生活数据来应用我们迄今为止的知识。数据来自tidy Tuesday——由 R for Data Science community 组织的每周一次的 R 社会数据项目。

它包含了自 2012 年以来上映的恐怖电影的数据。我问的是恐怖电影是否更有可能在每月的 13 号上映?

Photo by Allef Vinicius on Unsplash

如果你有正确的心态,任何事情都会感觉更好,如果你没有心情,任何事情都不会让我们开心。我们在事件发生前的心态会影响我们对事件的感受。这至少是行为科学家罗伯特·恰尔迪尼的研究所说的。

想象你是一个恐怖电影迷,你去了电影院。就在电影开始前,屏幕上播放了几则广告。你走近手机关掉声音,日期引起了你的注意,是 13 号。

通常我们会将数字 13 与诅咒事件联系在一起。你认为这会影响你对这部电影的印象吗?

我们不知道这是不是真的,但我想测试一下电影制作人是否有类似的想法,所以选择 13 日作为上映日期的次数比其他日子多。因此,我研究了恐怖电影的数据,并计算了这个月不同日子的上映数量。

这有意义吗?

在数据中,有 2782 部电影与上映日期相关联。因此,每天预计上映的电影是 92 (2782 / 32)

这是一个有 30 个类别的多项概率分布的好例子,由于样本数量很大,它将近似于二项分布。

因此,我们可以应用二项式概率分布来计算我们的多项式数据中的概率。

我们在上面看到,在某些日子里,上映的电影比预期的要多。我们想知道的是,哪一天在随机机会的范围内,哪一天有明显的 T2 偏好或厌恶来发行一部电影。

我将定义一个区间,它包含我们模拟分布中 95%的概率。外面的值将不是随机的。为此,我需要分布的 2.5 和 97.5 分位数。

我们可以通过 r 中的 qbinom() 函数来实现。例如,qbinom(0.975,size,p)将返回一个值,该值将定义包含 0.975 概率的截止值。我们的置信区间将是以下区间:

qbinom(0.025,size,p) < 置信区间 < qbinom(0.975,size,p)

lower <- qbinom(0.975, 2782, 1/30)
75
upper <- qbinom(0.025, 2782, 1/30)
112**75 <** Confidence Interval **< 112**

95%的时候,一个月中的某一天会有 75 到 112 部电影上映。根据我们的概率分布,高于或低于此范围的值不会因随机机会而发生。

每月 13 号上映的 124 部电影。该值高于 97.5 分位数。所以意义重大。但是确切的 p 值是多少呢?我们先定义 p 值。

P 值是该事件发生的概率之和加上同等可能性或可能性较小的类似事件发生的概率之和。

例如,在抛硬币游戏中,正面的概率是(0.5)。如果我们遵循我们的定义,p 值是该事件(0.5)和可能性相等或较小的类似事件(即尾部(0.5))的概率之和。所以我们的 p 值是 0.5 + 0.5 = 1。

类似地,在我们的恐怖电影数据中,这将是获得 124 部电影发行或事件的概率的总和,这些事件同样可能或更罕见。

在 R 中, pbinom 函数定义了累积概率。例如,pbinom(124,2782,1/30)将给出最多 124 部电影发行的累积概率。通过使用 1-pbinom(124,2782,1/30 ),我们可以找到概率之和,其概率等于或低于 124。

因此,获得至少 124 部电影发行的 p 值是;

p_val_binom <- 2 * (1 — pbinom(124, 2782, 1/30))
0.00133

我们乘以 2,因为同样罕见的事件也可能发生在我们置信区间的左侧。

让我们把这些 p 值放在我们的恐怖电影情节上,以突出重要的日子。

我们测试了关于电影制作者的假设,计算了 p 值,并使用了 pbinom()函数,找到了电影或多或少可能上映的其他几天。

然而,另一种广泛使用的计算 p 值的方法是计算分布的平均值及其标准差,并验证观察值与平均值相差多少标准差(z 得分)。

通过正态近似计算 p 值

当样本量很大时,二项式分布可以近似为正态分布。为了建立正态分布,我需要均值和标准差。这个我可以从恐怖片数据算出来。

 sample_mean is 92.7 
sample_sd is 89.64

我可以计算出我们对 13 号上映的 124 部电影的观察的 z 值。简单来说,z-score 就是:一个观测值离均值有多少标准差。由于 95%的观察值将落在正态分布平均值的 1.96 个标准偏差内,较高的 z 得分将表明我们的 p 值确实显著。

z_score <- (observation — sample_mean) / sample_sd
3.302

我可以通过使用一个正态分布函数 pnorm()和我们找到的 z 值来计算精确的 p 值。

p_val_nor <- 2 * pnorm(3.302, lower.tail = FALSE)
p_val_nor
0.00095

正如所料,通过使用正态分布的近似值和二项式分布,我发现了相似的值(正态:0.00095,二项式:0.00133) 。两种方法都证明恐怖片更有可能在 13 号上映。

结论

现实生活中的许多事件都可以用二项式概率分布来解释,它们允许我们计算这些事件的发生是否是随机的,并检验我们的假设。

它可以是有趣的数据分析,如恐怖电影中的数据分析,也可以是更严肃的主题,如新药测试或预测机器学习算法检测疾病的准确性。

下次见!

塞尔达尔

对 LAMB 优化器的直观理解

原文:https://towardsdatascience.com/an-intuitive-understanding-of-the-lamb-optimizer-46f8c0ae4866?source=collection_archive---------1-----------------------

大型深度学习模型分布式训练的最新技术

在软件工程中,减少周期时间对进度有超线性的影响。在现代深度学习中,周期时间通常在几小时或几天的量级。加速训练的最简单方法,数据并行,是在 GPU 和机器之间分发模型的副本,并让每个副本计算训练数据碎片上的损失。然后,可以使用单个参数服务器或 ring all-reduce(py torch 中的默认设置)等更好的工具来累计这些损耗的梯度。反向传播梯度后,用更新的模型重复。但是随着批量的增长,梯度会变得不稳定,导致训练出现偏差。

最近的一篇论文通过以一种更加细致入微的方式计算梯度,将最大和最受欢迎的语言模型之一 BERT 的训练时间从 3 天减少到 76 分钟,允许作者将批量规模扩大约 100 倍至 65K。虽然这篇文章描述了它对上一次迭代 LARS 的贡献,但在这篇文章中,我将从随机梯度下降(SGD)开始解释必要的背景,LARS 就是建立在这个基础上的。

首先,回顾一下基础知识。回想一下,对于 SGD,标准更新规则是

打破这一点,它说新的模型权重是现有的减去学习率乘以现有权重的梯度给定一个例子或一批的平均值。问题:

  1. 我们不知道真实的梯度,我们只有嘈杂的估计。噪声可能会导致虚假更新
  2. 渐变比例没有标准化,所以我们的更新很可能会随着时间的推移而消失或爆炸

圣经》和《古兰经》传统中)亚当(人类第一人的名字

在 Adam 中,我们保留了梯度及其方差的移动平均值:

其中,𝓂是移动平均值,𝓋是移动无中心方差,β₁是平均值的插值常数,β₂是无中心方差的插值常数,∇L 是损失的梯度。指数中的括号表示它实际上不是指数,而是时间步长。这看起来有点可怕,但重要的是要注意,𝓂和𝓋都只是梯度及其方差的线性插值(βx*₀+(1-β)x*₁),这给了我们一个移动平均值。β值越高,我们对每个新样本的移动平均值的更新就越少,从而使我们对各批次梯度的平均值和方差的估计更加平滑。这是我们对不同 betas 的嘈杂数据集进行平滑处理的可视化效果。

Linear interpolation for various strengths of beta (from fast.ai)

如果我们有一个小批量,我们对每一步梯度的估计可能会更嘈杂,所以我们需要一个更高的β。如果我们使用大批量的一致数据,我们可能需要更少的 beta。

上面的移动平均线的问题是,当算法第一次初始化时,移动平均线是 0。如果β接近 1,这将导致汇总统计数据比前两个时间步长更接近 0,因为我们从上一步中获取了大部分质量。这种影响在上面的 beta=0.99 的图表中尤其明显。

我们通过去偏置来解决这个问题

这导致:

Linear interpolation with debiasing (from fast.ai)

问题没有消失,但是好多了。

为了插入一些数字,如果β = 0.9,在第一次迭代中,debias 会将该值乘以 1/1–0.9 = 10。那么当我们线性插值时,β𝓍₀ + (1 — β)𝓍₁,第一项β𝓍₀ = 0。德拜斯因子 10 将在第二项中抵消(1 — β) = 0.1,因此我们完全使用新值𝓍₁.仅仅几步之后,debias 因子将收敛到 1。下图显示了 debias 项消失需要多少步(注意 y 轴上的差异):

Visualizing debias factor over time

现在,最后的参数更新是

分子表示“对于每个参数,在该参数的梯度方向上前进一步。”分母表示“根据标准偏差对步长进行归一化”

直观的解释是,当我们第一次开始更新参数时,我们可能会偏离很远。如果梯度都指向不同的方向(高方差),我们将谨慎地迈出一小步。相反,如果所有的梯度都告诉我们向同一个方向移动,方差会很小,所以我们会在那个方向上迈出更大的一步。无论哪种方式,如果所有梯度的比例很大,常数因子将在我们除法时抵消,因为我们使用的是无中心方差。随着训练稳定,损失越来越接近 0,平均值将接近 0,因此更新将自动变得更精细。

分母中的ε表示“好吧,我们可能认为我们根本没有噪声,但我们不要太疯狂,一次走一步。”当噪声方差接近零时,这有效地设置了步长的上限。

这个比率 m/sqrt(v)可能看起来像μ/σ,它是信噪比,但是这种解释只适用于标量。

(同 LocalAreaRadioSystem) 局域无线电系统

随着批量的增长,每个时期的迭代次数减少。为了收敛到相同的数据集迭代次数,我们可以通过提高学习速率来进行补偿。然而,随着学习率的增加,训练变得更加不稳定。SOTA 将使用学习率预热,但这只在一定程度上有帮助,在一定程度上学习将开始发散。热身是对真正问题的修补:梯度必须是嘈杂的。

分层自适应速率缩放( LARS )的作者解释了他们解决这个问题的技巧:

为了分析具有大 LRs 的训练稳定性,我们测量了层权重的范数和梯度更新的范数之间的比率。我们观察到,如果这个比例太高,训练可能会变得不稳定。另一方面,如果这个比例太小,那么权重的变化就不够快。

他们把这个比率叫做“信任比率”。当它更高时,梯度变化更快,反之亦然。由于我们现在对每一步都更有信心,学习速率计划中经常使用的谨慎预热不再必要,我们可以扩展到更大的批量,而不会出现偏差。

在英语中:逐层学习速率λ是全局学习速率η乘以层权重的范数与层梯度的范数之比。如果我们用重量衰减,我们可以把它加在分母上。当我们将其插入 SGD 时,分母最终会将梯度归一化为单位范数,这有助于避免发散。

分子是权重的范数,因为随着网络的加深,具有零均值、单位方差(ZMUV)权重变得很重要。这是因为在每一层,这些权重相乘,所以如果它偏离 ZMUV,这些值可能会爆炸或消失。当重量很小时,我们迈出一小步。当重量很大时,我们迈出更大的一步。结合重量衰减,这有助于我们稳步迈向 ZMUV 重量。

让我们了解一下这里发生了什么。在训练开始时,假设层输出 ZMUV,因此上面的分子将是 0 或接近它。我们采取的任何步骤都可能很小。相比之下,分母可能会很大,因为当一切都是错的时候,梯度就很大。这样,随着体重的增加,我们自然会暖和起来。当我们接近 0 损失时,梯度将变小,因此信任比将保持学习速率比没有信任比高 10 倍(由于削波),防止我们过早放弃达到最优。

小绵羊

LAMB 代表“用于批量训练的分层自适应矩优化器”它对 LARS 做了一些小改动

  1. 如果信任比率的分子(下面的 r₁)或分母(下面的 r₂)是 0,那么就用 1 来代替。这一部分很难阅读,所以我基于一些代码
  2. 固定权重衰减:在 LARS 中,信任比率的分母是|∇L| + β |w|,而在 LAMB 中是|∇L + β w|。这保留了更多的信息。
  3. 他们不使用 SGD 更新规则,而是使用 Adam 更新规则。
  4. 将信任比率削减为 10。

所以完全信任 LAMB 的比率是

最后一行是逐层 LAMB 更新规则。𝓇₂是具有权重衰减的亚当更新规则的规范,ηᴸ是由信任比率调整的逐层学习速率。因此,总的来说,这种方法可以概括为 LARS 应用于 Adam,因为它只是将旧的更新步骤乘以信任率。

作者没有报告 LAMB 是否提高了 LARS 的 ImageNet 训练性能,他们也没有比较 LARS 和 LAMB 对 BERT 的影响,所以很难说这些变化带来了多大的不同,但实现非常简单。

实验

为了更好地理解正在发生的事情,我在 Pytorch 中实现了 LAMB。我在 MNIST 身上做了一系列实验,发现在亚当偏离的地方,兰姆一直在突突前进。我选择 MNIST 是因为它很小,足以在 CPU 上尝试,但这意味着我们看不到任何收敛的改进。我将很快发表另一篇探索 LAMB 应用于大型变形金刚的帖子!

我想象了一些实验。

下面,我比较了亚当(下面蓝色)和兰姆(下面红色)的学习率 0.01 和 betas .9,. 99。它们非常相似,但是 LAMB 更能概括测试的准确性。

MNIST training loss and test accuracy over time for Adam (blue) vs LAMB (red)

为了弄清楚到底发生了什么,我想了解信任比率的分层组成,所以每隔几批后,我就将 r、r₁和 r₂的每个值记录为直方图。对于亚当,我计算值,但不要在任何地方使用它们。

如何解读下面的图表:Y 轴显示的是什么时间步长,第一个在顶部,X 轴是直方图桶,Z 轴是直方图频率。

LAMB parameter histograms on Adam (blue) vs LAMB (red) on MNIST

你可以看到在两边,r 都从 1 以下开始。在羊肉方面,这为所有层面创造了一个自然的热身期。然后,随着一些层开始获得更大的权重和更稳定的梯度,r 鼓励它们迈出更大的步伐。这夸大了相对于亚当基线的规范。

在接下来的实验中,我在 0.1 和 0.01 的学习率上比较了 LAMB 和它自己。Adam 在学习率. 01 时收敛正常,在 0.1 时完全不学习,这里就不做比较了。左边(蓝色)的学习率= 0.01,右边(绿色)的学习率= 0.1。在右侧,它在预热期间几乎立即收敛,但随后一些层权重开始爆炸(参见 X 轴比例的差异)并发散。

为了解决重量流失的问题,我在右下方添加了重量衰减 0.01。训练没有跑偏!一般来说,信任比率在小于 1 时保持缓慢学习,而在更舒适的状态下,它高达 4.5。

摘要

随着学习率的增加,普通 SGD 变得不稳定。

LARS 通过标准化梯度和权重的逐层信任比来调整 SGD 学习率。

Adam 使用由去偏方差归一化的去偏均值来调制更新。

LAMB 通过更精确的逐层剪切信任率来调整 Adam 的学习率。

结合所有这些技术使我们能够以高学习率进行大批量训练,将 BERT 的墙壁时间减少 100 倍!

感谢 雅罗斯拉夫 莎拉简·洪 的编辑和/fast . ai part 2 的灵感

对神经类型转移的直观理解

原文:https://towardsdatascience.com/an-intuitive-understanding-to-neural-style-transfer-e85fd80394be?source=collection_archive---------15-----------------------

神经风格转移是一种机器学习技术,它将一幅图像的“内容”与另一幅图像的“风格”融合在一起

[## 艺术风格的神经算法

在美术中,尤其是绘画,人类已经掌握了通过构图创造独特视觉体验的技巧

arxiv.org](https://arxiv.org/abs/1508.06576)

Creating a rainbow, mosaic hummingbird with neural style transfer

  • 内容:描述图像中物体及其排列的高级特征。内容的例子是人、动物和形状
  • 风格:图像的质感。风格的例子有粗糙度、颜色和锐度

Start by guessing with a white noise image

给定你的内容图像和风格图像,我们想要创建第三个图像,它是前两个图像的混合。让我们从一个简单的白噪声图像开始。为了优化效率,我们可以从内容图像或样式图像开始,但现在先不要担心这个。

现在假设我们有两个损失函数,内容损失风格损失。这些函数都接受我们生成的图像,并返回一个损失值,该值表示我们生成的图像的内容和样式分别与给定的内容图像和样式图像的内容和样式有多么不同。

目标是最小化我们生成的图像的内容和风格损失的加权和

就像任何其他神经网络模型一样,我们使用优化算法,如随机梯度下降法,但不是优化神经网络模型的参数,而是优化我们图像的像素值

Minimizing a weighted sum of style loss and content loss over the generated image. This is a progression of optimization across 600 steps

虽然风格和内容并不是完全相互独立的,但神经风格转移表明,在大多数情况下,我们可以很好地区分这两者。为了解决样式和内容之间的任何冲突,可以调整样式和内容损失的权重,以在生成的图像中显示更多的样式或内容。

这就结束了我们对神经类型转移的高级解释。

获取内容和风格损失函数

本节假设机器学习和卷积神经网络的基础知识。

我们使用经过训练的卷积神经网络(CNN)模型,例如 VGG19,来获取内容和风格损失函数。

内容

回想一下,内容是描述对象及其在图像中的排列的高级特征。图像分类模型需要在内容上训练有素,以便准确地将图像标记为“狗”或“汽车”。卷积神经网络(CNN)被设计成过滤掉图像的高级特征。CNN 本质上是从一个图像到另一个图像的顺序映射。每个连续的映射过滤掉更多的高级特征。因此,我们对 CNN 中的图像映射更感兴趣,因为它们捕捉了更多的内容。

关于 CNN 如何捕捉高级特征的更多详细信息,我推荐谷歌的这篇文章。它有很多很棒的视觉效果

VGG19 is a traditional CNN model, which sequentially maps images to images via convolutional filters (blue). The red blocks are pooling functions that simply shrink the images to reduce the number of parameters in training. Licensed under CC BY 4.0 — https://www.researchgate.net/figure/The-figure-maps-of-VGG19-in-our-approach-Blue-ones-are-got-from-convolutional-layer-and_fig4_321232691

我们将图像的内容表示定义为相对更深入 CNN 模型的图像映射。

We chose the fifth image mapping as our content representation. In more technical terms, we would say that our content representation is the feature response of the fifth convolutional layer.

我们可以通过仅使用内容表示来重建图像来可视化内容表示。我们首先天真地猜测一个白噪声图像,并迭代优化它,直到图像的内容表示收敛到原始图像的内容表示。这种技术被称为内容重建

Content reconstructions: The first image uses the content representation from the first image mapping, the second image uses the fifth image mapping and the third image uses the ninth mapping. With each successive image, there is more noise, but the high level structure of the bird is still retained. This indicates that the higher level features are being filtered out

风格

对于风格损失,我们希望捕捉图像的纹理信息,而不是结构信息。回想一下,一个图像包含多个通道,在 CNN 模型中,我们通常将图像映射到具有更多通道的图像,以便我们可以捕捉更多的特征。

让我们用单词 layer 来描述一个特定通道的图像切片。我们将样式表示定义为图像映射中各层之间的相关性

更具体地说,它是图像映射中所有层对的逐元素矩阵乘法的总和。格拉米矩阵经常被用来表达风格。对于给定的图像映射,格拉米矩阵的第 I 行和第 j 列的元素将包含展平的第 I 层和第 j 层之间的点积。

We chose the first image mapping as our style representation. Style representation is the correlation between all layers in an image. While we only used one image mapping here, we usually use multiple image mappings for style representation (e.g. the first 5 image mappings)

就像在内容重建中一样,我们可以通过仅使用样式表示来重建图像,从而可视化样式表示。我们开始天真地猜测一个白噪声图像,并迭代优化它,直到图像的风格表示收敛到原始图像。这种技术被称为风格重建

Style reconstructions: The first image uses the the style representation from the first image mapping, the second image uses the style representations from the first two image mappings… etc. With each successive image mapping, the textures we obtain become more high level.

现在我们可以定义内容损失和样式损失函数。

内容损失是输出图像和内容图像的内容表示之间的平方误差

样式损失是输出图像和样式图像的样式表示之间的平方误差

神经类型转移的高级过程

  1. 决定 CNN 模型的哪些图像映射用于内容表示和样式表示,然后从内容图像计算内容表示,从样式图像计算样式表示。对于所有这些图像,我将第五个图像映射用于内容表示,将前五个图像映射用于样式表示
  2. 初始化您的输出图像(可以是白噪音图像、样式图像或内容图像的副本,并不重要)
  3. 根据相同 CNN 模型的相同图像映射计算输出图像的内容表示和样式表示
  4. 计算内容损失和风格损失
  5. 在内容损失和样式损失的加权和上优化您的输出图像。这通常通过随机梯度下降来实现
  6. 重复步骤 2–5,直到您对结果满意为止

更多神经类型转移的例子

神经风格转移是一种惊人的机器学习技术,可以被艺术家广泛使用。这里还有一些神经类型转移的例子。所有图片都在 Pixabay 下授权

履行

有大量的神经类型转换的代码基础。我推荐看看 PyTorch 的教程系列中的

对衰减器网络的虚拟理解

原文:https://towardsdatascience.com/an-inutitive-understanding-to-fader-networks-a8fb7c7901a4?source=collection_archive---------15-----------------------

推子网络是一种神经网络,可以让您控制数据项的一组属性

在这篇博客中,我们将讨论控制图像属性的推子网络,因为它们是最容易理解的。

[## 推子网络:通过滑动属性操纵图像

本文介绍了一种新的编码器-解码器结构,它通过对图像进行解纠缠来重建图像

arxiv.org](https://arxiv.org/abs/1706.00409)

The left images are the originals. Here we are controlling for the binary attributes of “age (young/old)” and “gender (male/female)”. Image from the fader network paper.

我们假设你对神经网络有基本的了解

衰减器网络是自动编码器的变体

为了理解推子网络,我们将简要介绍一下自动编码器。

自动编码器(AE)是一种神经网络,用于在更小的维度空间中表示数据

An autoencoder is a neural network that learns how to compress data into a smaller space. Source: Wikipedia

自动编码器由两个主要部分组成,编码器解码器

  • 编码器是一个神经网络,它学习将图像映射到一个更小的维度空间,称为潜在空间(在上图中,他们称之为代码)。一个图像在潜在空间中的点被称为它的潜在表示。
  • 解码器通过仅从潜在空间获取对应点来学习重建原始图像。
  • 自动编码器的损失函数就是重建误差(即像素值的均方误差)

关于自动编码器的更详细的解释,请看这个博客

推子网络是如何修改自动编码器的

为了理解推子网络,让我们使用在人脸数据集上训练的自动编码器, CelebA ,其潜在空间维度为 2。我们想要控制性别属性。假设 0 表示男性,1 表示女性。训练之后,我们可以期望编码器像这样映射人脸。

An autoencoder with a 2-dimensional latent space on faces. We can expect the encoder to map the males and females to disjoint regions of the latent space so that the decoder can correctly reconstruct their genders

在高层次上,每个性别占据了潜在空间的一个不相交的区域,使得解码器可以容易地学习用正确的性别重建面部。

这是推子网络的不同之处。

A fader network is jut like an autoencoder except that the decoder takes in some attributes and the discriminator penalizes for any encodings of those attributes in the latent space

我们强制衰减器网络的解码器使用图像的给定属性,以及潜在表示来重建图像

推子网络是一个自动编码器,除了我们馈入解码器,不仅是潜在的表现,还有我们想要控制的图像属性。

为了迫使解码器使用给定的属性进行重构,我们必须破坏潜在空间中关于属性的所有信息。

在我们的例子中,给定了潜在空间中的一个点,我不应该能够说出这张脸的性别。通过破坏潜在空间中关于性别的任何信息,解码器被迫使用我们提供给它的给定属性来重建具有正确性别的图像。

为了破坏潜在空间中的属性,衰减器网络在其潜在空间上引入了鉴别器。这种鉴别器试图仅从图像的潜在表示中学习图像的属性。在我们的例子中,鉴别者试图从 2-D 潜在空间中学习图像的性别。在它被训练之后,通过惩罚潜在空间中属性的任何编码,它充当自动编码器的损失函数。

经过大量的训练后,我们希望看到鉴别器的表现不比随机猜测好,因为这表明我们已经成功地销毁了潜在空间中关于属性的所有信息。

通过完全训练的衰减器网络,我们可以通过改变属性值来控制重建图像的属性。在我们的例子中,我们可以在 0 和 1(男性和女性)之间滑动我们的性别属性,我们将看到男性和女性之间的人脸插值。

我们可以训练推子网络来控制多个属性,但随着我们想要控制的属性数量的增加,我们得到的重建和真实感质量会降低。

The left images are the originals. Here we are simultaneously controlling for the binary attributes of “opened eyes”, “glasses”, and “gender”. Image from the fader network paper

高级训练算法

回想一下,自动编码器的损失函数就是重建损失。在衰减器网络中,总损失函数是重构损失鉴别器损失的加权和(鉴别器损失的较高值表明鉴别器可以容易地从潜在空间辨别属性)。

正如在大多数 ML 培训课程中一样,可以使用随机梯度下降来优化推子网络。

开始时,将鉴别器损失的权重设置为 0,这样自动编码器可以首先获得良好的重建效果

对于给定的一批图像…

We alternatively train the discriminator and autoencoder within a batch of data. When we train the autoencoder, we are optimizing over a weighted sum of the discriminator loss (cross entopy) and the reconstruction loss (MSE). Overtime, we increase the weight of the discriminator loss to encourage disentaglement of the attributes from the latent space.

  1. 通过编码器输入批次,并在此潜在表示上优化鉴别器
  2. 将批次通过自动编码器和新优化的鉴别器,并计算总损耗(鉴别器损耗和重建损耗的加权和)。针对这一总损失优化自动编码器(编码器和解码器)
  3. 重复第 1 步和第 2 步,同时缓慢增加总损失函数中鉴频器损失的权重。

随着我们增加鉴别器损失的权重,性别属性开始越来越多地从潜在空间中消失,这逐渐迫使鉴别器在重建期间使用给定的性别属性。

履行

MNIST 推子网络笔记本

我在手写数字数据集 MNIST 上使用 Google Colab 实现了一个推子网络。我们控制的属性是图像的数字值。编码器和解码器分别是卷积和反卷积神经网络。鉴别器是一个简单的多层感知器,它为数字值输出一个 10 维概率向量。我们将鉴频器损耗计算为鉴频器输出和数字值的一键编码之间的交叉熵。重建损失是像素值之间的均方误差。回想一下,总损耗是重建损耗和鉴别器损耗的加权和。重建损失的权重总是 1。鉴别器损耗的权重从 0 开始,在每个时期后增加 3,在 15 结束。训练 50 个纪元大概需要 10 分钟。训练后,我们演示了一个渐变到另一个随机选择的数字。

R 平方的颂歌

原文:https://towardsdatascience.com/an-ode-to-r-squared-804d8d0ed22c?source=collection_archive---------11-----------------------

或者说, 统计学家的十字军东征:一场责任与决心的舞蹈

据说能够向另一个人解释某事是掌握它的第一步。作为一名有抱负的数据科学家,R 平方感觉像是我应该掌握的东西之王…

因此,本博客涵盖以下问题:

  • 什么是 R 平方,它告诉我们什么?
  • 怎样才能直观的推导出 R 平方的公式?
  • 为什么 R 的平方总是在 0–1 之间?

Portrait of Student Trying to Understand R-Squared, With Cat (c.2019)

什么是 R 平方,它告诉我们什么?

假设我们有一个输出度量 y,带有观察到的数据点, y ᵢ.那么预测未来观测值的最简单方法就是取现有观测值的平均值。

The baseline mean model, ȳ

注意这个基线模型如何总是为未来的观察预测相同的值。还要注意,这个预测不依赖于 x 的值。不用说,这不是一个很好的模型。

为了改善这种情况,假设我们改为创建一个线性回归模型, f ,根据观察到的数据点, y ᵢ,及其相关的 x 值来预测 y 的值。

Our model ‘f

那么我们可能需要一些统计数据(姑且称之为 R 平方)来告诉我们我们的模型有多好。特别是,我们的模型 f 比“基线均值模型”有多大的改进?

R 平方告诉我们:“我们的模型占了均值方差的多少?”

如果模型解释了 100%的方差(即 R 平方= 1),那么我们可以说它完美地解释了观察到的数据点。

如果模型解释了 0%的方差(即 R 平方= 0),那么我们可以说它对观察到的数据点没有任何精确的解释。

在现实世界中,R-Squared 善于促进模型之间的比较。然而,确定一个“好”的 R 平方值本身有点困难。一般来说,R 平方大于 0.6 的模型值得您关注,尽管还有其他因素需要考虑:

  • 任何试图预测人类行为的领域,如心理学,其 R 平方值通常低于 0.5。人类本来就很难预测!
  • 具有高 R 平方值的模型可能遭受其他问题,例如过度拟合。r 平方只是数据科学家评估其模型有效性的众多方法之一。

怎样才能直观的推导出 R 平方的公式?

与其一头扎进代数的海洋,我想形象地考虑一下 R 平方。

我们已经知道,回归将创建一个最小化残差的模型(即模型预测值 y 和实际观察值 y 之间的差异)。因此,查看我们模型的残差似乎是一个明智的起点。

Our model, f, (L) and the baseline case ȳ (R)

我们的模型 f (左边图表中的蓝色箭头)的残差可以被认为是我们的模型无法解释的观察值的比特。

一旦我们开始将这些残差作为公式的一部分进行求和,那么对它们的平方和进行求和是很有用的。这将确保我们不必处理任何负面价值。它还会放大较大个体误差的影响,这在模型预测不佳时会变得格外明显。

The squared residuals for our model, f, (L) and the baseline case ȳ (R)

同样,我们可以为我们的模型和基线情况可视化这些平方残差。在这里,蓝色的方块是另一种方式来显示我们的模型无法解释的那部分误差。蓝色方块的总面积可以用数学方法表示为:

The Residual sum of squared errors of our regression model also known as SSE (Sum of Squared Errors)

此外,橙色方块的总和可由下式给出:

The Total sum of squared error — the squared difference between y and ȳ

我们希望 R 平方是我们的模型与基线情况的比较。我们可以通过将蓝色方块的面积作为橙色方块面积的一部分来进行比较:

因此,这个表达式告诉我们,模型解释的是而不是偏离平均值ȳ的份额。因此,由模型解释的的方差份额,或传说中的 R 平方,可以给定为:

为什么 R 的平方总是在 0–1 之间?

R 平方最有用的性质之一是它的范围在 0 和 1 之间。这意味着我们可以很容易地比较不同的模型,并决定哪一个更好地解释了均值方差。

当然,从上面我们知道 R 平方可以这样表示:

所以要让 R 的平方有界在 0 和 1 之间,我们要求(ss RES/ss stot)本身在 0 和 1 之间。如果出现以下情况,就会发生这种情况:

  1. SSres≤SStot(对于 R 平方大于等于 0)
  2. SSres SStot都为正,或者都为负(对于 R 平方小于或等于 1)。

让我们依次来看这些。回想一下:

The sum of all the squared resisuals from the model.

The sum of all the squared residuals from the mean of observed values.

对于(1),我们可以做一个直观的论证。记住, SStot 代表观察到的 y 值之间的差距,以及它们的平均值,ȳ.

假定 y = ȳ 表示一条直线(特别是,一条穿过 x-y 平面的水平线), y = ȳ 本身就是我们数据集的线性模型。当然,这不是一个好模型,但它仍然是一个模型。

现在让我们考虑一下计算 R 平方的模型——这个模型产生了 f 项,因此产生了 SSres 。该模型是通过回归创建的,根据定义,我们知道回归过程会生成最小化数据集残差的模型。

我们有两种可能的情况:

  • 回归产生 y = ȳ 作为最小化残差的模型。这样,我们就有了ssres=sstot,因为 f ᵢ = ȳ跨越了数据集。
  • 回归产生了不同的模型。由于回归产生了一个最小化残差的模型,这个模型的残差必须小于 y = ȳ 的情况。所以我们要有SSres<SStot

于是,我们有了SSres≤SStot

因此,R 的平方将总是大于或等于 0。

对于(2),我们知道 SSresSStot 都是作为平方和给出的(见上图)。由于平方数总是正的,我们知道 SSresSStot 都将总是正的。

因此,R 的平方将总是小于或等于 1。

一项经常被忽视的数据科学技能

原文:https://towardsdatascience.com/an-often-overlooked-data-science-skill-ea4254e19c6b?source=collection_archive---------8-----------------------

Source: Pexels

你刚刚开始了你作为数据科学家的第一份工作,并且你很兴奋开始使用你的随机森林技能来实际改变。您已经做好了启动 Jupyter 笔记本的所有准备,但却意识到您首先需要“SSH”到另一台机器来运行您的模型。该公司利用云计算来大规模执行机器学习。你肯定听说过 AWS、Google Cloud Compute 和 Microsoft Azure,但是几乎没有在远程机器上运行模型的经验。

这种情况可能会让一些人感到惊讶,但我一直都在看。学校项目倾向于关注可以在笔记本电脑上合理运行的问题,甚至来自较小数据集领域的经验丰富的数据科学家也可以在他或她的笔记本电脑上运行模型。

然而,随着模型变得越来越渴求数据,数据科学家在远程机器(云或本地)上工作时越来越有可能需要舒适和高效。以下是我如何开始发展这些技能。

Source: Pexels

了解终端的基本知识

无论您使用的是 OSX、Linux 还是 Windows,您现在都可以访问基于 Linux/Unix 的终端(如果您使用的是 Windows,请参见此处)。在 Mac 上,按 command+空格键打开搜索栏,键入“终端”,然后按 enter。你现在应该感觉你是在矩阵里——一个真正的编码者。终端将允许你直接向计算机输入命令,而不需要任何图形支持。当使用远程机器时,这是非常有价值的。您将使用终端连接到机器,向它发送命令,并浏览您的文件。

有一本很棒的书叫做《命令行中的数据科学》,我强烈推荐阅读入门章节。仅这一章就能让你轻松地直接从终端操作你的机器。

如果你真的喜欢冒险,花点时间用 zshiterm2 修改你的终端。

发现 Vim

Vim 是一个文本编辑器,您可以直接从终端使用,它预装在大多数 Linux 系统上,或者非常容易安装。

Vim 有一个不错的学习曲线,但是即使只是学习基础知识,也可以让您快速地从终端对文件进行更改。当从远程机器上工作时,这可以节省您大量的时间。

要开始,请查看此互动指南

你也可以学习emacs——如果你讨厌你的小手指

SSH 和 SCP

SSH 是一个可以从终端运行的命令,用于连接到远程机器。SCP 是一个命令,允许您将数据从本地机器(如您的笔记本电脑)复制到远程机器。作为数据科学家,在机器之间移动数据的简单方法是非常有价值的。

有大量优秀的文章向您介绍这些命令。下面是我喜欢的一个教程

饭桶

我发现越来越多的数据科学家在开始他们的第一份工作时,至少掌握了一些 Git 知识,这令人惊讶。如果你还没怎么用过 Git,现在停下来,创建一个 GitHub 账户。

当使用远程机器时,代码的源代码控制变得更加重要,因为运行代码的位置每天都在变化(尤其是在云上),Git 将允许您轻松地跟踪、克隆和合并您正在使用的任何机器上的变化。

这个 GitHub 指南是一个很好的起点。如果你对该指南感到满意,那么你已经掌握了相当好的基础知识。根据我的经验,Git 的基础知识可以让你走得更远。

屏幕

屏幕是一个简单但非常有用的工具。一旦您了解了 SSH 并连接到您的第一台远程机器,您可能会痛苦地认识到,如果您的连接中断,在那台机器上运行的任何东西都将死亡。这对于长时间运行的数据科学工作来说并不理想。

答案是 Screen(注意:还有其他类似的更高级的工具,比如 tmux,但是我发现 screen 对初学者来说是最简单的)

Screen 允许您在一个进程中运行您的命令,即使断开连接,该进程也不会终止。

这很容易上手,你可以在这里学习如何

Source: Pexels

把所有的放在一起

至此,我们已经讨论了在远程机器上工作的基本工具。经验是最好的老师,所以我建议最重要的是使用这些工具。为此,我会在谷歌云计算上开一个免费账户。我推荐谷歌,因为它的免费账户将允许你访问 GPU 计算,如果你喜欢深度学习,这真的很有用。

这里有一篇很棒的文章可以带你完成这个过程:

[## 免费为 fast.ai 设置 Google Cloud 实例 GPU

编辑*本指南是为 fastai 版本 1 编写的,该版本在当前日期和时间(2018 年 1 月)正处于…

medium.com](https://medium.com/@jamsawamsa/running-a-google-cloud-gpu-for-fast-ai-for-free-5f89c707bae6)

走完所有这些步骤需要时间,你肯定会遇到困惑。但是,如果你坚持不懈,你将会创建一个免费使用的,带有 GPU 的远程机器。然后,您可以练习使用 SSH 从终端访问它,使用 Vim 编辑文件,使用 SCP 将数据传输到您的机器,使用 g it 移动和跟踪代码,以及使用 screen 在断开连接时不会丢失您的进程。

熟悉这种类型的数据科学工作流将让你为大数据和大计算时代做好准备,并让你在开始第一份工作时变得非常高效。

本文可在这里找到。

解决垃圾问题的奥威尔式方法

原文:https://towardsdatascience.com/an-orwellian-approach-to-the-litter-problem-1396ddb15701?source=collection_archive---------6-----------------------

Photo by Paweł Czerwiński on Unsplash

使用计算机视觉来检测有人遗漏了垃圾

任何生活在城市环境中的人都知道它有多肮脏。无论市政当局如何努力,垃圾总会像杂草一样在城市中蔓延。简单的解决方案包括派人带着垃圾清道夫去清理城市街道。不幸的是,人们并不总是知道垃圾在哪里。街道清洁工可以在低密度垃圾区漫步,而垃圾堆在更繁华的区域。

在我以前的大学最近举办的一次黑客马拉松中,我和我的团队试图解决垃圾问题,以改善我们的社区并安抚黑客马拉松的环境意识主题。结合我们在计算机视觉和机器学习原则方面的经验,我们希望创建一个切入源头的解决方案。我们的项目没有等待专门的垃圾清除服务,而是利用了城市中大量的安全摄像头和基本的人类自尊。

What a vile litterbug

人体跟踪

为了检测被扔的垃圾,我们想把一个人隔离成一团像素。如果整个人可以被转换成像素的二进制斑点,我们可以检测另一个像素斑点是否开始远离人。我们可以有把握地假设第二个斑点是一个被乱丢的物体。这个思考过程激发了使用衍生视频来跟踪场景变化的想法。这不是一个健壮的解决方案,因为即使在尝试了膨胀方案之后,图像中的人也经常是支离破碎的。

A derivative approach to motion detection in a scene. Red box shows trash and is not generated by program

在很快厌倦了这种幼稚方法的不一致性后,我们的团队转而使用梯度方向直方图来确定一个人的位置。猪探测器通常用于探测行人。该方法使用 Sobel 算子找到图像的梯度。然后,梯度图像被分割成 8×8 像素块。在每个小块中,计算梯度向量,并基于其方向将其添加到九仓直方图中。利用这些梯度,我们可以预测一个人可能在哪里。

实施猪检测器给出了令人惊讶的原始结果。可以跟踪一个人在场景中移动。该方法还可以在一幅图像中区分多个人。一旦检测到人,就创建一个边界框。人们发现,如果边界框太小,宽广而富于表情的动作有时会被混淆。结果,我们用一个常数值扩展了边界框。

The result of the HOG detector, with an enlarged bounding box

垃圾检测

检测真正的垃圾是这个项目中最棘手的部分。尝试了两种方法。第一种方法依靠机器学习原理来识别图像中的垃圾。垃圾文字图像的数据集被用来训练一个复杂的神经网络。这些图像的尺寸被调整为 60×60 像素的图像,并在 0 到 1 的尺度上进行归一化。神经网络本身包含三个卷积层和两个隐藏层。不幸的是,这种方法非常笨拙,成功率也不高。在最好的情况下,该团队在区分纸板和玻璃时能够达到 80%的成功率。

我们发现一种更成功的方法依赖于简单的图像处理方法。我们拍摄了前面提到的衍生图像,并监控由 HOG 检测器创建的边界框内的像素。如果检测到一组像素穿过边界框的边界,则标记该像素。该组像素由它们自己的盒子界定,并且存储相关联的彩色图像。

捕捉到潜在垃圾的图像后,使用跟踪算法来跟踪垃圾。OpenCV 提供了几种方便的跟踪算法。对于这个项目,使用了具有信道和空间可靠性(CSRT)跟踪器的判别相关滤波器。这种滤波器以其鲁棒性而闻名。这对于我们的目的来说很方便,因为它可以处理对象的遮挡。这种方法的缺点是计算复杂。但是,谁会在黑客马拉松上寻求优化呢?

如果 CSRT 跟踪到图像超出了垃圾者的范围,这个物体就被标记为垃圾。跟踪器继续跟踪垃圾,并保存其最终的图像坐标和尺寸。

Example of CSRT tracker resolving occlusion

除了抓住一个乱扔垃圾的人,该团队还想检测是否有人捡了垃圾。这样的乐善好施者可以避免派人去清理垃圾。更具侵略性的市政当局可以不遗余力地奖励整洁的个人。

由于垃圾的位置是已知的并被跟踪,清理垃圾的算法很简单。程序继续追踪这个垃圾。如果垃圾从其丢弃位置移动了一个阈值,并且包含在 HOG 生成的帧中特定数量的帧,则认为垃圾已被清除。

Being a good samaritan

推特垃圾

如前所述,该项目旨在通过针对问题的根源来遏制乱丢垃圾。完全缺乏共同的体面混合匿名的保护,让人们犯下这一令人发指的罪行。由于我们的方法能够检测出乱扔垃圾的个体,因此可以很容易地保存罪犯的图像。

使用 Twitter 令人难以置信的实用 API,通过将罪犯的图像上传到 Twitter,这个项目增加了一点魔力。这个信息让邻居看到是谁造成了他们社区的垃圾堆积。相机可能会报告其地理坐标以及图像。这将允许有礼貌的居民清理垃圾。在未来,我们希望增加一种奖励好心人的方法,无论是通过积极的 Twitter 帖子还是其他方式。

An example twitter post by the litter tracker

结果

这个黑客马拉松项目成功地展示了一个基本监控系统的原型。该方法能够监控个人是否不能将他们的垃圾放入垃圾容器中。

考虑这种方法的局限性很重要。我们的方法依赖于一个人从他们身边扔一片垃圾。我想象这是最常见的乱扔垃圾的方法(我个人经验不多)。然而,如果一个人决定蹲下,轻轻地把垃圾放在他们旁边,我们的算法将无法检测到垃圾。该程序也不能确定垃圾的类型。个人可能会丢失钱包,算法会将该物品视为垃圾。该团队最初希望用前面提到的神经网络来解决这个问题。不幸的是,由于数据集有限,这变成了一项艰巨的任务。

虽然这个项目没有让我们在黑客马拉松上获得胜利,但这是一次令人难以置信的激动人心的经历。过去,我在静态图像方面做了大量的工作,但在视频镜头方面做得很少。这个项目采用了许多计算机视觉技术,并将它们应用到一个愚蠢而有趣的应用程序中。

最终视频

我应该强调,这篇文章是一篇工程讽刺文章。实际上,我并不建议市政当局实施这样的制度,也不赞同将侵犯隐私和公开羞辱作为解决乱扔垃圾问题的一种手段。

神经网络分类输入处理综述

原文:https://towardsdatascience.com/an-overview-of-categorical-input-handling-for-neural-networks-c172ba552dee?source=collection_archive---------4-----------------------

image by sanwaldeen

为基于神经网络的预测器预处理数据时,总结处理分类数据(低基数和高基数)的多种方法的快速指南

在 2018 年的一次编码练习中,我被要求为描述员工及其工资的数据集编写一个 sklearn 管道和一个 tensorflow 估计器。目标是:创建一个预测器来预测某人的年收入是高于还是低于 5 万英镑。

我遇到的一个问题是对分类值的处理。虽然决策树或森林对这种数据没有问题(它们实际上处理得很好),但用神经网络处理起来有点棘手。当然,我们都知道 One-Hot-Encoding 是一种将这种数据映射成 NN 可通过格式的方法。但是我被要求开发一个处理分类列的多种方法的详尽列表。类别数量最多的列是具有 41 个唯一出现值的native-country

让我们假设数据集有一个名为“电子邮件域”的附加列,其中包含“@ Gmail . com”“@ hotmail . com”等域和“@pascalbrokmeier.de”等私有域。该列表可能包含数千个唯一值,这些值很难由神经网络处理。一个好的工具应该以某种有意义的方式对类别的含义进行编码,同时保持相对较低的维数。

事实证明有很多方法可以解决这个问题。因此,在接下来的文章中,我将概述用神经网络处理分类数据的许多方法。我将把列表分成两类:可以将任意符号列映射成适当表示的通用方法和特定领域的方法。对于领域特定的例子,我将描述以某种有意义的方式表示国家列的方法。

什么是分类数据?

在深入研究处理分类数据并将其传递给神经网络的方法之前,我想用几个词来描述它是什么。用我自己的话来说,分类数据是一组符号,用于描述感兴趣的某个对象、系统或实体的某个更高级别的属性。例如,概念“红”、“蓝”和“绿”描述了这样的事实,即一些物理对象辐射特定分布的电磁波谱,该电磁波谱转变为有意识的人的观察,该人仍然可以通过视觉来观察世界。这比简单的“1,2,3”要复杂得多。你如何订购颜色?你会如何看待它们之间的关系?什么是属于什么的?你认为以下四个词中的哪一个会缩短彼此之间的距离?“绿色、蓝色、天空、树叶”。

分类数据可以,但不是必须,遵循某种排序。然而,分类数据通常可能是不同的,甚至是重叠的。有时一个范畴集的可能值可以彼此有关系,有时它们彼此毫无关系。将分类输入转换到数值向量空间时,需要记住所有这些概念。

用维基百科的话说:

分类变量是一个变量,它可以呈现有限的中的之一,并且通常是固定数量的可能值,根据某个定性属性将每个个体或其他观察单位分配到特定的组或名义类别

够了,把别人的工作归功于自己。让我们开始吧:

与领域无关的解决方案

以下编码分类数据的方式与我们正在交互的类别类型无关。

顺序编码

让我们从最简单的形式开始:给每个可能的类别分配一个整数并传递它。这是一种非常幼稚的处理数据的方式,除了让它工作之外,它通常没有什么好处,意味着程序不会再崩溃了。当查看国家/地区列时,您可能会看到这样的内容:

这种方法有几个缺点:Canada != 1/2 * ChinaVietnam != 40/39*United-States。任何关于这些国家的高层信息都会在翻译过程中丢失。使用我的基准预测器网络时,结果显示性能下降:

>>>> ordinal_pp = helpers.to_pipeline(("ordinalencoder", preprocessing.OrdinalEncoder()))>>>> ordinal_pipeline = pipeline.get_pipeline(ordinal_pp, input_dim=14)>>>> helpers.execute_on_pipeline(ordinal_pipeline, X_train, y_train, X_test, y_test)Epoch 1/3
 - 1s - loss: 0.9855 - mean_absolute_error: 0.3605 - acc: 0.7362
Epoch 2/3
 - 1s - loss: 0.4939 - mean_absolute_error: 0.3108 - acc: 0.7741
Epoch 3/3
 - 1s - loss: 0.4665 - mean_absolute_error: 0.2840 - acc: 0.7970**0.8492152641473572**

一个热编码

我发现最常被“推荐”的方法是 OHE,也称为“虚拟编码”。当搜索“分类数据神经网络”时,弹出的几乎每一页上都有解释。它也是 sklearn 的一部分,因此可以很快应用于数据集。原理很简单,最好用一点代码来说明:

>>>> import helpers
>>>> from sklearn import preprocessing
>>>> import numpy as np
>>>> X_test, y_test = helpers.get_data(subset="test")>>>> ohe = preprocessing.OneHotEncoder()
>>>> categories = np.array(list(set(X_test['workclass'].astype(str).values))).reshape(-1,1)
>>>> ohe.fit(categories)OneHotEncoder(categorical_features=None, categories=None,
       dtype=<class 'numpy.float64'>, handle_unknown='error',
       n_values=None, sparse=True)>>>> categoriesarray([['Self-emp-inc'],
       ['Local-gov'],
       ['Private'],
       ['State-gov'],
       ['Never-worked'],
       ['Without-pay'],
       ['Federal-gov'],
       ['Self-emp-not-inc'],
       ['nan']], dtype='<U16')>>>> ohe.transform(categories).todense()matrix([[0., 0., 0., 0., 1., 0., 0., 0., 0.],
        [0., 1., 0., 0., 0., 0., 0., 0., 0.],
        [0., 0., 0., 1., 0., 0., 0., 0., 0.],
        [0., 0., 0., 0., 0., 0., 1., 0., 0.],
        [0., 0., 1., 0., 0., 0., 0., 0., 0.],
        [0., 0., 0., 0., 0., 0., 0., 1., 0.],
        [1., 0., 0., 0., 0., 0., 0., 0., 0.],
        [0., 0., 0., 0., 0., 1., 0., 0., 0.],
        [0., 0., 0., 0., 0., 0., 0., 0., 1.]])

原谅我没有把它作为主旨分享出来。出于某种原因,medium 把我粘贴的要点链接变成了要点的截图。很没用

结果是对先前变体的改进:

>>> ohe_encoder_pp = helpers.to_pipeline(("ohe", preprocessing.OneHotEncoder(handle_unknown='ignore', categories=categories.get_categories())))>>> ohe_pipeline = pipeline.get_pipeline(ohe_encoder_pp, input_dim=112)>>> helpers.execute_on_pipeline(ohe_pipeline, X_train, y_train, X_test, y_test)Epoch 1/3
 - 2s - loss: 0.3824 - mean_absolute_error: 0.2332 - acc: 0.8358
Epoch 2/3
 - 1s - loss: 0.3601 - mean_absolute_error: 0.2117 - acc: 0.8530
Epoch 3/3
 - 1s - loss: 0.3547 - mean_absolute_error: 0.2125 - acc: 0.8526**0.9069985244122271**

嵌入分类数据

这篇论文这篇关于它的帖子都描述了如何将表格数据转化为神经网络可以管理的东西。

Source: https://tech.instacart.com/deep-learning-with-emojis-not-math-660ba1ad6cdc

这可以让你预先训练一个嵌入层,用于你打算转换成神经网络可以消费的每一个类别。在上图中,instacart 团队使用了一个嵌入层将他们 1000 万件产品中的任何一件转化为 10 维嵌入。然后,下面的隐藏层只需要处理小得多的输入大小。此外,这些较低的维度具有固定大小,这对于构建模型很重要,因为第一层的输入大小需要在训练期间设置,并且后面的预测值也必须符合该大小。这个概念非常类似于自然语言处理方法,我们甚至可以利用预先训练的嵌入。稍后会详细介绍

这对我们的分类价值观意味着什么?对于数据集中的每个分类列,我们必须创建一个嵌入网络来学习该分类的嵌入。如果分类列包含来自预训练嵌入词汇表(例如颜色嵌入或另一个子域)的单词,那么采用这种预训练嵌入可能是有益的。如果类别中的词汇与众不同,那么训练(或改编)一个特定领域嵌入可能会更好。这带来了更低维度的额外好处。只需要描述彼此相关的颜色的向量空间可能比试图嵌入英语中所有单词的向量空间小得多。

特定领域解决方案

差异编码

差异编码可能有助于描述有序属性的分类值。让我们假设只有三种教育形式:没有,学校,大学。在本例中,结果将是具有以下值的三个新变量:

  • 无:0,0,0
  • 学校:-0.5,0.5,0
  • 大学:-0.25,-0.25,0.5

基本上,顺序越高,值越有表现力,因为越多的列远离 0 值。

字符串元数据

类别字符串中有多少单词,字符串有多长,哪些字母出现的频率有多高?虽然这可能是非常嘈杂的信息,但具有足够大数据集的神经网络可能能够从这些信息中提取一些小的预测能力。我记得《线性离题》中的凯蒂提到过她的一个直觉,大意是“如果你能想象一个人从数据中获得一些价值,机器学习算法也可能做得很好”。这对我们的数据集意味着什么?嗯,一个长的职位头衔可能意味着在一个(可以说是太深的)层级链中有更高的级别,因此增加了获得更高薪水的可能性。快速迂回:这一页把它发挥到了极致(并从我的坏例子中转移注意力)。

子信息(编辑:或 N-grams)

让我们跳回假设的电子邮件专栏。一个域有一个 TLD ,它可以保存关于个体起源的信息。这也可以给我们一个关于他们与非营利组织关系的指标。org)或者如果他们在教育机构工作(。edu)。这些信息对于神经网络的训练可能是有价值的。因此,将类别分成子列可能是有价值的。

编辑:也许最强大的技术是使用 n 元语法,特别是字符级 n 元语法。上面的段落已经回避了这一点,但是 n-grams 肯定是更通用的方法。假设你把每封电子邮件都做成一套 2-10 克的。现在,这些 n-grams 可以被编码并传递给 ML 算法。它们将包含几个字母,如“web.de”、“gmail.c”或“@apple.com”。当然,人们可以从这样的子串中获得大量的信息。此外,你现在有了一种向 ML 算法传递信息的方法,它包含了所有人没有gmailhotmail账户的情况。拥有个人域名的人当然属于不同的类别,如jonny95@gmail.com(抱歉,乔尼)。

数据丰富

如上所述,虽然许多电子邮件域,如来自 Google Mail 或 Hotmail 的电子邮件域在人群中非常普遍(因此不包含大量信息),但自定义域可能是一个人工资的有力指标,特别是如果这些自定义域不是个人域,而是属于某个组织。还有大量基于域名的数据可以从网上提取。可以将爬行器添加到管道中,对于每个遇到的域名,该爬行器执行对该域的 HTTP 调用,提取一些关键字并在训练期间使用它们。

概述

将类别转换成神经网络可以处理的东西是一个常见的问题,但找到多种方法来解决这个问题似乎很难。这个, 这个, 这个的问题表明,确实没有太多的选择。最终,任何需要神经网络或回归来将类别转换成某种向量表示的方法都需要从数字输入开始。除了简单地编号(OrdinalEncoder)或者将每个可能的值转换成它自己的二进制维度(OneHotEncoder)之外,没有多少其他方法来映射一组可选值。甚至在将固定大小的向量传递到预测层之前,嵌入也会绕过 OneHotEncoder。

如果你知道其他编码这些值的方法,请与我分享!我会相应地更新文章,当然也要感谢任何作者。

进一步阅读

[## 分类数据分析列表-维基百科

这是一个统计程序的列表,可用于分类数据的分析,也称为分类数据

en.wikipedia.org](https://en.wikipedia.org/wiki/List_of_analyses_of_categorical_data) [## 教程-什么是变分自动编码器?-贾恩·阿尔托萨尔

从两个角度理解变分自动编码器:深度学习和图形模型。

jaan.io](https://jaan.io/what-is-variational-autoencoder-vae-tutorial/) [## 基于 Keras 的分类数据嵌入学习研究

(这是乔·艾迪(Joe Eddy)解决方案对 Kaggle 的安全驾驶员预测的实施的分解和理解…

medium.com](https://medium.com/@satnalikamayank12/on-learning-embeddings-for-categorical-data-using-keras-165ff2773fc9) [## 当对分类输入进行一次热编码时,如何处理神经网络的不同输入大小?

感谢您为 Data Science Stack Exchange 贡献答案!你过去的一些回答并没有…

datascience.stackexchange.com](https://datascience.stackexchange.com/questions/43397/how-to-handle-different-input-sizes-of-an-nn-when-one-hot-encoding-a-categorical/43399#43399) [## 机器学习中为什么要一次性编码数据?

应用机器学习的入门可能很难,尤其是在处理真实世界的数据时。经常…

machinelearningmastery.com](https://machinelearningmastery.com/why-one-hot-encode-data-in-machine-learning/)

计算机视觉概述

原文:https://towardsdatascience.com/an-overview-of-computer-vision-1f75c2ab1b66?source=collection_archive---------8-----------------------

“If we want machines to think, we need to teach them to see.”
-Fei Fei Li, Director of Stanford AI Lab and Stanford Vision Lab

计算机视觉是人工智能的一个领域,训练计算机解释和理解视觉世界。机器可以准确地识别和定位物体,然后使用来自相机、视频和深度学习模型的数字图像对它们【看到】的东西做出反应。

从 20 世纪 50 年代末和 60 年代初开始,图像分析的目标是模仿人类视觉系统,并询问计算机它们看到了什么。在此之前,图像分析一直是使用 x 射线、MPIs 或高分辨率空间摄影人工完成的。美国宇航局的月球地图率先采用了数字图像处理技术,但直到 1969 年才被完全接受。

随着计算机视觉的发展,编程算法被创造出来解决个人挑战。机器变得更擅长重复进行视觉识别。多年来,深度学习技术和技术有了巨大的进步。我们现在有能力对超级计算机进行编程,让它们自我训练,随着时间的推移自我改进,并以在线应用的形式向企业提供功能。

我喜欢把计算机视觉想象成处理数百万次计算,以便识别模式,并具有与人眼相同的准确性。模式可以在物理上看到,也可以通过应用算法在数学上观察到。

计算机视觉的崩溃

图像被分解成像素,像素被认为是图片的元素或组成图片的最小信息单元。

计算机视觉不仅仅是将图片转换成像素,然后试图通过这些像素理解图片中的内容。你必须了解如何从这些像素中提取信息并解释它们代表什么。

Each pixel is represented by 8 numbers (bits of memory). In computer science, each color is represented by a value.

神经网络和深度学习使计算机视觉更有能力复制人类视觉

“神经网络是一套算法,大致模仿人脑,旨在识别模式。他们通过一种机器感知、标记或聚类原始输入来解释感官数据。它们识别的模式是数字的,包含在向量中,所有现实世界的数据,无论是图像、声音、文本还是时间序列,都必须转换成向量。”

图像分类和分割

一张图片的分类简单解释就是当计算机将一张图片分类到某个类别的时候。在下图中,第一个分类对象是羊。定位或位置由图片中物体周围的方框标识。

对象检测检测某类语义对象的实例。下图图中有 3 只羊。将它们(盒子)分类为 sheep1、sheep2 和 sheep3

每个像素属于一个特定的类。在下面的图片中,类别是绵羊、草地或道路。类中的像素用相同的颜色表示。(羊是橙色,路是灰色,草是绿色)。这描述了的语义切分

实例分割同一类的不同对象有不同的颜色。(羊 1 =亮黄色,羊 2 =暗黄色,羊 3 =橙色)

谁使用计算机视觉?

亚马逊推出了 18 家亚马逊商店,顾客可以绕过排队,立即付款。有了计算机视觉,摄像头被用来让员工知道什么时候有东西被下架了。它还可以识别退回的商品或从购物车中移除的商品。当你填完“虚拟篮子”后,你的亚马逊 prime 账户就会被扣款。

零售店中的计算机视觉它还可以提高安全性。随时跟踪店内的每个人可以确保每个购物者为商品付款。

脸书在自动标记发布到您个人资料的照片时使用面部识别(“DeepFace”)。由于隐私问题,在许多观众的负面反馈后,脸书只允许承认是选择进入。

军事|太空— 全球各国正在将人工智能嵌入武器、运输、目标识别、战地医疗保健、模拟训练以及其他用于陆地、空中、海上和太空的系统。基于这些平台的人工智能系统更少依赖于人类的输入,因为它们提高了性能,同时需要更少的维护。

利用当前的系统,人工智能减少了网络攻击,并可以保护网络、计算机、程序和数据免受任何未经授权的访问。

汽车 —计算机视觉是汽车行业的热门话题。特斯拉和谷歌等公司正在制造自动驾驶汽车。如今的汽车拥有自适应/动态巡航控制系统,能够与前方车辆保持安全距离。

根据世界卫生组织的统计,每年有一百多万人死于车祸,很大程度上是由于司机的疏忽。一旦计算机视觉完全安装到我们的车辆上,注意到汽车死亡数据的变化将是有趣的。

深度学习在制造业中的应用概述

原文:https://towardsdatascience.com/an-overview-of-deep-learning-applications-in-manufacturing-exxact-64018629ca?source=collection_archive---------40-----------------------

制造业深度学习简介

在进入制造业深度学习的细节之前,最好后退一步,查看一段简短的历史。自近代(即 18 世纪初)以来,概念、原始思维和物理发明一直在塑造着世界经济和制造业。

亚当·斯密(Adam Smith)和约翰·斯图亚特·穆勒(John Stuart Mill)等人提出的经济概念,第一次工业革命和蒸汽动力机器,工厂电气化和第二次工业革命,以及亨利·福特(Henry Ford)引入的装配线方法,只是寻求高效率和提高生产率一直是制造业核心的一些主要例子。

然而,几乎所有这些发明都是围绕着通过小心操纵力学热力学的法则,从人和机器身上提取最大效率。然而,在过去的几十年里,制造业最大的新收获来自于将信息或数据的概念加入到现有的组合中。

将深度学习信息融入其中

原材料、货物和零件的移动是任何制造系统的核心。在计算和信息技术革命之后,人们意识到,只有在信息处理引擎的监督下,以精确的方式控制这种运动,并结合数百种其他类似的运动,这种物理运动才能达到最佳效率。因此,硬件和软件的创新结合将“老工业”带入了智能制造时代。

但是,今天全世界的制造业正面临着一个源自这些信息处理系统的新问题。就是数据 泛滥信息爆炸 的双重(及相关)问题。

随着计算和存储的成本和操作复杂性以指数速度(摩尔定律)下降,由工人、机器、控制器、工厂、仓库和物流机械产生的信息内容在规模和复杂性上爆炸式增长,这让传统制造组织措手不及。

然而,他们并不孤单。在过去十年左右的时间里,即使是精通信息的软件和 IT 组织也不得不面对同样的问题。谷歌的博客和出版物已经承认他们软件项目的复杂性变得难以控制。

解决办法?

人工智能和机器学习领域的创新思想已经拯救了许多软件组织,使其免于淹没在数据的洪流中,并帮助他们理解他们每天需要处理的海量数据。

虽然还没有达到相同的规模,但世界各地的制造组织也开始接受利用这些领域的前沿进展来帮助和增强他们的运营,并继续为他们的客户和股东提供最高价值的想法。我们来看几个有趣的例子和实际案例。

深度学习在制造业中的潜在应用

值得注意的是,数字化转换和建模技术的应用已经在制造业领域进行了相当长的时间。60 年代和 70 年代,效率低下困扰着全球制造业,几乎每个大型组织都精简并采用了良好的实践,比如丰田的制造技术。这种技术依赖于对大量过程变量和产品特性的连续测量和统计建模。

随着这些信息的测量和存储变得数字化,计算机被用于建立这些预测模型。这是今天现代数字分析的前身。

然而,随着数据爆炸的继续,传统的统计建模无法跟上这种高维、非结构化的数据馈送。正是在这里,深度学习大放异彩,因为它天生能够处理高度非线性的数据模式,并允许您发现统计学家或数据建模师手动极难发现的特征。

机器学习和深度学习中的质量控制

一般来说,机器学习,特别是深度学习,可以显著提高大型装配线中的质量控制任务。事实上,根据福布斯的数据,分析和 ML 驱动的流程和质量优化预计将增长 35%,流程可视化和自动化预计将增长 34%。

传统上,机器只能通过产品的重量或长度等高级指标有效地发现质量问题。如果不花一大笔钱购买非常复杂的计算机视觉系统,当零件在装配线上高速运转时,就不可能检测出质量问题的细微视觉线索。

图片来源:Pixabay

即便如此,那些计算机视觉系统还是有些不可靠,无法有效地跨越问题领域。大型制造工厂的特定分支机构可能有这样的系统,但如果需要的话,它不能被“训练”来与工厂的其他部门一起工作。

深度学习架构,如卷积神经网络特别适合接替人类操作员在大型装配过程中发现和检测指示制成品和零件质量问题的视觉线索。它们比依赖手工制作的特征工程的老产品更具可扩展性,并且可以在制造工厂需要它们的任何部门进行培训和重新部署。再训练所需要做的就是用相关的图像数据训练系统。

图片来源:http://cs231n.github.io/convolutional-networks/(斯坦福 CS 231 级 Github repo)

过程监控和异常检测

过程监控和异常检测对于任何持续的质量改进工作都是必要的。所有主要的制造组织都广泛使用它。像 SPC(统计过程控制)图表这样的传统方法源于对过程变量统计分布性质的简单(有时是错误的)假设。

然而,随着相互影响的变量数量的增加,以及不断增加的传感器阵列获取关于这些变量的静态和时变数据,传统方法无法以高精度或高可靠性进行扩展。

这就是深度学习模型可以以一种意想不到的方式提供帮助的地方。为了检测异常或偏离规范,通常使用传统统计信号处理领域的降维技术,如 PCA(主成分分析)。然而,人们可以使用静态或可变自动编码器,这是深度神经网络,其层由渐进递减和递增卷积滤波器(和池)组成。

这些类型的编码器网络忽略了噪声和通常的方差,并将信号或数据流的基本特征编码在少量的高维比特中。当人们在连续运行的高容量过程中寻找异常时,如果高度编码的位发生意外变化,则跟踪高度编码的位要容易得多。

简而言之,过程监控的中心问题是可以由被称为无监督机器学习的机器学习分支来处理的事情。在这方面,深度学习自动编码器是你可以使用的一套强大的工具。

随着流程复杂性和相关的大数据无限制增长,毫无疑问,传统的统计建模(基于小规模数据采样)将让位于这种先进的 ML 技术和模型。

这些文章提供了一个很好的概述:

深度学习中的预测维护

深度学习模型已经被证明在经济学和金融建模领域非常有效,处理时间序列数据。类似地,在预测性维护中,随着时间的推移收集数据以监控资产的健康状况,目的是找到预测故障的模式。因此,深度学习可以为复杂机械和连接系统的预测性维护提供重要帮助。

确定何时对设备进行维护是一项异常困难的任务,涉及很高的财务和管理风险。每次机器离线维修,都会导致产量下降,甚至工厂停工。频繁的维修会导致明显的损失,但是不频繁的维护会导致代价更高的故障和灾难性的工业事故。

这就是为什么神经网络的自动化特征工程至关重要。用于预测性维护的传统 ML 算法依赖于狭窄的、特定领域的专业知识来手工制作特征以检测机器健康问题。而神经网络可以用足够高质量的训练数据自动推断这些特征。因此,它是跨域和可扩展的

特别地,具有长短期记忆(【LSTM】)细胞或门控循环单元(【GRU】)的循环神经网络 (RNN)可以基于过去的训练时间以时间序列的形式预测短期到中期的时间行为。

斯坦福 CS 231 级 Github Repo

幸运的是,有大量关于 RNN 的研究活动,目的是将它们应用到自然语言处理和文本分析领域。这一研究领域的所有知识都可以用于工业应用。例如,计算优化的 RNNs 可用于制造作业,在不牺牲太多预测能力的情况下,将计算负荷降至最低。它可能不是 NLP 任务的最佳表现,但对于预测机器健康参数的潜在问题来说,它已经足够强大了。

当然,人类专家将审查深度学习系统的预测,以最终决定维护工作。但是在一个智能、互联的工厂中,与工程师和技术人员一起使用这样的预测机器,可以节省制造组织的资金和人力,最终改善停工时间和机器利用率

事实上,在制造业中采用机器学习和分析只会提高预测性维护。根据普华永道的数据,预测性维护预计将在未来五年内增加 38%。微软的这篇文章提供了关于这个主题的更多信息:
利用长短期记忆网络进行预测性维护的深度学习

工厂投入优化

制造组织的盈利能力关键取决于优化进入生产流程的物理资源以及支持这些流程。例如,电力和供水是两个关键的工厂投入,可以从优化中受益。

通常采用复杂的优化过程和策略来最大化这些基本资源的利用率。随着工厂规模和机器对机器交互的增长,这些资源的流动变得难以用简单的预测算法来管理。这是像神经网络这样强大的学习机器需要被带入游戏的时候。

深度学习系统可以跟踪作为数百个工厂过程参数和产品设计变量的函数的用电模式,并可以动态推荐最佳利用的最佳实践。如果组织正在向采用可再生能源转变,那么来自深度学习算法的预测可以用来绘制出从化石燃料依赖到可持续能源足迹的最佳过渡轨迹。使用经典预测分析很难处理这种范式变化。

摘要

几十年来,基于信息系统的智能制造提高了大大小小的工业组织的生产率和质量。在这种智能制造环境下,随着机器生成和人类生成的数据的质量和倾向随着时间的推移而提高,数据分析、统计建模和预测算法的使用已经突飞猛进。工业革命始于上个世纪之交亨利·福特的装配线,在整个 20 世纪,自动化、控制系统、电子、传感器、数字计算和互联网的创新推动了工业革命。21 世纪的大数据革命有望通过释放指数级增长机会,最终将其提升到一个全新的水平。

为了充分利用这种数据爆炸,深度学习和相关的人工智能辅助技术必须集成到现代制造系统的工具包中,因为它们比经典的统计学习和预测系统强大得多。

深度学习能够与工业 4.0 的宏伟目标无缝集成——极端自动化和数字化工厂。工业 4.0 是围绕信息的持续连接而设计的——传感器、驱动器、阀门,所有这些都为了一个共同的目标而协同工作:最大限度地减少停机时间,提高效率。像深度神经网络这样的算法框架是处理特定类型任务的正确选择,它足够灵活,可以在各种数据类型连续流入时处理它们。

由此带来的生产率和质量的提高预计将远远超出满足企业盈利能力的狭隘目标。未来的智能制造将通过以可承受的成本提供高质量的商品和服务来丰富数十亿消费者的生活。整个社会都应该从这种范式转换中受益。

未来是光明的,我们期待着它。

原载于 2019 年 9 月 24 日https://blog.exxactcorp.com

现代机器学习中模型可解释性综述

原文:https://towardsdatascience.com/an-overview-of-model-explainability-in-modern-machine-learning-fc0f22c8c29a?source=collection_archive---------6-----------------------

更好地理解机器学习模型做出决策的原因,以及它的重要性

Photo by Chris Ried on Unsplash

模型可解释性是当今机器学习中最重要的问题之一。通常情况下,某些“黑盒”模型(如深度神经网络)被部署到生产中,并运行着从工作场所安全摄像头到智能手机的所有关键系统。这是一个可怕的想法,甚至这些算法的开发者都不明白这些算法为什么会做出这样的决定——或者更糟糕的是,如何防止对手利用它们。

虽然“黑盒”算法的设计者面临许多挑战,但这并不是完全没有希望的。实际上,有许多不同的方式来阐明模型做出的决策。甚至有可能了解模型预测中最显著的特征。

在这篇文章中,我给出了机器学习中更深层次模型的模型可解释性的全面概述。我希望解释传统上被认为是“黑箱”的更深层次的模型实际上是如何令人惊讶地解释的。我们使用模型不可知的方法将可解释性应用于所有不同种类的黑盒模型。

部分相关图

部分相关图显示了特征对 ML 模型结果的影响。

Partial dependence equation for regression

部分依赖通过在我们不感兴趣的特征(由集合 C 中的特征表示)的分布上边缘化机器学习模型输出来工作。这使得部分相关函数显示了我们确实关心的特征(我们通过在集合 S 中购买来表示)和预测结果之间的关系。通过边缘化其他特征,我们得到一个仅依赖于 s 中的特征的函数。这使得理解改变特定特征如何影响模型预测变得容易。例如,这里有 3 个温度、湿度和风速的 PDP 图,它们与通过线性模型预测的自行车销售相关。

PDP’s for temperature, humidity and wind speed for a regression problem where the number of bikes is the outcome. From these plots, it’s clear to see that temperature is an important determiner of how many bikes arre rented, and the hotter it is, the more bikes are rented.

PDP 甚至可以用于分类特征。这里有一个关于季节对自行车租赁的影响。

Partial dependence plot for the effect of seasons on bike rentals

对于分类,部分相关图显示了给定不同特征值时某一类的概率。处理多类问题的一个好方法是每个类有一个 PDP。

部分相关图方法是有用的,因为它是全局的。它强调了某个特性和该特性所有值的目标结果之间的整体关系。

优势

部分相关图非常直观。如果我们让所有的数据点都假定某个特征值,则某个值处的某个特征的部分相关函数代表平均预测值。

劣势

实际上,使用部分相关函数最多只能模拟两个特征。

独立性假设:假设正在绘制的要素与任何其他要素都不相关。例如,如果你根据身高和体重预测血压,你必须假设身高和体重不相关。出现这种情况的原因是,如果你在绘制身高,你必须对体重的边缘分布进行平均(反之亦然)。这意味着,例如,对于一个相当高的人来说,你可以有非常小的权重,这在你的实际数据集中可能看不到。

太好了!我想为我的模型实现一个 PDP。我从哪里开始?

这里有一个用 scikit-learn 实现的例子。

置换特征重要性

置换特征重要性是一种通过计算置换特征后模型预测误差的变化来衡量特征重要性的方法。如果置换其值会增加模型误差,则特征是“重要的”,如果置换值不会改变模型误差,则特征是“不重要的”。

该算法的工作原理如下:

input: a model f, feature matrix X, target vector Y and error measure L(y, f)1\. Estimate the original model error e⁰ = L(Y, f(x))2\. For each feature j:- Generate feature matrix X' by permuting feature j in the original feature matrix X.- Estimate the new error e¹=L(Y, f(X')) based off the model's predictions for the new data X'- Calculate the permutation feature importance FI=e¹/e⁰. You can also use e¹-e⁰.3\. Sort the features by descending FI.

按 FI 降序对要素排序后,可以绘制结果。这是自行车租赁问题的排列要素重要性图。

Permutation feature importance plot for bike rentals. You can clearly see that the model sees temperature and days since 2011 as the most important features.

优势

可解释性:特征重要性就是当一个特征被扭曲时,误差增加了多少。这很容易解释和形象化。

置换特征重要性提供了对模型行为的全局洞察。

置换特征重要性不需要训练一个新的模型或者重新训练一个现有的模型,简单地改变特征。

缺点

不清楚您是否应该为您的情节使用训练或测试数据。

如果特征是相关的,在置换特征后,你可能得到不真实的样本,使结果有偏差。

将相关特征添加到模型中会降低另一个特征的重要性。

太好了!我想为我的模型实现排列特征重要性。我从哪里开始?

这里有一个用 Python 实现的 eli5 模型。

累积局部效应图

ALE 图是部分相关图的一种更快且无偏差的替代方法。它们衡量特征如何影响模型的预测。因为它们是无偏见的,所以它们比 PDP 更好地处理相关特性。

如果机器学习模型的特征是相关的,那么部分依赖图是不可信的,因为你可以通过改变单个特征来生成实际上非常不可能的样本。ALE 图通过计算(也是基于要素的条件分布)预测中的差异而不是平均值来解决这个问题。解释这一点的一种方法是把麦芽酒想象成

让我向您展示模型预测如何在功能的一个小“窗口”中发生变化

这是一个关于麦芽酒情节的视觉解释。

ALE plot calculation. Divide x1 into “windows”. For all the points in each window, calculate the difference in prediction when we replace each point with the upper and lower bounds of the window.

这也可以通过两个特性来实现。

2D-ALE plot. Same general idea as the 1D plot, but instead of using the upper and lower “window” bounds, you calculate the difference in prediction over the four corners of the square in the grid.

一旦计算出每个窗口的预测差异,就可以生成 ALE 图。

ALE plot for bike rentals. Clearly, temperature has a strong effect on bike rental prediction, but you can also see that if humidity is above a certain point, it has a strong effect on bike rental prediction as well.

ALE 图也可以用于分类特征。

ALE plot for month and bike rentals. January and March seem to have little effect on the number of bikes rented, but December and November seem to have a large negative effect.

优势

ALE 图是无偏的,这意味着它们处理相关的要素。

ALE 图的计算速度很快。

对 ALE 情节的解读很清楚。

劣势

ALE 情节的实现很复杂,很难理解。

如果特征是强相关的,解释仍然是困难的。

二阶或 2D 啤酒图可能很难解释。

一般来说,最好使用 ALE 而不是 PDP,尤其是如果您希望相关的功能。

太好了!我想为我的模型实现 ALE。我从哪里开始?

这是一个提供 ALE 实现的库。

个体条件期望

单个条件期望(ICE)图每个数据点显示一行。它会生成一个图,显示模型对某个数据点的预测如何随着一个特征在一个集合中的所有数据点上的变化而变化。对于下面的图,您可以在训练集自行车租赁数据的所有实例中看到不同温度、湿度和风速的 ICE 图。

ICE plot for bike-sharing

看着这个情节,你可能会问自己:看一个 ICE 情节而不是 PDP 有什么意义?这似乎不太好解释。

PDP 只能向您展示特性和预测之间的平均关系。只有在计算 PDP 的特征和其他特征之间的相互作用不相关时,这种方法才能很好地工作,但是在强相关相互作用的情况下,ICE 图将更有洞察力。

优点

和 PDP 图一样,ICE 图非常直观易懂。

ICE 图可以比 PDP 图更好地揭示异构关系。

缺点

ICE 曲线一次只能显示一个特征。

这种方法生成的图可能很难阅读,而且过于拥挤。

太好了!我想为我的模型实现 ICE。我从哪里开始?

这里有一个关于 ICE 实现的可解释性的概述。

代理模型

代理模型是一种可解释的模型(如决策树或线性模型),它被训练为近似黑盒的预测。通过解释代理模型的决策,我们可以更好地理解黑盒。

生成代理模型的算法很简单。

1\. Select a dataset X that you can run your black box model on.2\. For the selected dataset X, get the predictions of your black box model. 3\. Select an interpretable model type (e.g. linear model or decision tree)4\. Train the interpretable model on the dataset X and the black box's predictions. 5\. Measure how well the surrogate model replicates the predictions of the black box model. 6\. Interpret the surrogate model.

一种通过 R 平方度量来衡量代理复制黑盒的方法是:

R 平方度量是一种测量代理模型捕获的方差的方法。接近 1 的 R 平方值意味着代理模型很好地捕获了方差,接近 0 意味着它捕获了非常小的方差,并且不能很好地解释黑盒模型。

优势

这种方法是直观的:你通过近似它来学习黑盒模型认为什么是重要的。

易于度量:很明显,可解释模型在通过 R 平方度量来近似黑盒时表现得有多好。

缺点

线性模型可能不能很好地近似黑盒模型。

你是在对黑盒模型而不是实际数据下结论,因为你是把黑盒的模型预测作为标签,而没有看到事实真相。

即使你很好地近似了黑盒模型,“可解释的”模型的可解释性可能实际上并不代表黑盒模型已经学到了什么。

可能很难解释这个可解释的模型。

太好了!我想实现一个代理模型。我从哪里开始?

这里概述了代理模型实现的可解释性。

可解释性的未来

随着机器学习在日常生活中变得更加突出,可解释性的未来比以往任何时候都更加重要。我相信一些趋势将对可解释性的未来进行分类,这将塑造我们未来与人工智能模型的交互方式。

模型不可知的可解释性焦点

深度学习研究的所有趋势都指向这样一个事实,即深度网络没有饱和我们当前的计算和数据限制。重要的是要认识到,随着我们的模型在从图像识别到文本生成的各个方面越来越深入,需要能够提供跨所有类型模型的可解释性的方法。随着机器学习在不同领域占据越来越多的位置,可推广性方面将变得越来越有用。我在这篇博文中讨论的方法是一个开始,但我们需要更认真地对待可解释性,以更好地理解为什么驱动我们日常生活的机器学习系统正在做出它们所做的决定。

自我解释的模型

一个我还没有看到的在大多数 ML 系统中扎根的趋势是自我解释模型的想法,我相信这个趋势在未来会存在。今天的大多数系统只是简单地做出一个对用户来说不透明的决定。在未来,我相信这种情况会改变。如果自动驾驶汽车决定停下来,我们就会知道为什么。如果 Alexa 不能理解我们的句子,它会告诉我们具体的细节哪里出错了,以及我们如何更清楚地表达我们的查询。有了自我解释的模型,我们可以更好地理解我们生活中的 ML 系统是如何工作的。

增加模型审查

最后,我相信我们作为一个社会已经把黑箱模型审查推到了地毯下面。我们不理解我们的模型正在做出的决定,这似乎没有特别困扰任何人。这种情况将来必须改变。随着模型开始出错,工程师和数据科学家将被追究责任,这将导致一种趋势,即我们用检验模型所做决策的同样严谨性来检验模型所依据的数据集。

我希望你喜欢这篇文章。我确实发现写这篇文章很有启发性,我希望它对你在机器学习领域的学习或研究有所帮助。

作品引用:

这里的大多数例子都是从优秀的可解释机器学习书里得到的启发。

(莫尔纳尔,克里斯托弗。“可解释的机器学习。让黑盒模型变得可解释的指南”,2019。https://christophm.github.io/interpretable-ml-book/)

如果你想进一步了解这个话题,我强烈建议你购买它。

日本 NLP 图书馆概述

原文:https://towardsdatascience.com/an-overview-of-nlp-libraries-for-japanese-be1805837143?source=collection_archive---------26-----------------------

PyCon JP 2019 日本 NLP 库简介

nagisa-tutorial-pycon2019

PyCon JP 2019 于 2019/9/16~ 2019/9/17 举办,为期两天。我会发布一些我感兴趣的讲座的帖子。

作为一名 NLP 工程师,我很高兴能找到一个与 NLP 相关的讲座。这篇文章是来自池田太史的 nagisa 演讲的简短英文摘要。你可以在这里找到幻灯片,在这里找到日语教程

两个图书馆

日本有大量的 NLP 库,但是如何选择一个好的来使用需要一些研究。感谢池田太史为我们节省了时间。上图收集了许多日本 NLP 库,并对它们进行了详细的比较。如果你不懂日语,没必要担心。我只推荐两个工具, Juman++nagisa

确定性能的一个简单标准是库是否提供了用于预测的基于神经的模型。换句话说,维护人员会随着技术的发展更新库吗?根据 Taishi Ikeda 的说法, Juman++和 nagisa 是仅有的两个提供基于神经的模型的库。

nagisa

因为池田太史的演讲主要是关于我就简单介绍一下渚。nagisa 使用的模型是 Bi-LSTM-CRF。CRF 层被忽略,因为他不想混淆那些不熟悉 NLP 的人。

nagisa 训练的语料库是 KWDLC 。nagisa 尤其在表情符号上表现出色

池田太史很好心的提供了 Colab 笔记本快速玩。

  1. basic _ usage . ipynb[Colab 笔记本
  2. word _ cloud . ipynbColab 笔记本

查看我的其他帖子 中等 一个分类查看
GitHub:
bramble Xu LinkedIn:徐亮 博客:bramble Xu

参考

正交偏最小二乘综述

原文:https://towardsdatascience.com/an-overview-of-orthogonal-partial-least-squares-dc35da55bd94?source=collection_archive---------4-----------------------

你听说过正交偏最小二乘(OPLS) 吗?这篇文章旨在给你一个清晰简明的概述 OPLS 及其在开发更有效的预测模型方面的优势。

什么是 OPLS?

首先,让我简单回顾一下,偏最小二乘法(PLS) 回归无疑是中最常用的,或者可能是最常用的化学计量学多元回归方法之一。事实上,PLS 最初是由赫尔曼·沃尔德在 1975 年左右开发的,用于计量经济学领域,后来在 20 世纪 80 年代被著名的化学计量学家所接受,例如赫尔曼·沃尔德的儿子贾译尊·沃尔德,他在 1971 年创造了术语化学计量学来描述在分析化学应用中使用高级统计和机器学习方法的新兴领域,仅举几个例子在过去的几十年中,PLS(无论是作为回归还是分类方法)在化学计量学从业者中非常流行,用于处理多变量校准和过程分析技术等应用中的多重共线性,在这些应用中,观测值(样本)通常比变量(波长)少。

2002 年,约翰·特里格和贾译尊·沃尔德在一篇题为“ 【正交投影到潜在结构(O‐PLS) ”的论文中引入了 PLS 的一种变体。新方法是一种受监督的多变量数据投影方法,用于将一组预测变量( X )与一个或多个响应( Y )相关联。基本上,像 PLS 一样,O-PLS 试图提取反映数据集中变化的最大信息,同时假设在X-数据中存在隐藏变量的一个小子集来预测响应变量。这些子集正式称为潜在变量(或 LVs),因为它们是不可测量的。从历史上看,数据集中隐藏结构的概念已经有一个世纪的历史了,它来自于主成分分析(PCA)等方法。由作者命名的 O-PLS 方法使用了 S. Wold 先前开发的正交信号校正—化学计量学智能。实验室。系统。, 1998,44 175-最大化第一个 LV 的解释协方差,而剩余 LV 捕捉预测因子的正交方差,即与响应变量统计不相关。简而言之,这意味着与 PLS 不同 PLS 可以很好地处理随机噪声——这种新方法也被称为正交偏最小二乘法(OPLS) ,它能够通过单独建模 X 预测值的变化来过滤掉数据集中的结构化噪声,这些预测值与 Y 响应相关或不相关。最终,除了允许识别、分析和调查正交变化的主要来源之外,这还通过降低 LV 的数量来降低模型的复杂性。

数学框架

让我们快速看一下 OPLS 背后的数学。这里我们将 X 视为大小为 n × p、Y 的矩阵,大小为 n × m ,其中 p 为预测变量的数量, m 为响应变量的数量, n 为观测值的数量。回想一下,PLS 被开发的目的是搜索一定数量的 LV 的方向——具有相互正交的约束——满足以下标准:(1)捕获 X 空间中的最大方差,(2)捕获 Y 空间中的最大方差,以及(3)最大化 XY 空间之间的相关性。

PLS 模型可以写成:

其中 T 是总结 X 预测值变化的得分矩阵,即样本之间的相似性/差异性, P 是加载矩阵,或通常称为 X 加载,以区别于 Y 加载, U 是总结 Y 响应变化的得分矩阵,C上标“t”表示矩阵转置。注意 P 表示 XU 的相关性,而 C 表示 YT 的相关性。****

Geometrical illustration of a PLS model. Data (black dots) on the X-space are projected (orthogonal projection) onto the subspace defined by the first two latent variables (LVs).

OPLS 模型的操作类似于 PLS 模型,但是将 X 中的系统变化分成三部分:(1)与 Y 相关的预测部分,(2)与 Y 不相关的正交部分“orth”,(3)噪声部分——残差变化。

因此,OPLS 模型可以表述为:

Geometrical illustration of the difference between PLS and OPLS models. Orthogonal variation (white dots) are filtered out by the second latent variable.

应该提到的是,事实上已经开发了两种不同的 OPLS 算法。第一种算法,最常被称为 O1-PLS 或简称为 OPLS,如上所述,是单向的(X****Y),这意味着只有在 X 空间中的正交变化被滤除。第二种算法称为 O2-PLS,是双向的( XY ),这意味着在 X -和y-空间中的正交变化都被滤除。

O2-PLS 模型可以写成:

O2-PLS 将 XY 分成三部分:(1)一个联合部分(关联部分 XY ),(2)一个正交部分——分别在 XY 中不相关的潜在变化,以及(3)一个噪声部分。

例如:LIBS 光谱

为了比较的目的,我使用植物材料的 LIBS 光谱,用偏最小二乘法和 OPLS 方法来预测钾的浓度。使用 R 包插入符号执行 PLS。由于 OPLS 在 caret 中不可用,我使用了包 ropls 来代替。五种植物样品的典型 LIBS 光谱如下所示— 关于 LIBS 的更多细节请参考我之前的 文章

LIBS spectra of five plant samples. A baseline offset has been applied for easier viewing of the spectra.

下图显示了 PLS(左图)和 OPLS(右图)建模的X-得分散点图(X-空间的投影)。在这两幅图中,x-轴代表第一分量(或潜在变量),而y-轴代表 PLS 的第二分量和 OPLS 的第一正交分量。彩虹色代表每个样品中钾(K)的浓度,从 1%(深蓝色)到 7%(深红色)。正如我们所见,OPLS 只需要一个成分就可以将样品中的变化与钾浓度联系起来(见黑色箭头)。

Comparison between the X-scores scatter plots for the PLS and OPLS models.

摘要

总之,要记住的最重要的事情是,OPLS(或 O2-PLS)提供了一个有价值的预处理工具,将有助于生成更有效的预测模型,特别是在结构噪声占主导地位的情况下。

Python 的数据表包概述

原文:https://towardsdatascience.com/an-overview-of-pythons-datatable-package-5d3a97394ee9?source=collection_archive---------2-----------------------

用于高效多线程数据处理的 Python 库,支持内存不足的数据集。

Photo by Johannes Groll on Unsplash

如果你是一个 R 用户,很可能你已经在使用data.table包了。[Data.table](https://cran.r-project.org/web/packages/data.table/data.table.pdf)是 R 中[data.frame](https://www.rdocumentation.org/packages/base/versions/3.6.0/topics/data.frame)包的扩展,也是 R 用户快速聚合大数据(包括 100GB 内存)的首选包。

R 的data.table包是一个非常通用和高性能的包,因为它易于使用,方便和编程速度。这是 R 社区中一个相当著名的软件包,每月下载量超过 40 万次,几乎有 650 个 CRAN 和 Bioconductor 软件包使用它( source )。

那么,这对 Python 用户有什么好处呢?好消息是,data.table包也有一个 Python 对应物,叫做datatable ,它明确关注大数据支持、高性能、内存和内存外数据集以及多线程算法。在某种程度上,可以称之为data . table** 弟弟妹妹。**

数据表

现代机器学习应用程序需要处理海量数据,并生成多种特征。为了更准确地构建模型,这是必要的。Python 的datatable模块就是为了解决这个问题而创建的。它是一个工具包,用于在单节点机器上以最大可能的速度执行大数据(高达 100GB)操作。datatable 的开发由 H2O.ai 赞助,datatable的第一个用户是 Driverless.ai

该工具包与熊猫非常相似,但更侧重于速度和大数据支持。Python 的datatable也努力实现良好的用户体验,有用的错误消息,强大的 API。在本文中,我们将了解如何使用 datatable,以及它在处理大型数据集时如何优于 pandas。

装置

在 MacOS 上,可以使用 pip 轻松安装 datatable:

pip install datatable

在 Linux 上,安装通过二进制发行版实现,如下所示:

# If you have Python 3.5
pip install [https://s3.amazonaws.com/h2o-release/datatable/stable/datatable-0.8.0/datatable-0.8.0-cp35-cp35m-linux_x86_64.whl](https://s3.amazonaws.com/h2o-release/datatable/stable/datatable-0.8.0/datatable-0.8.0-cp35-cp35m-linux_x86_64.whl)# If you have Python 3.6
pip install [https://s3.amazonaws.com/h2o-release/datatable/stable/datatable-0.8.0/datatable-0.8.0-cp36-cp36m-linux_x86_64.whl](https://s3.amazonaws.com/h2o-release/datatable/stable/datatable-0.8.0/datatable-0.8.0-cp36-cp36m-linux_x86_64.whl)

目前,datatable 不能在 Windows 上运行,但也在努力增加对 Windows 的支持。

更多信息参见构建说明

这篇文章的代码可以从相关的 Github 库中获得,或者可以通过点击下面的图片在我的文件夹中查看。

读取数据

正在使用的数据集取自 Kaggle,属于 Lending Club 贷款数据集 该数据集由 2007 年至 2015 年发放的所有贷款的完整贷款数据组成,包括当前贷款状态(当前、逾期、完全支付等。)和最新付款信息。该文件由226 万行145 列组成。数据大小非常适合展示数据表库的功能。

# Importing necessary Librariesimport numpy as np
import pandas as pd
import datatable as dt

让我们将数据加载到Frame对象中。数据表中的基本分析单位是一个Frame。这与 pandas DataFrame 或 SQL 表的概念是一样的:数据排列在具有行和列的二维数组中。

带数据表

%%time
datatable_df = dt.fread("data.csv")
____________________________________________________________________CPU times: user 30 s, sys: 3.39 s, total: 33.4 s                                
Wall time: 23.6 s

上面的fread()功能既强大又极快。它可以自动检测和解析大多数文本文件的参数,从。压缩档案或网址,阅读 Excel 文件,等等。

此外,数据表解析器:

  • 可以自动检测分隔符、标题、列类型、引用规则等。
  • 可以从多个来源读取数据,包括文件、URL、shell、原始文本、归档和 glob。
  • 提供多线程文件读取,实现最高速度
  • 读取大文件时包括进度指示器
  • 可以读取符合和不符合 RFC4180 的文件。

与熊猫

现在,让我们计算一下熊猫读同一个文件所用的时间。

%%time
pandas_df= pd.read_csv("data.csv")
___________________________________________________________CPU times: user 47.5 s, sys: 12.1 s, total: 59.6 s
Wall time: 1min 4s

结果表明,在读取大型数据集时,datatable 明显优于 pandas。熊猫需要一分多钟,而数据表只需要几秒钟。

帧转换

现有帧也可以转换为 numpy 或 pandas 数据帧,如下所示:

numpy_df = datatable_df.to_numpy()
pandas_df = datatable_df.to_pandas()

让我们将现有的帧转换成熊猫数据帧对象,并比较所用的时间。

%%time
datatable_pandas = datatable_df.to_pandas()
___________________________________________________________________
CPU times: user 17.1 s, sys: 4 s, total: 21.1 s
Wall time: 21.4 s

似乎将文件作为数据表帧读取,然后将其转换为 pandas 数据帧比读取 pandas 数据帧花费的时间要少。 因此,通过 datatable 导入一个大的数据文件,然后将其转换成 pandas dataframe 可能是一个好主意。

type(datatable_pandas)
___________________________________________________________________
pandas.core.frame.DataFrame

基本框架属性

让我们看看数据表框架的一些基本属性,它们与熊猫的属性相似:

print(datatable_df.shape)       # (nrows, ncols)
print(datatable_df.names[:5])   # top 5 column names
print(datatable_df.stypes[:5])  # column types(top 5)
______________________________________________________________(2260668, 145)('id', 'member_id', 'loan_amnt', 'funded_amnt', 'funded_amnt_inv')(stype.bool8, stype.bool8, stype.int32, stype.int32, stype.float64)

我们也可以使用head命令输出前‘n’行。

datatable_df.head(10)

A glimpse of the first 10 rows of the datatable frame

颜色表示数据类型,其中红色表示字符串,绿色表示整型,蓝色表示浮点型。

汇总统计数据

在 pandas 中计算汇总统计数据是一个消耗内存的过程,但现在有了 datatable 就不会了。我们可以使用 datatable 计算以下每列汇总统计信息:

datatable_df.sum()      datatable_df.nunique()
datatable_df.sd()       datatable_df.max()
datatable_df.mode()     datatable_df.min()
datatable_df.nmodal()   datatable_df.mean()

让我们使用 datatable 和 pandas 来计算这些列的平均值。

带数据表

%%time
datatable_df.mean()
_______________________________________________________________
CPU times: user 5.11 s, sys: 51.8 ms, total: 5.16 s
Wall time: 1.43 s

与熊猫在一起

pandas_df.mean()
__________________________________________________________________
Throws memory error.

上述命令无法在 pandas 中完成,因为它开始抛出内存错误。

数据操作

像 dataframes 这样的数据表是列数据结构。在 datatable 中,所有这些操作的主要载体是受传统矩阵索引启发的方括号符号和更多功能。****

datatable’s square-bracket notation

同样的 DT[i,j]符号在数学中用于索引矩阵,在 C/C++,在 R,在 pandas,在 numpy 等等。让我们看看如何使用 datatable 执行常见的数据操作活动:

#选择行/列的子集

下面的代码从数据集中选择所有行和funded_amnt列。

datatable_df[:,'funded_amnt']

下面是我们如何选择前 5 行和前 3 列

datatable_df[:5,:3]

#对框架进行排序

带数据表

按特定列对帧进行排序可以通过datatable完成,如下所示:

%%time
datatable_df.sort('funded_amnt_inv')
_________________________________________________________________
CPU times: user 534 ms, sys: 67.9 ms, total: 602 ms
Wall time: 179 ms

与熊猫:

%%time
pandas_df.sort_values(by = 'funded_amnt_inv')
___________________________________________________________________
CPU times: user 8.76 s, sys: 2.87 s, total: 11.6 s
Wall time: 12.4 s

请注意“可约会”和“熊猫”之间的巨大时差。

#删除行/列

下面是我们如何删除名为member_id的列:

del datatable_df[:, 'member_id']

#分组依据

就像在 pandas 中一样,datatable 也有 groupby 功能。让我们看看如何获得按grade列分组的funded_amount列的平均值。

带数据表

%%time
for i in range(100):
    datatable_df[:, dt.sum(dt.f.funded_amnt), dt.by(dt.f.grade)]
____________________________________________________________________
CPU times: user 6.41 s, sys: 1.34 s, total: 7.76 s
Wall time: 2.42 s

与熊猫

%%time
for i in range(100):
    pandas_df.groupby("grade")["funded_amnt"].sum()
____________________________________________________________________
CPU times: user 12.9 s, sys: 859 ms, total: 13.7 s
Wall time: 13.9 s

有什么用。f 代表什么?

f 代表frame proxy,提供了一种简单的方法来引用我们当前操作的框架。在我们的例子中,dt.f仅仅代表dt_df

#筛选行

过滤行的语法与 GroupBy 非常相似。让我们过滤掉那些loan_amnt的值大于funded_amntloan_amnt行。

datatable_df[dt.f.loan_amnt>dt.f.funded_amnt,"loan_amnt"]

保存帧

也可以将帧的内容写入一个csv文件,以便将来使用。

datatable_df.to_csv('output.csv')

更多数据操作功能,请参见 文档 页。

结论

与默认的 pandas 相比,datatable 模块无疑加快了执行速度,这在处理大型数据集时无疑是一个福音。然而,数据表在功能上落后于熊猫。但由于 datatable 仍在积极开发中,我们可能会在未来看到该库的一些主要新增内容。

参考

几种推荐系统综述

原文:https://towardsdatascience.com/an-overview-of-several-recommendation-systems-f9f8afbf00ea?source=collection_archive---------21-----------------------

协同过滤,KNN,深度学习,迁移学习,tfi df…等等探索所有这些

Photo by Alfons Morales on Unsplash

在本文中,我们将回顾几种推荐算法,通过 KPI 进行评估,并实时比较它们。我们将依次看到:

  • 一种基于流行度的推荐系统
  • 基于内容的推荐器(通过 KNN、TFIDF、Transfert Learning)
  • 基于用户的推荐器
  • 混合推荐器
  • 深度学习推荐器

N.B :我受到了Gabriel more IRA的伟大笔记本的极大启发,感谢他https://www . ka ggle . com/gspmoreira/recommender-systems-in-python-101一些类似用户剖析器和评估功能的模型或功能都来自于他的笔记本。

介绍

我将介绍数据库,并定义什么将允许我们评估我们的模型。我有动漫元数据,我稍微修改了一下,以便有更可靠的内容推荐。

然后是带有评级的用户项目数据库

加入这两者后,我们将分层将其分为训练集和测试集

interactions_train_df, interactions_test_df = train_test_split(interactions_full_df,
                                   stratify=interactions_full_df['user_id'], 
                                   test_size=0.20,
                                   random_state=42)#Indexing by personId to speed up the searches during evaluation
interactions_full_indexed_df = interactions_full_df.set_index('user_id')
interactions_train_indexed_df = interactions_train_df.set_index('user_id')
interactions_test_indexed_df = interactions_test_df.set_index('user_id')

现在,我们可以定义一个评估函数。

评价函数

我们使用前 N 名准确性指标,它评估向用户提供的前几名推荐的准确性,与用户在测试集中实际交互的项目进行比较。
该评估方法的工作原理如下:

  • 对于每个用户
  • 对于用户在测试集中交互的每个项目
  • 抽样 100 个用户从未互动过的其他项目。
    Ps。这里,我们天真地假设那些未交互的项目与用户无关,这可能不是真的,因为用户可能只是不知道那些未交互的项目。但是让我们保持这个假设。
  • 要求推荐器模型从由一个交互项目和 100 个非交互(非相关)项目组成的集合中产生推荐项目的排序列表
  • 计算推荐排名列表中该用户和交互项目的前 N 名准确性指标
  • 汇总全球前 N 名准确性指标

选择的前 N 名准确度度量是 Recall@N ,其评估交互项目是否在 101 个推荐给用户的排序列表中的前 N 个项目(命中)中。

基于流行度的模型

流行度模型是一种常见的(通常也是难以超越的)基线方法。这个模型实际上不是个性化的,它只是向用户推荐用户以前没有消费过的最流行的动画。

item_popularity_df = interactions_full_df.groupby('anime_id')['user_rating'].sum().sort_values(ascending=False).reset_index()

这里,我们根据上述方法执行流行度模型的评估。
实现了 0.59 的召回@5 ,这意味着测试集中大约 60 % 的交互项目被流行度模型排在前 5 位(从 100 个随机项目的列表中)。而召回@10 甚至更高(77 % ),不出所料。

这个模型对于我们投入的努力来说是非常好的!

基于内容的模型

基于内容的过滤方法利用来自用户已经交互的项目的描述或属性来推荐相似的项目。它仅依赖于用户先前的选择,使得该方法稳健以避免冷启动问题。对于文本项目,如文章、新闻和书籍,很容易使用原始文本来构建项目简档和用户简档。

为了从基于内容的模型中获得个性化推荐,我们将实施以下步骤:

对于每个用户:

  • 拿到他的监视名单

对于他的观察列表中的每个动画

  • 恢复动画与所有其他动画的相似性(感谢距离/特征矩阵),如 tfidf one
  • 恢复每个用户评级

最后,用来自评级的项目强度对我们从内容模型(我们的距离矩阵)获得的项目值进行加权平均。

术语频率逆文档频率(TFIDF)

我们将使用一种在信息检索(搜索引擎)中非常流行的技术,名为 TF-IDF 。这种技术将非结构化文本转换为向量结构,其中每个单词由向量中的一个位置表示,值衡量给定单词与文章的相关程度。由于所有的项目都将在同一个向量空间模型中表示,所以是为了计算文章之间的相似度。

word_vectorizer = TfidfVectorizer(ngram_range =(1,4),
                             min_df=5, max_df=0.9,
                             strip_accents='unicode',
                             stop_words = 'english',
                             analyzer = 'word',
                             use_idf=1,
                             smooth_idf=1,
                             sublinear_tf=1)

tfidf_matrix = word_vectorizer.fit_transform(anime['soup'])
tfidf_feature_names = word_vectorizer.get_feature_names()

*""" compute users profiles """*
U2P = Users_Profiler(tfidf_matrix, anime_ids)
U2tfifd = U2P.build_users_profiles()

现在,由于我们的基本推荐器和用户分类器,我们可以向特定用户推荐动画:

ContentBasedmodel = BaseRecommender(U2tfifd, tfidf_matrix, anime)ContentBasedmodel.recommend_anime(8)

我们来评价一下

print('Evaluating Content-Based Filtering model...')cb_global_metrics, cb_detailed_results_df = evaluate_model(ContentBasedmodel)print('**\n**Global metrics:**\n%s**' % cb_global_metrics)cb_detailed_results_df = cb_detailed_results_df[['_user_id', 'watched_count', "hits@3_count", 'hits@5_count','hits@10_count', 
                                                'recall@3','recall@5','recall@10']]
cb_detailed_results_df.head(10)

实现了 0.755召回@5 ,这意味着测试集中大约有 75 % 个交互项被流行度模型排在前 5 位(从 100 个随机项的列表中)。而召回@10 更高(81 % )。

这种内容模型似乎非常可靠。

k-最近邻

这里我们使用 k-最近邻算法,这是一种试图通过查看数据点周围的数据点来确定数据点属于哪个组的算法。这个与分类方法有点不同,因为他不是预测每个数据点属于哪个组,而是根据余弦距离度量返回每个数据点的 6 个最近邻居。由此我们将提取距离矩阵,并从中获得用户偏好。

from sklearn.neighbors import NearestNeighbors
from scipy.sparse import csr_matrix
from sklearn.preprocessing import MaxAbsScaler
mabs = MaxAbsScaler()# build dummies matrix
anime_features = pd.concat([anime["genre"].str.get_dummies(sep=","),
                            pd.get_dummies(anime[["type"]]),
                            pd.get_dummies(anime[["episodes"]]),
                            pd.get_dummies(anime[["members"]]),anime_ids = anime["anime_id"].tolist()
anime_features_scale = mabs.fit_transform(anime_features)nbrs = NearestNeighbors(n_neighbors=6, algorithm='brute', metric = "cosine").fit(anime_features_scale)distances, indices = nbrs.kneighbors(anime_features_scale)
distances =  csr_matrix(distances)

U2KNN = Users_Profiler(distances, anime_ids)
KNN_model = U2KNN.build_users_profiles()KNN_RECO = BaseRecommender(KNN_model, distances, anime)
print('Evaluating Content-Based Filtering model...')
global_metrics, detailed_results_df = evaluate_model(KNN_RECO)
print('**\n**Global metrics:**\n%s**' % global_metrics)

KNN 模型似乎没有产生有用的建议。它实现了 0.16 的召回@5 ,这意味着仅在测试集中就有大约 16 % 个交互项目被流行度模型排在前 5 个项目中(从具有 100 个随机项目的列表中)。

迁移学习(单词嵌入)

对于该方法,我们将依靠预训练的嵌入矩阵来创建嵌入向量。在神经网络的上下文中,嵌入是离散变量的低维、学习的连续向量表示。它们可以减少分类变量的维度并且有意义地表示变换空间中的类别。这里,目的是在嵌入空间中找到最近的邻居。这些可以用来根据用户兴趣进行推荐。

xtrain_embeddings = sc.fit_transform(xtrain_embeddings)
xtrain_embeddings = csr_matrix(xtrain_embeddings)
U2f = Users_Profiler(xtrain_embeddings, anime_ids)
U2fastt = U2f.build_users_profiles()
fastcontent = BaseRecommender(U2fastt, xtrain_embeddings, anime)

我们现在可以使用它进行推荐和评估。

print('Evaluating Content-Based Filtering model...')
fglobal_metrics, fdetailed_results_df = evaluate_model(fastcontent)
print('**\n**Global metrics:**\n%s**' % fglobal_metrics)
fdetailed_results_df = fdetailed_results_df[['_user_id', 'watched_count', "hits@3_count", 'hits@5_count','hits@10_count', 
                                                'recall@3','recall@5','recall@10']]
fdetailed_results_df.head(10)

Transfert Learning 比 KNN 好,但与 TFIDF 方法相比性能较差,其性能几乎是 tfi df 方法的一半,召回率为 37%。

协同过滤

协同过滤是一种通过收集众多用户的喜好或品味信息,对用户的兴趣进行自动预测(过滤)的方法。

奇异值分解

在这里,我们使用流行的潜在因素模型命名为奇异值分解。潜在因素模型根据潜在因素将用户项目矩阵压缩成低维表示。使用这种方法的一个优点是,我们将在低维空间中处理一个更小的矩阵,而不是拥有一个包含大量缺失值的高维矩阵。因素越多,模型越具体,如果因素太多,可能会导致过度拟合。

U, sigma, Vt = svds(R, k= 300)
sigma = np.diag(sigma)
predicted_ratings = np.dot(np.dot(U, sigma), Vt) 
cf_preds_df = pd.DataFrame(predicted_ratings, 
                           columns = pivpiv.columns, 
                           index=iddd).transpose()

实现了 0.755召回@5 ,这意味着测试集中大约有 75 % 的交互项被流行度模型排在前 5 位(从 100 个随机项的列表中)。而召回@10 更高(81 % )。

混合模型

我们将构建一个简单的混合方法,只需将 SVD 分数与基于内容的分数相乘,然后根据结果分数进行排序。

评估我们的混合 tfidf/svd 模型:

在这里,我们对每个召回都有几乎相同的@ n 82 %,这相当不错。

深度学习

最后,我们将使用深度学习来构建深度协同过滤模型,以结合我们之前看到的 2 个概念,潜在因素模型和嵌入。

由于这个模型,我们可以预测用户对未知商品的评价。

history = DeepCF.fit([train.user_id, train.anime_id], train.user_rating, batch_size=512, epochs=5, 
          validation_data=([valid.user_id, valid.anime_id], 
            valid.user_rating))

我没有评价是因为预测方法很慢但是不要犹豫去做。

我们将查看每个模型为单个用户提出的建议。

rated, compare = comparison(25, 5)

我没有显示这个用户的“著名”文集,因为有超过 100 篇文章,但从经验来看,除了 KNN,大多数这些建议似乎非常可靠。

最后

我们已经看到了几种类型的推荐系统,从非常简单的到更复杂的模型,你可以自由地改进或丰富它们。有趣的是,一些非常简单的模型,如流行度,可能是可靠的。我希望这些模型中的一个会对你的项目有用,如果你想看其他奇异的推荐模型,可以看看我的另一篇文章,比如:

谢谢大家!

代码可在此处获得:https://github . com/AlexWarembourg/Medium/blob/master/a-panel-of-recommender . ipynb

梯度下降算法概述

原文:https://towardsdatascience.com/an-overview-of-the-gradient-descent-algorithm-8645c9e4de1e?source=collection_archive---------3-----------------------

优化参数的微妙而强大的算法

优化参数是每个机器学习算法的最终目标。在线性回归问题中,您希望获得斜率和截距的最佳值,以获得最佳拟合线。您还希望在逻辑回归问题中获得 s 形曲线参数的最佳值。如果我告诉你梯度下降就可以了呢?

在了解它是如何工作的之前,让我们先弄清楚梯度和下降以及其他一些关键术语的含义。

术语

损失函数:该函数返回与模型相关联的成本,并测量我们的模型在训练数据上做得如何。如果成本太高,这意味着我们的模型的预测与观察到的数据偏离太多。在任何机器学习算法中,我们的最终使命都是最小化损失函数。我们使用的各种损失函数是:

回归损失:

  1. L1 损耗/平均绝对误差
  2. L2 损耗/均方误差
  3. 均方根误差

分类损失:

  1. 对数损失(交叉熵损失)
  2. SVM 损耗(铰链损耗)

学习率:这是决定梯度下降算法步骤的超参数。梯度下降对学习速率太敏感。如果太大,算法可能会绕过局部最小值而超调。如果它太小,可能会在很大程度上增加总计算时间。我们将在本文的后面深入了解学习速度的影响。

坡度:基本上是衡量一个斜坡的陡度。从技术上来说,当我们对一个函数中所有变量的一阶导数求和时,就会得到梯度。例如,如果我们考虑线性回归,我们有两个参数,斜率和截距,以尽量减少。因此,我们计算 w.r.t .的导数,两者都使截距倾斜&,然后将它们相加,得到截距的梯度。

下降:为了优化参数,我们需要最小化误差。梯度下降算法的目标是达到局部最小值(尽管我们总是以达到函数的全局最小值为目标。但是如果梯度下降算法一旦达到局部最小值,就几乎不可能达到全局最小值。).该算法通过在每次迭代中计算步长的迭代过程来实现这一点。并且,这种迭代计算步长以达到局部最小值(或者换句话说,下降到最小值点)被称为下降(足够的下山例子)。

履行

现在,让我们进入算法的技术细节。我们将使用一阶导数来计算梯度。在演示中,我们将使用 NumPy 对线性回归问题应用梯度下降。

让我们首先使用 NumPy 的 random 函数生成一个随机化的数据集,并用散点图来显示我们的数据集分布。

**# Importing Libraries**
import numpy as np
import matplotlib.pyplot as plt**# Generating Randomized dataset**
X = 3*np.random.rand(100,1)
y = 9 + 2*X+np.random.rand(100,1)# Scatter plot
plt.scatter(X,y)
plt.xlabel('X')
plt.ylabel('y')
plt.title('X vs y')
plt.figure(figsize=(15,25))

Scatter Plot: X vs Y

在上面的代码中,我们为自变量和因变量分别取了两个 NumPy 数组,即 X 和 y。从图中可以清楚地看出,这种关系是线性的。我们知道,可以将线性关系放入如下函数中:

Hypothesis function for our linear problem

分析方法

我们可以使用如下所示的分析方法计算θ_ 0 和θ_ 1 的值:

**# mean of x and y vector**
mean_x = X.mean()
mean_y = y.mean()**# calculating cross-deviation and deviation about x**
sum_yx = (X*y).sum()
x_sq = (X**2).sum()
ssxy = sum_yx - (len(X)*mean_x*mean_y)
ssxx = ((X - mean_x)**2).sum()**# calculating regression coefficients**
theta_1 = ssxy/ssxx
theta_0 = mean_y - (theta_1*mean_x)**# printing both the values**
print('Theta 0: {:0.3f}'.format(theta_0))
print('Theta 1: {:0.3f}'.format(theta_1))**Output:**
**Theta 0:** 9.482 **Theta 1:** 1.998

如果我们可以解析地计算最佳参数,为什么我们需要梯度下降?这是因为当我们拥有一个包含数百万个数据点的数据集时,分析方法在计算上变得非常昂贵。另一方面,梯度下降给我们类似的结果,同时大大减少了计算时间。让我们用梯度下降法求解 0 和 1,自己看看。

在数学上,成本函数和梯度可以表示如下:

Gradient & Cost Function for our problem

成本函数背后的直觉

我们的目标是以尽可能接近零的方式最小化成本函数。对于成本函数来说,高负值与高正值一样糟糕。因此,为了保持成本函数值> =0,我们将其平方。我们可以使用 absolute 来做同样的事情,但是我们没有这样做有两个主要原因。

  1. 将绝对值而不是平方值放在一起会对高残差和低残差的模型进行同等惩罚,而我们需要一个加权惩罚规则,其中具有较高残差的数据点受到更多惩罚,而较低残差受到较少惩罚。这可以简单地通过对残差/误差求平方来实现。
  2. 还有,根据高斯噪声概念,有两种误差,系统性随机性。简单地说,系统误差是沿着某个方向的东西。它在本质上是一致的,并且是可预测的。另一方面,随机误差是分布中的噪声。一旦我们考虑了系统噪声成分,当随机噪声最小化时,就获得了最佳预测值。换句话说,最佳预测值是预测值周围分布最紧密(方差最小)的预测值。最小化最小平方损失和最小化方差是一回事!这解释了为什么最小平方损失适用于广泛的问题。由于 CLT(中心极限定理),潜在的噪声通常是高斯噪声,而最小化平方误差被证明是正确的事情!

我们这样做是为了在计算梯度时最小化成本函数的导数,从而抵消掉“2 ”,使梯度更简洁。无论如何,它是一个常数,在计算θ值时无关紧要(因为我们要对它求导)。

此外,我们对 m 上的函数进行平均,m 是训练数据集中数据点的总数。这是为了使计算出的梯度值不会改变比例,并且在出现新数据点的情况下总是平均到一个中心值。

梯度下降实现

在我们实施梯度下降之前,了解其背后的直觉是必须的。既然我们现在已经完成了这一部分,让我们深入到它的实际实现中。

我们想要计算 0 和 1 的值,但是我们可以有多个特征(> =2)。在这种情况下,计算连续步长的一般公式为

The general formula for getting consecutive theta value

其中,α是学习率。我们现在可以从公式中推断出,α对步长的影响很大,因为我们在每次迭代中将梯度与α相乘。

数学讲够了,让我们从实际的代码开始。首先,我们将为要优化的参数初始化一个随机值,0 和 1。我们将编写两个函数,通过迭代计算成本和梯度下降,并将它们存储在两个不同的 NumPy 数组中。上述公式已经用于使用梯度计算成本和θ的连续值。

**def cost(theta,X,y):**
    '''
    Calculates cost of the function.
    X & y have their usual meaning.
    theta - vector of coefficients.
    '''
    m = len(y)
    **# Calculating Cost**
    c = (1/2*m) * np.sum(np.square((X.dot(theta))-y))  
    return c**def gradient_descent(X,y,theta,alpha,iterations):**
    '''
    returns array of thetas, cost of every iteration
    X - X matrix with added bias.
    y - target variable matrix
    theta - matrix of regression coefficients
    alpha - learning rate
    iteration - number of iteration to be run
    '''
    **#Getting number of observations.**
    m = len(y)

    **# Initializing cost and theta's arrays with zeroes.**
    thetas = np.zeros((iterations,2))
    costs = np.zeros(iterations)

    **# Calculating theta for every iteration.**
    for i in range(iterations):
            theta = theta - (1/m)*alpha*(X.T.dot((X.dot(theta))-y))
            thetas[i,:] = theta.T
            costs[i] = cost(theta,X,y)

    return theta,thetas,costs**# Learning Rate**
alpha = 0.01**# Number of iterations**
iterations = 3000**# Initializing a random value to give algorithm a base value.**
theta = np.random.randn(2,1)**# Adding a biasing constant of value 1 to the features array.**
X_bias = np.c_[np.ones((len(X),1)),X]**# Running Gradient Descent**
theta,thetas,costs = gradient_descent(X_bias,y,theta,alpha,iterations)**# printing final values.**
print('Final Theta 0 value: {:0.3f}\nFinal Theta 1 value: {:0.3f}'.format(theta[0][0],theta[1][0]))
print('Final Cost/MSE(L2 Loss) Value: {:0.3f}'.format(costs[-1])) **Output:**
**Final Theta 0 value:** 9.448
**Final Theta 1 value:** 2.015
**Final Cost/MSE(L2 Loss) Value:** 411.001

在代码中,我们可以看到我们已经运行了 3000 次迭代。但是,这是明确传递给函数的东西。在现实生活中,我们不会这样做。梯度下降停止运行的实际停止点应该是步长接近零时。

分析

让我们通过绘制图表来检查 L2 损失如何随着迭代次数的增加而减少。

**# Plotting Line Plot for Number of Iterations vs MSE**
plt.plot(range(iterations),costs)
plt.xlabel('Number of Iterations')
plt.ylabel('Mean Squared Error')
plt.title('Cost vs Iterations Analysis')

Number of Iterations vs MSE (Mean Squared Error): The Elbow Method

在上图中,我们看到,最初,误差显著减小。但是随着迭代次数的增加,误差并没有减少多少。在某个值之后,它几乎稳定下来,或者我们可以说它的下降可以忽略不计。

这就是梯度下降的美妙之处。当它开始接近局部最小值时,它开始向它迈出非常非常小的步伐,以便不超过它。另一方面,当它很远时,为了减少计算时间,需要更大的步长来更快地达到局部最小值。

因此,为了使用该图选择迭代次数的最佳可能值,我们使用肘方法。简单地说,MSE 值开始下降到可以忽略不计的点就是我们迭代次数的值(图的肘部)。

还有各种类型的梯度下降。我们上面所做的就是所谓的批量梯度下降。其他类型包括:

  1. 随机梯度下降。
  2. 小批量梯度下降。

结论

梯度下降可用于优化每个算法的参数,该算法的损失函数可被公式化并具有至少一个最小值。此外,我们澄清了我们对臭名昭著的梯度下降损失函数方程的理解。

我们学习了如何使用可视化方法来估计所需的迭代次数。最后,我们了解了著名的梯度下降算法背后的实际工作原理。

时间序列预测模型综述

原文:https://towardsdatascience.com/an-overview-of-time-series-forecasting-models-a2fa7a358fcb?source=collection_archive---------0-----------------------

我们描述了 10 个预测模型,并应用它们来预测工业生产指数的演变

Photo by Drew Beamer on Unsplash

这篇文章是关于什么的?

这篇文章提供了一个单变量时间序列建模和预测其演变可用的主要模型的概述。这些模型是用 RPython 开发的。相关代码可在这里获得。

时间序列预测是一个热门话题,有许多可能的应用,如股票价格预测,天气预报,商业规划,资源分配等。尽管预测可以被认为是监督回归问题的一个子集,但由于观察的时间性质,一些特定的工具是必要的。

什么是时间序列?

时间序列通常通过随机过程Y(t)建模,即随机变量序列。在预测设置中,我们发现自己在时间 t 并且我们对仅使用在时间t可用的信息来估计Y(t+h)感兴趣

如何验证和测试时间序列模型?

由于时间序列数据的时间依赖性,我们不能依靠通常的验证技术。为了避免有偏见的评估,我们必须确保训练集包含在验证集中的观察之前发生的观察。

克服这个问题的一个可能的方法是使用滑动窗口,正如这里所描述的。这个过程称为时间序列交叉验证,总结如下图,其中蓝色点代表每个“折叠”中的训练集,红色点代表相应的验证集。

Time series cross-validation. Credits to Rob J Hyndman

如果我们对预测下一个 n 时间步骤感兴趣,我们可以对前面的 1,2,…,n 步骤应用交叉验证程序。通过这种方式,我们还可以比较不同时间范围的预测的准确性。

一旦我们选择了最佳模型,我们就可以将其应用于整个训练集,并在随后的单独的测试集中评估其性能。可以通过使用用于交叉验证的相同滑动窗口技术来完成性能估计,但是不需要重新估计模型参数。

短数据探索

在下一节中,我们将应用不同的预测模型来预测工业生产指数的演变,该指数量化了在欧元区制造的电气设备。

数据可以通过 R 中的 fpp2 包轻松下载。要使数据在 R 之外可用,只需在 R 环境中运行以下代码。

library(fpp2)
write.csv(elecequip,file = “elecequip.csv”,row.names = FALSE)

该数据集对应于 1996 年 1 月至 2012 年 3 月期间欧元区(17 个国家)电气设备(计算机、电子和光学产品)的月度制造量。我们保留最后两年用于测试目的。

该时间序列在 2000 年底有一个峰值,在 2007 年有另一个峰值。我们在 2008 年底观察到的巨大下降可能是由于当年发生的全球金融危机。

似乎有一个每年的季节性模式。为了更好地显示这一点,我们用原始坐标和极坐标分别显示了每年的数据。

我们观察到强烈的季节性模式。特别是由于夏季假期,8 月份的产量大幅下降。

时间序列预测模型

我们将考虑以下模型:

  1. 天真,幼稚
  2. 季节分解(+任何模型)
  3. 指数平滑
  4. ARIMA、萨里玛
  5. GARCH
  6. 动态线性模型
  7. TBATS
  8. 先知
  9. 尼塔尔
  10. LSTM

我们对预测 12 个月的工业生产指数感兴趣。因此,给定到时间 t 的数据,我们希望预测指数在时间 t+1,…,t+12 的值。

我们将使用平均绝对误差(MAE) 来评估模型的性能。

1)天真,幼稚

天真模型中,每个时段的预测都对应于最后的观察值。

ŷ(t+h|t)= y(t)

这种预测假设产生时间序列的随机模型是随机行走的。

天真模型的扩展是由天真(季节性天真)模型给出的。假设时间序列具有季节性成分,并且季节性的周期为 T ,则由 s nave 模型给出的预测为:

ŷ(t+h|t)= y(t+h-t)

因此,对随后的 T 时间步的预测等于先前的 T 时间步。在我们的应用程序中,对下一年的简单预测等于去年的观测值。

这些模型通常被用作基准模型。以下图表显示了 2007 年两种模型的预测结果。

利用预测 R 软件包的naivesnaive功能对模型进行拟合。

2)季节分解(+任何模型)

如果数据显示出一定的季节性(如每日、每周、每季度、每年),将原始时间序列分解为三个部分的总和可能是有用的:

Y(T)=S(T)+T(T)+R(T)

其中 S(t) 是季节性成分, T(t) 是趋势周期成分, R(t) 是余数成分。

存在几种技术来估计这样的分解。最基本的一种称为经典分解,它包括:

  1. 通过滚动平均值估计趋势 T(t)
  2. 计算 S(t) 作为每个季节(例如每个月)的平均去趋势序列 Y(t)-T(t)
  3. 计算剩余数列为 R(t)=Y(t)-T(t)-S(t)

经典分解在几个方面得到了扩展。它的扩展允许:

  • 具有非恒定的季节性
  • 计算分解的初始值和最后值
  • 避免过度平滑

要获得时间序列分解方法的概述,您可以点击此处。我们将利用 STL 分解,它被认为是通用的和健壮的。

STL decomposition on industrial production index data

下面是使用分解进行预测的一种方法:

  1. 用某种分解算法(如 STL)对训练时间序列进行分解: Y(t)= S(t)+T(t)+R(t)。
  2. 计算经季节调整的时间序列 Y(t)-S(t) 。使用任何你喜欢的模型来预测季节性调整时间序列的演变。
  3. 将时间序列中最后一个时间段的季节性添加到预测中(在我们的示例中,去年的拟合 S(t) )。

在下图中,我们展示了经季节性调整的工业生产指数时间序列。

下图显示了通过使用 STL 分解和 nave 模型来拟合季节性调整时间序列而获得的对 2007 年的预测。

分解是通过使用 stats R 包的stl函数来拟合的。

3)指数平滑

指数平滑法是最成功的经典预测方法之一。其基本形式被称为简单指数平滑,其预测由下式给出:

ŷ(t+h|t)= ⍺y(t)+⍺(1-⍺)y(t-1)+⍺(1-⍺)y(t-2)+…

0 < ⍺ < 1

我们可以看到,预测等于过去观测值的加权平均值,随着时间的推移,相应的权重呈指数下降。

已经提出了简单指数平滑的几种扩展,以便包括趋势或阻尼趋势和季节性。指数平滑系列由 9 个模型组成,在此有详细描述。

下图显示了通过使用指数平滑模型(自动选择)来拟合原始时间序列和季节性调整时间序列而获得的 2007 年预测。

使用预测 R 软件包的ets功能对模型进行拟合。

4) ARIMA,萨里玛

至于指数平滑,ARIMA 模型也是时间序列预测中最广泛使用的方法之一。这个名字是自回归综合移动平均的缩写。

自回归模型中,预测对应于变量过去值的线性组合。在移动平均模型中,预测对应于过去预测误差的线性组合。

基本上,ARIMA 模型结合了这两种方法。由于它们要求时间序列是平稳的,差分(积分)时间序列可能是一个必要的步骤,即考虑差分的时间序列而不是原始的时间序列。

SARIMA 模型(季节性 ARIMA)通过添加季节性过去值和/或预测误差的线性组合来扩展 ARIMA。

关于 ARIMA 和萨里玛车型的完整介绍,请点击此处

下面的图显示了通过使用季节调整时间序列的萨里玛模型和 ARIMA 模型获得的对 2007 年的预测。

使用预测 R 软件包的auto.arimaArima功能对模型进行拟合。

5) GARCH

以前的模型假设产生时间序列的随机过程中的误差项是同伦的,即具有恒定的方差。

相反, GARCH 模型假设误差项的方差遵循自回归移动平均(ARMA)过程,因此允许它随时间变化。它对于模拟波动性随时间变化的金融时间序列特别有用。这个名字是广义自回归条件异方差的首字母缩写。

通常,均值也采用 ARMA 过程。关于 GARCH 模型的完整介绍,你可以点击这里这里

下面的图显示了通过使用 GARCH 模型来拟合季节性调整的时间序列而获得的 2007 年的预测。

使用 rugarch R 软件包的ugarchfit功能对模型进行拟合。

6)动态线性模型

动态线性模型代表了时间序列预测的另一类模型。想法是在每个时间 t 这些模型对应一个线性模型,但是回归系数随时间变化。下面给出一个动态线性模型的例子。

y(t) = ⍺(t) + tβ(t) + w(t)

⍺(t) = ⍺(t-1) + m(t)

β(t) = β(t-1) + r(t)

w(t)N(0,W),m(t)N(0,M),r(t)~N(0,R)

在前一个模型中,系数 ⍺(t)β(t) 遵循随机游走过程。

动态线性模型可以在贝叶斯框架中自然建模;然而,最大似然估计技术仍然可用。有关动态线性模型的完整概述,请点击此处

下图显示了通过使用动态线性模型来拟合季节性调整时间序列而获得的对 2007 年的预测。由于巨大的计算成本,我不得不保持模型极其简单,这导致了糟糕的预测。

使用 dlm R 包的dlmMLE功能对模型进行拟合。

7) TBATS

TBATS 模型是一种基于指数平滑的预测模型。该名称是三角函数、Box-Cox 变换、ARMA 误差、趋势和季节分量的缩写。

TBATS 模型的主要特点是能够处理多个季节性,通过基于傅立叶级数的三角表示法模拟每个季节性。复杂季节性的一个典型例子是每天对销售量的观察,通常同时具有每周和每年的季节性。

关于 TBATS 型号的完整介绍,请点击此处

下图显示了使用 TBATS 模型拟合时间序列获得的 2007 年预测值。

通过使用预测 R 软件包的tbats功能对模型进行拟合。

8)先知

Prophet 是另一个预测模型,它可以处理多重季节性。它是脸书核心数据科学团队发布的一款开源软件

prophet 模型假设时间序列可以分解如下:

y(t)= g(t)+s(t)+h(t)+ε(t)

三个术语 g(t)s(t)h(t) 分别对应趋势、季节性和节假日。最后一项是误差项。

模型拟合被框定为曲线拟合练习,因此没有明确考虑数据中的时间依赖结构。这也允许进行不规则间隔的观察。

趋势时间序列有两种选择:饱和增长模型和分段线性模型。多期季节性模型依赖傅立叶级数。已知和定制假日的效果可以很容易地整合到模型中。

prophet 模型被插入到贝叶斯框架中,它允许进行充分的后验推断,以将模型参数不确定性包括在预测不确定性中。

如需对 Prophet model 的完整介绍,请点击此处的。

下图显示了通过使用 Prophet 模型拟合时间序列获得的 2007 年预测。

通过使用 prophet R 软件包的prophet功能对模型进行拟合。

9)内塔尔

NETAR 模型是一个完全连接的神经网络。首字母缩写代表神经网络自回归。

NNETAR 模型在时间 t 之前接受输入序列的最后元素,并在时间 t+1 输出预测值。为了进行多步预测,网络被反复应用。

在存在季节性的情况下,输入也可能包括季节性滞后的时间序列。有关 NNETAR 型号的完整介绍,请点击此处

下面的图显示了 2007 年的预测结果,这些预测结果是通过使用带有季节性滞后输入的 NNETAR 模型和基于季节性调整时间序列的 NNETAR 模型获得的。

使用预测 R 软件包的nnetar功能对模型进行拟合。

10) LSTM

LSTM 模型可用于预测时间序列(以及其他递归神经网络)。LSTM 是长短期记忆的首字母缩写。

LSTM 网络的状态通过状态空间向量来表示。这种技术允许跟踪新观测值与过去观测值的相关性(即使是非常远的观测值)。

一般来说,LSTMs 是复杂的模型,它们很少用于预测单个时间序列,因为它们需要大量的数据来估计。然而,当需要对大量时间序列进行预测时,通常使用它们(检查此处)。

关于使用 LSTM 预测时间序列的完整介绍,点击此处

下图显示了通过对季节性调整时间序列拟合 LSTM 模型而获得的测试集中第一年的预测。

使用 Python 中的 Keras 框架对模型进行拟合。

估价

我们通过前述的交叉验证程序进行型号选择。我们没有计算动态线性模型和 LSTM 模型,因为它们的计算成本高,性能差。

在下图中,我们展示了每个模型和每个时间跨度的交叉验证 MAE。

我们可以看到,对于时间跨度大于 4 的情况,基于季节性调整数据的 NNETAR 模型比其他模型表现得更好。让我们检查通过在不同时间范围内求平均值计算出的总 MAE。

Cross-validated MAE

基于经季节性调整的数据的 NNETAR 模型是该应用的最佳模型,因为它对应于最低的交叉验证 MAE。

为了获得最佳模型性能的无偏估计,我们在测试集上计算 MAE,获得等于 5,24 的估计。在下面的图片中,我们可以看到在每个时间范围的测试集上估计的 MAE。

如何进一步提高性能

提高模型性能的其他技术可以是:

  • 对不同的时间范围使用不同的模型
  • 组合多个预测(例如,考虑平均预测)
  • 引导汇总

最后一种技术可以总结如下:

  1. 分解原始时间序列(例如使用 STL)
  2. 通过随机打乱剩余部分的块来生成一组相似的时间序列
  3. 对每个时间序列拟合模型
  4. 每个模型的平均预测

有关引导聚合的完整介绍,请单击此处的。

结束语

该项目的目标不是拟合工业生产指数的最佳预测模型,而是给出预测模型的概述。在现实世界的应用中,大量的时间应该花费在预处理特征工程特征选择上。

大多数先前描述的模型允许容易地结合时变预测器。这些可以从相同的时间序列中提取,或者可以对应于外部预测值(例如,另一个指数的时间序列)。在后一种情况下,我们应该注意不要使用来自未来的信息,这可以通过预测预测器或使用它们的滞后版本来满足。

最后,请注意,在本文中,我们只考虑了只有一个时间序列需要预测的情况。当我们有很多时间序列时,一个全局的方法可能是首选,因为它允许我们估计一个更复杂和可能更准确的模型。有关全球方法的介绍,请点击此处

弹性搜索及其应用综述

原文:https://towardsdatascience.com/an-overview-on-elasticsearch-and-its-usage-e26df1d1d24a?source=collection_archive---------1-----------------------

简介

Elasticsearch 是一个高度可扩展的开源全文搜索和分析引擎。它允许您以接近实时的速度快速存储、搜索和分析大量数据。它通常用作支持具有复杂搜索功能和需求的应用程序的底层引擎/技术。Elasticsearch 在 Lucene StandardAnalyzer 之上提供了一个分布式系统,用于索引和自动类型猜测,并利用一个基于 JSON 的 REST API 来引用 Lucene 特性。

它很容易开箱设置,因为它提供了合理的默认设置,并对初学者隐藏了复杂性。它有一个短的学习曲线来掌握基础知识,所以任何人只要稍加努力就可以很快变得富有成效。它是无模式的,使用一些缺省值来索引数据。

在消费者从电子商务网站搜索产品信息的情况下,目录面临着产品信息检索时间长等问题。这导致了糟糕的用户体验,进而错失了潜在客户。如今,企业正在寻找替代方法,以快速检索的方式存储大量数据。这可以通过采用 NOSQL 而不是 RDBMS(关系数据库管理系统)来存储数据来实现。

Elasticsearch 是一个 NOSQL 数据库,因为:

  • 它易于使用
  • 有一个很棒的社区
  • 与 JSON 的兼容性
  • 广泛的使用案例

后端组件

为了更好地理解 Elasticsearch 及其用法,对主要后端组件有一个大致的了解是有好处的。

结节

节点是作为集群一部分的单个服务器,存储我们的数据,并参与集群的索引和搜索功能。就像集群一样,节点由名称标识,默认情况下,名称是启动时分配给节点的随机通用唯一标识符(UUID)。如果需要,我们可以编辑默认的节点名。

集群是一个或多个节点的集合,这些节点共同保存您的全部数据,并提供联合索引和搜索功能。可以有 N 个节点具有相同的集群名称。
Elasticsearch 在分布式环境中运行:通过跨集群复制,辅助集群可以作为热备份发挥作用。

索引

索引是具有相似特征的文档的集合。例如,我们可以为特定的客户建立一个索引,为产品信息建立一个索引,为不同类型的数据建立一个索引。执行索引搜索、更新和删除操作时,索引由引用该索引的唯一名称来标识。在一个集群中,我们可以定义任意多的索引。索引类似于 RDBMS 中的数据库。

文件

文档是可以被索引的基本信息单元。例如,您可以有一个关于产品的索引,然后有一个针对单个客户的文档。该文档以 JSON (JavaScript 对象符号)表示,这是一种无处不在的互联网数据交换格式。类似于数据库中的单个原始数据。在一个索引中,您可以存储任意多的文档,因此在同一个索引中,您可以有一个针对单个产品的文档,还有一个针对单个订单的文档。

碎片和复制品

Elasticsearch 提供了将索引细分为多个片段的能力。当您创建一个索引时,您可以简单地定义您想要的碎片数量。每个碎片本身就是一个全功能的独立“索引”,可以托管在集群中的任何节点上。
Shards 非常重要,因为它允许水平分割您的数据量,还可能在多个节点上并行操作,从而提高性能。还可以通过将索引的多个副本制作成副本碎片来使用碎片,这在云环境中有助于提供高可用性。

弹性叠层

尽管搜索引擎是其核心,但用户开始使用 Elasticsearch 搜索日志,并希望轻松地摄取和可视化它们。 Elasticsearch、Logstash、Kibana 是弹性栈的主要组成部分,被称为 ELK

基巴纳

Kibana 让您可视化您的 Elasticsearch 数据并浏览 Elastic 堆栈。您可以从一个问题开始,选择赋予数据形状的方式,找出交互式可视化将把您引向何处。您可以从经典图表(直方图、折线图、饼图、太阳图等)开始,或者设计自己的可视化并在任何地图上添加地理数据。
您还可以执行高级时间序列分析,发现数据中的视觉关系,并利用机器学习功能探索异常情况。更多详情请看官方页面。

Kinbana console

Logstash

Logstash 是一个开源的服务器端数据处理管道,它同时从多个来源获取数据,对其进行转换,然后将其发送到 collect。数据通常以多种格式分散或污染在多个系统中。在 Logstash 上,可以接收日志、指标、web 应用程序、数据存储和各种 AWS 服务,所有这些都以连续流的方式进行。它可以与不同的模块一起使用,如 Netflow ,以获得对您的网络流量的见解。
它通过识别命名字段来构建结构,动态地转换和准备数据,而不考虑格式,并将其转换为通用格式。您可以使用 X-Pack 中的监控特性来深入了解关于您的 Logstash 部署的指标。在 overview dashboard 中,您可以看到 Logstash 接收和发送的所有事件,以及关于内存使用和正常运行时间的信息。然后,您可以深入查看特定节点的统计信息。更多详情请访问官方页面

logstash node stats

弹性搜索用例

Elasticsearch 可以以如此多的方式使用,以至于我很难捕捉到所有最有趣的用例。为了简单起见,我选择了三个主要类别和三个主要公司用例,如果你想深入了解,可以看看它们的用例[页](https://www.elastic.co/use-cases)。

  • 主数据存储:创建可搜索的目录、文档存储和日志系统。
  • 补充技术:给 SQL、mongoDB 增加可视化能力,给 Hadoop 增加 cast 索引和搜索,或者给 kafka 增加处理和存储。
  • 附加技术:如果您已经登录了 Elasticsearch,您可能希望添加指标、监控和分析功能。

网飞

幕后的网飞信息系统正在使用 Elasticsearch。消息系统分为以下几类:

  • 加入服务时收到的消息。
  • 一旦人们加入,他们会收到关于他们可能喜欢的内容或服务器上的新功能的消息。
  • 一旦他们通过机器学习算法对你有了更多的了解,他们就会发送更多关于你可能喜欢或喜欢看什么的迷人和个性化的信息。
  • 如果你决定退出服务,他们会告诉你如何回来。

这些都是通过邮件、app 推送通知、短信来完成的。为了有效地实现这一点,他们需要几乎立即知道消息传递中可能出现的问题。为此,为消息生命周期引入了 Elasticsearch(以前他们使用分布式 grep)。
简而言之,每条状态信息都记录在 Elasticsearch 上,合适的团队可以通过在 Kibana 上编写查询来过滤每个类别。

假设推出了一部新电影,在这种情况下,必须将“新片名”消息发送给所有客户。
使用 Kibana,他们可以实时看到有多少人收到了新消息的通知,以及消息发送的成功率。他们还可以验证某些消息失败的原因。这带来了更快地调查和解决问题的能力,例如 2012 年巴西的高比率消息失败。

通过使用 Kibana 中的饼图,他们几乎可以立即发现大量的无效会员失败。他们跟踪调查了国家提供商,发现在 7 月 29 日,在许多巴西地区,所有现有手机号码的左边都添加了数字 9,而不管它们之前的初始数字是多少。这一变化旨在增加圣保罗等大都市地区的电话号码容量,从而消除该地区长期存在的号码短缺问题。
多亏了 Elasticsearch,他们能够近乎实时地发现所有这些故障,并及时与提供商跟进。

国外手机交友软件

这是一家大型 tec 公司和 Elasticsearch 社区相互合作的例子。Tinder 的核心是一个搜索引擎。搜索查询非常复杂,涉及两位数的事件、数百个国家和 50 多种语言。
大多数用户交互都会触发 Elasticsearch 查询。
根据位置不同,与 tinder 的交互方式也不同。例如在亚洲,他们也用它作为语言交换或寻找导游。
因此,Tinder 中的查询非常复杂。它们必须是:

  • 个性化:机器学习算法也在这种情况下使用。
  • 基于位置:根据您在某个时间点的位置来查找匹配。
  • 双向:知道哪些用户会互相向右滑动,基本上就是匹配了。
  • 实时:大量用户的整个交互必须在几毫秒内发生,并且每个用户都有许多相关的变量。

考虑到所有这些功能,后端现实非常复杂,从数据科学和机器学习扩展到双向排名和地理定位。Elasticsearch 的基石是让这些组件以一种非常高效的方式协同工作。在这种情况下,绩效是一个障碍。为此,他们一直在与 Elasticsearch 团队合作,微调许多参数并解决问题。通过这种方式,他们一直在支持 Elasticsearch 社区,并帮助改善整个 Elastic stack 产品,同时改善 Tinder 本身的用户体验。

思科商务交付平台

Elasticsearch 于 2017 年推出,当时他们升级了他们的商业平台。他们从 RDBMS 转向 Elasticsearch 的原因如下:

  • 添加在主动/主动模式下工作的容错功能。RDBMS 不是分布式的,也不是容错的。
  • 基于等级和类型的提前搜索来自 30/40 属性的多个数据库的数据,以获得亚秒级响应。
  • 全局搜索:如果在搜索中没有指定特定的对象,搜索引擎将根据多个对象查找结果。

思科威胁情报部门

简而言之,思科威胁情报部门或思科 Talos 正在阻止恶意软件和垃圾邮件使“互联网管道”饱和。
在这个思科部门,他们每天查看超过 150 万个恶意软件样本。恶意负载和垃圾邮件占所有电子邮件流量的 86%(每天超过 6000 亿封电子邮件)。
Talos 的威胁情报团队负责在网络上发现新的全球规模的漏洞,并找出真正的坏人。
他们通过分析 ssh 终端和路由器蜜罐的流量模式来检测新的漏洞利用工具包,以收集异常行为,如使用暴力攻击猜测用户和密码的尝试登录。通过这种方式,他们记录了攻击者登录后使用的命令,他们从服务器下载和上传的文件(虽然难以置信,但互联网上的大多数凭证都像行密码和用户名 admin 一样简单)。
是他们在 2015 年阻止了所谓的ssh psychs。众所周知,该组织通过从特定类别的 IP 生成 SSH 暴力登录尝试,在互联网上创建了大量的扫描流量。一旦他们能够以 root 用户身份进入服务器,他们就可以下载并安装 DDoS rootkits。

自 2017 年以来,他们使用 logstash 和 kibana 来检测和分析可能的全球规模线程。

结论

Elasticsearch 是一个分布式、RESTful 和分析型搜索引擎,能够解决各种各样的问题。
许多公司正在转向 it 并将其集成到当前的后端基础设施中,因为:

  • 它允许使用聚合缩小到您的数据,并理解数十亿条日志行。
  • 它结合了不同类型的搜索:结构化、非结构化、地理、应用程序搜索、安全分析、指标和日志记录
  • 它真的很快,可以在只有一个节点的笔记本电脑上运行,也可以在有数百台服务器的集群上运行,这使得非常容易原型化
  • 它使用标准的 RESTful APIs 和 JSON。该社区还以多种语言构建和维护客户端,如 Java、Python、.NET、SQL、Perl、PHP 等。
  • 通过使用Elasticsearch-Hadoop(ES-Hadoop)连接器,可以将 elastic search 的实时搜索和分析功能应用于您的大数据。
  • KibanaLogstash 这样的工具允许你通过使用图表和执行粒度搜索,以非常简单和直接的方式理解你的数据。

在本文中,我们仅仅触及了弹性搜索能力和用例的皮毛,而各种业务挑战是可以解决的。如果你有兴趣了解更多或测试它,看看他们的产品页面和他们的教程快速开始。如果你对如何使用 django 和 elasticsearch 创建一个基本的搜索应用感兴趣,我鼓励你看看我以前的文章。

从词向量类推?

原文:https://towardsdatascience.com/analogies-from-word-vectors-77fe12f2de52?source=collection_archive---------14-----------------------

这些类比有多相似?

A close inspector (Source: own image)

关于词向量的入门级文章往往包含计算类比的例子,比如国王-男人+女人=王后。像这样引人注目的例子显然有它们的位置。它们引导我们对相似性的兴趣,将其视为一个有待挖掘的隐藏宝藏。然而,在真实数据中,类比往往不那么清晰和易于使用。

前段时间对德国维基百科的快照分析,留下了太多的问题,其中之一就是类比。当然,首先要测试的事情之一是国王-王后(或者在德语中:knig-knig in)的例子是否也适用于这个语料库——并不令人惊讶的是,它没有:

Candidates for king-man+woman from German Wikipedia corpus

没有一个候选人与国王和王后完全无关;排名第一和第四的是国王配偶的词汇,排名第二的是国王的单词形式,排名第三的是女儿,最后排名第五的是女王——没有像预期的那样突出。接下来是婚礼、皇位继承人、妃子、登基和妹妹。但是候选集对于某样东西是女性(相对于国王)还是与王权有关并不十分明显。因此结果集的实际直接适用性似乎相当有限。

类比的另一个常见例子是大写的派生。让我们来看看奥地利首都的候选城市有哪些:

Candidates for Austria-Germany+Berlin from German Wikipedia corpus

这一次我们成功了,的确维也纳对于奥地利就像柏林对于德国一样。其他候选人的名单也很有意义,我们发现奥地利五个联邦州的首府(格拉茨、克拉根福、林茨、因斯布鲁克、萨尔茨堡)和波兰一个省的首府(弗罗茨瓦夫)……以及德国萨克森州的两个城市正在竞争谁是真正的首府(德累斯顿、莱比锡)。

万岁。这个结果延伸了吗?让我们编写几行 Python 代码来测试和可视化所有欧洲国家的类比练习——不包括城市国家和哈萨克斯坦,在这些国家,语料库中没有足够的数据供其首都在模型中显示:

Test all pairs of countries and capitals for correctly guessed analogy and visualize the result

经过一些计算,我们得到 57.25%的命中和 42.25%的未命中,比实际希望的要差得多:

Result matrix of the country-capital guessing exercise

一个国家拥有猜测资本好坏的背后似乎没有什么模式。让我们来看看原始频率,下面有一个完整的列表。

## 国家和首都频率(德语维基百科)

有许多猜测失败的国家:英国(2482),捷克共和国(679),意大利(91024),冰岛(37591),摩尔多瓦(2585)。相比之下,一些国家有许多正确的猜测:奥尔巴尼(7067),丹麦(34079),爱尔兰(23024),葡萄牙(29124),罗马尼亚(22700)。英国和捷克共和国的官方名称很少被使用,这也许可以解释为什么在提到他们的首都时不会出现这种情况。此外,摩尔多瓦可能会因为国名和河流名不清而遭受损失。但这并不能解释意大利或冰岛。

同样,让我们对那些有许多猜测失败的城市做同样的比较:伦敦(114,921),布拉格(34,565),罗马(70,952),Rejkyavik (2,890),Chișinău (851)和有许多正确猜测的城市:地拉那(2,240),哥本哈根(18,092),都柏林(9630),里斯本(11,196),布卡拉斯特(8,350)。同样,我们没有明确的案例,这次也没有额外知识的支持。有人能解释一下这个吗?

总的来说,给人的印象是,类比有时效果惊人地好,有时则不然。在利用这些数据时,我们应该记住这一点,并为意外失败做好准备。

使用 Apache Drill 通过 SQL 查询分析 Kafka 消息

原文:https://towardsdatascience.com/analyse-kafka-messages-with-sql-queries-using-apache-drill-cc26420bb7c3?source=collection_archive---------20-----------------------

原文发布于此:https://blog . contact sunny . com/tech/analyse-Kafka-messages-with-SQL-queries-using-Apache-drill

在上一篇文章中,我们弄清楚了如何将 MongoDB 与 Apache Drill 连接起来,并使用 SQL 查询来查询数据。在这篇文章中,让我们扩展这方面的知识,看看如何使用类似的 SQL 查询来分析我们的 Kafka 消息。

在 Apache Drill 中配置 Kafka 存储插件非常简单,与我们配置 MongoDB 存储插件的方式非常相似。首先,我们运行 Apache Drill、Apache Zookeeper 和 Apache Kafka 的本地实例。在这之后,前往http://localhost:8047/storage,在那里我们可以启用 Kafka 插件。您应该在页面右侧的列表中看到它。单击启用按钮。存储插件将被启用。在这之后,我们需要添加一些配置参数来开始从 Kafka 查询数据。单击 Kafka 旁边的 Update 按钮,这将打开一个带有 JSON 配置的新页面。用以下内容替换 JSON:

{
   "type": "kafka",
   "kafkaConsumerProps": {
     "key.deserializer": "org.apache.kafka.common.serialization.ByteArrayDeserializer",
     "auto.offset.reset": "earliest",
     "bootstrap.servers": "localhost:9092",
     "group.id": "drill-query-consumer-1",
     "enable.auto.commit": "true",
     "value.deserializer": "org.apache.kafka.common.serialization.ByteArrayDeserializer",
     "session.timeout.ms": "30000"
   },
   "enabled": true
 }

如果需要,您可以更改此配置。如果您要连接到远程引导服务器,请更改引导服务器地址。一旦完成这些,我们就可以开始从 Kafka 主题中查询数据了。因此,让我们切换到终端,看看一些查询。

使用 Drill SQL 查询查询 Apache Kafka 消息

首先,我们来看看 Kafka 存储插件是否确实启用了。为此,我们只需运行 show 数据库;查询。这将列出我们已启用的所有存储插件,以及这些服务中的数据库(如果适用)。如果您运行此查询,您的输出应该类似于:

可以看到,卡夫卡被列为数据库。让我们使用下面的命令切换到这个模式:

use kafka;

要开始从 Kafka 主题中读取数据,我们需要首先查看该主题是否被 Drill 识别。Kafka 中的每个主题都会在 Drill 中以表格的形式出现在 kafka 数据库中。所以我们只需要列出这个数据库中的所有表。出于测试目的,您可以创建一个新主题。我创建了主题“drill ”,用于使用 Drill 进行测试。让我们看看它是否在这个数据库中显示为一个表。

这就是了。我们将在这个表上运行我们的查询。

这里你需要注意的一件事是,现在,对于最新版本的 Apache Drill 和 Kafka 存储插件,只有 JSON 消息可以工作。如果你发送的不是 JSON,Drill 会抛出一个异常,并且不能工作。所以让我们来解决这个问题。

让我们使用 Kafka 控制台生成器发送一些随机的 JSON 消息,看看 Drill 是否能够查询这些消息。

我将从一个控制台生成器向“drill”主题发送以下 JSON 消息(总共四条)。这是我在简单的谷歌搜索后在网上得到的一些样本数据。

{
  "id": 1,
  "first_name": "Jeanette",
  "last_name": "Penddreth",
  "email": "jpenddreth0@census.gov",
  "gender": "Female",
  "ip_address": "26.58.193.2"
}
{
  "id": 2,
  "first_name": "Giavani",
  "last_name": "Frediani",
  "email": "gfrediani1@senate.gov",
  "gender": "Male",
  "ip_address": "229.179.4.212"
}
{
  "id": 3,
  "first_name": "Noell",
  "last_name": "Bea",
  "email": "nbea2@imageshack.us",
  "gender": "Female",
  "ip_address": "180.66.162.255"
}
{
  "id": 4,
  "first_name": "Willard",
  "last_name": "Valek",
  "email": "wvalek3@vk.com",
  "gender": "Male",
  "ip_address": "67.76.188.26"
}

现在,让我们对 Drill 中的表运行以下简单的 SQL 命令,看看会得到什么输出:

select * from drill;

这就是我们想要的结果。从 Drill 查询阿帕奇卡夫卡就是这么简单。我不知道为什么我没有早点遇到这个工具。

分析比利时选举结果

原文:https://towardsdatascience.com/analysing-belgian-election-results-5c4124452689?source=collection_archive---------33-----------------------

对数据的深入研究

Photo by Element5 Digital on Unsplash

介绍

2019 年 5 月 26 日,比利时组织了联邦选举。在本文中,我不想讨论这些选举的政治含义。我想研究一下这些数据,看看我们能从中学到什么。

更具体地说,我想回答这样一个问题:“自上次选举以来,选民是如何改变他们的想法的”。

看总的结果,不可能回答这个问题。请注意,这是真的,即使只有两个政党参加选举。

举个例子,我们想象一下,连续两次选举,两党都拿到了半数选票。那么仍然不可能得出是没有一个选民改变主意,还是所有的选民都改变了主意,或者介于两者之间。

资料组

一切有趣的事情都始于数据集。所以我开始为自己寻找一个包含选举结果数据的数据集。

我偶然发现这个网站,上面有每个地区 2019 年和 2014 年(以前的选举)的投票结果数据。我所说的区在比利时被称为“行政区”,大约有 200 多个。

我是手动复制粘贴这个网站上的所有结果,还是采用不太合法的方法编写 Python 脚本来自动抓取结果,这是任何人的猜测。我只能说我强烈推荐“ BeautifulSoup ”库进行截屏。

我最终得到了一个数据集,它提供了 2019 年和 2014 年 200+个地区中每个政党的票数。

为了准确起见,我必须提到比利时分为三个自治区:佛兰德、瓦隆和布鲁塞尔首都,并非所有政党在所有地区都有代表。在这篇文章的结果部分,我将把重点放在最大的部分(佛兰德),但该方法也测试了其他部分。

模型描述

为了了解哪些选民改变了主意,我建立了一个非常简单的模型。
我将选举简化为一个 N 党制,放弃所有在 2014 年和 2019 年获得少于 15 万张选票的政党。

然后我假设所有在 2014 年投票的人,在 2019 年会以同样的方式改变他们的想法。更具体地说,在 2014 年投票给 Pᵢ党的人,在 2019 年投票给 Pᵣ党的概率是一样的。(我称这个概率为 X ᵢᵣ).

我们的目标是找到概率 X ᵢᵣ.的最佳值换句话说:“x 的哪些值 ᵢᵣ,根据 2014 年的结果最好地解释了 2019 年的结果”。

为了“解释”或“预测”2019 年政党 Pᵣ 的票数 V ⁰ ⁹,基于 2014 年的结果,我可以使用概率 X ᵢᵣ 如下:

那看起来很熟悉不是吗?这是一个简单的线性回归。所以我开始着手用 Python 实现这个模型。

应该注意的是,即使我们在谈论预测 2019 年的结果,我们也不关心预测 2019 年的选举,因为它们已经过去了。我们只是试图创建一个预测模型,然后研究“这个模型的内部”(概率 X ᵢᵣ).

初步结果

我将在热图中展示这个线性回归的结果。热图中的每个单元格都包含一个概率 X ᵢᵣ.

这个热图应该这样理解:每个单元格位于一行和一列的交叉点上。行代表在 2014 年投票给某个政党的人,列代表他们在 2019 年投票给的政党。单元格中的值表示 2014 年投票给第一个政党的人与 2019 年投票给第二个政党的人的比率。

举个例子:如果所有人在 2014 年和 2019 年以完全相同的方式投票,热图对角线上的值为 1,其他地方的值为 0。

我的第一个结果显示在下面的热图中。

Results of the first model: Not what I was hoping for

一张图说了千言万语,这次却是只喊一件事:“模型错了!”。

模型的问题

这个模型给出了无意义的结果,因为这个问题当然不是传统的线性回归问题,原因有二。

首先,在我对模型的解释中,参数 X ᵢᵣ 不能取任意值。因为它们代表选民转向另一个政党的概率,所以它需要是 0 到 1 之间的一个数字。在 2019 年,某个群体的选民有-59%的概率投票给某个政党,这根本没有意义。

其次,概率 X 和ᵢᵣ 并不是相互独立的。所有选民都需要在 2019 年投下新的一票,否则就有成为非法移民的风险,因为投票在比利时是强制性的。

因此,每个政党的总和 X ᵢᵣ 需要“大约”100%(因为在 2014 年和 2019 年之间,人们可能已经死亡、迁移或达到允许投票的最低年龄)。
我可以多做一点,添加 2014 年至 2019 年每个地区的人口变化信息,但为了简化问题,我假设它大致不变。

改进模型

因此,我修改了模型,将这些限制因素考虑在内。

该模型在两个方面进行了调整:

  1. 我从默认的线性回归转向最小二乘问题,用独立变量的界限来限制我的概率在 0 和 1 之间。
  2. 我为每个政党添加了一个等式,以迫使所有 2014 年的选民在 2019 年再次投票。这个方程用一个超参数加权来表示它的相对权重。

有趣的是,模型的“性能”(将在本文末尾讨论)只有在考虑到这些约束的情况下才会下降。但是鉴于我们对模型的解释比对预测能力更感兴趣,我们很乐意接受这种性能上的打击。

超参数调谐

上面提到的超参数定义了这个约束相对于“正确预测”的相对重要性。

我通过检查作为超参数函数的性能图来调整这个参数的值。在误差达到最高点之前,我选择了高原上的某个点。

为了让自己相信结果不太依赖于超参数,我很快检查了超参数值不同的模型之间的结果差异。结果并没有太大的不同,这是令人欣慰的。

改进模型的结果

在下面的热图中,您可以看到改进模型的结果。

Results of the improved model

该模型明确显示了一些有趣的结果。有些非常符合预期和“常识”。

该模型表明,人们在“志同道合”的政党之间改变主意。这方面的一些例子:

  • PVDA、格罗恩和 SP-A(都是左翼政党)主要是相互失去选票。
  • NV-A 只输给了另一个右翼政党(Vlaams Belang)

一些观察结果出乎意料:

  • 22%的七党联盟投票者,改变了他们对 OpenVLD(左翼转右翼)的看法
  • Vlaams Belang(一个相当极端的右翼政党)输给了一个相当极端的左翼政党(PVDA)10%的选票
  • OpenVLD(一个右翼政党)的选票输给了几乎所有政党(除了最极端的左翼政党)

表演

为了比较模型,(甚至为了训练模型),我需要选择一个“性能度量”。
一个很好的例子是“所有地区的错误预测票数”。

如果我在以下型号上使用此指标:

  • 初始线性回归模型: 9.9%错误预测选票
  • 改进后的模型: 13.5%误预测票
  • 基于投票的模型。我很幸运地找到了来自代表组织的一份研究报告,代表组织是一个由比利时五所大学的政治学家组成的联盟,描述了他们对选举结果进行的一次民意调查。使用他们的投票结果导致 18.9 %的选票被错误预测。

从这些绩效得分中观察到的一些情况:

  • 约束模型的表现比“初始线性回归”差(如预期的)。
  • 我很高兴地看到,我的模型比大学进行的民意调查表现得更好。这表明这种方法可能优于选举后投票。

可能的后续步骤

目前的模型只有有限的可用信息作为决策的基础。它使用的唯一数据点是:“一个人在 2014 年投票给了哪个政党?”。

因此,它必须认为所有在 2014 年投票给同一政党的人都是平等的。这当然是非常粗糙的简化。人们可以想象,在 2014 年投票给某个政党的人,有不同的背景和理由这样做。这些不同的原因可能会导致 2019 年选举中的不同行为。

如果我们希望模型能够做出类似于“Y 党失去了 X 党的大量富裕选民,同时重新获得了大量老年选民”的预测,我们需要对模型进行改进。为模型添加每个地区的财富分布、城市化或年龄分布信息,可能会释放这种潜力。

提高模型性能的另一种方法是改进训练数据,这种方法很容易实现。运行分析后,我发现选举结果也可以在更细粒度的级别上获得(称为“Gemeente”)。对这个更丰富的数据集重新运行相同的分析应该会产生更准确的结果。这也将使我能够纳入更多的政党,而不仅仅是最大的政党。

结论

使用相当简单的机器学习技术,绝对有可能获得一些关于选举结果的有趣见解。它比一个政治科学家财团进行的民意调查(样本规模为 3400 人)更好地解释了 2019 年的结果。

有足够的机会来改进模型或对该数据集执行不同的分析。

但最重要的是:下次当你怀疑你的投票是否会有所不同时,要知道你至少会成为线性回归的一部分;-)

使用深度学习分析乳腺癌

原文:https://towardsdatascience.com/analysing-breast-cancer-using-deep-learning-e3426f768c52?source=collection_archive---------29-----------------------

用于检测乳腺癌的过程非常耗时,小的恶性肿瘤区域可能会被遗漏。

为了检测癌症,将组织切片放在载玻片上。然后,病理学家在显微镜下检查这张载玻片,目视扫描没有癌症的大区域,以便最终找到恶性区域。由于这些载玻片现在可以数字化,计算机视觉可以用来加快病理学家的工作流程,并提供诊断支持。

一些术语

组织病理学
这包括在显微镜下检查玻璃组织切片,看是否存在疾病。在这种情况下,这将是检查淋巴结的组织样本,以检测乳腺癌。

整个载玻片图像(WSI)
用扫描仪拍摄的载玻片的数字化高分辨率图像。这些图像的大小可能有几千兆字节。因此,为了让它们用于机器学习,这些数字图像被切割成小块。

小块
小块是图像的一小块,通常为矩形。例如,一个 50×50 的小块是一个包含 2500 个像素的正方形小块,取自一个更大的图像,比如 1000×1000 个像素。

淋巴结是一个小豆状结构,是人体免疫系统的一部分。淋巴结过滤通过淋巴液的物质。它们含有淋巴细胞(白细胞),帮助身体对抗感染和疾病。

前哨淋巴结
在肿瘤附近注射蓝色染料和/或放射性示踪剂。这种注射物质到达的第一个淋巴结称为前哨淋巴结。我们将使用的图像是取自前哨淋巴结的所有组织样本。

转移
癌细胞扩散到身体新的区域,通常通过淋巴系统或血液。

数据

浸润性导管癌(IDC)是所有乳腺癌中最常见的亚型。几乎 80%确诊的乳腺癌都是这种亚型。这个 kaggle 数据集由 277,524 个大小为 50 x 50 的小块组成(198,738 个 IDC 阴性,78,786 个 IDC 阳性),这些小块是从 162 个以 40 倍扫描的乳腺癌(BCa)标本的整块载玻片图像中提取的。每个补片的文件名格式为:u_xX_yY_classC.png(例如,10253 _ idx 5 _ X 1351 _ Y 1101 _ class 0 . png),其中 u 为患者 ID (10253_idx5),X 为该补片裁剪位置的 X 坐标,Y 为该补片裁剪位置的 Y 坐标,C 表示类别,其中 0 为非 IDC,1 为 IDC。

下载和准备数据

首先,我们需要下载数据集并解压。这些图像将保存在“IDC_regular_ps50_idx5”文件夹中。每 279 名患者都有一个文件夹。患者文件夹包含 2 个子文件夹:文件夹“0”包含非 IDC 补丁,文件夹“1”包含相应患者的 IDC 图像补丁。

IDC dataset structure

50x50 图像补丁看起来像这样:

IDC images

现在,我们需要将所有患者的所有 IDC 图像放入一个文件夹,并将所有非 IDC 图像放入另一个文件夹。可以手动完成,但是我们编写了一个简短的 python 脚本来完成:

**import** os 
**from** shutil **import** copyfile src_folder = 'IDC_regular_ps50_idx5' 
dst_folder = 'train' os.mkdir(os.path.join(dst_folder, '0')) os.mkdir(os.path.join(dst_folder, '1')) folders = os.listdir(src_folder) 
**for** f **in** folders:
     f_path = os.path.join(src_folder, f)
     **for** cl **in** os.listdir(f_path):
         cl_path = os.path.join(f_path, cl)
         **for** img **in** os.listdir(cl_path):
             copyfile(os.path.join(cl_path, img), os.path.join(dst_folder, cl, img)) 

结果将如下所示。我们可以把它作为我们的训练数据。

然后,我们将 10%的训练图像放入一个单独的文件夹中,用于测试。为此,我们创建一个“test”文件夹,并执行以下 python 脚本:

**import** numpy **as** np
**import** os 
**from** shutil **import** movesrc_folder = 'train' 
dst_folder = 'test' 
test_ratio = 0.1 os.mkdir(os.path.join(dst_folder, '0')) os.mkdir(os.path.join(dst_folder, '1')) **for** cl **in** os.listdir(src_folder):
     class_path = os.path.join(src_folder, cl)
     class_images = os.listdir(class_path)
     n_test_images = int(test_ratio*len(class_images))
     np.random.shuffle(class_images)
     **for** img **in** class_images[:n_test_images]:
         move(os.path.join(class_path, img), os.path.join(dst_folder, cl, img)) 

安装机器学习工具

我们将使用 Intelec AI 创建一个图像分类器。你可以从这里免费下载并安装。

训练图像分类器

Intelec AI 为图像分类提供了 2 种不同的训练器。第一个是简单图像分类器,它使用浅层卷积神经网络(CNN)。训练速度很快,但是最终的准确度可能没有另一个更深层次的 CNN 那么高。第二个是深度图像分类器,训练时间更长,但准确率更高。

首先,我们使用简单的图像分类器创建了一个训练,并开始它:

Train a simple image classifier

培训总结如下:

Training summary on test data

测试集准确率为 80%。对于一个小车型来说也算是不错的成绩了。但是我们可以做得更好。因此我们尝试了“深度图像分类器”,看看我们是否能训练出更准确的模型。

Train a deep CNN for image classification

我们得到了更好的测试集准确性:

Deep CNN training summary

我们能够通过训练更深层次的网络来提高模型的准确性。添加更多的训练数据也可能提高准确性。

专家对计算病理学有什么看法?

计算病理学副教授、2016 年和 2017 年非常成功的camelion grand challenges的协调员耶鲁安·范德拉克教授认为,计算方法将在病理学的未来发挥重要作用。

在下一个视频中,诺丁汉大学的癌症病理学教授伊恩·埃利斯,他无法想象没有计算方法的病理学:

感谢

使用的来源:

用历史数据分析优秀运动员的跑步成绩

原文:https://towardsdatascience.com/analysing-elite-running-performance-with-historical-data-b9c6bdd9c5d8?source=collection_archive---------15-----------------------

1960 Olympic marathon (credit)

简介

每个级别的跑步者都努力提高自己的成绩。无论是旨在创造新的个人最好成绩的业余选手,还是志在赢得重大比赛的精英运动员,他们都面临着同一个问题:我如何跑得更快?

这是一个引人入胜的问题,直觉上我们可以预期答案是一个复杂的因素混合物。这一分析试图通过检查关于优秀跑步者表现的历史数据来为这一讨论做出贡献。具体而言,它解决了以下问题:

  1. 历史上,优秀跑步运动员的表现是如何变化的?
  2. 奥运选手的特征(身高、体重、年龄、体重指数(身体质量指数))在历史上有什么变化?
  3. 奥运跑者的特质和成绩有关系吗?

数据

数据集可以在 Kaggle 上获得,数据清理和分析的完整过程可以在 GitHub 上找到——参见下面的参考文献部分。值得注意的是,数据的一个局限性是性别失衡——男子比赛的数据比女子比赛的数据多。这是因为直到最近,女性才被允许参加所有现代奥林匹克距离的比赛。然而,通常有足够的数据来得出结论。

分析和调查结果

性能有所提高

绘制特定事件中最佳表现(指比赛中的完成时间)与日期的图表显示,历史上表现有显著改善。图 1 中的图表(来自参考文献[4])显示了一个例子:男子 200 米的成绩在 117 年间提高了近 20%。

Figure 1: Graph showing the improvement in men’s 200 m performances over time

不仅仅是 200 米的成绩有所提高,所有项目的男女运动员都有所提高。人们很自然会想是什么因素导致了这种情况。

运动员已经适应

一个原因是现代运动员与奥运会早期的运动员有很大不同。图 2 [4]是一个例子,显示了几个奥运会径赛项目中女运动员平均年龄的变化。很明显,平均年龄增加了,男运动员也有同样的趋势。这可能是成绩提高的一个因素:运动员在达到巅峰之前花更多的时间训练,这使得他们的成绩更好。

Figure 2: Graph showing the increase in mean age of female track athletes over time

年龄的变化只是运动员特征的几个变化之一。例如,短跑运动员的平均体重指数(身体质量指数)在历史上一直在增加,而长跑运动员的平均体重指数却在下降。这显示在图 3 [4]中。这是有道理的:短距离运动员依靠高身体质量指数产生的爆发性加速度。长距离运动员不需要太多的加速度,而是需要长时间有效工作的能力——低身体质量指数有助于这一点。运动员身体特征的变化证明了他们适应了每个项目的要求,从而取得更好的成绩。

特定项目的运动员有共同的特点

图 3 [4]显示了事件距离和平均身体质量指数之间的明确关系。对于短距离项目,平均体重指数都相对较高;对于长距离项目,平均身体质量指数较低,中距离项目介于两者之间。

Figure 3: Graph showing body mass index of male track athletes

身体质量指数并不是每个事件中围绕一个明显平均值分组的唯一特征:体重、身高和年龄也显示出这种效应。例如,比赛时间越长,运动员的平均年龄就越高。

具有一系列特征的运动员表现出色

每个项目似乎都有一套特定的特征值,一个运动员最有可能表现良好的“甜蜜点”。然而,最好的表现往往来自那些与平均水平有很大差异的运动员。图 4 [4]显示了最好的(意味着最低的)女子 400 米成绩分布在很大的身高值范围内,数据中没有特别的趋势。这也表明某个特定奥运项目的运动员群体,相对于所有运动员的一般人群,身高和成绩之间没有很强的关系。年龄、体重和身体质量指数也是如此。

Figure 4: Scatter plot showing variation in women’s 400 m times with athlete height

运动员体重是一个重要因素

在所有考虑的特征(身高、体重、年龄、身体质量指数)中,决定成绩最重要的是运动员体重。图 5 [4]显示每个项目的运动员平均体重被很好地分开。特别是,比较长跑运动员和短跑运动员的平均体重:他们相距甚远。具有短跑运动员体重的运动员不太可能成为成功的马拉松运动员,反之亦然。

Figure 5: mean and standard deviation of male athlete’s weights in different events

身体质量指数,作为一个重量的函数,显示了类似的模式。运动员在不同项目中的平均身高比体重更容易重叠。这表明,在特定项目中,身高对表现的影响较小。不同项目的平均年龄有很大的重叠。这表明年龄的影响很小,尽管需要谨慎对待:数据告诉我们关于顶尖运动员的表现,而且他们的年龄范围相当窄。这些数据无法告诉我们年龄对那些年龄明显偏大的老运动员的影响。

运动员和教练的实际应用

这一分析引出了一些有用的见解。

  • 为了在某项比赛中取得优异成绩,运动员的身高、体重、年龄和身体质量指数最好接近该项比赛中奥运会运动员的平均值。了解这一点可以影响训练和运动员选择参加的项目。
  • 然而,顶级运动员表现出的特征值的范围很广,一些非常优秀的运动员的特征值远离平均值。尤塞恩·博尔特是这种运动员的一个很好的例子——对于一个 100 米短跑运动员来说不寻常的高大和沉重,但却是世界纪录保持者。
  • 在所考察的四个特征中,体重对表现的影响最大。这也是一个运动员可以通过训练改变的特征。

结论

我们看到了精英运动员的表现是如何变化的,运动员是如何变化的,并对运动员特征与表现的关系有了一些了解。这项研究只调查了四个特征——身高、体重、年龄和身体质量指数。许多顶级运动员的特征值远低于平均水平,这一事实表明,其他因素肯定对成绩有重大影响。未来研究的一个很好的机会是检查各种因素的影响,如训练计划(如每周跑步距离、举重训练等技术)、饮食和运动员特征(如最大摄氧量)。

参考

使用的数据集是:

详细的数据清理和分析,包括本文中的所有图表,可以在这里找到:

致谢

感谢那些创建了这三个数据集(参考文献[1]、[2]、[3])并在 Kaggle 上发布它们的人。

文章顶部的图片来源:维基媒体 Commons,https://Commons . Wikimedia . org/wiki/File:Abebe _ biki la _ 1960 _ Olympics . jpg,来自原始来源:https://Roma . Corriere . it/foto-gallery/cron ACA/14 _ dicembre _ 15/olimpiadi-Roma-1960-4 e5b c10c-8491-11e 4-b9cc-80 d61e 8955

使用 Kibana 和 Elasticsearch 分析蜜罐数据

原文:https://towardsdatascience.com/analysing-honeypot-data-using-kibana-and-elasticsearch-5e3d61eb2098?source=collection_archive---------12-----------------------

oneypots 是一个有趣的数据来源,应该用来加强商业网络战略。一些公司已经部署了镜像一些核心服务的蜜罐,只是为了监控黑客正在进行何种攻击,而其他公司正在使用蜜罐来丰富其他系统并建立系统规则(即,如果 IP 出现在我们的蜜罐数据中,在我们的防火墙上拦截)。然而,对于学生来说,使用蜜罐数据来了解真实的网络攻击可能是进入日志分析、机器学习和威胁情报的 f̵u̵n̵好方法。我最近发表了一篇关于如何使用 Elastic Stack (Elasticsearch,Logstash & Kibana) 部署蜜罐的帖子,在两周的时间里,蜜罐已经在 GCP(谷歌云平台)——欧盟地区上线,在这篇帖子中,我们将了解它所遭受的所有攻击,威胁者是谁,以及我们如何利用这些数据。

蜜罐下面是什么?

  • Debian 10 ( Buster ) — 2 个 vCPUs,9GB RAM & 40GB 存储。
  • 蜜罐—T-Mobile 的 Tpot
  • Elastic Stack: Elasticsearch,Logstash & Kibana 版本 6.4 (D̳o̳c̳k̳e̳r̳s̳)

T-Pot 是用于此分析的一个很好的部署,因为它包括从电子邮件服务器到 RDP 服务器的 15 个不同的蜜罐系统,这确保了我可以获得足够大的数据池。

运行在 T-Pot 中的蜜罐的完整列表:

由于数据是在 Elasticsearch 中收集的,仪表盘是可用的,但我也可以构建自己的仪表盘来更好地理解数据。如果你以前从未设置过 Elasticsearch 集群,我推荐你阅读并尝试一下 Digital Ocean 关于设置 Elastic Stack 的教程。

弹性集群分析📉

由于这是一个运行 6.8.2 版本的单节点设置,我们无法访问机器学习(需要黄金/白金许可证,但有 30 天的试用期,您可以试用一些功能,或者可以试用 2 周的弹性云)。但是,我们确实使用了第三方工具 Elasticsearch Head ,它为我们提供了集群运行情况的概述。

The Elastic Cluster

那么,这一切的意义何在?

威胁情报是简单的答案。威胁情报(Threat intelligence)或网络威胁英特尔(cyber threat intel)简称(看起来更长)被描述为,“一个组织用来了解 已经、将要或当前 针对该组织的威胁的信息。”使用这个标准定义和我们的蜜罐数据,我们可以看到我们有一个关于正在进行的攻击、谁在进行攻击以及他们针对什么端口的数据池。这些数据可用于生成英特尔报告,这些报告可输入到 SOAR 系统或用于生成报告。知道谁是持久的攻击者也会帮助你抵御他们的攻击,你对敌人了解得越多越好,对吗?对于 EWS(预警系统)来说,什么是更好的数据源?

翱翔?

安全协调、自动化和响应正在成为事件响应和管理 SIEM 平台的重要组成部分。比如 Splunk 的用户会对 Phantom 比较熟悉。一个很好的有社区版的 SOAR 平台是德米斯图拉。可以将数据从您的蜜罐弹性集群直接馈送到连接到 SIEM 的 SOAR 平台。您可以将其用作事件的丰富工具,或者搜寻零日攻击。蜜罐给你的是持续不断的“真实”攻击和恶意行为者,随着你走向自动化决策,访问真实的威胁数据将有助于丰富你的威胁情报。

最后但同样重要的是,数据!📊

正在考虑构建一个数据湖?数据越多越好,对吗?即使你是一个渗透测试人员,想要更新你的密码列表,拥有一个收集最新用户名和密码组合的蜜罐意味着如果有任何数据泄漏和凭据被使用,你的蜜罐将让你访问数据。

Shout out to everyone still using admin/admin credentials!

让我们打开蜜罐吧!🍯

由于部署的系统已经运行了一段时间,我想看看已经发生的攻击,并调查一些恶意威胁行为者。由于数据在 Elasticsearch 中,可以通过 Kibana 查看,我们不需要抓取任何日志文件,这本身就是一个胜利。

最常见的攻击是什么?

The Cowrie honeypot had over 100k attacks!

Telnet 和 SSH 蜜罐受到的攻击最多也就不足为奇了。Cowrie 是一个中高交互蜜罐,旨在吸引和记录攻击者的暴力攻击和任何外壳交互。它的主要目的是与攻击者互动,同时监控他们在认为自己已经入侵系统时的行为。你可以在这里阅读更多关于 T2 的内容。

毫不奇怪,在 102,787 起攻击中, 32,607 起 攻击来自中国,美国以适度的 14,115 攻击位居第二。

Top 10 Attacking nations

Cowrie 标记任何已知的攻击者、大规模扫描仪、不良信誉攻击者、垃圾邮件机器人和 tor 出口节点,在 102,78799.95%的攻击中,这些都是已知的攻击者,之前已经报告过恶意活动。我决定调查攻击蜜罐最多的 IP(你好,128.199.235.18🙃)并使用 AbuseIPDB 我们可以看到,该 IP 因各种恶意活动已被报告超过 928 次。

This server is hosted on Digital Ocean (I notified them)

但是他们登录后会做什么呢?

Top 10 attacker input

了解攻击者在获得访问权限后正在做什么是构建防御的关键。并非所有攻击都来自来自未知 IP 的未知用户。对于大多数 SIEMs,如果用户使用任何列出的命令,都有可能触发警报。这样,如果您网络上的用户丢失了他们的凭证,如果使用了其中的任何命令,您可以将其标记为可疑行为,并设置规则来阻止帐户,直到确认这不是违规行为。

注意:不要阻塞' top '命令,我们仍然需要它!😭

并不总是通常的嫌疑人!

A map where all the attacks have come from

网络攻击不仅仅是四大(俄罗斯、中国、美国和伊朗)。对于安全团队来说,理解这一点是制定策略的关键。定期检查您的服务在哪里被访问/攻击也有助于确定是否有任何内部破坏正在进行。

这篇文章的主要目的是向网络安全爱好者介绍蜜罐背后发生的事情,数据以及你可以用它做什么。如果您对部署自己的蜜罐感兴趣,可以看看我的教程,了解如何设置我使用的部署。然而,我确实注意到,一些蜜罐码头工人在一次小的暴力攻击后一直在敲门,我单独设置了一个弹性集群来监控服务器,看它是否受到攻击,事实确实如此。我的下一篇文章将介绍如何使用最新版本的 Elastic 来使用 SIEM 功能监控一些测试环境。我还计划清理蜜罐,并单独部署它们以进行更好的分析,并利用来自 Elastic 的机器学习。

RDPY Attacks — Not all data has to be on Excel!

斯蒂芬·查彭达玛

分析空间和时间上的运动数据

原文:https://towardsdatascience.com/analysing-movement-data-in-space-and-time-8521c5e8bf46?source=collection_archive---------14-----------------------

时间序列和数据驱动的时空动画,包含 33 只鸟(金雕),历时十年。

空间和时间上的运动数据提供了关于所研究的物体,即车辆、人和动物的行为的关键信息。

对空间和时间运动的洞察推动了许多人类和生态研究。这些研究有助于深入分析和理解复杂的过程,如动物和人类的迁移、森林火灾和自然灾害以及流动性和运输。

Somayeh Dodge, A Data Science Framework for Movement

由于数据科学、人工智能和跟踪设备,科学家现在可以研究、模拟和预测鸟类。此外,他们可以了解自己的迁移模式、迁移原因、迁移目的地以及许多其他关键问题。

在本文中,我使用来自 Movebank 的数据集进行了深入的时空分析。数据集由北美西部 10 年来 33 只鸟(金雕)的轨迹组成。

探索性数据分析

我们像往常一样用熊猫读数据。

df = pd.read_csv(“goldenEagles_dataset.csv”)
df.head()

该数据由时间戳、纬度和经度列以及鸟的个人本地标识符组成。

让我们计算出每只鸟有多少行,并用 Seaborn 绘制出来。

fig, ax = plt.subplots(1, figsize=(14,12))
sns.countplot(y=’individual-local-identifier’, data=df);

Countplot

大多数鸟都有超过 500 分,但是我们也有超过 1000 分的鸟。低于 100 分的鸟可能是由于死亡或追踪器的技术问题。

让我们用简单的一行代码创建一个点的 Plotly Express 地图。

px.scatter_mapbox(df, lat=’location-lat’, lon=’location-long’, zoom=2, width=900, height=800)

Plotly Express 是 Plotly 的高级 API。有些人甚至把 Plotly Express 比作 Seaborn 之于 Matplotlib。从下面的地图可以看出,鸟类的飞行轨迹大多是墨西哥和北美的狭窄走廊。接下来我们将更深入地分析,但是现在,一些异常值需要我们注意——海洋中的那些点和东部的其他一些点是异常值。

数据集具有来自算法标记以及手动标记的离群值列。我们可以根据纬度和经度进行排除,但由于数据集中有标记异常值,我们从数据帧中过滤掉这些标记异常值。

# Filter out outliers
df= df[(df[‘algorithm-marked-outlier’].isnull())&(df[‘manually-marked-outlier’].isnull())]# Plot scatter map with Plotly Express
px.scatter_mapbox(df, lat=’location-lat’, lon=’location-long’, zoom=2, width=900, height=800)

如下所示,这是我们去除异常值后的曲线图。

最后,对于我们的探索性数据分析,我们参考数据集附带的参考表来了解这些鸟的附加属性。

ref_df = pd.read_csv(“reference_table.csv”)
ref_df.head()

下表显示了引用表的一些列。我们这里有一些有价值的栏目,可以揭示这种鸟的特征,即性别、产地、生命阶段和部署日期。

Reference table

这是这张桌子的一些引人注目的图像。

fig, ax = plt.subplots(2,2, figsize=(18,12))
sns.countplot(ref_df[‘animal-sex’], ax= ax[0,0])
sns.countplot(ref_df[‘animal-life-stage’], ax= ax[0,1])
sns.countplot(ref_df[‘study-site’], ax= ax[1,0])
sns.countplot(ref_df[‘age’], ax= ax[1,1])
plt.tight_layout()
plt.show()

下图显示了某些特征的计数图。左上角显示了雌鸟和雄鸟的分布——大多数鸟碰巧都是雄性。右上是部署开始时动物的年龄等级或生命阶段。左下显示了最初的研究地点,而右下是鸟类的年龄分布

Counplots

此外,在追踪这些分类特征的过程中,我们可以将鸟的年龄联系起来。比如我们可以看到学习地点和年龄的关系。

sns.catplot(x=”age”, y=’study-site’, kind=”boxen”, orient=”h”, height=8, aspect=10/8, data=ref_df);

现在,我们对数据集有了更好的理解,让我们进入动画和分析运动数据。然而,在此之前,我们将引用表合并到我们的数据框架中。

df_merged = pd.merge(df, ref, left_on=”individual-local-identifier”, right_on=”animal-id”)

这些鸟迁徙到哪里?什么时候?

让我们为数据帧创建一些时间戳。

df_merged['month'] = pd.DatetimeIndex(df_merged['timestamp']).month
df_merged['month_year'] = pd.to_datetime(df_merged['timestamp']).dt.to_period('M')
df_merged['quarter_year'] = pd.to_datetime(df_merged['timestamp']).dt.to_period('Q')
df_merged['quarter'] = df_merged['quarter_year'].astype(str).str[-2:]
df_merged['month_year_st'] = df_merged["month_year"].dt.strftime('%Y-%m')

上面显示的地图很拥挤,并且没有提供太多关于它们何时何地迁移的信息。这就是动画发挥重要作用的地方。

让我们首先为一年中的每个月(从 1999 年到 2009 年)制作鸟的动画。

px.scatter_mapbox(df, 
     lat=’location-lat’, 
     lon=’location-long’, 
     color= ‘individual-local-identifier’, 
     animation_frame=”month_year”, 
     zoom=2
 ).update(layout={“mapbox”:{“style”: “satellite-streets”}})

下面的 GIF 展示了数据集十年来每个月每只鸟的动画。

更好的洞察力,但不是那么细粒度的运动洞察力,因为这显示了一年中所有月份的顺序。然而,你可以看到这些鸟往返于墨西哥、美国和加拿大的所有动向。我们还可以将所有数据汇总到一年的各个季度,并制作动画,看看是否有什么模式。

px.scatter_mapbox(df_merged, 
 lat=’location-lat’, 
 lon=’location-long’, 
 color= ‘study-site’, 
 animation_frame=str(‘quarter’), 
 zoom=2,
 )

此外,这是基于季度的动画的 GIF。

这一较高的总量显示了一种更好的模式。在 Q1,几乎所有的鸟都在美国境内,只有少数在加拿大。相反 Q3,没有一只鸟在墨西哥。

结论

在本教程中,我们已经看到了如何通过使用 Panda 和 Plotly 库制作鸟类迁徙动画来获得洞察力。本文的代码可以从 Github 获得。

[## shaka som/运动

空间和时间中的运动数据提供了关于所研究物体(即车辆)行为的重要信息

github.com](https://github.com/shakasom/movement)

要直接体验本教程,请通过以下链接使用 Binder,无需任何安装。

[## GitHub:shaka som/运动/大师

单击运行此交互式环境。来自活页夹项目:可复制、可共享、交互式计算…

mybinder.org](https://mybinder.org/v2/gh/shakasom/movement/master)

使用 Python 和 Jupyter 笔记本分析调查数据

原文:https://towardsdatascience.com/analysing-survey-data-with-python-and-jupyter-notebooks-f0339ccd989d?source=collection_archive---------11-----------------------

笔记本环境非常适合处理调查数据的特殊性质

调查是数据世界的变形虫。不是因为它们会吃掉你的大脑(反正不是字面上的意思),而是因为它们的形状和结构一直在变化。

即使是那些旨在保持不变的调查——定期追踪我们对从政客到马桶刷等一切事物的感受的研究——也在不断变化。客户以他们可爱的创造力,抛弃问题,发明新的问题,并想出无穷无尽的新聚合来执行结果。

在本文中,我们将展示为什么 Jupyter 笔记本,一个交互式脚本和故事讲述环境,与 python 库 Quantipy 相结合,是驯服食脑者并使他们屈从于我们意愿的完美工具集。

A screenshot of a Jupyter Lab setup optimised for analysing survey data with the Python open source library Quantipy. The window on the right shows a list of all the variables in the data for quick lookup.

从 SPSS(或 CSV 或 ddfs)导入数据

调查数据通常一方面存储为数据,另一方面存储为元数据。在 SPSS 中,用户可以查看数据(在下图的左侧)或变量信息,即元数据(在图像的右侧)。

SPSS splits the data and the variable information (the metadata) into two seperate views. The open source python library Quantipy can read SPSS and other survey specific file types and remove the pain of mapping the numeric results in the data to human readable labels.

开箱即用,python 并不擅长处理丰富的调查元数据,其主要用途是处理结构简单得多的事务性数据。这意味着,在我们使用标准 python 库运行计算之后,我们必须将元数据中的变量标签映射到我们的结果上(清楚地表明,在我们的输出中,相对于“1”的百分比数字实际上是指“男性”)。这在处理 python 无法理解的专有数据格式(如 Unicom Intelligence 的 ddf/mdd 文件)时变得更加棘手。

但是,Quantipy 为 SPSS 和 Unicom Intelligence(以前称为 Dimensions)文件提供现成的阅读器,并将数据和元数据转换为 pandas 数据框架和自己的元数据模式。

快速浏览结果

我们首先命名并创建一个数据集(数据集就是数据和元数据的组合):

dataset = qp.DataSet("Customer satisfaction wave 1")
dataset.read_spss("customer_satisfaction.sav")

Quantipy 将响应存储在 dataframe( dataset._data)中,将元数据存储在 python 字典(dataset._meta)中。我们可以通过查看字典的 columns 元素来引用关于特定变量的元数据。

dataset._data.head()
dataset._meta['columns']['gender']

数据部分看起来和在 SPSS 中一样,但是 json 元数据模式是 Quantipy 独有的。它支持多种语言和各种类型的变量(列):单选、分隔集和网格。

Quantipy 提供了一个方便的快捷功能,可以通过命令查看元数据

dataset.meta('gender')

那么,让我们看看有多少男性和女性做了顾客满意度调查。

#the pct parameter decides whether we show percentages or the count
dataset.crosstab(“gender”, pct=True)

等等,我们知道只有 59%的顾客是女性,但她们却是调查对象的 64.1%。我们需要权衡我们的变量,这样我们的结果才能真正代表我们的客户群。

对答案进行加权以正确代表总体

我们将使用 Quantipy 的 RIM 加权算法实现(它有其他加权选项),这允许我们使用任意数量的目标变量进行加权。在这种情况下,我们只使用一个;性别。

# Quantipy's Rim class implements the RIM weighting algorithm
scheme = qp.Rim('gender weights')# Men should be 41% and women 59%
scheme.set_targets({'gender':{0: 41, 1: 59}})dataset.weight(scheme,
               unique_key='RespondentId',
               weight_name="Weight",
               inplace=True)

当 Quantipy 运行权重时,它会生成一个权重报告,这允许我们仔细检查权重是否做了任何疯狂的事情。这里的最大重量是 1.14,我们对此很满意。现在,我们的数据集中有了一个新变量,叫做“权重”,我们可以在计算中使用它。

dataset.crosstab(‘gender’, pct=True, w=’Weight’)

现在我们可以看到,我们的客户群中有 41%是男性,这在结果中并没有被低估。

快速可视化我们的结果

我们在 Jupyter 实验室环境中的事实意味着我们可以很容易地看到结果。我们关注价格变量,它显示了客户对定价的满意程度。

dataset.crosstab('price', 'gender', w='Weight', pct=True)

现在让我们想象一下,以便更好地了解结果。为了简洁起见,我们不会深入细节,但是您可以看到使用标准功能来可视化数据是多么容易。

import blender_notebook.plot as plots
plots.barplot(dataset.crosstab('price', 
                               'gender', 
                               w='Weight', 
                               pct=True), 
              stacked=False)

为未来的项目自动化我们的工作

在 Jupyter 笔记本上工作还有另外一个好处:它让我们的笔记本可以重复使用,从而使我们的工作自动化。基于网飞数据科学团队的想法(参见:B eyond Interactive:网飞笔记本创新),我们之前已经报道过如何自动化数据处理任务,如清理、加权和重新编码以及如何自动化生成 PowerPoint 幻灯片组。这些都是因为我们的工作是在笔记本上完成的。

Jupyter 笔记本正在数据科学界掀起风暴,这一次,调查数据分析不应落后。用笔记本分析调查数据消除了数据处理专业人员和研究人员的全部痛苦,并能对双方的生产力产生奇迹。

Geir Freysson 是 Datasmoothie 的联合创始人,这是一个专门从事调查数据分析和可视化的平台。如果你对使用开源软件进行调查数据分析感兴趣,注册我们的时事通讯,名为自发认知

分析美国队对澳大利亚队的篮球推文

原文:https://towardsdatascience.com/analysing-team-usa-vs-australian-basketball-tweets-using-rtweet-in-r-465b62a29a5d?source=collection_archive---------27-----------------------

在 R 中使用 rtweet 和 tidyverse

2019 年 8 月 24 日,澳大利亚男子篮球队 Boomers 创造了历史,他们能够上演自己的大卫和歌利亚时刻,有史以来第一次击败美国队。更令人印象深刻的是,美国队 13 年来从未输过一场比赛。这是澳大利亚篮球历史上的一个奇妙时刻,当美国派出了被广泛认为是他们中较弱的球队之一时,这是一个让我们都回味的时刻。不管结果如何,我们能够让世界上最好的国家参加表演赛,这是值得庆祝的。

事实并非如此…

在漫威体育场历史性的第一场男子篮球赛后,媒体的叙述似乎充满了负面,主要集中在昂贵的座位上,球迷的视野很差。

我怀疑这种情况在任何地方都会发生,但我们澳大利亚人似乎比大多数人更容易让自己的观点摇摆不定——当事情进展不顺利时,我们非常乐意取笑个人或团队,但当事情进展顺利时,我们会迅速转变态度(尼克·克耶高斯打招呼)。

这项分析将着眼于两场比赛前后的 Twitter 活动,试图证明或反驳叙事的变化。

为了收集 tweet 数据,使用了rtweetROAuth包。blow analysis 收集并分析了 8 月 22 日至 8 月 25 日下午 2 点之间的推文。使用官方标签- #BoomersUSA引用@BasketballAus的推文被删除。

这个项目的完整代码库和数据可以在这里找到

如果这条推文是在2019-08-24 04:00:00 UTC(第二场比赛的提示时间)之后录制的,它将被归类为Game2 Starts中的推文。这使得我们可以将历史性的第二场比赛之前的推文与神奇之夜期间和之后发生的推文进行比较。

推特分析

查看自第一场比赛以来的所有推文,我们可以看到第二场比赛每小时的推文更多。毫无疑问,令人震惊的结果在其中起了很大的作用。

Tweets per hour peaked during the historic game 2

在 4019 条“收藏夹”中,NBATV 的以下推文是最受欢迎的推文:

感觉棒极了。…我希望我们都能以此为基础。@Patty_Mills 描述了他带领篮球队首次战胜美国队后的心情

在所分析的时间段内,被转发次数最多的推文来自 NBL,有 833 次转发。推文是:

第四节帕蒂·米尔斯是一件艺术品🔥# BoomersUSA @ SBSVICELAND @ SBSOnDemand

使用的 TWEET 单词

在我们可以测量推文的情绪之前,推文字符串需要被分割成“令牌”(或单个单词)。

一旦这些标记被取消嵌套(分离),我们就可以画出最常用的单词。重要的是,停用词和其他我们在分析中不想要的词已经被省略了。停用词包括“and”、“the”、“a”等,这些词对情感分析没有太大帮助。此外,“BoomersUSA”被删除了,因为这是游戏的标签,几乎在所有的推文中都会提到。

下面列出了第二场比赛前后推特上最常用的 20 个词。

不出所料,“座椅”、“塑料”、“座椅”是第二场比赛开始前推特中频繁出现的词汇,而第二场比赛开始后推特中只出现了“座椅”。对于第二场比赛开始后的推文,“历史”,“帕蒂·米尔斯”,“真棒”和“爱”都频繁出现在推文中——非常软和糊状嘿?

Not so many seating issues for tweets after game 2 started (left panel)

下面的图表可以让我们更好地了解第二场比赛前后使用的单词之间的差异。贯穿剧情的对角线右下方的单词表示在第二场比赛之前在推特上更频繁使用的单词,而该线上方的单词在第二场比赛期间和之后更频繁使用。

看起来我们终于是快乐的一群了…

推特情感分析

一旦标记被分离,就可以计算情感分数。

将使用的方法是由芬恩·厄普·尼尔森(http://www2.imm.dtu.dk/pubdb/views/publication_details.php?)创建的情感分析常用词典 id=6010 ),称为 AFINN 词典。更积极的词(比如“棒极了”)比更消极的词(比如“崩溃了”)得分更低,前者得分更低。

为了感受情绪分析的力量,下面这条推文是最积极的推文,积极指数为 17:

对婴儿潮一代今天的胜利感到非常激动,帕蒂·米尔斯在关键时刻表现得非常出色。非常棒的团队合作。带来世界杯!#BoomersUSA

在光谱的(完全)另一端,下面的推文是最负面的,得分为-18(抱歉,我已经尽最大努力清除它们):

谁他妈的!&%雇了这些人来组织这次活动,真是愚蠢!&%ing bs stich up。邦宁斯的$椅子有分叉的障碍吗?&%.像 WTF 一样,投资建造体育场的公司肯定没有那么穷。#BoomersUSA

不出意外,最积极的推文是在我们赢了之后,最消极的是在第一场比赛之后。

绘制每条推文的情绪得分分布,我们可以清楚地看到,第二场比赛开始后的推文变得更加积极——这些推文的积极得分中位数(积极词与消极词的比率)为 0.95,是第二场比赛前推文中位数 0.43 的两倍多。

正如我所料,我们在历史性的胜利后变得更加开心…几乎到了忘记座位“崩溃”的地步,尽管第二场比赛是在确切的场地进行的,座位安排也是确切的…非常奇怪。

总有一天,我会将我们澳大利亚人的这一理论进行终极测试,看看我们如何回应基尔吉奥斯的成功……如果他尝到了终极成功的滋味!

本帖原创,发布在不怪数据博客【https://www.dontblamethedata.com】

分析英国退出欧盟的影响:统计方法

原文:https://towardsdatascience.com/analysing-the-effects-of-brexit-a-statistical-approach-aeb276289fa3?source=collection_archive---------12-----------------------

了解英国退出欧盟事件如何影响我们周围的世界

Photo by Habib Ayoade on Unsplash

依我拙见,数据科学家的武器库中最强大的武器之一无疑是将统计应用于特定用例的能力,以提取关于相应数据的底层结构的有意义的见解。通过统计建模和分析,数据科学家将能够更好地理解正在研究的领域;从而为进一步的机器学习建模和其他分析打下坚实的基础。因此,鉴于我的背景,我决定加强我的统计能力,这是我所知道的唯一有效的方法——用用例来练习。

随着对英国退出欧盟越来越多的关注,我立即发现这是一个绝佳的实践机会。下面是不同过程、技术和分析的总结。

首先,我想从最重要的英国退出欧盟事件开始,如下图所示。

The Major Brexit Events

获得这些主要数据后,我们就可以着手分析、关联和测试这些英国退出欧盟事件和其他影响之间的潜在因果关系。这一统计分析背后的计划如下:抓取重大事件,分析英镑/欧元汇率、英镑有效汇率指数、英国交易数据、英国消费者价格指数,最后分析对加密货币金融市场的影响。

英镑/欧元汇率

OHLC

从 2014 年 1 月 1 日到 2019 年 6 月 19 日的英镑/欧元历史汇率数据是通过 quantmod R 的软件包从雅虎财经获得的。第一步是按年份分组,以便能够绘制 OHLC 图表,并计算每一年的一些描述性统计指标。

OHLC 图是一种条形图,显示每个时期的开盘价、最高价、最低价和收盘价。OHLC 图表很有用,因为它们显示了一段时间内的四个主要数据点,收盘价被许多交易者认为是最重要的。— 投资媒体

此外,在 OHLC 图表的顶部,还绘制了各种其他统计图表,如布林线(BB)、移动平均线收敛背离(MACD)、变化率(ROC)、随机动量指数(SMI)、相对强弱指数(RSI)、商品通道指数(CCI)、止损反转(SAR) 。这些图表都提供了对特定时间序列所遵循的趋势的统计洞察。不用说,这些统计工具在金融交易和投资领域被广泛采用。

OHLC charts of the GBP/EUR Exchange Rate along with some other statistical charts.

因果效应

除了分析 OHLC 价格,我还想确定一个特定的事件是否对时间序列有直接的因果影响。经过一番研究,我找到了谷歌发布的这篇论文,它完美地完成了我想要分析的内容。简而言之,本文介绍了一种通过构建贝叶斯结构时间序列模型来确定单个事件因果影响的统计显著性的方法。反过来,这个模型然后被用来预测时间序列可能是什么样子,假设该事件从一开始就没有发生过。然后,基于贝叶斯单侧尾区概率,获得 p 值来说明这种因果影响的统计显著性。

Causal Impact Result Visualisation taken from the package’s Github page.

此外,所提供的软件包还可以生成可视化结果(如下图所示),并能够将统计结果输出为通俗易懂的报告。总之,感谢参与这项研究的每一个人。工作做得非常好!

分析

基于上述设想,2016 年初,英镑相对于欧元的价值遭受重创,英镑/欧元汇率开始下跌。正如布林线(描述波动性)所示,英镑/欧元汇率波动极大,在上下区间波动。然而,在 2016 年 6 月(英国退出欧盟投票)前后,汇率遭受了毁灭性的负面影响,导致不断触及布林波动较低波段。与此一致,MACD 也支持英国退出欧盟投票对汇率产生负面影响的假设。后者主要是因为 MACD 线已跌破信号线,而不是投票前后的时间点,这似乎更符合信号。同样,中华民国路线也支持和暗示英国退出欧盟投票所带来的不利影响的事实。就在 2016 年 7 月开始之前,ROC 线描绘了一个急剧的负尖峰,这强烈表明熊市投资,意味着投资亏损。此外,在构建贝叶斯模型并测试获得这种效果的概率后,获得的 p 值具有统计学意义;因此,这表明英国退出欧盟的投票确实损害了英镑/欧元的汇率。

同样,SMI 也暗示了 2016 年 6 月下旬左右的看跌投资,该信号继续下降到 2016 年 7 月的最终低点-60(投资者通常认为 SMI-40 是高度看跌的趋势)。除此之外,基于 RSI,作为投资的英镑/欧元似乎在 2016 年 6 月下旬极度走软。诚然,蜡烛图以及之前讨论的统计方法似乎在 2016 年 7 月中旬开始企稳,这大约是特里萨·梅(Theresa May)被任命为英国首相的时间。然而,这一事件在统计上可能不会对汇率产生积极影响,因为汇率在今年剩余时间里仍然高度不稳定。这一结论也得到了因果贝叶斯推理模型的支持,该模型得出了一个不显著的 p 值。

进入 2017 年,英镑/欧元外汇收盘价再次持续触及布林带下轨,导致持续高度波动的下行模式,主要是在参考 ROC 图时。今年的第一个重大英国退出欧盟事件发生在 1 月 17 日;因此,大约在那个时候,所有图表都显示汇率收盘价出现了负峰值。CCI 甚至达到了-200 的数值,证明了在那个时候,汇率遭受了坚定的下跌趋势。除此之外,还可以看到 SMI 线已经跌破了均线信号线。此外,当在原始时间序列上绘制 SAR 图时,除了确认 1 月中旬的大幅下跌之外,它还突出了该月剩余时间内收盘价的上涨。同样,这种变动可能与这一汇率表现出的极度波动行为高度相关,因为从贝叶斯模型获得的 p 值未能拒绝具有统计显著性的零假设。CCI 表明 2017 年 3 月下旬左右的看涨趋势(绝佳的投资机会-表明未来收盘价上涨),这可能与里斯本条约第 50 条的触发有关,这也导致了因果推断的统计显著 p 值。在此期间,汇率达到了今年迄今为止的最高值。正如 CCI 所代表的,汇率的下一个令人兴奋的运动将发生在 2017 年 5 月下旬,接近英国大选(6 月 8 日)。

此外,CCI 的分析也潜在地暗示了 6 月初的稳定下降;然而,像 SMI 和 RSI 这样的其他方法在这一天似乎没有受到太大的影响。因此,解释这种行为的一个假设可能是,投资者可能在选举日之前就采取了行动,从而产生了早期效应。为了支持这一结论,2017 年 4 月 18 日举行了一次提前选举,因此,这也是今年最重要的价值下跌的开始,在 8 月底达到最低点。因此,这是一个非常可行的假设,即提前大选的影响主要是在事件本身之前观察到的。接下来,从尾区概率获得的 p 值显示了对汇率的统计上显著的不利影响。

今年的最后一件大事是北爱尔兰无缝边境支持协议(12 月 8 日)。从年底到 2018 年,收盘价似乎再次上涨,这是有道理的,因为支持协议将意味着英国与欧盟保持密切的关系。一致的是,在构建贝叶斯模型之后,p 值也显示出在这一事件之后统计学上显著的值增加。此外,2018 年的表现与前几年非常相似,显示出类似的波动特征,市场数据在布林线之间来回波动。ROC 似乎相当稳定,只有 6 月下旬(负峰值)和 11 月下旬(负峰值)是例外。巧合的是,在此期间,也有两个与英国退出欧盟相关的重大事件,可能引发了极端运动。然而,CCI 圆图在这些时期没有显示出显著的效果,并且 SMI 似乎平滑地跟随信号,然而,发现在影响负面效果方面是显著的(两个 p 值都< 0.05)。

目前,2019 年似乎为英镑/欧元汇率提供了一些稳定性。虽然仍然相当不稳定,但 CCI、SMI 和 RSI 图显示交易中性,尤其是在 2 月和 4 月之间,价值似乎也相对保持在布林线之间。在 1 月 15 日和 3 月 12 日,May 失去了两次必要的投票,这两次投票都导致了所有统计指标的上升趋势,这是基于获得的尾部区域概率 p 值的具有统计意义的结果。此外,英国退出欧盟的初始结束日期(2019 年 4 月 12 日)导致价值下降,后来通过延迟英国退出欧盟的决定重新平衡。令人惊讶的是,乍一看,梅的辞职似乎并没有改变交易所的行为,因为 ROC 图显示当时几乎没有显著的变化率;尽管如此,ROC 图表明,在该特定事件之后,交易所的价格可能会上升(正的 ROC 表明潜在的看涨趋势)。此外,使用贝叶斯模型获得的 p 值表明对英镑/欧元值有显著的不利影响。然而,如上所述,ROC 非常小,并且积极影响的指示也没有得到其他指标的支持。

Analysing the Statistical Significance and Impact (positive or negative) of the Causal Effect on the GBP/EUR per Major Brexit Event.

英镑/欧元投资风险

为了有效地确定构建风险评估的最佳模型,我们必须首先检查正态性、独立性和统计平稳性

Basic Descriptive Statistics for the GBP/EUR Exchange per year.

首先,对组成时间序列的描述性统计数据进行一些分析对于开始理解这些数据的基本结构是必不可少的。2016 年是方差最大、负偏差最大、对数收益峰值最高(峰度较高)且均值最低(也是负值)的一年。计算归一化的对数回归,并绘制成折线图和直方图,以便更好地理解回归的密度,同时还绘制了一些描述性统计数据,如下所示。

Descriptive Statistics Plots for GBP/EUR Closing Log Returns per year.

此外,如下所示,对数回归时间序列通过降低其幅度进行了清理,然后绘制在原始对数回归时间序列上,这有助于提供一些关于潜在异常值的见解。

Outlier Detection for the Closing Log Returns of the GBP/EUR

此外,还创建了每年对数收益的分位数-分位数(Q-Q)图。很明显,Q-Q 图显示了一些偏离正态分布的情况,表明这个时间序列并不遵循高斯分布。为了进一步检查正态性,进行了两个统计测试——Jarque-Bera 测试(对整个时间序列执行)和夏皮罗-维尔克测试(每年子集)。对于这两种检验,零假设表示数据确实来自正态分布。Jarque-Bera 测试得出 p 值< 0.05;因此,拒绝了零假设,并确认了从 Q-Q 图得出的结论。

此外,对数据子集(每年)运行夏皮罗-维尔克检验,得出 2014 年、2016 年、2018 年和 2019 年的 p 值< 0.05,这进而拒绝了正态性的零假设。此外,在其他年份,测试未能拒绝零假设。尽管如此,鉴于股票市场数据不遵循正态分布的已知性质,假设这些年也不遵循正态分布。这个假设也是基于这样一个事实,即整个数据集上的 Jarque-Bera 测试返回了一个显著的 p 值。为了检验时间序列的独立性,使用了永盒检验。该测试获得了一个不显著的 p 值;因此,不能拒绝自相关的零假设。基于这个测试,然后假设这个时间序列没有任何自相关。最后,使用扩展的 Dickey-Fuller 检验来检验平稳性,其返回了拒绝单位根的零假设的显著 p 值。基于这些统计检验,构建了 AR 和 MA 值为 0 的 ARIMA 模型。通过构建扩展的自相关和互相关函数(EACF)来选择这些值。使用 ARCH 的拉格朗日乘数(LM)检验对 ARIMA 模型的残差进行了检验。该测试返回的 p 值是显著的;因此,表明 ARIMA 模型的残差中存在 ARCH 效应。由于没有 ARCH 效应的零假设被拒绝,该时间序列然后由 GARCH 模型建模。

在拟合时,模型的拟合优度使用调整后的皮尔逊检验进行测试,结果发现残差之间没有相关性。拟合优度也使用 Box-Ljung 检验进行了测试,该检验未能拒绝零假设。因此,基于这两个结果,该模型被认为是一个很好的拟合。

此外,如侧图所示,绘制了自相关函数(ACF)和偏自相关函数(PACF)、Q-Q 图和标准化残差的经验密度,以进一步总结拟合模型。使用拟合的 GARCH 模型,绘制了对数收益波动率,如下所示。

Volatility plots of the GBP/EUR exchange based on the GARCH Model

最终,使用 GARCH 模型和蒙特卡洛模拟,计算出未来 20 个交易日的投资风险,结果是-2.784%,显著性水平为 0.05。因此,该风险分析表明,英镑/欧元汇率高度波动且不可预测,任何外汇投资都可能导致不良结果。

英镑有效汇率指数

作为有效模拟英镑汇率强度的尝试,英镑有效汇率指数的历史数据以. csv 文件的形式从英国国家统计局获得。然后将指数时间序列可视化,并在图上添加代表主要英国退出欧盟事件的标记。该图的强大之处在于能够进一步支持前面讨论的因果推断分析,并且能够有效地将欧元的类似兑换行为映射到其他货币。

英国贸易数据

分析英国进出口贸易数据的目的是为了了解英镑汇率的实际波动,以及英国退出欧盟以外的外部事件对英镑汇率的影响。与前一小节类似,对这一方面进行的主要分析集中在按国家显示进出口数据的流动。通过使用垂直线标记,每个标记代表一个特定的英国退出欧盟事件,可以估计对单个国家的价值的影响。从结果来看,英国退出欧盟事件和各自与欧盟国家的进口关系之间似乎没有关联。然而,德国似乎是一个例外,在英国退出欧盟发生重大事件后,德国的进出口似乎都出现了变化。诚然,这一特征可以用不断增长的物质市场和人口来解释,这反过来会导致更多的进口和出口。

另一方面,英国退出欧盟事件后,来自/非欧盟国家的进出口似乎受到很大影响。无论是进口还是出口,数量似乎都会在特定事件发生后立即激增,这表明了直接的因果关系和影响。这种行为在中国、挪威和美国尤其明显。因此,根据这一分析,可以假设英国退出欧盟事件对英镑汇率指数有很大影响;然而,进一步的假设检验将有助于接受这一基于统计学意义的观察结果。

UK Trading Data filtered by the top EU and non-EU Countries.

英国消费者价格指数

这部分分析是为了更好地理解英国退出欧盟事件如何影响英国的生活质量。选定数量的消费物价指数(从英国国家统计局获得)的原始时间序列数据被绘制出来,通货膨胀百分比也是根据这些数据计算出来的。虽然所有被调查的消费物价指数都受到通货膨胀持续上升的影响,但似乎没有明显的迹象表明这些指数受到英国退出欧盟事件的深刻影响。尽管如此,值得一提的是,从英国退出欧盟交易开始(2016 年 6 月),英国公民的平均生活成本上升了 6.362%。同样,这种差异可能被认为是不属于本分析项目调查范围的其他事件。

UK Inflation for a number of CPI’s.

加密货币金融市场

Top 10 Cryptocurrencies by Market Cap.

如上图所示,目前市值排名前 5 的加密货币分别是比特币、以太坊、Ripple (XRP)、莱特币、比特币现金。因此,这五种加密货币在一些英国退出欧盟事件后的表现也进行了分析。从比特币开始,英国退出欧盟似乎对其价值产生了积极影响。

在每一次重大的英国退出欧盟事件之后,比特币的价格都会上涨。在使用贝叶斯推理对时间序列进行建模后,突然大选和支持交易的因果影响概率为 0.9998,尾部概率为 0.0002。因此,根据构建的贝叶斯模型,英国退出欧盟事件对比特币价值的明确提升具有统计学意义。

同样,以太坊在后台交易会议后的价格上涨也导致了统计上的显著性。以以太坊为例,在' lost '标记处,事件发生后价格似乎会下跌;我们还对这种潜在的因果关系进行了调查,得出了一个不显著的结果,该结果可以解释为基于英国退出欧盟以外其他不同事件的随机波动。英国退出欧盟事件似乎也没有影响莱特币的走势,使其流通在整个时期相对稳定。然而,也有人指出,在背景会议后的一段时间内进行的测试导致 p 值<为 0.05,这使得莱特币在统计上具有显著的正面因果影响,约为+150%。比特币现金也受益于显著的积极影响,有时收益高达 100%。同样,Ripple 似乎也受到了这些英国退出欧盟事件的积极影响;然而,在这种情况下,涨幅只有 10%左右。

总结

总之,该分析彻底调查了英国退出欧盟事件如何影响英镑/欧元外汇指数以及加密货币金融市场。除此之外,作为分析的一部分,英镑有效汇率指数也进行了研究,以更好地了解英镑在整个外汇市场的实际实力。这种分析允许将使用英镑/欧元兑换调查的结果复制到英镑兑换的其他货币,从而允许进行更全面的分析。此外,该项目还考虑了英国进出口贸易数据方面,其中主要国家(欧盟和非欧盟)的贸易量以及英国的通货膨胀率都进行了检查。这一方面为关于英国退出欧盟事件和 GBP 事件之间的相关性和因果关系推论的评论提供了更确凿的证据。这一部分有助于确定英镑的升值或贬值是直接受到英国退出欧盟的影响,还是受到其他外部因素的影响,如进出口贸易的下降/上升。

此外,该分析还提供了一个额外的分析视角,即英国退出欧盟是否对英国的进出口货物贸易有任何影响。反过来,这个项目在建立统计知识和应用于现实世界的基础方面具有很高的价值,并成为真正展示适当的统计分析和建模的好处的一种方式。此外,尽管这一分析面临一些限制,如没有考虑其他股票市场,特别是欧盟内部的股票市场,或者未能从统计上证明对英国进出口贸易的重大影响,但这一分析仍然设法得出了相对可靠和结论性的结果。

扩展这项工作

  1. 考虑其他金融市场,如富时 100 指数、标准普尔 500 指数和道琼斯工业平均指数。
  2. 通过纳入其他国家的贸易数据,对比变化率,对进出口贸易数据进行更深入的统计分析。
  3. 分析英国退出欧盟对汇丰银行、劳埃德银行和巴克莱银行等英国公司的影响。
  4. 分析英国退出欧盟对英国和欧盟失业率的影响。

这个项目的更多信息和完整源代码可以在这个 GitHub 资源库中找到。

如果你想联系——davidfarrugia53@gmail.com

Linkedin——Twitter

熊猫艺术调查分析

原文:https://towardsdatascience.com/analysis-of-an-art-survey-using-pandas-ea782c0d0691?source=collection_archive---------28-----------------------

熊猫 是用于数据科学Python 开源库,它允许我们轻松地处理结构化数据,如 csv 文件SQL 表Excel 电子表格。在这篇文章中,我们用熊猫来分析布拉迪斯拉发的夸美纽斯大学统计学学生进行的艺术调查的结果。学生们被要求从 1 到 5(意思是 1“一点也不喜欢”)给 39 幅知名画作打分。该数据集包括评级,以及绘画、艺术运动和艺术家的名称,每个艺术运动包含 3 幅绘画。数据集可以在中找到。 Kaggle 是一个数据科学家和机器学习者的在线社区,其中包含了各种各样的数据集

** [## 涂漆

学生评价不同艺术运动的名画。

www.kaggle.com](https://www.kaggle.com/miroslavsabo/paintings)

探索性数据分析和数据清理

探索性数据分析包括分析数据集的主要特征,通常采用可视化方法汇总统计。目标是理解数据,发现模式和异常,并在我们执行进一步评估之前检查假设。

从 Kaggle 下载 csv 文件后,我们可以使用Pandas . read _ CSV函数将其加载到 Pandas dataframe 中,并使用 pandas 可视化前 5 行。data frame . head方法。

由于列的数量太大,我们无法使用 head 方法看到所有的列。一种选择是改变显示选项,以便我们可以可视化整个数据帧。另一种选择是使用列属性,如下所示:

正如我们所看到的,dataframe 包含 51 列:48 个评级,以及绘画、艺术运动和艺术家的名称。学生们总共给 39 幅画打分。

不适当的数据类型和缺失值是数据集最常见的问题。我们可以使用 熊猫轻松分析这两者。data frame . info方法。这个方法打印关于数据帧的信息,包括索引数据类型和列数据类型、非空值和内存使用情况。

我们已经验证了不存在空值,并且数据类型是预期的类型。列 S1-S48 包含整数,其他列(艺术运动、艺术家和绘画)包含对象(熊猫中的字符串)。在这种特殊情况下,我们不需要执行任何清理操作,但这与其说是一种规则,不如说是一种例外,因为数据集通常非常混乱。

我们还可以评估数据集是否包含空值,如下所示:

或者,我们可以使用熊猫来评估数据类型。DataFrame.dtypes** 属性。这将返回包含每列数据类型的序列。**

Pandas 提供了一个名为pandas 的方法。DataFrame.describe 生成数据集的描述性统计数据(集中趋势、离散度和形状)。默认情况下,describe 方法只分析数字列,但是它也可以通过向参数 include 提供 all 来分析对象列。由于 describe 方法返回的 summary 是一个 dataframe,我们可以通过使用 pandas 轻松访问它的元素。DataFrame.loc 方法。

如上图所示,每个学生总共评价了 39 张图片。我们还可以得出结论,一些学生比其他人更挑剔。例如,学生 9 给出的平均评分为 1.8974,比学生 10 低 1 分左右。除了学生 9(最大值=4)和学生 46(最小值=2)之外,大多数学生给出的最低评分为 1,最高评分为 5。虽然五个数字的摘要(最小值、25%、50%、75%、最大值)为我们提供了关于观察值分布的信息,但通过可视化的方式来分析评级的分布将会很有趣。我们会做到的!继续读😉

我们还可以验证专栏、艺术运动、艺术家和绘画中独特元素的数量,如下所示:

熊猫。series . nunicque方法返回多个唯一元素。如上所示,dataframe 包含不同艺术家的 39 幅画,包括每个艺术运动的 3 幅画。****

该数据集不包含大量样本。为此,它不需要重要的清洁操作;但是,我们可以执行一些小的更改,以便于进一步分析数据集。

  1. 消除列名中的空格→使用点符号按名称选择单个列。
  2. 通过绘画计算平均评分→评估对绘画和艺术运动的偏好。
  3. 将绘画列设置为索引→以便使用绘画名称而不是索引轻松访问信息。

执行更改后,我们可以使用数据轻松地得出结论。💪 😊我们开始吧!

回答问题并得出结论

探索性数据分析数据清理是让我们对数据集有所了解并准备好数据集以便使用它轻松得出结论的步骤。现在!我们准备使用数据集回答以下问题。****

哪 5 幅是评价最高的画?

要获得最高评分的画作,我们可以使用之前创建的平均评分栏,如下所示:

我们还可以创建一个条形图来可视化结果。条形图分类数据一起使用,其中每个条形图代表一个特定的类别。条形的高度与它们所代表的值成比例。

我们可以很容易地访问关于最佳评级画作的所有信息,如下所示:

评分最高的画作是穆卡的《四季》,平均评分为 3.96。阿尔丰斯·穆夏是捷克画家和新艺术运动大师,最著名的是他独创的女性海报,海报周围环绕着装饰性的植物图案。《四季》描绘了以乡村季节景色为背景的年轻女性。他总共画了 3 个系列(1896-1897-1900)。因为没有提供日期,我们不能断定哪个系列被展示给学生。但是都很神奇!😍

Four Seasons — Serie 1896

下面的情节描绘了其他的顶级画作。我相信你知道其中一些😍

哪 5 幅画的评分最低?

为了分析评分最低的画,我们像以前一样进行。首先,我们创建一个包含平均评级的系列。然后,我们使用条形图来可视化信息。

********

和以前一样,我们可以通过以下方式轻松访问关于最低评级绘画的所有信息:

评分最低的画是弗朗西斯科·戈雅画的裸体玛雅。戈雅是西班牙浪漫主义画家,也是 18 世纪末 19 世纪初最重要的艺术家之一。裸体的玛嘉被认为是最早展示全裸女性的肖像画之一,它可以在马德里的普拉多博物馆找到。虽然他的画是调查中评分最低的,但我不得不承认戈雅是我最喜欢的画家之一,他有大量的绘画作品,从宫廷肖像到可怕的战争场景。

哪些被认为是评价最高的艺术运动?

该数据集包含 13 种不同艺术运动的绘画:(1)文艺复兴,(2)巴洛克,(3)新古典主义,(4)浪漫主义,(5)印象主义,(6)后印象主义,(7)象征主义,(8)新艺术,(9)立体主义,(10)抽象艺术,(11)超现实主义,(12)欧普艺术,(13)波普艺术。要评估最高评级的艺术运动,我们必须计算属于每个艺术运动的三幅绘画的平均评级。我们可以很容易地通过使用 熊猫来计算。DataFrame.groupby 方法 T3。groupby 操作包括拆分对象、应用函数和组合结果的组合。

首先,我们按艺术运动分组。然后,我们计算每组的平均值。如前所述,我们可以通过使用如下条形图轻松解释结果:

如上图所示,评价最高的艺术运动是印象派。我们可以通过以下方式获得本次调查中使用的印象派画作:

哪个学生给了最高分?哪个学生得分最低?

之前,我们已经计算了每幅画的平均评分。现在,我们必须计算每个学生提供的平均评分。

前面的代码返回一个数列,其中包含每列值的平均值。我们可以按以下方式使用 head 方法观察数列的第一个值:

我们可以使用以下方法获得最高分和最低分的学生

如上所示,学生 48 提供了平均 4.05 的最高分。相反,21 号学生得分最低,平均为 1.84 分。

我们可以用柱状图直观地显示两个学生各自的分数。

********

学生如何分配他们的分数?

我们可以通过绘制之前创建的 series(students _ average)来可视化学生提供的平均评分。

毕加索的《格尔尼卡》在排名中占据什么位置?

《格尔尼卡》是西班牙艺术家巴勃罗·毕加索的一幅大型布面油画,被认为是毕加索最著名的画作之一。《格尔尼卡》展现了战争的悲剧,是为了回应西班牙内战(1936-1939)期间位于西班牙北部的小镇格尔尼卡的轰炸而创作的。这幅画位于欧洲和美洲的不同城市。佛朗哥独裁统治结束后,西班牙成为一个民主国家,这幅画于 1981 年回到西班牙。如今埃尔·格尔尼卡被认为是现代艺术和强有力的反战绘画中最重要的标志之一。

我们可以用 熊猫来获得埃尔格尔尼卡的排名位置。index . get _ locT3该方法返回特定索引的整数位置。首先,我们必须按降序对平均评级列进行排序。然后,我们将 get_loc 方法应用于系列的索引。

因为 python 和 pandas 中的索引是从 0 开始的,所以 el Gernica 的排名位置是 16。

关键要点

  • 探索性数据分析包括分析数据集的主要特征,通常采用可视化方法汇总统计。熊猫。头()。info()形容()。努尼克()。形状是探索性数据分析的有用方法。****
  • 我们可以使用来访问一组行和列。loc() 法。
  • 我们可以用熊猫。DataFrame.plot 方法使用 matplotlib 对数据帧进行绘图。图的类型在参数种类中指定。**
  • 如果未指定条形图的 x 轴,则使用数据框的索引。
  • 。value_counts() 方法返回一个包含唯一值计数序列。
  • 。sort_values() 方法用于对数据帧中的值进行排序。参数 ascending=False 用于按降序排序。

感谢阅读!!!😍**

使用 Pandas 分析波士顿犯罪事件公开数据

原文:https://towardsdatascience.com/analysis-of-boston-crime-incident-open-data-using-pandas-5ff2fd6e3254?source=collection_archive---------9-----------------------

Pixabay.com

当我在 Python 中使用 Pandas 学习数据分析时,我对分析我目前居住的城市的开放数据很感兴趣。

开放数据为人们提供了无数的机会,让他们随心所欲、不受限制地使用和分析数据。通过查看一个城市的犯罪事件公开数据,您可以了解这个城市或特定社区是否安全。因此,我使用波士顿犯罪事件报告的公开数据,通过使用 Pandas 来分析和可视化它们。希望你看完我的经历,能对获取、分析、可视化开放数据有更好的理解。

获取数据

  • 为了获得数据,我复制了下载 csv 格式数据的链接:
url = “[https://data.boston.gov/dataset/6220d948-eae2-4e4b-8723-2dc8e67722a3/resource/12cb3883-56f5-47de-afa5-3b1cf61b257b/download/tmppj4rb047.csv](https://data.boston.gov/dataset/6220d948-eae2-4e4b-8723-2dc8e67722a3/resource/12cb3883-56f5-47de-afa5-3b1cf61b257b/download/tmppj4rb047.csv)”
  • 使用wget命令下载数据。

  • 进口熊猫

import pandas as pd

  • 使用熊猫中的read_csv读取数据并保存到数据框中

df = pd.read_csv('tmppj4rb047.csv')

  • 检查是否成功获取数据。

df.head()

数据分析

1.犯罪类型

获得数据后,我想知道波士顿有多少种犯罪类型。

  • 在熊猫身上用value_counts

value_counts帮助统计不同类型犯罪的出现次数,并进行排序。

df.OFFENSE_CODE_GROUP.value_counts().iloc[:10]

为了便于展示,我只要求返回前十个结果。

Top 10 Crime Incidents in Boston

在这里,我们可以看到波士顿发生最频繁的犯罪事件是“机动车事故反应”,“盗窃”也发生得非常频繁。

然后,为了更好的可视化,我绘制了结果。

df.OFFENSE_CODE_GROUP.value_counts().iloc[:10].sort_values().plot(kind= “barh”)

2.分析具体的犯罪

我想具体分析一下波士顿的盗窃罪。因此,我将数据帧中包含盗窃的部分放到另一个数据帧中,并将其称为“盗窃”

larceny = df[df.OFFENSE_CODE_GROUP.str.contains(“Larceny”)]
larceny.head()

  • 检查“盗窃”数据的大小
larceny.shape() 

盗窃事件记录 17961 条,每条记录 17 列。

3.分析地点

我想知道波士顿不同地点的犯罪事件数据,更具体地说,波士顿哪些地方更危险。

我用熊猫里的groupby函数对犯罪地点类型进行分组,用size函数查看条目数量。

larceny.groupby(“STREET”).size().sort_values(ascending = False)

First few entires of the result

查看结果,我们可以看到波士顿盗窃案发生率较高的地点是华盛顿街、博伊尔斯顿街和纽伯里街。

4.分析时间

我还想知道波士顿盗窃事件的趋势。

larceny.groupby(“MONTH”).size().plot(kind = “bar”)

根据我计算的柱状图,盗窃在 5 月、6 月和 12 月发生最多,而 9 月、10 月和 8 月似乎更安全。

让我们看看盗窃事件的数量在一天内是如何变化的。

larceny.groupby(“HOUR”).size().plot(kind= “bar”) 

在这里,我们可以告诉你波士顿一天中最不容易发生盗窃的时间是凌晨 5 点。然而,人们需要在下午 4 点到 6 点更加小心。

现在,我想全面了解一下波士顿每月和 24 小时内的盗窃事件数据。由于 2019 年还没有结束,数据不完整,我们具体看一下 2018 年的数据。

如果我们在熊猫中使用groupby对月和小时进行分组,我们会得到以下结果。

larceny[larceny.YEAR == 2019].groupby([‘MONTH’, ‘HOUR’]).size()

但是,这对我们轻松读取数据没有帮助。为了使它更好,我使用了unstack,这将把结果转换成可读性更好的形式。

larceny[larceny.YEAR==2018].groupby([‘MONTH’,’HOUR’]).size().unstack(0)

现在,我想把结果可视化。

因为我将 12 个月的数据可视化为 12 张图表,所以我想使用分面图。在熊猫的plot中有一个参数叫做subplots。初始化为True。我还可以通过使用figsize来调整图形的长度和宽度。

larceny[larceny.YEAR==2018].groupby([‘MONTH’,’HOUR’]).size().unstack(0).plot(subplots=True, kind = “bar”, figsize = (5, 30)

现在,我们对 2018 年发生在波士顿的盗窃事件有了完整的可视化。

摘要

通过使用 Pandas,我分析并可视化了波士顿犯罪事件报告的公开数据。在提取、分组、排序、分析和绘制数据方面,Pandas 确实是一个非常强大的 Python 包。如果你对数据分析感兴趣,使用熊猫来分析一些真实的数据集是一个很好的开始。

使用 Pandas、Matplotlib 和 lyum 分析巴塞罗那的车祸

原文:https://towardsdatascience.com/analysis-of-car-accidents-in-barcelona-using-pandas-matplotlib-and-folium-73384240106b?source=collection_archive---------3-----------------------

巴塞罗那开放数据是巴塞罗那的数据服务,包含约 400 个数据集,涵盖广泛的主题,如人口,商业或住房。该项目诞生于 2010 年,主要目标是最大限度地利用可用的公共资源,允许公司、公民、研究人员和其他公共机构利用生成的数据。

在本文中,我们采用了包含 2017 年巴塞罗那市当地警方管理的起事故的数据集。该数据集包括按严重程度划分的受伤人数、涉及的车辆数量、日期和事故的地理位置等信息。

[## 巴塞罗那市地方警察管理的事故-巴塞罗那开放数据

巴塞罗那市当地警方处理的事故清单。将受伤人数纳入…

open data-a jument . Barcelona . cat](https://opendata-ajuntament.barcelona.cat/data/en/dataset/accidents-gu-bcn)

由于数据集是加泰罗尼亚语的,我们将使用 Kaggle 中可用的英语版本。

[## 巴塞罗那数据集

下载数千个项目的开放数据集+在一个平台上共享项目。探索热门话题,如政府…

www.kaggle.com](https://www.kaggle.com/xvivancos/barcelona-data-sets#accidents_2017.csv)

探索性数据分析和数据清理

探索性数据分析包括分析数据集的主要特征,通常采用可视化方法汇总统计。目标是理解数据,发现模式和异常,并在我们执行进一步评估之前检查假设。

从 Kaggle 下载 csv 文件后,我们可以使用Pandas . read _ CSV函数将其加载到 Pandas dataframe 中,并使用 pandas 可视化前 5 行。data frame . head方法。

正如我们所观察到的,数据帧包含 15 列:Id、地区名称、邻居、街道、工作日、月、日、小时、一天的一部分、轻伤、重伤、受害者、涉及的车辆、经度、纬度。

我们可以很容易地使用 熊猫来打印带有列名的列表。data frame . columns方法。另外,熊猫。DataFrame.info 方法提供关于 DataFrame 的信息,包括列类型、非空值和内存使用情况。

显然,没有空值,因为所有列都有 10339 个条目。但是,有些条目包含字符串 Unknown。我们可以用非数字替换这个字符串,并通过使用 熊猫来再次评估空值的数量。DataFrame.info 方法。

正如我们所看到的,只有列 District Name 和 Neighborhood Name 包含空值。因为我们在进一步的分析中不打算使用这些列,所以我们不需要考虑空值。我们不会用区名和街坊名来分析事故发生在哪里,而是用经纬度来分析。

在我们开始使用我们的数据得出结论之前,我们要清理它。第一步清理包括删除不必要的列以简化数据帧。

删除列后,我们修改了一些数据类型。我们可以通过使用 pandas 来查阅数据类型。data frame . info方法或熊猫。DataFrame.dtypes 属性。后者返回包含每列数据类型的序列。****

正如我们所观察到的,月、日和小时不是日期时间对象。我们可以使用pandas . to _ datetime函数轻松地将这些列合并成一列。在使用这个函数之前,我们修改列名,用下划线代替空格,用小写字母代替大写字母。此外,我们还包括一个年份栏。

现在,我们可以将工作日、月、日、小时和年合并到一个名为 date 的列中。为了避免值错误,我们必须在使用pandas . to _ datetime函数之前将月份名称转换成整数。

转换后,我们可以使用上述函数获得日期时间列,如下所示:

通过使用熊猫,我们可以很容易地检查日期列的数据类型。DataFrame.dtypes 属性。

要访问日期的单个元素,如月、日或小时,我们可以使用 熊猫。Series.dt 属性。我们甚至可以通过使用 熊猫来访问星期几。Series.dt.dayofweek 属性,其中星期一=0,星期日=6。💪

因为我们可以使用 pandas 访问我们需要的与事故日期相关的所有信息。Series.dt 属性,我们可以删除月、年、小时、日和星期几列,因为不再需要它们。

最后,我们也可以删除街道列,因为我们将只使用经度和纬度来可视化事故发生的位置。

如上所示,获得的数据帧包含 8 列:id、轻伤、重伤、受害者、涉及的车辆、经度、纬度和日期。

为了方便地访问有关车祸的信息,我们将把 id 设置为数据帧的索引,删除 id 条目前面的尾随空格。

最后的清理步骤包括评估数据帧中是否有重复条目。如果是这样,我们将从数据框中移除这些重复的条目,因为它们代表相同的车祸。

数据清理完成!!👏现在!我们准备回答问题,并利用我们的数据得出结论。👌 🍀

回答问题并得出结论

探索性数据分析数据清理是让我们对数据集有所了解并准备好数据集以便使用它轻松得出结论的步骤。现在!我们准备使用数据集回答以下问题。****

时间分析

2017 年巴塞罗那警方登记了多少起事故?

我们用 熊猫就能轻松获得巴塞罗那登记的事故总数。DataFrame.shape 属性,因为数据帧的每个条目都代表一次不同的车祸。

2017 年,巴塞罗那警方登记了 10330 起事故。

每月车祸分布

为了分析每月车祸的分布,我们雇佣了 熊猫。DataFrame.groupby 函数。groupby 操作包括拆分对象、应用函数和组合结果的组合。首先,我们按月分组,然后我们计算每个月的事故数量。我们可以通过使用如下柱状图轻松解释结果:

********

正如我们所观察到的,事故数量在八月和十二月减少了。一个原因可能是这几个月开车上班的人少了。

一周中每天的车祸分布

正如我们对月份所做的那样,我们也可以通过使用条形图来分析车祸在一周中的分布情况。

如上图所示,周末车祸数量减少了。工作日平均每天发生 1656 起车祸,比周末多 600 起左右(平均每天 1025 起车祸)。

下一幅图描绘了一年中每天的事故数量。正如我们所观察到的,每天有 10-50 起事故,周五的事故数量通常比周日的事故数量高得多。

每小时车祸分布

按照与之前相同的程序,我们根据时间绘制这次车祸的分布。

正如我们在图中所观察到的,更多的事故发生在清晨 8-9 点和 12-20 点之间。

一周内每天和每小时的车祸分布

我们还可以使用并排条形图来分析一周中每天和每小时的事故数量。在这种特殊情况下,我们使用一个水平图来更好地可视化。

正如我们很容易观察到的,周末晚上发生的事故比平日多。相反,工作日从清晨(8)到下午(19)的交通事故比周末多得多。

时间分析—结论

  1. 8 月份是 2017 年车祸数量最低的月份,为 651 起。接下来的几个月里会发生 800-900 起事故。
  2. 周末车祸的数量减少了。
  3. 更多的车祸发生在(8-9)和(12-20)。
  4. 大多数事故发生在周末的晚上。

我们总是可以根据不同的时间变量进行分组,并创建更复杂的图,以便提取关于时间相关性的更复杂的模式和结论。

事故分析的类型

我们正在分析的数据包含与(1)事故日期,(2)事故类型,(3)事故地点相关的信息。关于事故类型,数据框包括诸如受害者人数、事故中涉及的车辆数量以及伤害类型(轻微或严重)等信息。和以前一样,我们可以用柱状图来检验所有这些变量的分布。

涉及的车辆

前面的图按照涉及车辆的数量描绘了 2017 年的事故数量。在大多数事故中,涉及两辆车(2017 年 7028 起事故)。此外,警方记录了涉及多达 14 辆车的车祸;但是,车辆多的车祸并不常见。

轻度——严重伤害

数据框包括关于在每起车祸中有多少受害者遭受轻度和重度伤害的信息。我们可以很容易地用饼图表示轻度和重度伤害的百分比,如下所示:

剧情显示只有 2%的伤是重伤。虽然车祸中的大多数伤害都是轻微的,但分析在何种情况下(时间、日期、地点)严重伤害更频繁会很有趣。

下图显示了一周中各天的受伤百分比。轻度伤害遵循一个预期的模式,因为在工作日,当更多的事故发生时,他们呈现较高的比率。然而,尽管周末的平均事故数量(1656 起)低于平日(1025 起),但严重伤害在周末的发生率很高。这表明周末的事故往往比平日更严重。

我们还可以根据小时绘制受伤的百分比。

正如我们所观察到的,事故往往在深夜和夜间更加严重。

事故分析类型——结论

(1)在大多数事故中,涉及 1、2 或 3 辆车。巴塞罗那警方在 2017 年登记的车祸中,涉及的车辆多达 14 辆。

(2)2017 年车祸受伤的人,大部分是轻伤(98%)。

(3)事故往往在夜间、深夜和周末更加严重。

位置分析

分析空间数据的最佳方式是使用地图。follow是一个 python 库,可以帮助你创建几种类型的传单地图。我们可以很容易地生成巴塞罗纳的地图,创建一个叶子地图对象位置参数允许将地图置于特定位置的中心(在我们的例子中是巴塞罗纳)。我们还可以提供一个初始缩放级别到那个位置,将地图缩放到中心。

尽管有初始缩放级别,但生成的地图是交互式的,这意味着您可以轻松地放大和缩小。

数据集包括每起车祸的经纬度。我们可以很容易地用圆圈标记来形象化它们。下图显示了造成严重伤害的事故,通过弹出标签显示了严重伤害的数量。

在 flour 中,我们还可以使用 MarkerCluster 对象将标记分组到不同的簇中。下面的情节描述了和以前一样的有严重受伤的受害者的车祸,但是这次事故被分组。

叶子的一个显著特点是可以创建动画热图,根据特定维度(如小时)改变显示的数据。我们可以通过使用 HeatMapWithTime() 类方法轻松实现这一点。首先,我们创建一个嵌套列表,其中每个位置都包含特定小时内所有车祸的经度和纬度。例如,hour_list[0]包含从 00:00:00 到 00:59:00 发生的车祸(例如,hour_list[0] → [[lat1,lon1],[lat2,lon2],[lat3,lon3],…,[latn,logn])。然后,我们调用方法并将其添加到地图中。

查看上面的时间线,我们可以观察到事故数量如何从 8 小时开始增加,一直保持高水平,直到 21 小时开始下降。

感谢阅读!!!😊 🍀

Using Natural Language Processing to Predict Topics of Articles (now in Chinese!)

原文:https://towardsdatascience.com/analysis-of-chinese-media-393c5c60c644?source=collection_archive---------24-----------------------

A Look into the Chinese Media

I have a complicated relationship with the Chinese media. I’ve done work for CCTV in the past, and most of my translation clients have some sort of government ties. Overall, I think that the daily news (新闻联播) that gets presented on CCTV is generally objective when it comes to international news. However, when it comes to domestic Chinese news, there can be more of an agenda. Having been a regular consumer of 新闻联播 before, I’m well aware of how the program will often shape a story to be very pro-China, and will often do fluff pieces on important figures.

But as a Data Scientist, I wanted to perform an exploration of this, and see if there were any recognizable trends in how many fluff pieces (for XXX in particular) are produced over time.

The Dataset

The dataset I’m using was found on Kaggle, and features every written news article published for use on the 新闻联播 program between January 1, 2016 to October 15, 2018. It has 4 columns: Date, Tag, Headline, and Content.

The Tag column differentiates the rows in the dataset between ““详细全文” some relatively long news, “国内“ domestic short news, “国际“ international short news.”

Project Goals:

  1. Explore whether there is any sort of trend in positive news/fluff pieces about XXX (especially surrounding the time of the constitutional change).
  2. Come up with a way to predict whether a piece will be about XXX.
  3. Create a filter for fluff pieces about XXX (sometimes it can feel like you are being bombarded by propaganda)(future work )

Data Exploration and Code

To get started, here’s a list of all the imports that were used in this project:

Most of these are fairly standard for NLP, but one package that some might be unfamiliar with is jieba. Jieba is a popular tokenizer specifically for Chinese characters, and typically does a great job parsing which should be compound characters and which should not. It also allows you to add custom tokenization rules pretty easily, if something isn’t parsing quite right.

And this is typically what the data looked like:

It had 20,738 rows with only 100 or so stories that repeated. Since these were all stories that did actually air, I decided to leave them in.

Non-NLP Feature Engineering

Before getting to the NLP aspect of the project, I wanted to see if there was perhaps an increase in XXX-friendly stories surrounding times when there may typically be negative public sentiment about him (specifically in March, when he changed to constitution to remove presidential term limits). This required me to “manually” determine if each news story was about Xi, an arduous task with over 20,000 rows of data.

So I counted the ratio of mentions of XXX (or Chairman Xi, Secretary Xi, etc.) to the character count of an article, getting the percentage he was mentioned, and cross-referenced articles with high “Xi counts” with whether or not he is mentioned in the title.

This was typically a good enough measure for whether an article was truly about Xi or not, which allowed me to tag it (for later use by NLP classifiers). I did do a manual count of about 2,000 rows, and found 33 false positives. Logically, I didn’t see how an article could be about XXX without actually mentioning him, so wasn’t worried about false negatives in articles with a Xi count of 0.0, and 33/2000 false positives is a good enough error that the rule seems alright.

Results

We can see that the number of articles about XXX varies throughout the year, but has generally been on the rise in 2018. However, the rise for the time period around March specifically could just be random variation. If we had another year of data, it would be interesting to see if this rise continued, or if it was simply a slightly larger increase than the normal variation we see throughout the seasons of the rest of the years. 2.5 years isn’t really a long enough time to observe definite trends in something as abstract as whether the media is trying to promote more positive pieces about the President.

Predictions with NLP Classifiers

The dictionary keeping track of all the values was rather long, so I cut it down to only record words/phrases that appeared 20 times or more. Some of the top words we see throughout the dataset are ‘发展’ (development), ‘中国’ (China), ‘***’ (XXX), ‘合作’ (cooperation), etc. This isn’t very surprising for a dataset of Chinese mainstream news articles.

Methodology

I was able to train NLTK's basic Naive Bayes classifier using all 12,000+ characters as a feature set, but ran into memory issues when training other classifiers, so ended up using just the top 5,000 character combinations as features. All 20,738 of the articles were shuffled using random.shuffle, then the first 15,000 were used to train, resulting in roughly a 72/28 split for training and testing.

NLP Results

The first pass with all 12,000 characters as a featureset is interesting to examine because of the changes that occurred when less characters were used. Most notably, some of the figures that strongly indicate an article is about XXX are different, and both 检阅台 (review/inspection platform) and 挥手致意 (waving to express regards/respect) are absent in 5k-character featureset’s list of most informative features. Both of these terms (highlighted in red) are almost exclusively used during a review of the troops (typically done by XXX).

And the most informative people (in order) were:

Ding Xuexiang 丁薛祥 (General Secretary of the CPC)

Yang Jiechi 杨洁篪 (Director of the Office of Foreign Affairs)

Fang Fenghui 房峰辉 (Former Chief of Joint Staff)

Ma Xiaotian 马晓天 (Former Deputy Chief of Joint Staff)

Zhao Keshi 赵克石 (Former Nanjing Commander)

In the second pass, with a 5,000-character featureset, we see that 丁薛祥 (Ding Xuexiang, XXX’s aide) and 杨洁篪 (Yang Jiechi, a key leader of China’s foreign policy) are found in both featuresets. Interestingly, it appears that XXX himself (highlighted in green) appears throughout the dataset so much that he is 45 times more likely to appear in articles that aren’t actually about him. The 中央办公厅 (the General Office of the CPC, highlighted in red) is also present in this featureset’s 25 most important features, but was absent in the previous version’s most important features.

And the most informative people (in order) this time were:

Ding Xuexiang 丁薛祥 (General Secretary of the CPC)

Yang Jiechi 杨洁篪 (Director of the Office of Foreign Affairs)

Liu He 刘鹤 (Vice Premier of the People’s Republic of China)

Wang Huning 王沪宁 (Chinese political leader)

Purely by looking at how likely these people/features were to indicate whether a story was about XXX, we can see the importance of certain politicians that might not often appear in the public eye.

Models

The baseline of this dataset was 89.787%, which is relatively high, but it turns out most of the articles in the dataset were not about XXX.

Here’s how each of the classifiers I used performed:
1. Multinomial Naive Bayes: 92.646%
2. Bernoulli Naive Bayes: 85.953%
3. Logistic Regression: 95.904%
4. Support Vector Clustering (SVC): 93.883%

Most of these classifiers actually did improve upon the baseline, except for the Bernoulli NB classifier, but I imagine with proper tweaking it might also be able to get better.

Final Thoughts

Overall, this was a very fun project, and first foray into Natural Language Processing. I learned a lot more than mentioned in this post, and will write about unsupervised LDA models for parsing Chinese once I have performed some more exploration. As for this project, the next step could be to turn it into a filter of XXX-related news, or apply the techniques used here to filter out any topic one could want. It could also be used to draw a map of relationships in the CPC based on the proximity of certain political figures to XXX. It is also one step along the way of defining that vague concept of what it means for an article to be “about” someone or something, and handling it in a way that computers can understand.

本文中使用的所有代码和可视化都可以在这里获得: GitHub

如果你有任何关于用中文争论/分析数据的问题,请随时通过 LinkedIn 联系我!

使用正确的关键词创建您的数据科学简历

原文:https://towardsdatascience.com/analysis-of-data-job-descriptions-97721046d8d4?source=collection_archive---------34-----------------------

深度学习,管理,卷积神经网络,大数据,协作,分析,机器学习

Medium 的建议算法是否选中了我的字幕?如果我在找工作,我应该使用类似的策略吗?

在 ATS 系统的世界里,最重要的是你的简历要符合基于你资历/状态的“热门词汇”。ATSs 基于关键词进行匹配,作为一名目前正在申请的入门级数据科学家,通过简历筛选的任何帮助都是至关重要的。

在这篇简短的文章中,我们将利用空间来涵盖职位描述中最常用的词汇,以此来归类这些流行的职位名称…

  1. 入门级
  2. 中等水平
  3. 经理

这四种状态…

  1. 加利福尼亚
  2. 马萨诸塞州
  3. 华盛顿
  4. 纽约

请注意——我不是每个级别之间界限的专家,因为我是根据职位头衔做出假设的。关注我在文末的 jupyter 笔记本寻求建议/改进:)

NLP 详细信息

单词标记化、停止单词移除和过滤以包括…

词性:形容词和名词
依存关系:DOBJ、CONJ、AMOD、NUM、ADVMOD、QUANTMOD、MEASURE

Notable terms: Research, Analysis, Skills

Notable Terms: Team, Machine (Learning), Experience

Notable Terms: Experience, Team, Business, Management

标题摘要

回顾这些发现后,大多数数据都指向我们的直觉告诉我们的东西。职称之间的一些关键发现

1.数据是工作描述中最常用的术语,入门级角色使用频率最高。

2.团队、业务、开发、管理和产品位于经理职位描述的顶端。

3.经验、研究、团队、机器、学习在中级职位上比在初级职位上出现得更频繁。

Notable Terms: Business, Machine (Learning), Skills

Notable Terms: Business, Product, Technical

Notable Terms: Development, Research, Clinical

Notable Terms: Experience, Data, Team

状态摘要

在回顾了各州的职位描述后,我们发现了一些要点。

  1. 马萨诸塞州——临床和能力出现在提及次数的前十位(与其他州不同),发展几乎是其他州的两倍。
  2. 纽约—在体验和团队提及方面排名最低,但在数据方面排名最高
  3. 华盛顿——产品和技术出现在提及次数的前十名中(与其他州不同),并领先于商业提及
  4. 加利福尼亚州——接近其他三个州的平均水平,除了出现在十大提及中的分析

你可以随意翻翻 jupyter 笔记本,自己看看!

使用 Python 分析前 50 首 Spotify 歌曲

原文:https://towardsdatascience.com/analysis-of-top-50-spotify-songs-using-python-5a278dee980c?source=collection_archive---------18-----------------------

2019 年哪些歌曲最受欢迎?

Photo by John Tekridis on Pexels

2019 年最受欢迎的歌曲有哪些?2019 年哪些流派最受欢迎?哪些艺术家最受欢迎?

在本帖中,我们将分析排名前 50 的 Spotify 歌曲数据集,这些数据可以在 Kaggle 上找到。该数据集提供了 2019 年 Spotify 上听得最多的 50 首歌曲。它摘自整理你的音乐网站。

数据集包含以下字段:

  1. 追踪。名称 —轨道名称
  2. 艺人。名字 —艺人的名字
  3. 流派 —曲目流派
  4. 节拍。每分钟 —歌曲的速度
  5. 能量——宋的能量——数值越高,能量越大
  6. 可跳舞性 —该值越高,就越容易随着歌曲跳舞
  7. 响度..dB。。—数值越高,歌声越响亮。
  8. Liveness —值越高,歌曲越有可能是现场录制的。
  9. 化合价。—值越高,歌曲的情绪越积极。
  10. 长度。—歌曲的持续时间。
  11. 声音..值越高,歌曲的声音越大
  12. 语速。—值越高,歌曲包含的口语单词越多
  13. 流行度 —数值越高,歌曲越流行。

首先,让我们将数据读入 pandas 数据帧,并打印前五行:

import pandas as pddf = pd.read_csv("top50.csv", encoding="ISO-8859-1")print(df.head())

我们可以按降序对数据帧进行排序,以查看前 5 首最流行的歌曲:

df.sort_values('Popularity', ascending = False, inplace = True)print(df.head())

排名前五的流行歌曲和对应的艺人分别是:

  1. 坏蛋,比莉·埃利什
  2. 再见(壮举。年轻的暴徒),后马龙
  3. 卡莉塔,坏兔子
  4. 坟墓里的钱。里克·罗斯),德雷克
  5. 中国,阿努埃尔 AA

在这篇文章的其余部分,我们将关注“流派”和“艺术家”。名称”,但是可以对其他一些专栏做进一步的分析。

让我们从使用 python 集合模块中的 Counter 方法来查看每个流派出现在前 50 个列表中的频率开始。让我们从集合中导入“计数器”并打印每个流派的频率:

from collections import Counter 
print(Counter(df['Genre'].values))

我们还可以将输出限制在最常见的 5 种类型:

print(Counter(df['Genre'].values).most_common(5))

然后,我们可以使用 matplotlib 在条形图上显示结果:

import matplotlib.pyplot as plt
bar_plot = dict(Counter(df['Genre'].values).most_common(5))
plt.bar(*zip(*bar_plot.items()))
plt.show()

我们看到,在前 50 名的榜单中,属于舞曲流行这一体裁的歌曲出现了 8 次,流行出现了 7 次,拉丁出现了 5 次,加拿大嘻哈出现了 3 次,edm 出现了 3 次。

我们可以为艺术家做同样的事情:

print(Counter(df['Artist.Name'].values))

并且只限于最常见的五位艺术家:

print(Counter(df['Artist.Name'].values).most_common(5))

并绘制结果:

bar_plot = dict(Counter(df['Artist.Name'].values).most_common(5))
plt.bar(*zip(*bar_plot.items()))
plt.show()

我们可以看到,艾德·希兰的歌曲在前 50 名中出现了 4 次,比利·埃利希、波斯特·马龙、塞克和里尔·纳斯克斯各出现了 2 次。

出于代码重用的目的,我们可以定义一个函数,该函数接受分类变量的列名,并打印一个包含列值和该值出现的次数的字典,以及一个显示每个值出现频率的条形图:

def get_frequencies(column_name):
    print(Counter(df[column_name].values))
    print(dict(Counter(df[column_name].values).most_common(5)))
    bar_plot = dict(Counter(df[column_name].values).most_common(5))
    plt.bar(*zip(*bar_plot.items()))
    plt.show()

现在,如果我们用“流派”调用这个函数,我们得到:

get_frequencies('Genre')

和“艺术家”。姓名':

get_frequencies('Artist.Name')

我就讲到这里,但是您可以随意处理数据和编写代码。这篇文章的代码可以在 GitHub 上找到。感谢您的阅读!

Python 中关于小丑(2019 年电影)的推文分析

原文:https://towardsdatascience.com/analysis-of-tweets-about-the-joker-2019-film-in-python-df9996aa5fb1?source=collection_archive---------28-----------------------

Photo by Pixabay on Pexels

在本帖中,我们将分析与小丑(2019 年电影)相关的推特推文。首先,你需要申请一个 Twitter 开发者账户:

Source

您的开发人员帐户获得批准后,您需要创建一个 Twitter 应用程序:

Source

申请 Twitter 开发者账户和创建 Twitter 应用的步骤在这里有所概述。

为了访问 Twitter API,我们将使用免费的 python 库 tweepy。tweepy 的文档可以在这里找到。

  1. 安装

首先,确保您已经安装了 tweepy。打开命令行并键入:

pip install tweepy 

2.导入库

接下来,打开您最喜欢的编辑器,导入 tweepy 和 pandas 库:

import tweepy
import pandas as pd**AUTHENTICATION**

接下来,我们需要我们的消费者密钥和访问令牌:

Source

请注意,该网站建议您保持您的密钥和令牌私有!这里我们定义了一个假的密钥和令牌,但是在创建 Twitter 应用程序时,您应该使用真正的密钥和令牌,如上所示:

consumer_key = '5GBi0dCerYpy2jJtkkU3UwqYtgJpRd' 
consumer_secret = 'Q88B4BDDAX0dCerYy2jJtkkU3UpwqY'
access_token = 'X0dCerYpwi0dCerYpwy2jJtkkU3U'
access_token_secret = 'kly2pwi0dCerYpjJtdCerYkkU3Um'

下一步是创建 OAuthHandler 实例。我们传递上面定义的消费者密钥和访问令牌:

auth = tweepy.OAuthHandler(consumer_key, consumer_secret)
auth.set_access_token(access_token, access_token_secret)

接下来,我们将 OAuthHandler 实例传递给 API 方法:

api = tweepy.API(auth)

3 。TWITTER API 请求

接下来,我们为我们有兴趣分析的字段初始化列表。现在,我们可以查看推文字符串、用户和推文时间。接下来,我们在一个 tweepy“Cursor”对象上编写一个 for 循环。在“Cursor”对象中,我们传递“api.search”方法,为我们想要搜索的内容设置查询字符串(q =“Joker”),并设置“count”= 1000,这样我们就不会超过 twitter 的速率限制。我们还使用“item()”方法将“Cursor”对象转换为 iterable。

为了简化查询,我们可以删除转发,只包含英文推文。为了了解该请求返回的内容,我们还可以打印附加到每个列表的值:

twitter_users = []
tweet_time = []
tweet_string = []
for tweet in tweepy.Cursor(api.search,q="Joker", count=1000).items(1000):
        if (not tweet.retweeted) and ('RT @' not in tweet.text):
            if tweet.lang == "en":
                twitter_users.append(tweet.user.name)
                tweet_time.append(tweet.created_at)
                tweet_string.append(tweet.text)
                print([tweet.user.name,tweet.created_at,tweet.text])

Tweets related to “Joker”

我们也可以使用查询字符串。让我们把它从“小丑”改成“华金”,这是小丑中男主角的名字:

for tweet in tweepy.Cursor(api.search,q="Joaquin", count=1000).items(1000):
        if (not tweet.retweeted) and ('RT @' not in tweet.text):
            if tweet.lang == "en":
                twitter_users.append(tweet.user.name)
                tweet_time.append(tweet.created_at)
                tweet_string.append(tweet.text)
                print([tweet.user.name,tweet.created_at,tweet.text])

Tweets related to “Joaquin”

接下来,我们可以将查询结果存储在数据帧中。为此,让我们定义一个函数,该函数将一个关键字作为参数,并返回一个包含与该关键字相关的 1000 条推文的数据帧:

def get_related_tweets(key_word):
    twitter_users = []
    tweet_time = []
    tweet_string = [] 
    for tweet in tweepy.Cursor(api.search,q=key_word, count=1000).items(1000):
            if (not tweet.retweeted) and ('RT @' not in tweet.text):
                if tweet.lang == "en":
                    twitter_users.append(tweet.user.name)
                    tweet_time.append(tweet.created_at)
                    tweet_string.append(tweet.text)
                    #print([tweet.user.name,tweet.created_at,tweet.text])
    df = pd.DataFrame({'name':twitter_users, 'time': tweet_time, 'tweet': tweet_string})
    df.to_csv(f"{key_word}.csv")
    return df

当我们用“Joker”调用函数时,定义一个 dataframe 作为函数的返回值,并打印它的前五行,我们得到:

df_joker = get_related_tweets("Joker")
print(df_joker.head(5))

First five rows of dataframe of tweets for “Joker”

如果我们对“华金”做同样的事情:

df_joaquin = get_related_tweets("Joaquin")
print(df_joaquin.head(5))

First five rows of dataframe of tweets for “Joaquin”

我们还可以搜索带有“小丑”和“糟糕电影”的推文。csv '行):

def get_related_tweets(key_word):
    twitter_users = []
    tweet_time = []
    tweet_string = [] 
    for tweet in tweepy.Cursor(api.search,q=key_word, count=1000).items(1000):
            if (not tweet.retweeted) and ('RT @' not in tweet.text):
                if tweet.lang == "en":
                    twitter_users.append(tweet.user.name)
                    tweet_time.append(tweet.created_at)
                    tweet_string.append(tweet.text)
                    #print([tweet.user.name,tweet.created_at,tweet.text])
    df = pd.DataFrame({'name':twitter_users, 'time': tweet_time, 'tweet': tweet_string})
    return df
df_bad = get_related_tweets("Joker bad movie")
print(df_bad.head(5))

让我们通过遍历 dataframe 索引并从 tweet 列中选择值来仔细查看几行:

Expanded strings of ”Joker bad movie” tweets

对于带有“小丑”和“好电影”的推文:

df_good = get_related_tweets("Joker good movie")
print(df_good.head(5))

Expanded strings of ”Joker good movie” tweets

在下一篇文章中,我们将使用一个名为 TextBlob 的 python 库对其中一些推文进行情感分析。在此基础上,我们可以构建一个情绪分析器,将一条推文分类为负面情绪或正面情绪。这篇文章的代码可以在 Github 上找到。感谢您的阅读!祝好运,机器学习快乐!

用 Python 分析 2019 年香港抗议运动的推文

原文:https://towardsdatascience.com/analysis-of-tweets-on-the-hong-kong-protest-movement-2019-with-python-a331851f061?source=collection_archive---------21-----------------------

Photo by Joseph Chan on Unsplash

免责声明:本文无意对香港当前形势作任何形式的政治或社会评论。所做的分析完全基于手头数据集的推断。

最近,在完成了吴恩达教授的 Coursera 深度学习课程后,我有动力做一个关于情感分析的宠物项目,其中一个专业是序列模型。我写这篇文章是为了巩固和分享我的学习和代码。

随着香港抗议运动已经发生了将近 6 个月,我突然有了一个想法,收集关于抗议的 Twitter 推文,并将其用于这个项目。例如,我不想使用 Kaggle 上容易获得的现有(可能已经清理过的)数据集。我想这是一个让我把手弄脏并学习抓取推文的过程的机会。

该项目的目标是发现:

  1. 微博对抗议的总体看法,特别是,这些微博对中国中央政府、香港政府和警方的立场/观点是什么
  2. twitter 用户的人口统计数据
  3. 标签的流行度
  4. 顶级用户和一般用户的行为
  5. 每日热门推文

本文的结构将不同于通常的教程,在通常的教程中,流程是数据清理和预处理,接着是探索性的数据分析,然后是模型训练和调优。在这里,我们希望读者首先关注数据分析和可视化。数据清理和预处理步骤将在后面介绍。您可以从这个访问源代码。

使用 Tweepy 抓取 Twitter 消息

因为抓取 Twitter tweets 也不是本文的重点,所以我另外写了一篇文章详细描述抓取的过程。如果你需要一步一步的指导,点击这个链接

探索性数据分析

Source: https://miro.medium.com/max/810/1*p3Ste5R_iJzi5IcSmFkmtg.png

让我们用常用的数据可视化库——seaborn 和 matplotlib——来探索和可视化已经处理过的推文。

1.WordCloud——在关于抗议的推文中找到的流行词汇的快速预览

首先,我们使用一个词云,它可以立即向我们显示在与抗议相关的推文中使用最多的词。所需的代码如下:

from wordcloud import WordCloud
import matplotlib.pyplot as pltdef show_wordcloud(data, title = None):
    wordcloud = WordCloud(
        background_color = 'white',
        max_words = 200,
        max_font_size = 40, 
        scale = 3,
        random_state = 42
    ).generate(str(data))fig = plt.figure(1, figsize = (15, 15))
    plt.axis('off')
    if title: 
        fig.suptitle(title, fontsize = 20)
        fig.subplots_adjust(top = 2.3)plt.imshow(wordcloud)
plt.show()

# print wordcloud
show_wordcloud(data['cleaned_text'])

Our word cloud for the top 100 words found in the tweets

我们为前 100 个单词生成了一个单词云,其中一个单词越受欢迎,该单词在单词云中就越大(您可以通过更改“max_words”的值来调整该参数)。

一些很快打动我们的词是:厌恶、警察、消防员、抗议者、催泪瓦斯、公民、失败、信任等等。总的来说,如果没有推特的背景,我们无法确定每个词,作为它自己,是否代表对政府或抗议者的负面或正面情绪。但对于我们这些一直关注社交媒体和新闻的人来说,对警察的反对声很大。

2.正面情绪的数量与负面情绪的数量

接下来,我们看看正面和负面推文的分布情况。基于 NLTK Vader-Lexicon 库的 SentimentIntensityAnalyzer,这个分析器检查一个句子的情感,关于它是积极的、中性的还是消极的。

我们可以用下面的方式来解释这种情绪。如果一种情绪是积极的,这可能意味着它是亲政府和/或警察的。然而,负面情绪可能意味着它是反政府和/或反警察的,是支持抗议者的。

分析器为每个句子返回 4 个分数,即“肯定”、“否定”、“中性”和“复合”。分数“复合”返回范围为[-1,1]的句子的总体情感。出于我们当前的目的,我们使用“复合”分数将每条推文分为 5 类,并为每类分配一个数值范围:

  1. 非常正的“5”——[0.55,1.00]
  2. 正' 4' — [0.10,0.55]
  3. 中性' 3 '——(-0.10,0.10)
  4. 负“2”——(-0.55,-0.10)
  5. 非常负的“1”——[-1.00,-0.55]

注意:中性情绪的值范围更严格。

事实证明,由于抗议的性质,使用基于规则的方法分析推文的情绪是极其不准确的。每条推文的情绪可以是关于政府或抗议者的。另一方面,在诸如酒店评论的其他情况下,每个评论的情感分析是关于酒店的,而不是给出评论的酒店客人的。因此,很明显,好的情绪分数意味着对该酒店的评论是好的,而坏的情绪分数意味着对该酒店的评论是坏的。然而,在我们目前的案例研究中,一条推文的良好情绪得分可能意味着支持一方,也可能意味着反对/否定另一方。这将在下面显示出来。

根据数据的“复合”分数,将数据分类:

# Focus on 'compound' scores
# Create a new column called 'sentiment_class'
sentimentclass_list = []for i in range(0, len(data)):

    # current 'compound' score:
    curr_compound = data.iloc[i,:]['compound']

    if (curr_compound <= 1.0 and curr_compound >= 0.55):
        sentimentclass_list.append(5)
    elif (curr_compound < 0.55 and curr_compound >= 0.10):
        sentimentclass_list.append(4)
    elif (curr_compound < 0.10 and curr_compound > -0.10):
        sentimentclass_list.append(3)
    elif (curr_compound <= -0.10 and curr_compound > -0.55):
        sentimentclass_list.append(2)
    elif (curr_compound <= -0.55 and curr_compound >= -1.00):
        sentimentclass_list.append(1)# Add the new column 'sentiment_class' to the dataframe
data['sentiment_class'] = sentimentclass_list# Verify if the classification assignment is correct:
data.iloc[0:5, :][['compound', 'sentiment_class']]

我们制作了一个 seaborn countplot 来显示数据集中情感类别的分布:

import seaborn as sns# Distribution of sentiment_class
plt.figure(figsize = (10,5))
sns.set_palette('PuBuGn_d')
sns.countplot(data['sentiment_class'])
plt.title('Countplot of sentiment_class')
plt.xlabel('sentiment_class')
plt.ylabel('No. of classes')
plt.show()

让我们来看看每个情感类中的一些推文:

  1. 10 条被归类为“负面情绪”的随机推文——1 类和 2 类
# Display full text in Jupyter notebook:
pd.set_option('display.max_colwidth', -1)# Look at some examples of negative, neutral and positive tweets# Filter 10 negative original tweets:
print("10 random negative original tweets and their sentiment classes:")
data[(data['sentiment_class'] == 1) | (data['sentiment_class'] == 2)].sample(n=10)[['text', 'sentiment_class']]

10 random tweets with negative sentiments. This means that the tweets are SUPPOSED to show support towards the protestors but not seem to the Hong Kong government and/or police.

很明显,这些推文是关于谴责所谓的警察暴力,争取国际支持——特别是来自美国的支持——以及报道警察反对抗议者的活动。

  1. 10 条被归类为“中性情绪”的随机推文——第三类
# Filter 10 neutral original tweets:
print("10 random neutral original tweets and their sentiment classes:")
data[(data['sentiment_class'] == 3)].sample(n=10)[['text', 'sentiment_class']]

10 random tweets with neutral sentiments. This means that the tweets are SUPPOSED to show support neither towards the protestors nor the Hong Kong government and/or police.

除了最后一条索引为 114113 的推文,大多数推文的立场应该是中立的。但考虑到背景,可以推断这些推文是为了支持抗议者和他们的事业。

  1. 20 条随机推文被归类为“积极情绪”——第 4 类和第 5 类
# Filter 20 positive original tweets:
print("20 random positive original tweets and their sentiment classes:")
data[(data['sentiment_class'] == 4) | (data['sentiment_class'] == 5)].sample(n=20)[['text', 'sentiment_class']]

随机挑选了 20 条推文,但几乎所有推文的情绪都是负面的,这意味着它们反对香港政府和/或警方。快速观察发现,这些推文涵盖了以下主题:在美国通过香港民主和人权法;取消香港政客的奖学金;总体上支持香港抗议者。

这支持了之前提出的论点,即在这种情况下,使用 Vader 词典库对推文进行基于规则的情感分析在识别真正的积极情感方面是不准确的,给我们留下了许多假阳性。它没有检查和考虑推文的背景。大多数“积极情绪”的推文包含更多“积极”的词语,而不是“消极”的词语,但它们实际上是对抗议者及其事业的支持,而不是对香港政府和/或中国的支持。

3.标签的流行度

回想一下,这些推文是使用预定义的搜索词搜集的,其中包含与抗议活动相关的特定标签列表。此外,推文还可以包含搜索项中未定义的其他标签,只要推文包含由搜索项定义的标签。

在这一部分,我们想找出 Twitter 用户在他们的推文中使用的最受欢迎和最不受欢迎的标签。

# the column data['hashtags'] returns a list of string(s) for each tweet. Build a list of all hashtags in the dataset.hashtag_list = []for i in range(0, len(data)):
    # Obtain the current list of hashtags
    curr_hashtag = data.iloc[i, :]['hashtags']

    # Extract and append the hashtags to 'hashtag_list':
    for j in range(0, len(curr_hashtag)):
        hashtag_list.append(curr_hashtag[j])

使用的 hashtags 的总数可以通过以下方式确定:

# No. of hashtags
print('No. of hashtags used in {} tweets is {}'.format(len(data), len(hashtag_list)))

在 233651 条推文中使用的标签数量是 287331

我们构建了一个简单的数据框架用于可视化:

df_hashtag = pd.DataFrame(
    {'hashtags': hashtag_list}
)print(df_hashtag.head())
print('Shape of df_hashtag is:', df_hashtag.shape)

基本视觉化:使用的前 15 个标签

让我们来看看用户使用的前 15 个标签

# Define N to be the top number of hashtags
N = 15
top_hashtags = df_hashtag.groupby(['hashtags']).size().reset_index(name = 'counts').sort_values(by = 'counts', ascending = False).head(N)
print(top_hashtags)# seaborn countplot on the top N hashtags
plt.figure(figsize=(30,8))
sns.set_palette('PuBuGn_d')
sns.barplot(x = 'hashtags', y = 'counts', data = top_hashtags)
plt.title('Barplot of Top ' + str(N) + ' Hashtags used')
plt.xlabel('Hashtags')
plt.ylabel('Frequency')
plt.show()

A Seaborn bar plot for the all-time top 15 hashtags used by users.

不出所料,15 个标签中有 14 个包含关键词“香港”和“香港”,因为用户使用它们来识别他们与香港和抗议活动有关的推文。唯一与众不同的标签是#中国。

有 6 个标签明确表示支持抗议者,并谴责香港警方的行动和行为——这些标签是:#fightforfreedom、#freehongkong、#fightforfreedom、#hkpoliceterrorism、#hkpolicestate 和#hkpolicebrutality。

高级可视化:过去 7 天前 10 个标签的时间序列(不完全是时间序列…)

我们希望看到从 2019 年 11 月 3 日开始收集数据时开始的标签使用量的增长。随着时间的推移,一个或几个标签变得越来越流行了吗?让我们来看看:

from datetime import datetimeind_to_drop = []
date = []# First find out which 'tweetcreatedts' is not a string or in other weird formats
for i in range(0, len(data)):
    ith_date_str = data.iloc[i,:]['tweetcreatedts']
    ith_match = re.search(r'\d{4}-\d{2}-\d{2}', ith_date_str)
    if ith_match == None:
        ind_to_drop.append(i)
    else:
        continue# Drop these rows using ind_to_drop
data.drop(ind_to_drop, inplace = True)# Create a new list of datetime date objects from the tweets:
for i in range(0, len(data)):
    ith_date_str = data.iloc[i, :]['tweetcreatedts']
    ith_match = re.search(r'\d{4}-\d{2}-\d{2}', ith_date_str)
    ith_date = datetime.strptime(ith_match.group(), '%Y-%m-%d').date()

    date.append(ith_date)

# Size of list 'date'
print('Len of date list: ', len(date))

日期列表长度:233648

# Append 'date' to dataframe 'data' as 'dt_date' aka 'datetime_date'
data['dt_date'] = date# Check to see that we have the correct list of dates from the dataset
data['dt_date'].value_counts()

# Create a new dataframe first
timeseries_hashtags = pd.DataFrame(columns = ['hashtags', 'count', 'date', 'dayofnov'])# Obtain a set of unique dates in 'date' list:
unique_date = np.unique(date)

我们定义了一个函数,允许您选择要显示的前 N 个标签,以及最近 T 天的数据,而不是自 2019 年 11 月 3 日以来的每天数据(虽然您可以选择,但这会使图变得混乱)

def visualize_top_hashtags(main_df, timeseries_df, N, T, unique_dates):
    # main_df - main dataframe 'data'
    # timeseries_df - a new and empty dataframe to store the top hashtags 
    # N - number of top hashtags to consider
    # T - number of days to consider
    # unique_dates - list of unique dates available in the table

    # Returns:
    # timeseries_df

    # Start counter to keep track of number of days already considered
    counter = 1# Starting from the latest date in the list
    for ith_date in reversed(unique_dates):
        # Check if counter exceeds the number of days required, T:
        if counter <= T:

            # Filter tweets created on this date:
            ith_date_df = main_df[main_df['dt_date'] == ith_date]# From this particular df, build a list of all possible hashtags:
            ith_hashtag_list = []for i in range(0, len(ith_date_df)):
                # Obtain the current list of hashtags:
                curr_hashtag = ith_date_df.iloc[i,:]['hashtags']# Extract and append the hashtags to 'hashtag_list':
                for j in range(0, len(curr_hashtag)):
                    ith_hashtag_list.append(curr_hashtag[j])# Convert the list into a simple DataFrame
            ith_df_hashtag = pd.DataFrame({
                    'hashtags': ith_hashtag_list
            })# Obtain top N hashtags:
            ith_top_hashtags = ith_df_hashtag.groupby(['hashtags']).size().reset_index(name = 'count').sort_values(by = 'count', ascending = False).head(N)# Add date as a column
            ith_top_hashtags['date'] = ith_date
            ith_top_hashtags['dayofnov'] = ith_date.day# Finally, concat this dataframe to timeseries_hashtags
            timeseries_df = pd.concat([timeseries_df, ith_top_hashtags], axis = 0)# Increase counter by 1
            counter += 1

        else: # break the for loop
            break

    print('The newly created timeseries_hashtag of size {} is: '.format(timeseries_df.shape))
    timeseries_df.reset_index(inplace = True, drop = True)

    # Visualization
    plt.figure(figsize=(28,12))
    ax = sns.barplot(x = 'hashtags', 
                   y = 'count',
                   data = timeseries_df,
                   hue = 'dayofnov')# plt.xticks(np.arange(3, 6, step=1))
    # Moving legend box outside of the plot
    plt.legend(bbox_to_anchor=(1.05, 1), loc=2, borderaxespad=0.)
    # for legend text
    plt.setp(ax.get_legend().get_texts(), fontsize='22')
    # for legend title
    plt.setp(ax.get_legend().get_title(), fontsize='32') 
    plt.xlabel('Top Hashtags')
    plt.ylabel('Count of Hashtags')
    plt.title('Top ' + str(N) + ' Hashtags per day')
    sns.despine(left=True, bottom=True)
    plt.xticks(rotation = 45)
    plt.show()

    return timeseries_df

我们终于可以制作剧情了:

timeseries_hashtags = visualize_top_hashtags(main_df = data,
                       timeseries_df = timeseries_hashtags,
                       N = 10,
                       T = 7,
                       unique_dates = unique_date)

Top 10 hashtags over the last 7 days from 16th November 2019.

我认为用条形图查看每个标签的趋势比用散点图更容易,即使它会显示时间序列,因为当有这么多颜色和类别(标签)时,很难将每个点与图例相关联。

自 2019 年 11 月 16 日以来,过去 7 天每天排名前 10 位的标签显示了该运动常用的标签-#香港、#香港抗议、#香港警察、#standwithhongkong 和#香港警察。

除了常见的标签,可视化功能可以揭示独特和重大的事件/事件,因为用户在谈论这些事件时会在他们的推文中使用这些标签。

Throughout the period, we see sudden appearance of hashtags such as #blizzcon2019 (not shown because of different parameters N and T), #周梓樂 (represented by squares in above graph), #japanese, #antielab, #pla, and #hkhumanrightsanddemocracyact.

这些标签与重要的里程碑相关联:

  1. blizzcon 2019/blizzcon 19—https://www . scmp . com/tech/apps-social/article/3035987/will-blizzcon-begin-最新-战场-香港-抗议

  2. 周梓樂 — https://www.bbc.com/news/world-asia-china-50343584

  3. hkust (related to #周梓樂) — https://www.hongkongfp.com/2019/11/08/hong-kong-students-death-prompts-fresh-anger-protests/

  4. 日本人(一名日本人被误认为是中国大陆人,因此遭到抗议者攻击)——https://www3 . NHK . or . jp/NHK world/en/news/2019 11 12 _ 36/#:~:target text = Hong % 20 kong % 20 media % 20 reported % 20 on,take % 20pictures % 20of %抗议% 20 活动

  5. antielab(抗议者抵制选举,因为 Joshua Wong 被禁止参加选举)——https://www . scmp . com/news/hong-hong kong/politics/article/3035285/democracy-activity-Joshua-Wong-banted-running-hong-hong kong

  6. pla(中国人民解放军(pla)驻香港部队帮助清理和清除被抗议者封锁和破坏的街道)——https://www . channel news Asia . com/news/Asia/China-s-PLA-soldiers-help-clean-up-Hong Kong-streets-but-12099910

除了通常的标签外,预计未来重大事件将继续引发新的标签。

4.最受欢迎的推文

在这一部分,我们将重点关注最受欢迎的推文。有两个指标可以帮助我们做到这一点——一条推文的转发数和收藏数。不幸的是,我们只能提取 retweet 计数,因为在从。json 格式(知道怎么做的请随时留言评论!).

我们将执行以下操作:

  • 有史以来的前 N 条推文
  • 特定日期的前 N 条推文
  • 过去 T 天的前 N 条推文

史上十大推文

# Convert the data type of the column to all int using pd.to_numeric()print('Current data type of "retweetcount" is:',data['retweetcount'].dtypes)data['retweetcount'] = pd.to_numeric(arg = data['retweetcount'])print('Current data type of "retweetcount" is:',data['retweetcount'].dtypes)

“retweetcount”的当前数据类型为:object
当前数据类型为:int64

我们定义了一个函数来提取前 10 条推文:

def alltime_top_tweets(df, N):
    # Arguments:
    # df - dataframe
    # N - top N tweets based on retweetcount

    # Sort according to 'retweetcount'
    top_tweets_df = df.sort_values(by = ['retweetcount'], ascending = False)
    # Drop also duplicates from the list, keep only the copy with higher retweetcount
    top_tweets_df.drop_duplicates(subset = 'text', keep = 'first', inplace = True)
    # Keep only N rows
    top_tweets_df = top_tweets_df.head(N)

    # Print out only important details 
    # username, tweetcreatedts, retweetcount, original text 'text'
    return top_tweets_df[['username', 'tweetcreatedts', 'retweetcount', 'text']]print('All-time top 10 tweets:')
print('\n')
alltime_top_tweets(data, 10)

All-time top 10 tweets between 3rd Nov to 16th Nov 2019.

某一天的前 10 条推文

我们还可以创建另一个函数来提取某一天的前 N 条推文:

def specified_toptweets(df, spec_date, N):
    # Arguments
    # df - dataframe
    # N - top N tweets
    # date - enter particular date in str format i.e. '2019-11-02'

    # Specific date
    spec_date = datetime.strptime(spec_date, '%Y-%m-%d').date()

    # Filter df by date first
    date_df = df[df['dt_date'] == spec_date ]

    # Sort according to 'retweetcount'
    top_tweets_date_df = date_df.sort_values(by = ['retweetcount'], ascending = False)
    # Drop also duplicates from the list, keep only the copy with higher retweetcount
    top_tweets_date_df.drop_duplicates(subset = 'text', keep = 'first', inplace = True)
    # Keep only N rows
    top_tweets_date_df = top_tweets_date_df.head(N)

    print('Top ' + str(N) + ' tweets for date ' + str(spec_date) + ' are:')
    # Print out only important details 
    # username, tweetcreatedts, retweetcount, original text 'text'
    return top_tweets_date_df[['username', 'tweetcreatedts', 'retweetcount', 'text']]

让我们试试 2019 年 11 月 5 日:

specified_toptweets(data, '2019-11-05', 10)

Top 10 tweets for 5th Nov 2019.

过去 5 天的前两条推文

好了,最后,我们还可以使用以下函数提取最近 T 天的前 N 条推文:

def past_toptweets(df, T, N, unique_date):
    # Arguments:
    # df - dataframe 'data'
    # T - last T days 
    # N - top N tweets
    # List of all unique dates in dataset

    # Create a df to store top tweets for all T dates, in case there is a need to manipulate this df
    past_toptweets_df = pd.DataFrame(columns = ['username', 'tweetcreatedts', 'retweetcount', 'text'])
    print(past_toptweets_df)

    # Filter data according to last T dates first:
    # Do a check that T must not be greater than the no. of elements in unique_date
    if T <= len(unique_date):
        unique_date = unique_date[-T:] # a list
    else:
        raise Exception('T must be smaller than or equal to the number of dates in the dataset!')

    # Print out top N for each unique_date one after another, starting from the latest:
    for ith_date in reversed(unique_date):
        # Filter tweets created on this date:
        ith_date_df = df[df['dt_date'] == ith_date]

        # Sort according to 'retweetcount'
        top_tweets_date_df = ith_date_df.sort_values(by = ['retweetcount'], ascending = False)
        # Drop also duplicates from the list, keep only the copy with higher retweetcount
        top_tweets_date_df.drop_duplicates(subset = 'text', keep = 'first', inplace = True)
        # Keep only N rows
        top_tweets_date_df = top_tweets_date_df.head(N)
        # Keep only essential columns
        top_tweets_date_df = top_tweets_date_df[['username', 'tweetcreatedts', 'retweetcount', 'text']]

        # Append top_tweets_date_df to past_toptweets_df
        past_toptweets_df = pd.concat([past_toptweets_df, top_tweets_date_df], axis = 0)

        # Print out the top tweets for this ith_date
        print('Top ' + str(N) + ' tweets for date ' + str(ith_date) + ' are:')
        # print only essential columns:
        print(top_tweets_date_df)
        print('\n')

    return past_toptweets_dfpast_toptweets(data, T = 5, N = 2, unique_date = unique_date)

Top 2 tweets for the last 5 days from 12 Nov to 16 Nov 2019.

函数“past_toptweets”的一个缺陷是,它可以返回完全相同的推文。例如,第一天的热门推文可以在随后的几天被其他用户转发。这个函数可以选择这样的 tweet,因为还没有实现逻辑来只考虑不是从较早日期选择的 tweet。

5.Twitter 用户的行为

每日推文数量

让我们来看看每日推文数量的趋势。我们将建立另一个数据框架,用于绘制可视化。

top_user_df = pd.DataFrame(columns = ['username', 'noTweets', 'noFollowers', 'dt_date'])# Convert datatype of 'totaltweets' to numeric
pd.to_numeric(data['totaltweets'])for ith_date in unique_date:
    print('Current loop: ', ith_date)

    temp = data[data['dt_date'] == ith_date]

    # pd.DataFrame - count number of tweets tweeted in that day - noTweets
    temp_noTweets = temp.groupby(['username']).size().reset_index(name = 'noTweets').sort_values(by = 'username', ascending = False)

    # pd.Series - count max followers - might fluctuate during the day
    temp_noFollowing = temp.groupby(['username'])['followers'].max().reset_index(name = 'noFollowers').sort_values(by = 'username', ascending = False)['noFollowers']

    # *** NOT WORKING
    # pd.Series - count max totaltweets - might fluctuate during the day. Note this is historical total number of tweets ever since the user is created.
    # temp_noTotaltweets = temp.groupby(['username'])['totaltweets'].max().reset_index(name = 'noTotaltweets').sort_values(by = 'username', ascending = False)['noTotaltweets']

    # Concat series to temp_noTweets, which will be the main df
    final = pd.concat([temp_noTweets, temp_noFollowing], axis = 1) # add as columns
    final['dt_date'] = ith_date

    print(final)

    # Append 'final' dataframe to top_user_df
    top_user_df = pd.concat([top_user_df, final])

绘制可视化图:

# hue = retweetcount and followers, totaltweets
f, axes = plt.subplots(3, 1, figsize = (22,22))
sns.set_palette('PuBuGn_d')
sns.stripplot(x = 'dt_date', y = 'noTweets', data = top_user_df, jitter = True, ax = axes[0], size = 6, alpha = 0.3)
sns.boxplot(y = 'dt_date', x = 'noTweets', data = top_user_df, orient = 'h', showfliers=False, ax = axes[1])
sns.boxplot(y = 'dt_date', x = 'noTweets', data = top_user_df, orient = 'h', showfliers=True, fliersize = 2.0, ax = axes[2])# Axes and titles for each subplot
axes[0].set_xlabel('Date')
axes[0].set_ylabel('No. of Tweets')
axes[0].set_title('No. of Tweets Daily')axes[1].set_xlabel('No. of Tweets')
axes[1].set_ylabel('Date')
axes[1].set_title('No. of Tweets Daily')axes[2].set_xlabel('Date')
axes[2].set_ylabel('No. of Tweets')
axes[2].set_title('No. of Tweets Daily')plt.show()

Top: Seaborn strip plot showing the number of tweets daily; middle: Seaborn box plot showing the distribution of tweets per user daily WITHOUT outliers; bottom: Seaborn box plot showing the distribution of tweets per user daily WITH outliers.

从 Seaborn box 图和 strip 图中,我们看到数据集中的大多数用户一天都不会发很多微博。从带状图中,我们可能无法辨别数据集中的异常值,并且可能认为大多数用户每天发的微博数量在 1 到 30 条以上。

然而,盒子情节告诉我们一个不同的故事。可视化中间的第一个方框图显示,大多数用户大约发了 1 到 8 条微博。另一方面,在可视化底部的第二个方框图中显示了许多异常值。这些用户发了很多推文,从 10 条起。在考虑的时间段内,至少有 7 个用户每天至少发 100 条以上的推文。

每日发推次数最多的前 5 名用户

让我们通过找出谁是顶级用户来进一步放大。

# To change the number of users, adjust the value in head()
# top_user_df.set_index(['dt_date', 'username']).sort_values(by = ['dt_date','noTweets'], ascending = False)
user_most_tweets_df = top_user_df.sort_values(by = ['dt_date', 'noTweets'], ascending = False, axis = 0).groupby('dt_date').head(5)# Extract 'days' out of dt_date so we can plot a scatterplot
# Will return an int:
user_most_tweets_df['dayofNov'] = user_most_tweets_df['dt_date'].apply(lambda x: x.day)
user_most_tweets_df['noTweets'] = user_most_tweets_df['noTweets'].astype(int)# Plot 2 subplots
# 1st subplot - show who are the users who tweeted the most
# 2nd subplot - trend in number of tweets
f, axes = plt.subplots(2, 1, figsize = (20,20))
f = sns.scatterplot(x = 'dayofNov', y = 'noTweets', hue = 'username', data = user_most_tweets_df, size = 'noFollowers', sizes = (250, 1250), alpha = 0.75, ax = axes[0])
sns.lineplot(x = 'dayofNov', y = 'noTweets', data = user_most_tweets_df, markers = True)# Axes and titles for each subplot
# First subplot
axes[0].set_xlabel('Day in Nov')
axes[0].set_ylabel('No. of Tweets')
axes[0].set_title('Most no. of tweets daily')# Legends for first subplot
box = f.get_position()
f.set_position([box.x0, box.y0, box.width * 1.0, box.height]) # resize position# Put a legend to the right side
f.legend(loc='center right', bbox_to_anchor=(1.5, 0.5), ncol=4)# Second subplot
axes[1].set_xlabel('Date')
axes[1].set_ylabel('No. of Tweets')
axes[1].set_title('Trend of no. of tweets by top users')plt.show()

Daily activities of top 5 users

6.Twitter 用户的人口统计数据

推特用户的位置

location = data['location']
print('No. of distinct locations listed by twitter users is:', len(location.value_counts()))
unique_locations = location.value_counts()# Remove n.a.
unique_locations = pd.DataFrame({'locations': unique_locations.index,
                                'count': unique_locations.values})
unique_locations.drop(0, inplace = True)# See top few locations
unique_locations.sort_values(by = 'count', ascending = False).head(10)

预计会看到这些用户中的许多人声称居住在香港,因为这些用户应该更接近地面。因此,他们可以通过亲眼所见迅速传播消息。

我们将把“香港”从视觉化中剔除,并专注于其余位置的分布:

# To remove 香港
hk_chinese_word = unique_locations.iloc[1,0]# Obtain the row index of locations that contain hong kong:
ind_1 = unique_locations[unique_locations['locations'] == 'hong kong'].index.values[0]
ind_2 = unique_locations[unique_locations['locations'] == 'hk'].index.values[0]
ind_3 = unique_locations[unique_locations['locations'] == 'hong kong '].index.values[0]
ind_4 = unique_locations[unique_locations['locations'] == 'hongkong'].index.values[0]
ind_5 = unique_locations[unique_locations['locations'] == hk_chinese_word].index.values[0]
ind_6 = unique_locations[unique_locations['locations'] == 'kowloon city district'].index.values[0]list_ind = [ind_1,ind_2,ind_3,ind_4,ind_5, ind_6]# Drop these rows from unique_locations
unique_loc_temp = unique_locations.drop(list_ind)# Focus on top 20 locations first
# Convert any possible str to int/numeric first
count = pd.to_numeric(unique_loc_temp['count'])
unique_loc_temp['count'] = count
unique_loc_temp = unique_loc_temp.head(20)# Plot a bar plot
plt.figure(figsize=(16,13))
sns.set_palette('PuBuGn_d')
sns.barplot(x = 'count', y = 'locations', orient = 'h',data = unique_loc_temp)
plt.xlabel('Count')
plt.ylabel('Locations')
plt.title('Top 20 Locations')
plt.show()

Top 20 locations of users

快速统计一下排名前 20 位的地点(不包括香港),就会发现这些地点大多来自西方国家。我们看到了预期中的国家,如美国、加拿大、英国和澳大利亚,那里的一些人和政治家也在关注抗议活动,并公开反对执政的政府和警察。

拥有最多关注者的前 30 名用户

# Reuse code from top_user_df
# Sort according to noFollowers
top_user_df = top_user_df.sort_values(by = 'noFol lowers', ascending = False)
user_most_followers = top_user_df.groupby('username')['noFollowers', 'dt_date'].max().sort_values(by = 'noFollowers', ascending = False)
user_most_followers['username'] = user_most_followers.index
user_most_followers.reset_index(inplace = True, drop = True)# plot chart
plt.figure(figsize = (25, 8))
sns.set_palette('PuBuGn_d')
sns.barplot(x = 'noFollowers', y = 'username', orient = 'h', data = user_most_followers.head(30))
plt.xlabel('No. of Followers')
plt.ylabel('Usernames')
plt.title('Top Twitter Accounts')
plt.show()

Seaborn bar chart for top 30 twitter accounts in terms of number of followers.

在排名前 30 位的账户中,大多数都属于新闻机构或媒体,如法新社、CGTNOfficial、EconomicTimes 和 ChannelNewsAsia。其余属于记者和作家等个人。约书亚·王(Joshua Wong)的账户是名单中唯一可以被确认为抗议活动一部分的账户。

大客户活动

user_most_followers_daily = top_user_df.sort_values(by = ['dt_date', 'noFollowers'], ascending = False, axis = 0).groupby('dt_date').head(5)
print(user_most_followers_daily)# Extract 'days' out of dt_date so we can plot a scatterplot
# Will return an int:
user_most_followers_daily['dayofNov'] = user_most_followers_daily['dt_date'].apply(lambda x: x.day)
user_most_followers_daily['noFollowers'] = 
user_most_followers_daily['noFollowers'].astype(int)

Top 5 users and their tweets per day

f, axes = plt.subplots(1, 1, figsize = (15,10))
f = sns.scatterplot(x = 'dayofNov', y = 'noTweets', hue = 'username',data = user_most_followers_daily, size = 'noFollowers', sizes=(50, 1000))# Axes and titles for each subplot
# First subplot
axes.set_xlabel('Day in Nov')
axes.set_ylabel('No. of Tweets')
axes.set_title('Daily activity of users with most number of followers')# Legends for first subplot
box = f.get_position()
f.set_position([box.x0, box.y0, box.width * 1, box.height]) # resize position# Put a legend to the right side
f.legend(loc='center right', bbox_to_anchor=(1.5, 0.5), ncol=3)

Daily activity of users with most number of followers. The size of each point is proportional to the number of followers.

尽管这些顶级账户有很多粉丝,但他们平均每天发布的推文数量不到 10 条。这种活动与“T4”栏目下每日发推次数最多的前 5 名用户相比就相形见绌了。

7.最常提及的用户名

我们能从这些推文中发现抗议运动中更多受欢迎的人物吗?Twitter 用户可能会标记这些人,以告知他们当地正在发生的事件。他们的背景可以是律师、立法者、政治家、记者,甚至抗议领袖。

def find_users(df):
    # df: dataframe to look at
    # returns a list of usernames

    # Create empty list
    list_users = []

    for i in range(0, len(df)):
        users_ith_text = re.findall('@[^\s]+', df.iloc[i,:]['text'])
        # returns a list
        # append to list_users by going through a for-loop:
        for j in range(0, len(users_ith_text)):
            list_users.append(users_ith_text[j])

    return list_users# Apply on dataframe data['text']
list_users = find_users(data)mentioned_users_df = pd.DataFrame({
    'mentioned_users': list_users
})mentionedusers = mentioned_users_df.groupby('mentioned_users').size().reset_index(name = 'totalcount').sort_values(by = 'totalcount', ascending = False)
mentionedusers.head()

Most mentioned users

plt.figure(figsize=(30,8))
sns.set_palette('PuBuGn_d')
sns.barplot(x = 'mentioned_users', y = 'totalcount', data = mentionedusers.head(15))
plt.xlabel('Mentioned users in tweets')
plt.ylabel('Number of times')
plt.title('Top users and how many times they were mentioned in tweets')
plt.show()

Most mentioned users in tweets from 3rd Nov to 16th Nov 2019.

在 15 个被提及最多的用户中,大部分(如果不是全部的话)都与香港和抗议运动直接相关。在谷歌上对这些用户进行快速搜索,结果显示他们要么支持抗议者和抗议活动,要么反对香港政府和警方。总而言之:

  1. @ Solomon yue——与美国通过的《香港人权与民主法案》有关的美籍华人政治家
  2. @ joshuawongcf——当地抗议领袖,原计划参加选举,但被禁止。
  3. @ GOVUK——威胁要制裁香港官员对抗议的处理
  4. @ HawleyMO——美国政治家
  5. @ heather wheeler——亚太事务部长,就拟议中的制裁致函香港政府官员。

Photo by Jonathan Chng on Unsplash

EDA 的结论

总而言之,从 2019 年 11 月 3 日开始到 2019 年 11 月 16 日的 14 天内,超过 20 万条关于 2019 年香港抗议运动的推文被删除。所需的主要步骤是设置 Twitter API 调用;对推文进行清理和处理;和创造海洋视觉效果。该项目的数据分析/可视化集中在几个主题上:

  1. 最受欢迎的词有一个词云
  2. 用来自 NLTK 的 Vader-Lexicon 进行情感分析
  3. 标签的流行度
  4. 最受欢迎的推文
  5. Twitter 用户的活动
  6. Twitter 用户的人口统计
  7. 最常提及的用户名

标签的有用性

值得注意的是,通过监测用户使用的标签的每日受欢迎程度和趋势,有可能确定抗议活动中的重要里程碑。理论上,这意味着人们可以简单地监控标签,而不用阅读新闻或滚动社交媒体来了解抗议运动的最新动态。

热门推文的有用性

最受欢迎的推文也有助于揭示普通推特用户对运动的持续情绪。我们可以这样理解。当关于某个事件或内容的推文被许多人转发时,这可能意味着这些人对该信息产生了共鸣,并希望与尽可能多的人分享。例如,《香港人权和民主法案》就是这样一个热门话题。最受欢迎的推文也可以提供关于一天的主要话题/事件的进一步细节和粒度。在上面标题为“最受欢迎的推文”的部分显示的证据中,我们看到这些推文经常涉及警察暴力和涉嫌不当使用武力的案件。

个人观察

完成这个项目后,我更加相信,对一个话题/想法的整体情绪可能取决于社交媒体平台,即 Twitter、脸书、微博等。

到目前为止,我们已经从这些推特上看到了香港抗议运动的整体情绪,对香港政府和警察的负面情绪压倒一切,但对抗议者的积极和支持。同样,在微博和其他中国媒体网站等平台上,我们可能会得到相反的反应,这些平台对香港政府和警方表示支持和赞扬。

然而,也有可能是我错了,因为搜索词中使用了标签,所以推文收集中存在缺陷。我们在搜索中使用的标签都是关于警察负面的,比如#hkpolicebrutality。使用它的人显然是用它来谴责这些所谓的暴行。回想起来,考虑# support hong kong police # supporthkgovt # supporthkpolice 等标签会更公平。我将把这个留给读者去探索这个元素。

基于规则的情感分析的缺点

我们在上面使用 NLTLK 的 Vader 库进行的基本情绪分析揭示了大量的误报——在仔细检查这些被评为对政府和警察积极的随机推文后,它们实际上要么是对他们消极,要么是支持抗议者的事业。因此,我们需要转向深度学习技术,这将为我们提供更好、更可靠的结果。

覆盖深度学习工作不在本项目的范围和目的之内。在分类一个小型推特数据集方面还需要做更多的工作,以便它可以用于预训练模型的迁移学习。

然而,根据我们手头的推文,抗议者和他们的事业得到了压倒性的支持,但公众对警察的暴行和不当行为表示强烈抗议。任何将推文分为正面或负面情绪的尝试,最终都可能导致对香港政府和警方负面情绪的高度倾斜分布。因此,用深度学习来预测情绪可能是不值得的。在我看来,相关 Twitter 推文的情绪很大程度上是负面的。

清理和预处理推文

从这里开始,对这个项目的数据清理流程感兴趣的读者可以继续阅读本文的剩余部分。

Photo by pan xiaozhen on Unsplash

导入库和数据集

在另一个 Jupyter 笔记本中:

# Generic ones
import numpy as np
import pandas as pd
import os# Word processing libraries
import re
from nltk.corpus import wordnet
import string
from nltk import pos_tag
from nltk.corpus import stopwords
from nltk.tokenize import WhitespaceTokenizer
from nltk.stem import WordNetLemmatizer# Widen the size of each cell
from IPython.core.display import display, HTML
display(HTML("<style>.container { width:95% !important; }</style>"))

每一轮 tweet 抓取都会创建一个. csv 文件。各读各的。先将 csv 文件转换成数据帧:

# read .csv files into Pandas dataframes first
tweets_1st = pd.read_csv(os.getcwd() + '/data/raw' + '/20191103_131218_sahkprotests_tweets.csv', engine='python')
..
..
tweets_15th = pd.read_csv(os.getcwd() + '/data/raw' + '/20191116_121136_sahkprotests_tweets.csv', engine='python')# Check the shape of each dataframe:
print('Size of 1st set is:', tweets_1st.shape)# You can also check out the summary statistics:
print(tweets_1st.info())

将所有数据帧连接成一个数据帧:

# Concat the two dataset together:
data = pd.concat([tweets_1st, tweets_2nd, tweets_3rd, tweets_4th, tweets_5th, tweets_6th, tweets_7th, tweets_8th, tweets_9th, tweets_10th, tweets_11th, tweets_12th, tweets_13th, tweets_14th, tweets_15th], axis = 0)print('Size of concatenated dataset is:', data.shape)# Reset_index
data.reset_index(inplace = True, drop = True)
data.head()
print(data.info())

您将在数据框中看到的片段:

检查重复条目并删除它们

由于我们是在彼此靠近的地方进行抓取,所以只要它们在 search_date 起 7 天的搜索窗口内,就有可能抓取到相同的推文。我们从数据集中删除这些重复的行。

# Let's drop duplicated rows:
print('Initial size of dataset before dropping duplicated rows:', data.shape)
data.drop_duplicates(keep = False, inplace = True)print('Current size of dataset after dropping duplicated rows, if any, is:', data.shape)

删除重复行之前数据集的初始大小:(225003,11)
删除重复行(如果有)之后数据集的当前大小为:(218652,11)

删除非英语单词/符号

由于可能会删除日常英语对话中使用的非英语单词,如姓名等,因此按中文过滤可能会更好。

# Remove empty tweets
data.dropna(subset = ['text'], inplace = True)# The unicode accounts for Chinese characters and punctuations.
def strip_chinese_words(string):
    # list of english words
    en_list = re.findall(u'[^\u4E00-\u9FA5\u3000-\u303F]', str(string))

    # Remove word from the list, if not english
    for c in string:
        if c not in en_list:
            string = string.replace(c, '')
    return string# Apply strip_chinese_words(...) on the column 'text'
data['text'] = data['text'].apply(lambda x: strip_chinese_words(x))
data.head()

提取每条推文中提到的 Twitter 用户名

我们希望从每条推文中获得有用的信息,因为我们可以分析谁是抗议运动中的热门人物。

# Define function to sieve out [@users](http://twitter.com/users) in a tweet:
def mentioned_users(string):
    usernames = re.findall('@[^\s]+', string)
    return usernames# Create a new column and apply the function on the column 'text'
data['mentioned_users'] = data['text'].apply(lambda x: mentioned_users(x))
data.head()

主文本清理和预处理

从每个文本中删除和提取中文单词和用户名后,我们现在可以做繁重的工作了:

# Define Emoji_patterns
emoji_pattern = re.compile("["
         u"\U0001F600-\U0001F64F"  # emoticons
         u"\U0001F300-\U0001F5FF"  # symbols & pictographs
         u"\U0001F680-\U0001F6FF"  # transport & map symbols
         u"\U0001F1E0-\U0001F1FF"  # flags (iOS)
         u"\U00002702-\U000027B0"
         u"\U000024C2-\U0001F251"
         "]+", flags=re.UNICODE)# Define the function to implement POS tagging:
def get_wordnet_pos(pos_tag):
    if pos_tag.startswith('J'):
        return wordnet.ADJ
    elif pos_tag.startswith('V'):
        return wordnet.VERB
    elif pos_tag.startswith('N'):
        return wordnet.NOUN
    elif pos_tag.startswith('R'):
        return wordnet.ADV
    else:
        return wordnet.NOUN# Define the main function to clean text in various ways:
def clean_text(text):

    # Apply regex expressions first before converting string to list of tokens/words:
    # 1\. remove [@usernames](http://twitter.com/usernames)
    text = re.sub('@[^\s]+', '', text)

    # 2\. remove URLs
    text = re.sub('((www\.[^\s]+)|(https?://[^\s]+))', '', text)

    # 3\. remove hashtags entirely i.e. #hashtags
    text = re.sub(r'#([^\s]+)', '', text)

    # 4\. remove emojis
    text = emoji_pattern.sub(r'', text)

    # 5\. Convert text to lowercase
    text = text.lower()

    # 6\. tokenise text and remove punctuation
    text = [word.strip(string.punctuation) for word in text.split(" ")]

    # 7\. remove numbers
    text = [word for word in text if not any(c.isdigit() for c in word)]

    # 8\. remove stop words
    stop = stopwords.words('english')
    text = [x for x in text if x not in stop]

    # 9\. remove empty tokens
    text = [t for t in text if len(t) > 0]

    # 10\. pos tag text and lemmatize text
    pos_tags = pos_tag(text)
    text = [WordNetLemmatizer().lemmatize(t[0], get_wordnet_pos(t[1])) for t in pos_tags]

    # 11\. remove words with only one letter
    text = [t for t in text if len(t) > 1]

    # join all
    text = " ".join(text)

    return(text)# Apply function on the column 'text':
data['cleaned_text'] = data['text'].apply(lambda x: clean_text(x))
data.head()

# Check out the shape again and reset_index
print(data.shape)
data.reset_index(inplace = True, drop = True)# Check out data.tail() to validate index has been reset
data.tail()

处理列“hashtags”

列“hashtags”的数据类型最初是 string,所以我们需要将其转换为 Python 列表。

# Import ast to convert a string representation of list to list
# The column 'hashtags' is affected
import ast# Define a function to convert a string rep. of list to list
## Function should also handle NaN values after conversion
def strlist_to_list(text):

    # Remove NaN
    if pd.isnull(text) == True: # if true
        text = ''
    else:
        text = ast.literal_eval(text)

    return text# Apply strlist_to_list(...) to the column 'hashtags'
# Note that doing so will return a list of dictionaries, where there will be one dictionary for each hashtag in a single tweet.
data['hashtags'] = data['hashtags'].apply(lambda x: strlist_to_list(x))data.head()

因为每个“hashtag”条目包含一个字典列表,所以我们需要遍历列表来提取每个 hashtag:

# Define a function to perform this extraction:
def extract_hashtags(hashtag_list):
    # argument:
    # hashtag_list - a list of dictionary(ies), each containing a hashtag

    # Create a list to store the hashtags
    hashtags = []

    # Loop through the list:
    for i in range(0, len(hashtag_list)):
        # extract the hashtag value using the key - 'text'
        # For our purposes, we can ignore the indices, which tell us the position of the hashtags in the string of tweet
        # lowercase the text as well
        hashtags.append(hashtag_list[i]['text'].lower())

    return hashtags# Apply function on the column - data['hashtags']
data['hashtags'] = data['hashtags'].apply(lambda x: extract_hashtags(x))# Check out the updated column 'hashtags'
print(data.head()['hashtags'])

处理列“位置”

# Replace NaN (empty) values with n.a to indicate that the user did not state his location
# Define a function to handle this:
def remove_nan(text):
    if pd.isnull(text) == True: # entry is NaN
        text = 'n.a'
    else:
        # lowercase text for possible easy handling
        text = text.lower()

    return text# Apply function on column - data['location']
data['location'] = data['location'].apply(lambda x: remove_nan(x))# Check out the updated columns
print(data.head()['location'])# Let's take a quick look at the value_counts()
data['location'].value_counts()

不出所料,大多数推文是由来自/在香港的用户发布的。由于这些是每条推文用户的位置,现在确定实际的人口统计数据还为时过早。我们以后再处理这个问题。

处理列“acctdesc”

我们通过删除 NaN 值并用字符串“n.a”替换它们来清理这个列 twitter 用户的帐户描述。

# Apply the function already defined above: remove_nan(...)
# Apply function on column - data['acctdesc']
data['acctdesc'] = data['acctdesc'].apply(lambda x: remove_nan(x))# Check out the updated columns
print(data.head()['acctdesc'])

特征工程——基于规则的文字处理

到目前为止,我们已经删除了重复的行,提取了重要的信息,如标签,提到了用户和用户的位置,还清理了推文。在这一节中,我们将重点放在基于规则的文字处理来进行情感分析。一旦我们有了所有的要素,探索性的数据可视化将在以后完成。

使用 NLTK Vader_Lexicon 库从推文中产生情感

我们使用 NLTK 的 Vader_lexicon 库为每条推文生成情感。维德使用词汇来确定推文中的哪些词是积极的或消极的。然后,它将返回一组关于文本的积极、消极和中立性的 4 个分数,以及文本是积极还是消极的总分数。我们将定义以下内容:

  1. 积极—“积极”
  2. 消极——“消极”
  3. 中立——“新”
  4. 总分—“复合”
# Importing VADER from NLTK
from nltk.sentiment.vader import SentimentIntensityAnalyzer# Create a sid object called SentimentIntensityAnalyzer()
sid = SentimentIntensityAnalyzer()# Apply polarity_score method of SentimentIntensityAnalyzer()
data['sentiment'] = data['cleaned_text'].apply(lambda x: sid.polarity_scores(x))# Keep only the compound scores under the column 'Sentiment'
data = pd.concat([data.drop(['sentiment'], axis = 1), data['sentiment'].apply(pd.Series)], axis = 1)

提取附加特征——每条推文中的字符数和字数

# New column: number of characters in 'review'
data['numchars'] = data['cleaned_text'].apply(lambda x: len(x))# New column: number of words in 'review'
data['numwords'] = data['cleaned_text'].apply(lambda x: len(x.split(" ")))# Check the new columns:
data.tail(2)

单词嵌入—使用 Gensim 训练 Doc2Vec

单词嵌入涉及将文本语料库中的单词映射到数字向量,其中共享相似上下文的相似单词也将具有相似向量。它涉及一个浅层两层神经网络,该网络训练一个称为嵌入矩阵的矩阵/张量。通过取嵌入矩阵和语料库中每个词的一热向量表示的矩阵乘积,我们获得嵌入向量。

我们将使用 Gensim——一个开源 Python 库——来生成 doc2vec。

注意:应该在 word2vec 上使用 doc2vec 来获得“文档”的向量表示,在本例中,是整个 tweet。Word2vec 只会给我们一个 tweet 中单词的向量表示。

# Import the Gensim package
from gensim.test.utils import common_texts
from gensim.models.doc2vec import Doc2Vec, TaggedDocumentdocuments = [TaggedDocument(doc, [i]) for i, doc in enumerate(data["cleaned_text"].apply(lambda x: x.split(" ")))]# Train a Doc2Vec model with our text data
model = Doc2Vec(documents, vector_size = 10, window = 2, min_count = 1, workers = 4)# Transform each document into a vector data
doc2vec_df = data["cleaned_text"].apply(lambda x: model.infer_vector(x.split(" "))).apply(pd.Series)
doc2vec_df.columns = ["doc2vec_vector_" + str(x) for x in doc2vec_df.columns]
data = pd.concat([data, doc2vec_df], axis = 1)# Check out the newly added columns:
data.tail(2)

计算 TD-IDF 列

接下来,我们将使用 sklearn 库计算评论的 TD-IDF。TD-IDF 代表词频-逆文档频率,用于反映一个词在集合或语料库中对一个文档的重要程度。TD-IDF 值与单词在文档中出现的次数成比例地增加,并被语料库中包含该单词的文档的数量所抵消,这有助于调整某些单词通常出现更频繁的事实。

  1. 术语频率—术语在文档中出现的次数。
  2. 逆文档频率—逆文档频率因子,减少文档集中出现频率很高的术语的权重,增加出现频率很低的术语的权重。

由于 NLTK 不支持 TF-IDF,我们将使用 Python sklearn 库中的 tfidfvectorizer 函数。

from sklearn.feature_extraction.text import TfidfVectorizer# Call the function tfidfvectorizer
# min_df is the document frequency threshold for ignoring terms with a lower threshold.
# stop_words is the words to be removed from the corpus. We will check for stopwords again even though we had already performed it once previously.
tfidf = TfidfVectorizer(
    max_features = 100,
    min_df = 10,
    stop_words = 'english'
)# Fit_transform our 'review' (the corpus) using the tfidf object from above
tfidf_result = tfidf.fit_transform(data['cleaned_text']).toarray()# Extract the frequencies and store them in a temporary dataframe
tfidf_df = pd.DataFrame(tfidf_result, columns = tfidf.get_feature_names())# Rename the column names and index
tfidf_df.columns = ["word_" + str(x) for x in tfidf_df.columns]
tfidf_df.index = data.index# Concatenate the two dataframes - 'dataset' and 'tfidf_df'
# Note: Axis = 1 -> add the 'tfidf_df' dataframe along the columns  or add these columns as columns in 'dataset'.
data = pd.concat([data, tfidf_df], axis = 1)# Check out the new 'dataset' dataframe
data.tail(2)

关闭

我希望你获得了和我一样多的见识。欢迎留下评论来分享你的想法,或者就任何技术方面或我对数据的分析来纠正我。

感谢您花时间阅读这篇冗长的文章。

方差及其变异分析

原文:https://towardsdatascience.com/analysis-of-variance-and-its-variations-6ef3f8fbeb05?source=collection_archive---------10-----------------------

在统计学中,当试图比较样本时,我们首先想到的是进行学生的 t 检验。它比较两个样本(或一个样本和总体)的平均值相对于平均值或合并标准差的标准误差。虽然 t 检验是一个稳健而有用的实验,但它仅限于一次比较两组。

为了一次比较多个组,我们可以看 ANOVA,或方差分析。与 t 检验不同,它比较每个样本内的方差与样本间的方差。罗纳德·费雪在 1918 年引入了术语方差及其正式分析,方差分析在 1925 年因费希尔的研究人员统计方法而广为人知。学生 t 检验遵循 t 分布,遵循正态分布的形状,但是它具有较厚的尾部,以说明样本中更多远离平均值的值。

Source: Wikipedia

然而,方差分析遵循 f 分布,这是一个具有长尾的右偏分布。对于仅有的两组,我们可以直接使用 f 分布来比较方差。

如果 U1 和 U2 是独立变量,分别由自由度为 d1 和 d2 的卡方分布分布,则随机变量 X(其中 X = (U1/d1)/(U2/d2))遵循参数为 X~F(d1,d2)的 F 分布,其 PDF 由下式给出:

Source: Wikipedia; (B=Beta Function)

Anova 使用相同的分布,但是它计算 f 值的方式因所执行的 ANOVA 测试的类型而异。最简单的方差分析形式是单向方差分析测试,它允许我们通过评估一个自变量和一个因变量来比较多个组。一般而言,方差分析遵循三个主要假设:

因变量的分布应该是连续的和近似正态的

样本的独立性

方差的同质性

Anova 随后评估组间方差与组内方差的比值,以计算其 f 值。下表给出了单因素方差分析:

Source: Analytics Buddhu

一旦我们计算出我们的 F 比率,我们就可以将其与我们的 F 临界进行比较,以确定我们是否可以拒绝我们的零假设。对于 Anova 检验,我们的替代假设是组中至少有一个组彼此不同,因此可以进行特别检验,如最小显著性平方或 Tukey 的 HSD(诚实显著性检验)。这些过滤器通过所有组合来确定哪些样本组彼此不同。只有当我们的 Anova 返回具有统计学意义的结果时,才执行这些测试。

方差分析的变化

正如我上面所说的,单向方差分析只能解释一个独立变量和因变量。单向方差分析有一些扩展,允许我们避开这些限制。第一个是双向方差分析。这个测试仍然要求我们只有一个因变量,但是我们能够包括多个自变量来分析组间的方差。由于我们有多个变量,两个计算发生,主要影响和相互作用的影响。主效应分别考虑每个独立变量,而交互效应同时考虑所有变量。

双向方差分析实际上是一种因子方差分析,这意味着测试将包含多个独立变量水平(也称为因子)。简单地说,双向方差分析是水平为 2 的因子方差分析。所以三向方差分析有三个自变量,四向方差分析有四个自变量,依此类推。最常见的水平是 2 和 3,因为在单向方差分析中很难解释以上水平。变异性在组内和组间进行比较,而阶乘方差分析将每个因素的水平与其他因素进行比较。

单向方差分析的另一个限制是通过执行方差分析来解决的,它允许我们比较一个以上因变量的组间方差。与返回单变量 f 值的 anova 相比,Manova 将返回多变量 f 值。多变量 f 值将仅指示检验是否显著,它不提供关于组间哪个特定变量不同的信息。为了了解一个或多个因变量中哪些是显著的,需要进行单向 Anova 测试以获取每个变量的单变量 f 值,然后进行特别测试。

以上所有测试的一个主要假设是我们的样本是相互独立的。这种假设意味着我们无法随着时间的推移对群体进行评估,或者测量同一受试者的多个结果。对于仅有的两组,这可以很容易地通过使用相关 t 检验来解决。重复测量 Anova 是从属 t 检验的扩展,它允许我们在多个类别或时间内评估相同的从属受试者。

重复测量方差分析的计算非常类似于单向方差分析。它不是在组之间和组内划分,而是在时间/条件之间划分,在条件/时间内划分为 2 个更小的类别,其中 SSw 等于 ss subjects+s error。由于我们在每组中使用相同的受试者,我们可以消除受试者的可变性,从而使组内误差更小。

Source: statistics.laerd.com

这种划分最终增加了我们的 F 统计量,这意味着重复测量方差分析在发现统计差异方面具有更大的能力。然而,如果我们组内可变性的减少超过自由度的减少,这只会导致更强有力的测试。

我最近做了自己的项目,比较了几十年来每年的平均气温。我最初的错误是进行单向方差分析,忘记了我的不同“组”是相互依赖的。我无法摆脱这种感觉,即我进行了错误的测试,我想更深入地挖掘,因此我写了这篇文章。我回到我的数据,使用重复测量 Anova 在 Python 中重新运行测试,得到了以下结果。

给定我的结果和 0.05 的α,我发现 F 临界值为 2.77,因此我能够拒绝我的零假设,即不同年代的温度保持不变。理解测试的假设和需求总是很重要的,这样才能确保我们执行准确和正确的测试。作为一名数据科学家,我们的工作是确保我们总是执行正确的测试,而不仅仅是那些给我们想要的答案的测试。

来源:

[## 方差分析

方差分析(ANOVA)是统计模型及其相关估计程序的集合(例如…

en.wikipedia.org](https://en.wikipedia.org/wiki/Analysis_of_variance) [## 方差分析检验:定义、类型、实例

统计学定义>方差分析内容:方差分析测试单因素方差分析双因素方差分析什么是方差分析?什么是阶乘…

www.statisticshowto.datasciencecentral.com](https://www.statisticshowto.datasciencecentral.com/probability-and-statistics/hypothesis-testing/anova/#targetText=There are two main types,double-testing that same group.) [## f 分布

在概率论和统计学中,F 分布,也称为斯奈德尔的 F 分布或…

en.wikipedia.org](https://en.wikipedia.org/wiki/F-distribution#targetText=In probability theory and statistics,%2C e.g.%2C F-test.) [## 重复测量方差分析

重复测量方差分析相当于单向方差分析,但对于相关的,而不是独立的群体,是…

statistics.laerd.com](https://statistics.laerd.com/statistical-guides/repeated-measures-anova-statistical-guide.php)

使用 Python (Pandas,Plotly,SodaPy)分析轻轨网络

原文:https://towardsdatascience.com/analysis-on-the-light-rail-network-using-python-pandas-plotly-sodapy-6a8f255eb225?source=collection_archive---------12-----------------------

我记得当我听说堪培拉最新的公共交通时,我是多么兴奋。我只去过澳大利亚的几个地方,但我觉得堪培拉错过了悉尼和墨尔本的轻轨系统,因为它们非常方便,感觉很棒🏎

我喜欢轻轨运行的平稳程度 (可能除了在到达终点站 Gungahlin 之前的那一小段,在那里感觉好像电车从轨道上刮去了税款) ,它如何节省汽油、停车或只是一般的旅行费用(优惠利率——我在大学,我有折扣,政府理解我的财务困难,因为我把钱都花在大米上了sob)。乘坐电车往返城市对我来说很有意义,这太棒了!

但是就像世界上的所有事情一样,轻轨解决方案也有一些问题需要解决,比如险些出事🤦🏽和事故,这可能会导致其他事情的延迟。在这篇文章中,我想看看延迟并收集一些见解。

TL;速度三角形定位法(dead reckoning)

Jupyter 笔记本:

(全代码)

平均上,轻轨在高峰时段延误有多严重?— 全行程* (阿林加圣⟷贡加林广场)

  • 到阿林加街:晚 13.8 秒(上午 8 点)
  • 到 Gungahlin Pl: 晚 25.5 秒(下午 5 点)

服务—完成百分比?💯

  • 工作日: 212 次-100%
  • 星期五: 224 次旅行— 100%
  • 星期六: 152 次旅行——100%
  • 周日: 123 趟——100%

记录的最长延迟时间是多少,是否与任何事故有关?

哪个车站在终点站停车后延迟最长?

  • 到阿林加街:埃卢埃拉街—9: 上午 25 点(9.1 分钟;8 月至 12 日)
  • 到贡加林 Pl: 曼宁克拉克 Cr —上午 7:18(11.3 分;8 月 20 日)

关于数据

堪培拉地铁运营 (CMO)运营着堪培拉有史以来第一条轻轨。轻轨系统已经运行了几个月,往返于城市和贡加林之间。你可能听说过在电车向公众开放的第一个月,人们来回乘坐电车。ACT 政府最近开始通过他们的开放数据门户发布轻轨数据 ( 车辆车次)。他们以通用交通馈送规范(GTFS)格式提供完整的时间表,其中集成了谷歌地图的实时更新。有关更多信息,请参考以下链接:

数据收集

Socrata 开放数据 API :我从 ACT 的开放数据门户对 轻轨历史档案 进行了 API 调用,以获取几个月的 行程更新 记录,因为有时数据越多越有趣—

(注:轻轨有 2 组信息实时更新并存档— 车辆行程更新,以下要点从门户拉存档的行程** 更新)**

Retrieve data from ACT Open Data Portal

对于以下文件,我们可以从堪培拉交通局网站上发布的 GTFS 数据馈送 中提取。

行程(GTFS) :我们想从获取trips.csv文件,因为它包含每个行程route_id,这将有助于以后将部分(井场→贡加林 Pl | EPIC→阿林加 St)行程与全部(贡加林 Pl →阿林加 St)行程分开。

停靠站(GTFS) :我们也想得到这个stops.csv,因为我们想显示停靠站的名称,而不只是让它的stop_id在以后可视化。

在 GTFS,全车次有一个*ACTO001*,而部分车次可以是 *X1* *X2* ****

数据争论

这里是我对数据集做的一些事情。(朱庇特笔记本)**

  • 按时间顺序对数据集进行排序(最早到最晚)**
  • 选择适合用于此分析的列
  • 转换列的数据类型
  • 重命名一些列
  • 将轻轨记录与预约公交车沿轻轨路线行驶并在高峰时段将人从 A 点到 B 点的公交车分开**
  • 掉起飞延误(departure delay好像和arrival delay一样。我期望在某些事件期间看到到达和延误之间的一些变化,例如电车故障、事故、未遂事故——但在数据集中似乎没有变化**

删除预测记录

我想查看数据集中的到达和离开时间,并将其与指示数据检索时间的时间戳进行比较。我这样做的原因是,我只想汇总历史记录。查看下面列出的date range,似乎在我们的数据集中有预测到达时间的行。

Last 10 rows of the data pulled from the Open Data Portal with a filter to see which rows have predicted values

添加其他信息

我还想为每次旅行添加路线类型,以便能够通过添加monthdays来帮助我按照月份和工作日对行进行过滤和分组,从而将分类为partial tripfull trip

这段代码将为我们提供这个分析的最终数据集。

First five rows of the working dataset

数据分析

我想在宏观层面上查看数据集,我想根据行程的路线和目的地对行程进行分类:

  • 路线 id :部分(X1X2)和全部(ACTO001)行程。
  • 行程目的地 : ( Gungahlin Pl)和(Alinga St)。

我有兴趣看到以下内容:

高峰时段轻轨平均晚点多少?

轻轨的总行程数是多少(按路线、目的地和服务)?

记录的最长延迟时间是多少,是否与任何事故有关?

哪个车站在终点站停车后延迟最长?

假设—高峰时段的延误

参照 CMO 出版的 频率指南 可以得知峰值时间如下:

到阿林加街(每 6 分钟一趟,电车到达每个车站):**

  • 上午 7:00 至 9:00:早高峰时间
  • 下午 4:00 到 5:30:晚高峰时间

到 Gungahlin Place ( 每 6 分钟—电车到达每个车站):

  • 早上 7:30 到 9:00:早高峰时间
  • 下午 4 点到 6 点:晚高峰时间

Data visualisation of the aggregated (average) delays from the trips in the dataset — (Plotly)**

从上图中,我们可以看出,在所有 13 个站点中,前往 思域 的轻轨平均在上午 8:00 左右晚点 13.8 秒,前往 君临 的轻轨平均在下午 5:00 左右晚点 25.5 秒

考虑到人们正前往工作,人们已经预料到去 Civic 的最高到达延迟将是在清晨左右。有趣的是,到达冈加林的时间会延迟。去思域的时候几乎是两倍的量。

分析 1——计划行程与观察行程的总次数

查看堪培拉交通局提供的trips.csv文件,我们可以提取轻轨的静态时间表,并计算出某一天应该有多少趟车。GTFS 有一个名为service_id的元数据,它为计划的旅行次数指定了工作日。

Number of expected trips for each weekday taken from static timetable (GTFS) — (Plotly)

现在看看工作数据集,我们可以细分每个月(6 月 19 日-8 月 24 日)的图表。

Number of actual trips from the 19th of June to the mid-day of 24th of August

然后,我们可以开始绘制静态时间表和每天发生的行程之间的差异,并获得每天完成的行程的百分比。

看上面的图表,汇总每天的数据来查看周五和周日是否完成了旅行次数有点棘手。这是因为周五和周日的服务与其他日期重叠,当数据被聚合时,重叠的数据被添加到它所属的工作日,而不是到服务本身。

我们可以根据服务 id 来计算唯一行程 id 的数量,而不是每天汇总数据。—我们 100%完成了行程!**

分析 2 —记录的最高延迟时间;它与任何事件有关吗?

图中最明显的异常是发生在 7 月 16 日的延迟。汽车撞上电车的日期是哪一天?—https://www . Canberra times . com . au/story/6276799/car-and-tram-crash-on-light-rail-line/

**********

延迟上升的第一个实例发生在斯温登街(停止序列 8)——我们可以将此与纳拉伯大道和斯温登街交叉口发生事故的新闻相关联。由于坠机,延误了 11.8 分钟。****

对于 8 月,异常值来自 8 月 12 日。还有一起事故,一名行人被电车撞了。—https://www . ABC . net . au/news/2019-08-12/行人被堪培拉轻轨撞/11404506 。延迟时间长达 9.6 分钟。

分析 3-在终端停止后,哪个停止的延迟最高?

Stop Sequence 12 to Alinga St. is Elouera Street

这里延迟最高的是前往阿林加街的行程,8 月 9 日到达埃卢埃拉街时,比*晚了 9 分钟到达。*******

Stop Sequence 9 is Well Station Drive

有趣的是,记录到 Gungahlin 的最高延迟是 712 秒的井站驱动(停止顺序:9)或延迟 717 秒(大约 12 分钟)的nullabor Avenue(停止顺序:10)。****

最终考虑

理解有轨电车服务的延误对于物流问题和环境原因是很重要的。如今,越来越多的居民尝试乘坐电车,并不得不应对对这种公共交通工具日益增长的需求。

在这里,我们试图研究这个问题的一部分:通过显示哪些停靠序列和哪些行程具有最高的延迟。我们可以更好地安排需求,并确定未投入使用的轻轨的最佳维护日期。过马路时请小心,注意周围的环境🙏。

注意:我还计划建立一个仪表板,使用 Elasticsearch 框架将所有这些信息汇集到一个视图中。我对数据分析和这类事情还很陌生,所以如果你知道有关于 elasticsearch 或 Kafka 的好材料的文章或教程,请让我知道!在那之前-保持可爱!

分析师来自金星,经理来自火星

原文:https://towardsdatascience.com/analysts-are-from-venus-managers-are-from-mars-9193113167cd?source=collection_archive---------19-----------------------

你好,我的名字是 Aviad,我是一个数据迷。

作为一名分析师,我有时会对与高层管理人员一起工作感到沮丧。这不是针对个人的,我们只是有两种不同的心态。这篇文章是关于解决管理者对数据分析的一些常见误解。

他使用统计数据就像一个醉汉使用灯柱一样——为了支撑而不是为了照明。

~苏格兰小说家安德鲁·朗

错误 1

让我们检查一切!

给分析师数据并指示他“告诉我一些我不知道的事情”是一个冒险的举动,结果会有很大的不同(以意想不到的方式),这取决于分析师的技能、经验和随机因素,如他当前的精神状态——这根本不是科学方法的工作方式。

对于人群中的所有怀疑者,我提供一个简单的测试:去找你的家庭医生,要求做所有的测试。他的答案将是直截了当的“不”,第一个原因是这是浪费时间和资源,第二个也是更重要的原因是你得到假阳性。

更正确的方法是让你的分析师使用数据提出有趣的假设,而你,经理,将评估哪些假设对业务有潜在的重要意义。然后,分析师将尝试验证或否定这些特定的假设。

错误 2

只有一个事实

分析相同的数据集并不能保证不同的人会得到相同的结果。从相同的原始数据中得到相互矛盾的结果,这可能会让一些经理感到惊讶。重要的是要明白,重要的不仅是你算什么,还有你怎么算

你下一个生日是几岁?让我们假设你出生于 2000 年 1 月 1 日。2030 年 1 月 2 日,你几岁了?嗯,根据公历的假设,你将是 30 岁,但你的韩国年龄实际上是 31 岁,你的回历年龄大约是 29 岁零 10 个月。

我们在分析数据时盲目应用的假设对数据本身的质量同样重要。作为经理,你需要理解潜在的假设,而不仅仅是最终结果。不这样做的经理们倾向于强迫他们的分析师总是重复相同的假设(即使这是一个严重的错误),只是为了让结果看起来一致,容易比较,尽管事实上并非如此。

错误 3

相关性表明因果关系

它没有!让我们用这个有趣的例子:你配偶的平均快乐程度与你给他们买花的次数成强烈的负相关。你有没有注意到,就在你递给他/她一束漂亮的花的时候,他们总是在为某件事烦恼?显然,这个事实并不意味着送花会让人难过。

A 和 B 之间的相关性可能意味着以下三种情况之一:

  1. a 导致 B
  2. b 导致 A
  3. 或者在我们的具体例子中,C 导致 A B(你做了一些愚蠢的事情,让你的配偶感到不安和内疚,让你给他们买花)

发现相互关系、现象、效果等。远不如建立解释它们为什么会发生的理论模型重要。观察到可以用单一理论解释的矛盾现象并不少见。不理解这一点的经理有可能根据短暂的观察做出糟糕的临时决策。

错误 4

数据不会说谎

具体来说,我说的是图表……不要误解我的意思,图表很神奇,它让你不用浪费太多脑力就能立即发现趋势和异常——但是可能会带来问题。即使使用 100%准确的数据,用图表撒谎也是如此容易。

这里有一个小练习:试着理解这三个例子中的偏见【感谢: Chiqui Esteban,国家地理】。

1.破碎的鳞片

2.虚假因果关系

3.缺失的视角

总结:数据政治

在这篇短文中,我们讨论了关于数据的四种常见误解。我认为它们源于管理者和分析师对数据的不同理解:

  • 经理们倾向于使用数据来支持他们的决策,公司的议程,有时只是为了感觉在控制中。因此,管理者通常寻求高度可视化和一致的数据。
  • 分析师寻求“狩猎的刺激”,揭示复杂和隐藏的真相。对于分析师来说,数据是一个游乐场,但我们确实需要知道游戏规则。

分析师和经理应该协同工作:经理定义游戏的方向和目标。分析师只是想找点乐子,确保没人作弊。一个好的经理应该理解游戏规则,就像一个好的分析师应该理解他为什么要玩游戏一样。

分析——公司犯的 5 个错误

原文:https://towardsdatascience.com/analytics-5-mistakes-that-companies-make-5ab2af614f56?source=collection_archive---------16-----------------------

分析是每个公司都在研究的东西。从初创公司到传统公司,我们看到了数据使用和分析的繁荣。

抛开隐私问题和人工智能收购恐慌,这里是我看到的(新旧)公司在分析方面犯的 5 个错误:

Fancy new tool [ Photo by Markus Spiske on Unsplash ]

为那个漂亮的新锤子找个钉子

数据分析有很多工具可以做很多事情。然而,我看到一些公司采取了错误的方式:他们首先选择工具,然后寻找问题来打击他们。因此,为了赶上数据科学炒作的列车,他们寻找任何有大量数据的数据库,并试图提出他们可以使用它们的东西。

示例:上下班打卡时间。你可以试着分析为什么员工会错过工作日,或者他们会迟到多长时间,甚至可以跟踪办公室里流行的流感。最终,它不会解决任何问题,也不会给你带来任何有用的见解,还会增加任何员工都不喜欢的监督(也许除了一个糟糕的经理)。人的因素和当地的例外太大了,不容忽视。如果你打算由此产生任何行动,那只会很尴尬。

另一方面,例如,关于顾客进出健身房的数据是非常需要的。你可以画出你一天中最忙的时间,为更好的课程或额外的教练做计划。这是有用的数据,将带来有实际影响的行动。

总是使用最好的工具而不是最便宜的工具

工作的最佳工具并不总是最合适的。我知道这听起来违背直觉,但请耐心听我说。有时候,如果你能使用更简单/更便宜的工具,你就不需要在工具上花很多钱/时间。当我们谈到用于分析的数据存储时,我们可以使用许多东西:SQL 数据库、数据仓库、NoSQL 数据库、数据湖等。各有各的用处,各有各的价格。公司有时更喜欢将数据仓库用于 PowerBI 报告,因为 DW 是存储结构化数据的理想场所。完美,他们 100%正确。但是,如果您的数据集市上只有大约 10 个合理大小的表,为什么会得到一个 DW 呢?SQL 数据库肯定可以完成这项工作,只需一半的价格。价格标签可能是扼杀你的项目的唯一问题。

将 BI/分析部门置于 IT/营销/财务部门之下

要实现真正的数据民主,你的分析部门不能在一个职能领域之下。它需要和它们肩并肩。否则,它将强烈地偏向那个地区,并将公司拉向那个地区。如果在 it 之下,它将专注于技术,无法为公司提供新产品和收入流。如果在金融领域,它将过于关注成本/回报,可能会破坏创新、实验项目和非营利项目(想想社区福祉之类的)。如果是在营销之下,那将是一个专注于花言巧语的梦工厂,不一定能带来想要的结果。对于一个好的数据分析操作来说,平衡技术强、有创造力且注重效率的人是必要的。

分离数据科学和数据工程团队,或将数据科学家和工程师融合成一个人

一些经理喜欢将这两种完全不同的技能组合在一个角色中。虽然他们听起来几乎一样,但他们应该是两个独立的团队。数据工程师是与职能部门一起工作的 IT 专家。数据科学家/分析师是有远见的人,更倾向于数学和统计。你可以让一个人同时做这两件事,但是这是不可扩展的。一个小的操作可能会工作一段时间,但随着项目的增长,这些人迟早会变得专业化。

数据科学和数据工程团队需要尽可能地合作。让他们在同一个经理手下,在同一个房间里,面对面坐着,在同一个邮件群里,等等。没有一个是没有另一个的,一个中间人只会碍手碍脚。数据工程师需要看到他们的工作被使用,他们可能会发现数据科学家会感谢上帝的微小改进。数据科学家需要看到他们的数据到达他们手中,他们可能会在他们可能不需要的东西上节省数据工程的大量时间。

浪费完美的数据

到处都有很多被浪费的潜力。不是由数据驱动的公司会错过很多机会。管理层忙于运营,以至于经常忽视数据的价值。公司内部应该有一个对分析潜力的长期观察。有用的数据不难识别,请注意以下几点:

答:客户行为数据
任何有助于对客户进行细分、描述或聚类的数据都是好数据。它可用于利用营销活动/经常性销售/总销售额,甚至瞄准新的销售线索。

b. 供应商行为数据
同样的思路。虽然我在这里看到了更大的浪费。公司通常不会像分析客户那样分析他们的供应商,他们正在错失良机。与主要供应商的良好关系是无价的。

c. 遥测/传感器数据/工业数据
运营部门用于日常监控和任务的相同数据可用于预测性维护。预测性维护是高级分析领域的明星。如果您没有使用它,这是时候拿出 ML 算法,看看那些维护成本被削减到最低限度。有人会在这里得到提升,我保证!

d. 销售业绩
投资回报率需要记在每个人的心里。活动跟踪至关重要。要知道,每笔销售的精确来源是为了获得更大的销售。可视化工具在这里是必须的。

e. 仓库/库存状态
任何关于库存变动的数据都可以识别浪费、优化潜力、未来需求和损失预防方面的改进。

这是我的真实想法,我很乐意进一步讨论这个话题。作为我的第一个帖子,这是令人兴奋的!请让我知道你的想法:)

分析构建模块:二元分类

原文:https://towardsdatascience.com/analytics-building-blocks-binary-classification-d205890314fc?source=collection_archive---------11-----------------------

模块化笔记本电脑,以控制面板的方式用最少的编码调整和比较 9 种分类算法

Common Binary Classification Task

欢迎来到第二期分析构建模块!我的回归笔记本上的反馈是出版分类笔记本的巨大动力。如果您已经使用了回归笔记本,您可以滚动到底部,从我的 GitHub repo 访问该笔记本,因为结构保持不变。如果没有,请继续阅读…

本文总结并解释了我的分类模块(我正在开发的用于执行常见分析任务的简单模块化笔记本之一)的关键模块。该笔记本旨在帮助对分类模型和 Python 编程有一定了解的用户更快地进行实验。然而,这一次我已经包括了一些其他的伟大的文章,给用户关于这个主题的先验知识。GitHub 到笔记本的链接在文章底部!

介绍

与回归问题类似,分类也是分析学中的经典问题之一。通过预测数据属于某一类的概率,任何分类都可以转化为回归问题,但我们暂时不会深入探讨。这是我分享创建这些笔记本的标准动机:很多时候,在执行分析任务时,通过测试不同的模型形式来确定最合适的模型,以根据手头的问题提供准确性、复杂性和执行效率的良好平衡,这是很好的快速失败。RapidMiner 等一些软件提供此功能。然而,出于这个目的使用软件产品会导致在调整模型和探索一些复杂性方面的黑盒方法。因此,我决定创建一个简单的 python 脚本,它具有足够的模块化和参数化,能够测试和调整许多广泛使用的分类算法,只需对代码进行最小的更改。
本笔记本摘要如下:

目标:

在 Python 中以最少的人工干预测试、调整和比较各种分类模型。
本模块包含的车型有:

  • 逻辑回归
  • 脊线分类器
  • k 个最近邻居
  • 决策树分类器
  • 随机森林
  • 打包(默认使用决策树)
  • 梯度推进
  • XGBoost
  • 支持向量机

用户熟练程度:

用户应该对每种算法的工作原理有一个直观的了解,并且很好地理解改变一个特定的超参数会如何影响结果。需要对 python 有基本的了解,以便能够有效地利用代码,并根据需求进一步定制代码。

尽管如此,我还是包含了一些很棒的文章的链接,以便理解这些算法的基础:

  • 逻辑回归:

[## 逻辑回归—详细概述

逻辑回归在二十世纪早期被用于生物科学。它后来被用于许多社会…

towardsdatascience.com](/logistic-regression-detailed-overview-46c4da4303bc)

  • 决策树分类:

[## 决策树很容易解释

决策树(DTs)是一种用于分类和回归的非参数监督学习方法。决定…

medium.com](https://medium.com/@chiragsehra42/decision-trees-explained-easily-28f23241248)

  • 集合模型:

[## 两个比一个好:集合模型

组装起初听起来像是一个非常吓人的词,但实际上看起来很简单…让我解释一下组装…

towardsdatascience.com](/two-is-better-than-one-ensembling-models-611ee4fa9bd8)

  • 评估分类模型的指标:

[## F1 评分 vs ROC AUC vs 准确性 vs PR AUC:应该选择哪种评价指标?|海王星的…

所以你在做一个机器学习项目,并且在想:什么时候准确度是比 ROC AUC 更好的度量?什么是…

海王星. ai](https://neptune.ai/blog/f1-score-accuracy-roc-auc-pr-auc) [## 理解 AUC-ROC 曲线

在机器学习中,性能测量是一项基本任务。所以说到分类问题,我们可以…

towardsdatascience.com](/understanding-auc-roc-curve-68b2303cc9c5)

关键可修改输入:

以下是关键输入(行内注释中为每个输入提供了更多详细信息)。这些部分在代码中用注释“突出显示,在此处进行修改”:

  • 用于分类分析的输入数据集:在本例中,我使用了来自熊猫默认数据集的“乳腺癌”数据集
  • 测试数据比例:0 到 1 之间,默认为 0.3(或 30%)
  • 归一化:0-无归一化,1-最小-最大缩放,2-Z 分数缩放
  • 要测试的模型对象列表
  • 网格搜索的折叠次数(超参数调整)
  • 确定最佳模型的评分标准(例如,准确性)—代码注释中提供了更多详细信息
  • 在模型拟合期间查看端子详细程度的标志:0-无输出,1-所有详细信息,2-进度条
  • 超参数库:代码中的一个全局字典,为每个模型表单提供一组超参数进行调整

一般执行步骤:

获取这些输入后,对考虑中的每个模型形式执行以下动作:

*正向特征选择
*标准化
*网格搜索超参数调整
*最佳模型的度量计算

输出:

创建了一个 pandas 数据框架“结果”,它为标签 1 测试的每个模型提供了以下指标。您可能需要根据哪个类对基于上下文的分析更重要来调整输入数据。

  • 具有最佳超参数的模型细节
  • 模型精度
  • 精确度和召回率
  • f-测度
  • 受试者工作特征曲线下面积(AUC)

此表有助于比较各种模型形式。精确度和召回率指标有助于选择更符合业务目标而不仅仅是精确度的模型。

重要提示:

该模块不以任何方式处理特征工程,仅基于输入数据执行特征选择。为了改善任何模型的结果,执行有效的特征工程是非常重要的。用户可能会观察到一种模型形式比另一种给出更好的结果,但是任何模型的整体性能都可以随着预测变量的改进而显著提高。

剧本:

各种任务的模块

第一个函数根据用户在控制面板中指定的条件,为标准化和网格搜索创建管道。

def create_pipeline(norm, model):
    if norm == 1:
        scale = StandardScaler()
        pipe = Pipeline([('norm', scale), ('reg', model)])
    elif norm == 2:
        scale = MinMaxScaler()
        pipe = Pipeline([('norm', scale), ('reg', model)])
    else:
        pipe = Pipeline([('reg', model)])
    return pipe

第二个函数执行正向特征选择,并返回最佳特征的索引。

def select_features(model, X_train, Y_train, selection,
                    score_criteria, see_details, norm=0):
    pipe = create_pipeline(norm, model)
    sfs = SequentialFeatureSelector(pipe,
                                    forward=selection,
                                    k_features='best',
                                    scoring=score_criteria,
                                    verbose=see_details)
    sfs = sfs.fit(X_train, Y_train)
    return list(sfs.k_feature_idx_)

该函数对所提供的参数网格执行网格搜索,并返回最佳模型对象。

def run_model(model, param_grid, X_train, Y_train,
              X, Y, score_criteria, folds,
              see_details, norm=0):
    pipe = create_pipeline(norm, model)
    model_grid = GridSearchCV(pipe,
                              param_grid,
                              cv=folds,
                              scoring=score_criteria,
                              verbose=see_details)
    model_grid.fit(X_train, Y_train)pipe = create_pipeline(norm, model_grid.best_estimator_)
    return model_grid.best_estimator_

最后一个函数计算最佳超参数组合的所有相关指标,并返回这些指标的 pandas 系列。

def get_model_eval(model, X_train, Y_train, X_test, Y_test):
    cm = confusion_matrix(Y_test, model.predict(X_test))
    t1, f1, t0, f0 = cm[1, 1], cm[1, 0], cm[0, 0], cm[0, 1]
    precision = precision_score(Y_test, model.predict(X_test))
    recall = recall_score(Y_test, model.predict(X_test))
    return pd.Series([model,
                      (t1 + t0) / (t1 + t0 + f1 + f0),
                      precision,
                      recall,
                      2 * precision * recall / (precision + recall),
                      -1 if type(model.steps[1][1]) == RidgeClassifier else roc_auc_score(Y_test, model.predict_proba(X_test)[:, 1])])

全局超参数字典(在此进行修改)

这是该模块中所有模型的各种模型参数的全局字典。在基于癌症数据集的典型范围的代码中已经填充了一些缺省值集。该词典包含每个模型的一些关键超参数,但并不详尽。鼓励用户访问 scikit-learn 文档以获得所有参数的列表,并根据他们的要求添加到下面的字典中。

# Global model paramater grid dictionary------------------------------------
# Change your hyperparameter ranges for grid search in this section
PARAM_DICT = {
  LogisticRegression: {
    'reg__tol': [1e-2, 1e-4, 1e-6],
    'reg__fit_intercept': [True, False],
    'reg__penalty': ['l1', 'l2']
  },
  RidgeClassifier: {
    'reg__alpha': [0.1, 1, 100],
    'reg__copy_X': [True, False],
    'reg__fit_intercept': [True, False],
    'reg__tol': [0.1, 1],
    'reg__solver': ['auto', 'svd', 'cholesky', 'lsqr',
      'sparse_cg', 'sag', 'saga'
    ]
  },KNeighborsClassifier: {
    'reg__n_neighbors': [5, 30, 100]
  },
  GaussianNB: {
  },DecisionTreeClassifier: {
    'reg__max_depth': [5, 10, 20],
    'reg__max_features': [0.3, 0.7, 1.0],
    'reg__max_leaf_nodes': [10, 50, 100],
    'reg__splitter': ['best', 'random']
  },BaggingClassifier: {
    'reg__bootstrap': [True, False],
    'reg__bootstrap_features': [True, False],
    'reg__max_features': [0.3, 0.7, 1.0],
    'reg__max_samples': [0.3, 0.7, 1.0],
    'reg__n_estimators': [10, 50, 100]
  },
  RandomForestClassifier: {
    'reg__bootstrap': [True, False],
    'reg__max_depth': [5, 10, 20],
    'reg__max_features': [0.3, 0.7, 1.0],
    'reg__max_leaf_nodes': [10, 50, 100],
    'reg__min_impurity_decrease': [0, 0.1, 0.2],
    'reg__n_estimators': [10, 50, 100]
  },SVC: {
    'reg__C': [10 ** -3, 1, 1000],
    'reg__kernel': ['linear', 'poly', 'rbf'],
    'reg__shrinking': [True, False],
    'reg__probability': [True]
  },GradientBoostingClassifier: {
    'reg__learning_rate': [0.1, 0.2, 0.5],
    # 'reg__loss': ['ls', 'lad', 'huber', 'quantile'],
    'reg__max_depth': [10, 20, 50],
    'reg__max_features': [0.5, 0.8, 1.0],
    'reg__max_leaf_nodes': [10, 50, 100],
    'reg__min_impurity_decrease': [0, 0.1, 0.2],
    'reg__min_samples_leaf': [5, 10, 20],
    'reg__min_samples_split': [5, 10, 20],
    'reg__n_estimators': [10, 50, 100]
  },
  XGBClassifier: {
    'reg__booster': ['gbtree', 'gblinear', 'dart'],
    'reg__learning_rate': [0.2, 0.5, 0.8],
    'reg__max_depth': [5, 10, 20],
    'reg__n_estimators': [10, 50, 100],
    'reg__reg_alpha': [0.1, 1, 10],
    'reg__reg_lambda': [0.1, 1, 10],
    'reg__subsample': [0.3, 0.5, 0.8],
    'reg__probability': [True]
  }}

按键输入的用户控制面板(在此进行修改)

可以在此处更改模块的输入。这是这个脚本的控制面板,介绍中提到的所有变量都可以在这里修改,以测试各种场景。请参考评论了解变量。

# --------------------------------------------------------------------------
# USER CONTROL PANEL, CHANGE THE VARIABLES, MODEL FORMS ETC. HERE# Read data here, define X (features) and Y (Target variable)
data = datasets.load_breast_cancer()
X = pd.DataFrame(data['data'])
X.columns = data['feature_names']
Y = data['target']# Specify size of test data (%)
size = 0.3# Set random seed for sampling consistency
random.seed(100)# Set type of normalization you want to perform
# 0 - No Normalization, 1 - Min-max scaling, 2 - Zscore scaling
norm = 1# Mention all model forms you want to run
to_run = [DecisionTreeClassifier,
          BaggingClassifier,
          RandomForestClassifier,
          GradientBoostingClassifier,
          XGBClassifier,
          SVC,
          KNeighborsClassifier,
          RidgeClassifier,
          GaussianNB,
          LogisticRegression]# Specify number of crossvalidation folds
folds = 2# Specify model selection criteria
# Possible values are:
# 'accuracy'
# 'precision'
# 'recall'
# 'f1'
# 'roc_auc'score_criteria = 'accuracy'# Specify details of terminal output you'd like to see
# 0 - No output, 1 - All details, 2 - Progress bar
# Outputs might vary based on individual functions
see_details = 0

模型执行

该部分迭代地为用户指定的每个模型找到最佳的超参数集,计算度量并填充结果表,用于进一步的分析/实验。

# Model execution part, results will be stored in the dataframe 'results'
# Best model can be selected based on these criteriaresults = pd.DataFrame(columns=['model', 'Accuracy', 'PrecisionLab1', 'RecallLab1',
                                'FMeasureLab1', 'AUC'])X_train, X_test, Y_train, Y_test = train_test_split(X, Y, test_size=size)for model in to_run:
    with warnings.catch_warnings():
        warnings.simplefilter('ignore')
        best_feat = select_features(model(), X_train, Y_train, True,
                                    score_criteria, see_details, norm)
        model = run_model(model(), PARAM_DICT[model],
                          X_train.iloc[:, best_feat],
                          Y_train,
                          X.iloc[:, best_feat], Y,
                          score_criteria, folds, see_details, norm)
        stats = get_model_eval(model, X_train.iloc[:, best_feat], Y_train,
                               X_test.iloc[:, best_feat], Y_test)
        stats.index = results.columns
        results = results.append(stats, ignore_index=True)print(results)
results['Form'] = [str(i).split()[-1].split('.')[-1] for i in to_run]
sb.lmplot('RecallLab1', 'Accuracy', hue='Form', data=results, fit_reg=False)

结论

在癌症患者检测的情况下,从形式上来说,检测所有患者对于我们的模型具有尽可能高的召回率是非常重要的。从上图中,我们可以观察到有三种模型能够达到完美的召回率:岭分类器、逻辑回归和支持向量机。在这种情况下,最好的方法是在这些模型中选择精度最高的模型,即 SVM 模型。

与回归笔记本中的示例类似,逻辑回归和岭分类器等更简单的模型比集成模型表现得更好。

我希望这个模块能够加快实验速度,并提供一个机会,根据您的需求在它的基础上构建进一步的定制!

点击此处查看完整的笔记本:

[## himanshu0394/AnalyticsToolkit

通过在 GitHub 上创建一个帐户,为 himanshu0394/AnalyticsToolkit 开发做出贡献。

github.com](https://github.com/himanshu0394/AnalyticsToolkit/blob/master/Classification Block.ipynb)

分析不是讲故事…

原文:https://towardsdatascience.com/analytics-is-not-storytelling-a1fe61b1ab6c?source=collection_archive---------2-----------------------

关于分析的本质,第 1 部分,共 2 部分

Here’s the audio version of the article, read for you by the author.

From the TV show “How I Met Your Mother

典型的分析 101 课程会发生什么?你通常会学习一些分析软件的基础知识(在 R-Python-SQL-SAS-Stata-MATLAB-big query-Tableau-Excel-Looker-whatever 中),如何将数据加载到那个软件中,以及如何做出像上面的饼状图和条形图这样的可视化汇总。

If you forgot how to read a bar chart or a histogram, just think of the versions you find in nature. Same thing!

但这就像艺术和画笔一样需要分析。艺术将会在过去的绘画中幸存,分析将会比电子表格更长久。为了在庆祝今天的节日时看到没有典型装饰的分析的本质,这里有一个万圣节风味的帖子供你娱乐…

免责声明:对于那些今年在网上玩“不给糖就捣蛋”游戏的人,请注意一些细微差别被故意省略了,因为它们将在 第二部分 中出现,或者我已经在我的其他文章中讨论过了。[1][2][3][4][5][6

领域专业知识很重要

想象一下你从来没有庆祝过万圣节。但是你刚刚被说服参加今晚的派对。你是负责服装决定的决策者,我是你的分析师。你会得到很好的帮助,因为作为一个狂热的万圣节爱好者,我正在学习相关领域的知识。

A tricky Priority One Bug caught and fixed at Google. (Why, what do you wear to the office?)

领域专业知识对分析师来说极其重要——如果我没有,我最好去争取。从来没有听说过万圣节的分析师在帮你挑选服装时会受到严重限制。他们可能会忽略各种有用的数据,因为他们不知道自己在看什么。看到一个分析师进入一个新的领域而没有立即问,“我在哪里可以找到一个领域大师交谈呢?”这是一个不好的迹象

分析师可以讲故事,但他们不是讲故事的人

与普遍的看法相反,分析师的职能不是“讲故事”或用数据说服人。那叫营销。(或者可能是新闻业。)

在每个成年人的生活中,都会有这样一个时刻,我们必须推销我们的工作,以便我们的利益相关者重视我们,并做我们希望他们做的事情,但让我们把这种黑暗艺术称为什么,并在另一篇文章中谈论它。当然,优秀的分析师非常了解人类的注意力,并能操纵他们的观众,但这是一种职业为另一种职业打开大门的副产品。能够讲故事是分析师需要具备的技能,但他们的工作是另外一回事。

分析不是营销。区别在于,一个是关于扩大决策者的视角,而另一个是关于缩小它。

用万圣节的术语来说,我作为分析师的工作不是说服你穿上我去年穿过的蟑螂服。我享受万圣节甚至比愚人节和我的生日加起来还要多,所以说到服装,我自然是各种意见。

It’s okay if you don’t get it. Measure theory isn’t for everyone.

我喜欢书呆子。我的服装越概念化、越晦涩越好。我每年只需要一个怪人的笑声,就能让整个努力变得有价值。今年我重现了最初的 R.U.R .服装,而前几年包括一个印有“万圣节快乐”的 FORTRAN 打孔卡和一个上面有勒贝格测量西格玛字段

然而,这个项目是关于你的品味,而不是我的。我作为分析师的角色不是操纵你得出我已经得出的结论。我的意见不是重点…除非你喜欢我为你挑一套服装。然后你就可以把决策权下放给我,把我从分析师变成决策者。(这样的话,让我们给你穿上多臂强盗。我们所需要的只是几双长手套、脱脂棉、一把玩具手枪、一块大手帕……)

分析师充当你的眼睛

作为一名分析师,我不应该卖给你任何东西。我是你的眼睛,每分钟给你尽可能多的灵感。你首先需要一个分析师的原因是你没有时间去研究数据,但是你仍然想成为发号施令的人。在这种情况下,我可能比你有更多的领域专业知识……但这并不意味着你会同意我为你挑选服装。你雇我是为了让你开阔眼界,而不是代表你做决定。你不想放弃选择的权利,我有责任尊重这一点。这就是将分析与决策和营销分开的原因。

如果决策者不想放弃选择的权力,分析师有责任尊重这一点。即使分析师比决策者更了解领域。

如果我采用营销或讲故事的方法,我会蒙蔽你的双眼,削弱你对可能性空间的看法。一个好的分析师会做相反的事情,让你很快接触到各种各样的观点。理想情况下,如果你是那个花时间在数据中漫游的人,我会帮助你吸收所有你想寻找的信息……加上你甚至不知道你应该要求查看的有用的东西。

工具是达到目的的手段

外面有万圣节的信息,分析师的工作就是找到它,检查它,为你过滤它,然后让你尽快吸收尽可能多的最有前途的东西。

不管我是用 R,SQL,C++,一个图书管理员,还是一个搜索引擎来表层信息,都是分析。如果你对数据的理解仅限于电子表格和数据库,那么你的思维不够开阔。你可以在这里找到我对数据本质及其与格言“知识就是力量】 的关系的思考。

尽量不要浪费决策者的时间

一位专家分析师对速度的优点持严肃态度。那不仅仅是有快速查找东西的手指。我应该努力不浪费你的时间。我有无限多的选择来为你提供信息,但是你的派对是今晚的。如果我开始用你需要提前几个月订购的“鼓舞人心的”精致手工服装轰炸你,我就是一个愚蠢的分析师。

Creepy costume I saw last weekend in NYC, complete with mechanical baby arms. Probably not something you could cobble together in a day.

在我们更进一步之前,我需要了解你与时空连续体的关系,这样我就能知道你可以去哪些服装店,以及要取消哪些运输选项。我还应该问一下预算。如果你的预算是一个脚趾甲,我会浪费你的时间,如果我给你太多关于花费一只胳膊和一条腿的衣服的信息。

Maybe your budget is literally some toenails? Who am I to judge?

我可能还是会给你看一两个昂贵的选择,以防这些未知的未知会激发你重新考虑你的预算。

快速激发灵感是这个游戏的名字。

我对数据和你的品味了解得越多,我就能更好地帮助你吸收和理解什么是可能的,这样你就能很快获得灵感。

作为一名分析师,我不是来引导你接受我的观点的。我是来帮你组建你自己的。

了解你的事件的性质将有助于我将我的调查转向最有可能有帮助的方面。室内舞会不适合穿会剜眼睛的尖尖的衣服,而穿过北极荒原的室外游行会限制你对温暖和笨重的选择。如果你要去参加一个工作聚会,我可能会避免给你看像性感 贝叶斯后验 (配有一堆重金属马尔可夫链)……尽管我在一次统计聚会上看到了这一点。我们统计学家是一群有趣的人。

Cool indeed, but maybe not the best choice for a dance party.

如果你没给我太多信息,我只能靠自己了。我可以列出离你坐标最近的三家服装店,还有他们的营业时间。我可以给你一个他们的相对价格的指示,使用他们所有库存的几个项目的指数。我可以告诉你,一个典型的美国万圣节商店有你需要的所有东西来组合一套完整的服装,除了鞋子。

我可以调查我的朋友,并根据服装颜色制作一个饼图(这样你就知道你必须选择什么来融入或突出我的朋友们的聚会…如果你的朋友不像我的朋友,这可能与你实际参加的活动完全无关)。

我可以试着找到万圣节有多贵的信息,以及制作自己的服装和购买服装需要多长时间。也许我会制作更好版本的这份调查的图表(基于 1000 名神秘的美国人,他们可能是也可能不是专业的服装制作人——小心那些你对一无所知的来源的数据):

I’m not going to give a critique of these charts. Nope. Won’t even grumble about the color and legend serving no purpose.

我可以给你一个分类清单(和范例):经典怪物(吸血鬼)、动物(老虎)、职业(宇航员)、人(圣女贞德)、卡通人物(本德)、概念(西格玛菲尔德)、艺术品(蒙克的尖叫)、食物(胡萝卜)、物品(打孔卡)等等。

我可以在谷歌趋势上查找伴随万圣节的最受欢迎的关键词,看看主导类别是什么——一些善良的灵魂已经为我们做了这个,产生了下面的列表:

Harry Potter is still a top 10 costume? What year is it?

  1. 《堡垒之夜》
  2. 蜘蛛侠
  3. 哈利·奎因
  4. 《神奇女侠》
  5. 黑豹
  6. 《死侍》
  7. [文学作品]哈利波特
  8. 猫女
  9. 便士
  10. 金·卡戴珊

显然,流行文化才是王道。但不是我的国王。

我可以更进一步,为您所在的地区制作一个类似这样的列表,标出两个地区的相对受欢迎程度……但是时间有限,这可能不是您所关心的。只有当细粒度的流行信息可能对你有所帮助时,才值得这么做。然而,从广义上讲,上面的列表可能足以让一个万圣节新手形成一种印象,即许多人都在寻找流行文化服装。我严重怀疑你会有额外的顿悟,追求那条线索到筋疲力尽,所以我也不会去那里。

我见过新手分析师在这一点上惊慌失措。他们在数据中搜寻,没有发现任何看起来像是明显的宝石的东西。哦亲爱的!也许没有人会注意到,如果你开始尽可能漂亮地绘制数据,也许还有动画?深呼吸,然后往前走。不要打磨一块垃圾。这是浪费——

没错。

回到手头的任务,我可以试着寻找一些不显眼的服装,然后整理出一个清单,列出那些可以激发灵感的

更奇怪的是,你可以看看人工智能生成的服装建议,比如这些(由 aiweirdness.com 提供):

如果我认为你的目的是尽可能少付钱,我可以查一下最便宜的现成服装。逛逛网上零售商告诉我,你可以花不到 10 美元买到一件斗篷和一个面具,所以也许这些东西会是你在实体店看看的好选择。你还可以在旧货店找到破旧的衣服,外加廉价的眼影和红色唇膏,进行僵尸 DIY。

我可能还想提醒你,如果你的国家不是最喜欢庆祝的国家之一——除非你在橙色区域庆祝,否则你可能会在去派对的路上吸引陌生的目光。我自豪地穿着我的怪异,但其他人可能会考虑外套。

Source: Twitter. Since this is someone else’s data, we’re too smart to trust it. Good! Decision-makers, treat it as inspiration only. Want something better? Then you’ll have to invest your team’s time and effort. Analysts, make sure the decision-maker considers time spent polishing something like this a good investment before rushing off to do it. If the decision-maker hasn’t asked for better quality, don’t polish anything unless you’ve truly got nothing better you could spend your work hours on.

我可以开始偏离轨道(今年的万圣节),转向各种各样的好奇,比如“人们什么时候开始在网上搜索万圣节服装信息?”对你今年的服装来说不是很有用,但我还是想象出了它——看,一只松鼠

Some inspiration about when to start planning your costume next year if you want to be like the Joneses.

希望您开始看到领域专业知识的重要性,但是如果不了解我的决策者的业务,很难猜测会出现什么样的信息。最后,我会花很多时间跑来跑去,试图猜测你想知道什么。

当你参加分析课程时,一个关键的组成部分——与决策者的关系——通常会缺失。教数据新闻更容易,所以这可能是你学到的。这也是讲故事的重点所在。数据新闻最好的例子是* 讲故事,就其本质而言,网上的例子是为大众制作的,所以很容易对真实的工作产生扭曲的印象。

数据新闻不是帮助特定的个人做决定。这是关于呈现具有大众吸引力的信息。事实上,这与分析师给项目带来的东西正好相反。

数据新闻不是帮助特定的个人获得他们需要的数据。这是关于呈现具有大众吸引力的信息。事实上,这与分析师给项目带来的量身定制的帮助正好相反。不要误解我的意思,一个成功的一刀切的故事有一些美丽的东西,那种像病毒一样传播并给许多人一点启发的故事。但是,除非这完全是惊天动地的消息,否则它只会一点点改变你的决策者的生活。与一个熟练的分析师所能提供的相比,这只是一个安慰奖:能让你的领导和你的企业实现巨大飞跃的灵感。

当你对决策者或者他们的挑战和优先事项一无所知时,激发灵感是很棘手的。你最终会试图从事一刀切的新闻报道,用漂亮的情节和故事来弥补。这并没有解决根本问题。当分析是分析师和决策者之间的对话时,它有更多的机会增加价值。

前往第二部分了解是什么让分析师变得优秀。

感谢阅读!人工智能课程怎么样?

如果你在这里玩得开心,并且你正在寻找一个为初学者和专家设计的有趣的应用人工智能课程,这里有一个我为你制作的娱乐课程:

Enjoy the entire course playlist here: bit.ly/machinefriend

喜欢作者?与凯西·科兹尔科夫联系

让我们做朋友吧!你可以在 TwitterYouTubeSubstackLinkedIn 上找到我。有兴趣让我在你的活动上发言吗?使用表格联系。

解读大学录取

原文:https://towardsdatascience.com/analyze-college-education-admissions-967cccc12115?source=collection_archive---------25-----------------------

Photo by Pang Yuhao on Unsplash

我们大多数人都会同意,大学入学可能是一个高度偏见的过程,普遍缺乏透明度。一年前对申请人有效的方法,一年后可能就完全无效了。就其本身而言,这并不奇怪。一所大学的需求每年都会发生变化。有一年,他们可能需要一个出色的四分卫。下一年,也许会是一个优秀的赛跑运动员或物理明星学生。这些需求会以我们永远不知道的方式指导招生委员会。例如,在许多学校,遗产和运动员有优势(尽管很难衡量有多少)。

至少可以说,最近关于招生过程中作弊的新闻破坏了它的可信度。因此,我决定以数据驱动的方式研究大学招生。鉴于录取过程缺乏透明度,我从看 SAT 成绩开始。SAT 考试的设计可能并不完美,但它确实给了我们一个一致的指标来分析。

获取数据

我使用了谷歌的数据集搜索,这是一个追踪数据的神奇工具。我刚刚搜索了“加州 SAT”,最初的几个结果是不同学年的 SAT 报告,最近的是 2015-2016 年的加州 SAT 报告,可从 data.world 下载。数据集显示了加州每所学校的平均分数。(为了保持匿名,数据集不包括参加考试的学生少于 15 人的学校的分数。)

探索和可视化分数

SAT 的最高分数为 2400 分,阅读、写作和数学三个独立的部分的分数从 200 到 800 不等。

数据集中的一列显示了得分大于或等于 1,500 分的学生的百分比。我决定将每个学校的百分比按县分组,然后取每个县的平均值。对于 1500 分及以上的分数,平均百分比最高的五个县是:

内华达州——67.8%

阿玛多——65.6%

马林——65.2%

埃尔多拉多——62.4%

圣马特奥——60.5%

平均百分比最低的五个县是:

默塞德——21.1%

Colusa——23.6%

弗雷斯诺——24%

图莱雷——24.9%

河边——27.4%

California Counties Average Percentage of Students with SAT Higher than 1,500.

California Counties Average Total SAT Score.

我决定也看看各县 SAT 的平均总分,换句话说,就是各县三个部分(阅读、写作和数学)的平均分数之和。由于总分在 600-2,400 之间,所以我除以 2,400,再乘以 100,以百分比的形式查看这一指标。同样,我们看到了相同的高点和低点的一般模式:

内华达州——67.3%

马林——66.9%

圣克拉拉——66.9%

圣马特奥——66.6%

埃尔多拉多——66%

…与…相比

Merced——54.7%

弗雷斯诺——54.9%

图莱雷——55.4%

因约——55.6%

河边——55.8%

我发现平均总分最高的来自圣克拉拉县:85.3%。这是 2400 分中的 2043 分。在圣克拉拉县,最高分来自弗里蒙特联合高中学区的蒙他维斯塔高中。我能够使用 Zillow 来验证结果的准确性,它提供了大量组织良好的学校信息。不足为奇的是,Zillow 将蒙他 Vista 排在了十分之十的位置。(我展示的是 2017 年的结果,但在 Zillow 应用中,你可以看到过去 3 年的结果。)

在后续的文章中,我将探索每个学校或地区的房地产价格数据的相关性。我怀疑有一个很强的。

SAT 部分之间的相关性(阅读、写作和数学)

我怀疑数学部分分数高的学生在阅读和写作方面的分数会更低。我能够通过计算阅读、写作和数学考试之间的线性相关性来探索这个想法。我错了。事实上,配对(数学,阅读)和(数学,写作)之间的线性相关性都相当强,正如你在下面的图中所看到的。我想知道这种强烈的相关性是否也适用于 GRE 成绩,在 GRE 考试中,更大比例的考生是非英语母语者。

Correlations Between Reading, Writing and Math SAT Scores Sections

摘要

由于公共数据很少,解读大学录取很难。作为替代,我查看了加州 2015 年至 2016 年的 SAT 成绩,以探索其在县、区和学校的分布情况。我还观察到 SAT 分数的不同部分之间的相关性很强。换句话说,在某一方面表现出色的学生在其他方面也会表现出色。对于这一探索的第二个阶段,我很高兴引入县的财产成本和学校水平,以了解它们与 SAT 分数的关系。

特别感谢史蒂夫·摩尔对这篇文章的大力反馈。

**T3【豪尔赫·卡斯塔尼翁】博士 **

Twitter:@ castan LinkedIn:@jorgecasta

使用 Seaborn 通过数据可视化分析数据

原文:https://towardsdatascience.com/analyze-the-data-through-data-visualization-using-seaborn-255e1cd3948e?source=collection_archive---------7-----------------------

使用不同的图来可视化数据,并学习何时使用这些图。

数据可视化是任何数据分析的重要组成部分。它有助于我们认识变量之间的关系,也有助于我们发现哪些变量是重要的,或者哪些变量会影响预测的变量。

Explorative data analysis

在机器学习模型中,当训练任何模型时,你需要首先找到哪些特征是重要的,或者结果依赖于哪些特征。这可以通过数据分析和数据可视化来实现。

我们将学习如何可视化不同类型的数据,我们可以从图中推断出什么,以及何时使用它们。

Seaborn 是一个建立在 matplotlib 之上的库。它很容易使用,可以很容易地与 Numpy 和 pandas 数据结构一起工作。

我们将使用 seaborn name tips提供的内置数据集。

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

加载数据集

tips = sns.load_dataset("tips")
tips.head()

Tips dataset head

我们可以看到性别、吸烟者、日期和时间是分类数据。total_bill、tip 和 size 是数字数据。

我们将检索一些公共信息,如给定数值数据的最小值、最大值、唯一值和计数。

tips.describe()

Descriptive statistics of numerical data.

现在我们将使用图来推断不同变量之间的关系。

单变量图

这些图基于单个变量,显示了给定变量的唯一值的频率。

柱状图

sns.distplot(tips['tip'], kde=False, bins=10);

Histogram

箱值越大,结果越准确。

Histogram for bins=30

我们可以看到数据集中出现的不同 tip 值的计数,并推断大多数 tip 在 2 和 4 之间。

肯纳密度估计(KDE)

sns.distplot(tips['tip'],hist=False, bins=10);

Kernel density estimate of tip

KDE 是一种估计连续随机变量的概率密度函数的方法。当你需要知道变量的分布时,就会用到它。

二元图

当您需要找出两个变量之间的关系以及一个变量的值如何改变另一个变量的值时,可以使用这种类型的图。根据变量的数据类型,使用不同类型的图。

统计数据类型

散点图

sns.relplot(x="total_bill", y="tip", data=tips);

Scatterplot

relplot的默认绘图类型是散点图。它显示了两个变量之间的关系。所以,如果需要找到两个变量之间的相关性,可以使用散点图。

在给定的例子中,我们可以看到,如果total_bill在 10-20 之间,那么小费通常会高于 2。

我们还可以在散点图中添加第三个变量,使用不同颜色或形状的点。

sns.relplot(x="total_bill", y="tip", hue="smoker", data=tips);

scatterplot for 3 variables

线图

该图类似于散点图,但它不是点,而是通过排列 x 轴上表示的变量值来显示连接所有点的线。

sns.relplot(x="total_bill", y="tip", kind="line", data=tips)

Lineplot

正如我们所看到的,相对于总账单,小费的分布过于随意。我们可以推断,小费并不太依赖于 total_bill 的值。

因为线图按照 total_bill 排列行,然后连接点,所以我们可以禁用排序。

sns.relplot(x="total_bill", y="tip", sort=False, kind="line", data=tips)

lineplot sort false

情节太混乱了,我们无法在这张图表中做出准确的推断。

对于大型数据集,该图需要时间,因为首先需要排序。

分类数据类型

散点图

sns.catplot(x="sex", y="tip", data=tips);

categorical scatterplot

我们可以看到,不管gender如何,大部分提示都集中在 2 和 4 之间。

使用 seaborn 中的属性kind可以制作不同类型的散点图。

第三个变量可以在 seaborn 中使用属性hue

sns.catplot(x="day", y="total_bill", hue="sex", kind="swarm", data=tips);

scatterplot using hue and kind

要在 x 轴上表示的类别按照熊猫类别排序。如果你想要你的需求顺序,你可以使用 seaborn 中的order属性。

sns.catplot(x="smoker", y="tip", order=["No", "Yes"], data=tips);

scatterplot using order

箱线图

箱线图(或盒须图)以一种便于变量之间或分类变量水平之间比较的方式显示定量数据的分布。它可以在一个图中给出数据集.describe中提供的所有统计数据。如果数据集太大,值的范围太大,那么它会根据四分位函数将一些值显示为异常值。

boxplot description

sns.catplot(x="day", y="total_bill", kind="box", data=tips);

boxplot

阴影框表示 25-四分位数和 75-四分位数之间的值。阴影框中的水平线表示中间值。底部和顶部的两条水平线分别代表最小值和最大值。圆点表示基于四分位间距函数计算的异常值。使用这些图表,我们可以在一个图表中比较不同类别的值。我们可以从给定的图表中推断出 total_bill 的金额在周末比平日高。

要在箱线图中使用第三个变量

sns.catplot(x="day", y="total_bill", hue="sex", kind="box", data=tips);

Boxplot using the third variable

我们可以从一张图中获得如此多的信息。在这张图表中,我们可以看到女性的平均总账单金额总是少于男性。因此,我们可以说total_bill的数量依赖于sex

小提琴情节

该图用于可视化数据的分布及其概率密度。这张图表是箱线图和密度图的组合。因此,如果你需要找到频率分布以及箱线图,而不是小提琴图。

Violin plot description

sns.catplot(x="day", y="total_bill", hue="sex",
            kind="violin", data=tips);

violin plot

在星期五,我们可以看到女性的账单总额比男性的账单总额少得多。

点图

散点图通过散点图点的位置来表示数值变量集中趋势的估计值,并使用误差线来表示该估计值周围的不确定性。点图仅显示平均值和这些平均值周围的误差率。它们提供的信息不多,但很容易发现基于不同类别的变量的变化。

sns.catplot(x="day", y="total_bill", hue="sex", kind="point", data=tips);

Point plot

使用这个图,很容易找到 total_bill 按天的变化。随着周末的到来,男性的总账单会上升,而女性的总账单会在周五下降,周六会上升,周日基本保持不变。

这些图可用于各种数据分析,我们可以推断关于不同变量之间关系的信息,并有助于从数据集中提取更重要的特征。

分析 38 万 Kickstarter 活动

原文:https://towardsdatascience.com/analyzing-380k-kickstarter-campaigns-10649bbf4e91?source=collection_archive---------30-----------------------

在今天的帖子中,我想做一些不同的事情。最近,他们都专注于数据科学的某个领域,但今天我想做一个基本的探索性分析,总结一下我过去谈论的所有内容。

Photo by Kaboompics .com from Pexels

而你,我的读者朋友,这将是对你的款待。不,我不会给你巧克力棒,但我有更好的东西——在我的 GitHub 个人资料上有完整的分析笔记本。

我将使用的数据集可以在这个链接上找到。你不必跟着编码,但是嘿,为什么不呢?我故意不在谷歌上搜索任何关于这个数据集的探索性分析,因为,嗯,我想给你一些原创的东西。前所未见的东西。在这个过程中,也许我会犯一个灾难性的错误,这个错误可以通过做一些研究来避免,但是我喜欢生活在边缘。

事不宜迟,让我们开始吧!

一些基本统计数据

数据集导入后,首先我想看看数据是什么样的,至少是前几行(希望您可以轻松阅读):

Head of Kickstarter Dataset

好吧,15 栏,没什么疯狂的。需要以某种方式管理大量文本数据。在本文中,我不会开发任何预测模型,所以没有必要为标签编码而抓狂,但一些行动将是必要的。

调用 。数据集上的形状 产生以下结果:

没错。数据量不错,差不多 380K 行!我必须说有很多战役。天知道这些数据收集了多少年——应该以后再探索。这里我要检查的最后一件事是缺失值:

哇,这是我见过的最完整的数据集之一。很奇怪,活动名称怎么会是空的,这真的没有意义。对于第二个缺失的属性,USD _ pleated,数据集的文档说明它表示质押列的“美元转换(由 Kickstarter 完成的转换)。“没什么好担心的,至少可以说。

现在是图表时间

该是我最喜欢的部分了——数据可视化。承认吧,你不喜欢看表格数据。这很正常。人类并不打算这样做。即使是你,数据科学家,或者有抱负的数据科学家,也应该知道,在你专业工作的某些方面,你需要向你的上级展示你的成果。

浏览一大堆只有表格数据的幻灯片对你来说绝对是一个好方法不要得到你一直想得到的提升,所以,让我们看看如何制作一些好看的可视化效果。我已经在我以前的一篇文章中讨论过这个问题:

[## 使用 Matplotlib 实现惊人可视化的 5 个步骤

Matplotlib 烂透了。默认情况下。以下是对此的处理方法。

towardsdatascience.com](/5-steps-to-amazing-visualizations-with-matplotlib-ca61f0ec5fec)

按年份列出的活动数量

我想展示的第一件事是每年活动的数量,如果你读过前面的部分,这不会让你感到惊讶。380,000 次活动听起来确实很多,所以我预计至少需要 5-7 年的时间跨度。

我已经决定声明一个用于绘制条形图的自定义函数(,因为我觉得我会在这个分析中做很多次):

Bar Chart Function — https://gist.github.com/dradecic/97652676c6d228ed571c0ed67dc0eeb2

现在制作这种可视化并不是最困难的任务——但是请记住,数据集中没有单独的年份列,所以您将需要使用 lambda 函数的魔力来从launch属性中提取它们。代码如下:

Years Bar Chart — https://gist.github.com/dradecic/0b827e5f3a4a74cc7dd198c4b3fdc8b5

这是图表(最后,天哪):

啊,当 Matplotlib 图表看起来不像是用 Matplotlib 制作的时候,真是太好了。如果你做的那些看起来还是很糟糕,参考我上面链接的文章。此外,这个官方 Kickstarter 绿色在条形图上看起来真的很好。

按国家列出的活动数量

现在是时候使用同一个make _ bar _ chart函数来可视化 country 属性了——因此来看看这些活动是从哪里来的(我感觉好像有一个国家来统治它们所有的)。
我相信你有能力让这个函数自己调用,你只需要把“已启动”改为“国家”,并根据你的意愿调整标题和轴标签。

一旦你做了调整,点击 SHIFT 和回车键,看看魔术在行动:

我的假设没有错。美国有差不多 30 万个竞选活动。这没什么不好,但这让我想知道为什么其他国家没有参与进来。

探索活动类别

现在让我们再次使用make _ bar _ chart函数来查看特定类别有多少个活动—attributemain _ category。与前面的图表一样,我不会编写函数调用的代码,因为您只需要更改属性名称和标题(,如果您愿意的话)。

貌似电影&视频,旁边还有音乐在 Kickstarter 上很受欢迎。舞蹈活动最少,但这并不意味着它们的整体成功率最低——这将在一分钟内进行探讨。

活动持续时间

但在此之前,我想了解一下这些活动的平均持续时间。为此,我需要做一些编码,因为没有活动持续时间的数据。为了计算它,我将从属性中减去属性 【已启动】 的值,然后将结果保存为两者之间天数的整数表示。

听起来像一个简单的计划,所以让我们执行它。我已经使用 pythonzip函数同时迭代两个数组(或系列)。代码如下:

Duration Attribute Creation — https://gist.github.com/dradecic/436539fceeeca338c3ed803b4412a231

这里均值和中值真的很接近,但是标准差感觉怪怪的。这需要进一步探索。我已经打印出了持续时间最长的 10 个活动,得到了一些有趣的结果:

由此看来,第一次运动开始于 1970 年 1 月 1 日,这显然没有意义。我决定过滤掉任何持续超过 100 天的活动(其中 7 天是)。

现在,我还声明了一个绘制直方图的函数,因为我想可视化这个连续变量的分布:

Histogram Function and Call — https://gist.github.com/dradecic/229903b0a35198a2650cdf652e4722f3

在这里,您可以看到—看起来大约 20 万个活动持续了一个月,两个月之后似乎会有一个高峰—大约 4 万个活动。

现在让我们来看看好东西。到目前为止,这很容易,现在是我用更长的代码,但也是更惊人的可视化来抨击你的时候了。我相信你,我的读者朋友,我知道如果你花时间一行一行地阅读代码,你将能够理解一切。

按类别探索营销活动的成功

首先,数据集需要以某种方式改变。存在一个属性— state —它代表了活动的状态,您可能不会相信!其中一些还在进行中(好吧至少在 2018 年初是这样的,所以那些会被过滤掉。然后,我将替换属性中的值,因此最终它的编码是这样的:

  • 0:活动不成功
  • 1:活动很成功

用 Python 完成这个任务并不困难,但是在完成之后,还需要做一些其他的修改和调整。在下面的代码片段中了解更多信息:

Success vs. Failure chart — https://gist.github.com/dradecic/a34b36a2f9c56495d2e382a0cd1b17c3

执行这个代码单元将会产生这个惊人的可视化效果:

简而言之,它以百分比的形式显示了每个类别中有多少活动失败(深绿色)以及有多少活动成功(浅绿色)。从这里可以清楚地看到, 手艺技术是大忌(大多数情况下),而剧场舞蹈看起来大有可为。**

活动目标与承诺分析

让我们更深入地了解一下,看看每个单独的活动类别中,设定为活动目标的平均金额(嗯,中位数)与实际获得的金额。再次强调,实现这一点需要一些代码,但我相信你:

Money Goal vs. Pledged — https://gist.github.com/dradecic/e469bffddcbf13d6ff502f7c57f978a4

上图的结论仍然成立——舞蹈戏剧似乎仍然是最有希望的竞选类别。

标题探索

现在让我们讨论一下今天将要绘制的最终图表。我敢于进一步探索头衔,探索特定头衔长度组的平均所得金钱(中值再一次)。

的帮助下,我将标题长度分成了 10 个分位数。qcut 功能:

Obtained Money per TItle group — https://gist.github.com/dradecic/a4477c8e18b91baf022fc0b8fbc3c4fa

这是最终的图表:

看起来,如果他们想筹集一些资金,活动应该尽可能地描述他们的标题— 谁会说?

最后的话

有一点是肯定的——这不是一个详尽的探索性数据分析项目。但是我已经介绍了足够多的基础知识,所以我的读者朋友,你可以自己进一步探索。

也许你想开发一个预测模型,它将能够确定一个给定的活动是否会成功。也许你想通过 NLP 进一步分析竞选标题。也许这对你来说已经足够了。不管是哪一种,我肯定你能想出下一步该怎么做。

现在该说再见了,但只是一小会儿。感谢阅读…

By GIPHY

喜欢这篇文章吗?成为 中等会员 继续无限制学习。如果你使用下面的链接,我会收到你的一部分会员费,不需要你额外付费。

** [## 通过我的推荐链接加入 Medium-Dario rade ci

作为一个媒体会员,你的会员费的一部分会给你阅读的作家,你可以完全接触到每一个故事…

medium.com](https://medium.com/@radecicdario/membership)**

分析亚马逊野火数据

原文:https://towardsdatascience.com/analyzing-amazon-wildfire-data-a4f9122a8877?source=collection_archive---------22-----------------------

Photo by Pixabay on Pexels

由于气候变暖,亚马逊雨林的野火越来越令人担忧。在这里,我们将探索和分析巴西政府提供的巴西火灾数据集。数据在这里可用。

在数据科学中,探索数据通常是构建预测模型的第一步。探索性数据分析包括总结数据集的特征。这包括关于数据特征的统计摘要,如平均值、标准差、分布和记录数。

第一步是用 python 导入 pandas 包,并将数据读入 pandas 数据框。您可以将熊猫数据框想象成数据表或 excel 电子表格。

import pandas as pddf = pd.read_csv(“amazon.csv”, encoding = “ISO-8859–1”)print(df.head())

前五行的输出是:

如你所见,数据包括年份、巴西州、月份、野火数量和日期。我们可以从计算每个州的火灾平均数开始分析。我们在熊猫身上使用了“分组”方法:

df = df.groupby(‘state’)[‘number’].mean().reset_index()print(df)

Mean Number of fires for each state

我们也可以使用 python 中的“seaborn”包来实现这一点:

import seaborn as snsbar = sns.barplot(df['state'], df['number'], color = "red")
bar.set_xticklabels(df['state'], rotation=45)

Mean Number of fires for each state

我们还可以查看每个州火灾数量的标准偏差:

df = df.groupby(‘state’)[‘number’].mean().reset_index()
bar = sns.barplot(df['state'], df['number'], color = "black")
bar.set_xticklabels(df['state'], rotation=45)

Standard Deviation in Number of fires for each state

我们还可以查看各州火灾数量的分布情况:

我们可以看到森林火灾数量的分布是长尾的。巴西各州的情况也是如此。

如果我们想要查看单个状态的集合,我们可以如下操作:

print(set(df['state'].values))

当被执行时,其给出:

The unique set of states

这在您有一个大型数据集并希望分析特定的数据段或数据组时尤其有用。在这种情况下,我们只有 22 个州,现在让我们称它们为类别。有些情况下,您可能有数百万行,并且对一组可能只有 5 个值的类别感兴趣。手动查看 excel 文件来计算类别的数量是非常困难的。此外,您可以查看每个类别有多少数据可用:

from collections import Counter 
print(Counter(df['state'].values))

The number of rows/records for each state

小警告:对于大于 1 GB 的数据集,pandas 非常慢,最好使用其他工具进行分析。其他工具包括 Spark clusters、Hadoop 和 Hive。因为这些工具需要大量的时间来学习和设置其他替代方法,包括将数据分成几批,使用 pandas,以及使用 numpy 数组。

建立精确预测模型的一个好方法是找到将整个数据集分成具有相似属性的聚类的方法。如果我们希望查看单个州的数据,比如说“罗赖马”,我们可以过滤数据框:

df = df[df['state'] == 'Roraima']
df = df.head().reset_index()
df.drop('index')
print(df.head())

我们还可以通过绘制罗赖马州 1 月份的野火数量与年份的对比图,来寻找任何给定月份和州的野火数量的规律:

import matplotlib.pyplot as plt
df = df[df['month'] == 'Janeiro']
plt.plot(df['year'], df['number'])
plt.xlabel('Year')
plt.ylabel("Number of Wildfires")
plt.title("Wildfires in Roraima in the month of January")

您还可以针对不同的州和月份执行此分析:

这将为您的模型构建过程提供信息。一个有趣的方法是为每个州和每个月建立一个模型。这不是唯一的前进道路,但探索性数据分析的目的是了解您的数据,并随后从特征工程和模型构建中获得灵感。

在下一篇文章中,我们将使用 python 机器学习包“sklearn”中的随机森林算法建立一个预测模型。

感谢您的阅读!

分析和预测星巴克的选址策略

原文:https://towardsdatascience.com/analyzing-and-predicting-starbucks-location-strategy-3c5026d31c21?source=collection_archive---------7-----------------------

点击这里查看第二部分

在波士顿,感觉走不出一个街区就看不到星巴克了。事实上,在 Stax 波士顿办事处方圆一英里的范围内,我们有 15 个(!)星巴克的位置。

Starbucks locations in Back Bay, Boston

鉴于此,很自然会问:星巴克是如何考虑选址的?

从更广的层面来看,他们的商店位置能告诉我们关于他们的客户群的什么信息,以及他们认为服务于这个客户群的有吸引力的位置是什么?我们能否从高层次上推断出他们应该或将要在哪里探索进一步的门店扩张?

通过分析商店数据以及这些数据与人口普查数据的对应关系,我们可以对星巴克认为有价值的位置创建一个高层次的“轮廓”,此外还可以看到在这些区域及其周围可能有进一步扩大足迹的机会。

R 中的完整项目代码, 点击此处

我们将从美国商店的总体情况开始分析。

Note: Each dot represents one Starbucks location and darker regions means more stores. Data is as of 2017 and will not include more recent openings.

从视觉上看,我们可以看到对沿海地区和主要大都市地区的偏好,所有这些都是有道理的,因为作为一个高端大众市场品牌,我们正在寻找能够支付略高价格的消费者。

事实上,我们将通过tidycensus获得的美国社区调查的结果进行对比,并比较有星巴克和没有星巴克的地点的人口统计数据,这些数据证实了这一点:

Demographics of U.S. (red) versus Starbucks locations (blue).

数据清楚地表明,星巴克的目标位置是更富裕的家庭(家庭收入中值约为 6.5 万美元对 5 万美元)、更多的人(人口中值约为 3.15 万美元对 3K)、更年轻的年龄(37.6 岁对 41.7 岁)以及受教育程度更高的劳动力。

如果你了解这个品牌,这一点都不奇怪,但用数据填充直觉是一种重要的方式,可以让你对每一组数据探索和策略更有信心。

现在,让我们更深入地了解位置。下面的地图有助于我们理解,在一个州的水平上,星巴克位置的数量,点的大小代表位置与人口的比例。例如,加州拥有最多的星巴克门店(截至 2017 年约 2750 家;最暗的红色)而华盛顿拥有最多的人均位置(最大的气泡)。

从上面我们可以看出,星巴克不仅有更多与人口增长成比例的位置(即人口越多的州有更多的商店),而且他们在有主要大都市地区的州指数过高(即这些位置有更多的商店和更多的人口商店)。

因此,下一步是寻找哪些位置“看起来”像今天的星巴克位置——使用星巴克位置的人口统计数据——但还没有星巴克。

为了简洁起见,我们将只测试新的邮政编码,而不是在现有邮政编码范围内的扩展。为了实现这一点,我们将使用逻辑回归模型来预测一个邮政编码有星巴克位置的可能性,并查看没有星巴克位置的最高预测概率。接下来,我们将使用星巴克位置的“典型”特征,并在这些因素中寻找最高的邮政编码相似性。

逻辑回归预测

使用人口统计变量的基本逻辑回归可以正确预测大约 60%有星巴克的邮政编码和 90%没有星巴克的邮政编码。考虑到数据集的不平衡性质——31,000 个观察值和大约 5,500 个星巴克观察值——60%的预测率应该足以满足本练习的目的。

我们的最高结果(没有星巴克的最高预测概率)是邮政编码 60629,位于芝加哥。一项小小的调查显示了以下情况:

Left: Zip code area of 60629. Right: Starbucks locations near this area; Note how they fall just outside the boundaries. Maybe the area is residential?

该邮政编码在区域外有 2 个毗邻星巴克的位置,模型预测该邮政编码有 99%的可能性有星巴克。这应该会给我们信心,让我们相信这个模型是可行的。

下面的地图显示了目前没有星巴克的县一级邮政编码的总概率。例如,如果一个县有 20 个没有星巴克的邮政编码,该地图将显示所有这些地理区域的预测概率总和。

虽然这偏向于有更多邮政编码的县——因此有更多潜在的邮政编码要加总——但我认为这没关系,因为每个县不应该被同等加权;我们只对那些最有机会的人感兴趣。

Darker green = higher total probability of attractive locations; Rolled up from a zip-code level to county. The color scale is set to the median probability as a baseline and darker green indicates a probability increasingly above that level.

对我来说,这表明有机会在目前的大都市及其周边地区的邮政编码水平上进一步扩张。特别是,芝加哥、南加州、大纽约和大波士顿似乎仍有空间容纳更多的位置。鉴于我们所知道的他们过分强调人口密集地区的倾向,我们会说在这些地区有进一步的增长。

相似度

接下来,我们过渡到邮政编码的相似性。这里的方法是计算所有星巴克位置的中值统计,并在标准化变量以抵消不同尺度(即人口数量>年龄数量)的影响后,计算每个非星巴克行与中值之间的差异。

事实上,当用基本的人口统计信息重新构建箱线图时,这种方法的发现是有效的。下面,你可以看到前 100 个最相似的非星巴克所在地的邮政编码的比较,以及它与星巴克所在地的邮政编码的比较。

Top 100 Non-Starbucks locations by similarity compared to Starbucks locations. Note how this compares more favorably compared than the previous chart above.

这些相似的地点在哪里?让我们看看下面按州排列的前 20%的邮政编码:

Top 20th percentile of similar Non-Starbucks zip-codes

风险和后续步骤

不受约束地扩张到新的有吸引力的地点在理论上可能看起来不错,但还有其他因素要考虑。以下是我在 Stax Inc. 工作的地方,如果有客户找到我们,我们可能会问的几个问题:

  • 与公司战略保持一致:管理层制定了什么样的前进战略,哪些地点与该战略保持一致?
  • 评估顶级地区的竞争活动:有哪些国家连锁店,数量如何?有哪些区域连锁店?谁应该被视为我们的竞争对手?
  • 了解当地市场的细微差别:每个市场的当地细微差别是什么?与波特兰或俄勒冈州(重视本地和氛围)相比,马萨诸塞州波士顿的进一步渗透(重视便利和速度)如何?为了在每个市场中获胜,我们需要相信什么和做什么?
  • 考虑市场饱和:在什么情况下市场会过度饱和,并存在商店之间互相蚕食的风险?在一个给定的位置有多少家店是“太多”了?
  • 房产和人力成本:每个市场都有哪些房产?成本会阻碍开设一家盈利的商店吗?劳动力可用性和成本如何?
  • 描述目标客户:在每个市场中,谁是我们的目标客户?我们知道这个位置应该反映出上面的参数——高收入、年轻、密集——但是在这个群体中,我们希望接触到 75000 美元到 90000 美元或者 100000 美元到 120000 美元的家庭吗?25-34 岁还是 45-60 岁?想要工作空间的人拿了就走?这些人有多少?

随着我们一步一步地走下去,我们不仅能更好地了解位置,还能更好地了解顾客。这将有助于我们分析那些竞争太激烈和/或太昂贵、没有足够的特定目标客户、或者没有推进我们公司战略的地点。然后,在这个练习之后,我们应该希望留下一个较小的高价值位置集,并过渡到思考与开设新店相关的运营和物流因素。

所展示的分析并没有告诉我们在哪里开设一个位置,而是帮助我们将美国的范围缩小到一组目标位置,在这些位置上我们可以进行更深入的探索。这些数据为我们提供了一个平台,让我们在制定战略、实现增长目标以及最终实现更好的业务成果时更加自信。

作为后续,我发表了第二个故事,强调了定位策略的新方法。点击这里查看

有兴趣讨论你的企业或项目的选址策略吗?在 jordan@jordanbean.com 给我发邮件或者在 LinkedIn 上联系我。

分析 R 中的动漫数据

原文:https://towardsdatascience.com/analyzing-anime-data-in-r-8d2c2730de8c?source=collection_archive---------16-----------------------

如果你是一个动漫迷,那么你会喜欢我在 R 中做的这个分析。这个数据来自于 MyAnimeLis t 网站,是 R for Data Science 社区发起的 Tidy Tuesday 计划的一部分。你可以从这里下载这个数据的整洁版本。他们每周发布有趣的数据集,社区分享他们的分析,大多使用 Tidyverse 软件包,这是一个很好的学习资源。我还建议关注大卫·罗宾逊的 YouTube 频道。他每周都会上传新的视频,在视频中他分析了来自 Tidy Tuesday 的新数据集,你可以从他那里学到很多很酷的东西。

加载库

像往常一样,我们将加载一些库。

library(tidyverse)# Data manipulation and visualization
library(scales)# Converting data values to units
library(patchwork) # For Patching multiple ggplots together

数据的读取和初步调查

使用 read_csv 函数,我可以通过为文件参数提供到数据集的链接,直接从网站读取数据。加载数据后,让我们使用视图功能来查看数据

tidy_anime <- read_csv(file="[https://raw.githubusercontent.com/rfordatascience/tidytuesday/master/data/2019/2019-04-23/tidy_anime.csv](https://raw.githubusercontent.com/rfordatascience/tidytuesday/master/data/2019/2019-04-23/tidy_anime.csv)")View(tidy_anime)

如您所见,这是一个巨大的数据集,我不需要所有的列来进行分析。如果你看第一张截图,你会看到每个动画 ID 都被复制了。这是因为 MyAnimeList 网站上的每部动漫都被归类在不同的流派下。因此,每部不同类型的动漫都有一行,因此出现了重复。同样的问题也出现在制作人工作室栏目,因为一部动漫可以有多个制作人和工作室

tidy_anime <- tidy_anime%>%
select(-c(title_synonyms,synopsis,background,related,genre,studio,producer))

要删除这些列,我只需将它们包装在一个 "-" 中,这是一种取消选择的方式。

unique_anime <- tidy_anime%>%
distinct()%>%
filter(!is.na(title_english))View(unique_anime)

然后我们使用 distinct 函数,这样我们就可以为每一行获得一个唯一的动画 ID。我只对那些有英文标题的感兴趣,所以我删除了所有没有英文标题的。现在让我们再看一下数据。

不错!现在我们在每一行都有一个唯一的动漫 ID。我们现在可以开始分析我们的数据。

分析和可视化

如果你们中的任何一个人是动漫迷,那么你应该知道动漫电视剧和动漫电影不应该被放在一起比较。两者应该在各自的范畴内进行比较。为此,我们将进一步将这些数据分为电视和电影类别

tv_anime <- unique_anime%>%filter(type=="TV")
tv_plot <-tv_anime%>%
  mutate(graph_name=paste0(title_english," (",premiered,")"))%>%
  top_n(-20,wt=popularity) %>% 
  ggplot(aes(reorder(graph_name,desc(popularity)),popularity,colour=title_english))+
  geom_point(show.legend = FALSE)+
  geom_segment(aes(x=graph_name,xend=graph_name,y=0,yend=popularity),show.legend = FALSE)+
  coord_flip()+
  theme_classic()+
  labs(x="",y="Popularity",title = "Top 20 Most Popular Anime TV Shows")

让我们一步一步地看这段代码:

  • 我只过滤电视节目的日期
  • 在我的图中,我还想看看它们何时开始,所以我使用 mutate 函数创建了一个新列— graph_name 。在 mutate 函数中,我使用了 Paste0 函数来组合 title_englishpremiered
  • 然后我用 top_n 函数得到了最受欢迎的 20 部动漫。请注意,我使用了-20,因为这将获得 20 个最低值,而且因为这是一个基于排名的值,最低值意味着最受欢迎
  • 然后我使用标准的 ggplot 函数来绘制我们的 x 和 y 轴值。我在 x 轴上使用了 reorder 函数,因为我想根据流行度值对它进行排序
  • 我正在创建一个棒棒糖图,为此,我需要将几何点几何段组合在一起以获得我的结果。几何点绘制点,而几何段绘制线
  • coord_flip 使其垂直和其他标准功能来标记情节和改变主题的外观。

这没什么奇怪的。所有这些节目都非常受欢迎,但值得注意的一件有趣的事情是,所有这些节目目前都没有播出,因此像 Once Piece漂白剂这样的节目也没有播出。让我们来看看目前正在播放的最受欢迎的节目

tv_anime_airing <- unique_anime%>%filter(type=="TV",airing=="TRUE")
tv_plot_airing <-tv_anime_airing%>%
  mutate(graph_name=paste0(title_english," (",premiered,")"))%>%
  top_n(-20,wt=popularity) %>% 
  ggplot(aes(reorder(graph_name,desc(popularity)),popularity,colour=title_english))+
  geom_point(show.legend = FALSE)+
  geom_segment(aes(x=graph_name,xend=graph_name,y=0,yend=popularity),show.legend = FALSE)+
  coord_flip()+
  theme_classic()+
  labs(x="",y="Popularity",title = "Top 20 Most Popular Anime TV Shows")+
  theme(axis.text.y.left = element_text(size = 12))

代码和以前一样。我对目前正在播放的节目的过滤做了一点调整

啊!一块放在当前正在播放的节目的顶部。我很惊讶一拳第二季袭提坦第三季(下)不在这里。收集这些数据时,它们可能还没有播出。我只看过这些中的暴民惊魂记 100** 。**我们也来看看评分最高的动漫吧。

嗯,有些令人失望的是,这些动漫中的大多数甚至没有超过 8 分。接下来,我有兴趣看看哪些流行动漫得分高,它们与这些动漫的得分人数有什么关系

tv_anime %>% 
  filter(popularity <= 50) %>%
  mutate(title_english = str_replace(title_english, "Code Geass: Lelouch of the Rebellion", "Code Geass")) %>%
  ggplot(aes(score, scored_by)) + 
  geom_point(shape=21,aes(fill=title_english,size=members)) + 
  geom_text(aes(label = title_english ), check_overlap = T, show.legend = F, size = 3, hjust = 1) + 
  xlim(c(6, 10)) +
  scale_y_log10()+
  labs(title = "Which popular anime also score high?", 
       subtitle = "Top 50 anime shown based on popularity",
       y = "Number of users that scored",
       x = "Score (1-10)") +
  theme_classic()+
  theme(legend.position = 'none',aspect.ratio = 0.5)

死亡笔记再次置顶。我会假设像死亡笔记攻击泰坦剑术在线这样的动漫有一个真正忠诚的粉丝群,他们会去网站为他们评分。像 Once Piece 这样的节目已经播出了相当长一段时间,但相对而言,很少有人获得它的评分。

现在让我们来看看流行度与分数。有没有哪部热门动漫没得高分,反之亦然。

tv_anime%>%
  filter(popularity<=100) %>% 
  ggplot(aes(popularity,score,fill=rating))+
  geom_point(shape=21,size=3,alpha=0.8)+
  geom_text(aes(label=title_english),size=3,check_overlap = TRUE)+
  scale_x_log10()+
  theme_classic()+
  scale_color_brewer(palette = 'Set1')+
  theme(legend.position = "bottom")+
  labs(title = "Popularity vs Score",subtitle = "Do all Popular Anime score high?")

所以最受欢迎的动漫肯定得分最高。虽然图表中充满了 PG-13 级的节目,但得分最高的动画肯定是 R-17+。有点惊讶的是,《我的赫拉学院》第二季&第三季没有第一季那么受欢迎,尽管它们的收视率都比第一季高。

最后,我想比较一下前 20 名最受欢迎的成员和最受欢迎的人。

**most_members** <- tv_anime%>%
  top_n(20,wt=members) %>%
  mutate(graph_name=paste0(title_english," (",premiered,")"),graph_name=fct_reorder(graph_name,members))%>%
  ggplot(aes(graph_name,members,fill=graph_name))+
  geom_bar(stat = 'identity',width=0.5,show.legend = FALSE,color='black')+
  coord_flip()+
  theme_classic()+
  scale_y_continuous(limits = c(0,1700000),labels = comma)+
  geom_text(aes(label=comma(members)),size=3)+
  labs(x="",y="Rank",title = "Top 20 Most Members")**most_favorite**<-
  tv_anime%>%
  top_n(20,wt=favorites) %>% 
  mutate(title_english=fct_reorder(title_english,favorites))%>%
  ggplot(aes(title_english,favorites,fill=title_english))+
  geom_bar(stat = 'identity',width=0.5,show.legend = FALSE,color='black')+
  coord_flip()+
  theme_classic()+
  scale_y_continuous(limits = c(0,150000),labels = comma)+
  geom_text(aes(label=comma(favorites)),size=3,hjust=1,fontface='bold')+
  labs(x="",y="Favourites",title = "Top 20 Most Favorite")**most_scored**<-
  tv_anime%>%
  top_n(20,wt=scored_by) %>% 
  mutate(title_english=fct_reorder(title_english,scored_by))%>%
  ggplot(aes(title_english,scored_by,fill= title_english))+
  geom_bar(stat = 'identity',width=0.5,color='black',show.legend = FALSE)+
  coord_flip()+
  theme_classic()+
  scale_y_continuous(limits = c(0,1500000),labels = comma)+
  geom_text(aes(label=comma(scored_by)),size=3,hjust=1,fontface='bold')+
  labs(x="",y="Favourites",title = "Top 20 Most Scored by")most_favorite + most_members+ most_scored + plot_layout(widths = 20)

很明显,拥有最多成员的动漫会有更多人给它打分。我从未在我的动画列表上为一部动画打分,但我认为你需要成为这部动画的一员才能为它打分。最喜欢的是一个不同的故事。这可以潜在地突出具有最忠实的粉丝基础的动画,这些粉丝如此喜爱该动画以至于他们将它添加到他们的最爱中。

结论

我希望你觉得这个分析很有趣。如果你想分析动画电影,你可以使用相同的代码,但唯一的区别是只过滤电影而不是电视。

分析 Billboard 的说唱排行榜

原文:https://towardsdatascience.com/analyzing-billboards-top-rap-charts-f7dee52532a8?source=collection_archive---------22-----------------------

从小到大,我身边都是说唱音乐。店面、汽车收音机和电视扬声器发出的刺耳声音是所有不同海岸的声音汇集在一起。这种对嘻哈音乐的不断接触和我受保护的亚洲成长环境让我讨厌它,我花了一部分青少年时光沉浸在经典摇滚中。

这并没有持续很长时间。

在我高中的第一年,我被介绍给新鲜的说唱行为,如丹尼布朗,运行珠宝,和索尔威廉姆斯。我被重新介绍给像坎耶·韦斯特和图帕克这样的童年旧爱。嘻哈音乐占据了我的世界,我的品味在大学期间也慢慢变得更好了。在被介绍给 Geto 男孩后,我对南方说唱产生了一种近乎不自然的痴迷。这个地区结合了我对身临其境讲故事的热爱,不仅有我可以跟着跳舞的节拍,还有黑暗制作,就像我童年时喜欢的朋克音乐和我小时候可以听的一小部分“可接受”音乐中常见的爵士乐影响。南方是实验的温床,我想传播这个福音。

从那以后,我的大部分工作都围绕着既古老又新颖的南方嘻哈音乐。我不断发现新的艺术家和声音从南方的每一个缝隙里传出来。我认为南方在主流音乐中很大程度上被低估了,只是在过去的三年里才看到了复兴。像 A\(AP Rocky 这样的艺术家对孟菲斯传奇人物托米·怀特三世进行了采样,并尝试了由得克萨斯州自己的 DJ Screw 开创的切碎和拧紧制作。Cardi B 在她的热门专辑《侵犯隐私》中收录了 Project Pat 的《小鸡头》。一个\)AP Ferg 在他的单曲《平凡的简》中重新构思了三个 6 黑手党的地下热门歌曲《Slob On My Nob》。甚至在最近,Lil Nas X 的“老城路”在复兴“乡村说唱”方面取得了巨大的成功,德克萨斯的 UGK 在几十年前就以他们独特的南方鼻音和勇敢的乐器开创了这一潮流。

我决定通过查看 Billboard 从 1990 年到 2018 年的顶级说唱歌曲排行榜来验证这个理论。为了简洁起见,我决定省略他们的 R & B 图。根据 airplay,每首歌曲都被确定为全国第一,直到 2012 年,流媒体数字和数字下载被加入到标准中。我编辑了我的列表,只从每首歌曲中选取艺术家,并找到他们来自的州及其相应的海岸,这意味着我排除了任何不是来自美国的艺术家。如果他们出生在德克萨斯州,但他们的事业和成功却源于纽约,那么他们就是来自纽约的东海岸艺术家。使用世界地图集上这张方便的地图可以区分海岸。

Image courtesy of World Atlas

我每年还会拿出副本。因此,如果梅西·埃丽奥特在一年内三次排名第一,我只统计了一次,以免进一步扭曲数据。在接下来的几年里,我会把她算作第一名。这是关于艺术家,而不是歌曲。

总而言之,我查阅了 291 行数据。我找到了 1990 年到 2018 年的 191 位独特的艺术家。在研究的最后,我还发现自己在调查一个完全不同的问题。

我决定先问一个最简单的问题:这些艺术家来自哪个地区?结果令我吃惊。

查看 28 年的数据,就近 300 首歌曲中的第一名而言,南方紧随东海岸之后(再次记住,每年都有重复的艺术家被淘汰)。我决定看看十年来沿海趋势是如何变化的。

有趣的是,从 2000 年开始,南方实际上主导了排行榜。回顾我的数据,奥特卡斯特和耐莉在 2000 年代早期都有好几年的冠军单曲。考虑到当时的音乐氛围,这是有意义的。南方大量生产有趣的、适合跳舞的热门歌曲,挤满了舞厅,手机扬声器里响起铃声。最重要的是,南方有独特的声音和来自各州的艺术家,相比之下,其他沿海地区有独特的音乐中心,如纽约和加利福尼亚。我想看看每年有哪些州入选,我把它编成了一个有趣的 gif!越黑暗的州,越多的顶级艺术家来自那里。

在 90 年代,纽约和加州是游戏的主要参与者,但加州在 00 年代初开始淡出。随着 1996 年图派克·夏库尔和 1997 年臭名昭著的 B.I.G .死亡后海岸战争的停止,他们各自的州在排行榜上的统治也不约而同地结束了,加州更甚于纽约州。随着 21 世纪的到来,更多的佛罗里达、乔治亚和德克萨斯艺术家加入了排行榜。由于纽约州和加利福尼亚州一直位居榜首,我想看看在我观察的 28 年中各州代表的多样性。

正如我所料,纽约是东海岸说唱游戏中最大的玩家。对于 hip hop 的发源地,我不期待少一点。它也是一个非常大的州,是东海岸的文化中心。另一方面,南方有更多的变化。

佐治亚州是一个明显的主要参与者,因为亚特兰大是一个交通和文化中心,有一个大型机场,地理位置便利,正好位于其他州的中间。作为一个文化中心,佛罗里达很像佐治亚州,并且是许多适合跳舞的音乐的故乡,因为它靠近加勒比群岛,所以继续占据排行榜的主导地位。南方和它所有的州共享各种各样的声音和文化。西海岸?没有那么多。

在这种情况下,饼状图不能公正地显示数据。西海岸 24 位独特的艺术家中,只有一位不是来自加州,那就是华盛顿自己的麦克摩尔。其余的艺术家都来自加州。虽然令人震惊,但我并不感到惊讶,因为加州是一个包含大部分沿海地区的大州。也许更深入地看图表,我们可能会发现稍微多一点的州变化,但是为了这个故事的目的,我们只看排名第一的热门歌曲。

我的发现让我想到了我的最后一个假设:随着数字媒体和下载的兴起,观众听的新音乐还不够多。在 90 年代,有几年见证了 20 多位独特的艺术家轮流争夺令人垂涎的第一名。2014 年,有四个。四位独特的艺术家。在测试这个理论时,我并没有完全错。

以下是按十年细分的数据,让我们看得更清楚一些:

这种下降令人痛心,尤其是当我知道每周有多少美妙的音乐从这个国家的每一个地方传出来。发生了什么事?那个,我回答不了。作为音乐爱好者,当我们的手机上有源源不断的音乐可供收听时,我们可能会感到精疲力竭。这也可以从电台作为一种可靠的听音乐方式的衰落中得到启示。当时,音乐可以通过物理媒体和广播电台获得。电台有更大的动机来提高音量以保持听众的兴趣。然后,盗版音乐在 21 世纪初成为一种普遍现象,Limewire 和 Napster 等客户让人们更容易在自己的时间通过电脑访问音乐。便携式音乐播放器带来了 CD 和唱片,现在你可以随时随地把几乎无穷无尽的音乐放在口袋里。当具有互联网功能的智能手机进入市场时,那些 iPods 和 Zunes 被塞进抽屉,mp3 文件开始在我们的桌面上堆积数字灰尘。现在对多样化的刺激减少了,广播电台每小时播放蕾哈娜或德雷克的同一首歌更容易了。它把钱放进了他们的口袋。

我记得我是一个年轻的,易受影响的 11 岁的孩子,偶然发现了纽约另类摇滚宝藏 101.9 RXP。他们从不在一个小时内演奏同一位艺术家两次,我听到了从《新秩序》到《红辣椒乐队》再到当地乐队的所有音乐。周日,我会听 DJ Rich Russo 的任何音乐,他会在只有几百名 Twitter 粉丝的新兴纽约乐队中演奏布鲁斯·斯普林斯汀。DJ 们成了我的朋友。他们真诚地接受请求,并在编程中抓住机会。他们最后一次广播的那天令人心碎,我再也没有过同样的广播经历。然而,那个电台启发了我去利用互联网。我得自己去找这音乐。

我从事这项工作的目的是为了找出南方是否出现在说唱排行榜上,最终我意识到这并不重要。排名第一的点击率只能量化受欢迎程度。重要的是,我们都找到了对我们说话的音乐,不管它是不是每小时通过广播电台播放,或者在 Youtube 的最深处找到。让我们更加自觉地支持我们热爱的艺术家。

今天找一个新的艺人来听,告诉一个朋友!买张 CD!去看表演!让音乐重新变得有趣。

分析 CNET 的标题

原文:https://towardsdatascience.com/analyzing-cnets-headlines-3f350bb97cd4?source=collection_archive---------17-----------------------

使用 Python 和熊猫探索 CNET 上发布的新闻

Photo by M. B. M. on Unsplash

我写了一个爬虫从 CNET 的网站地图中抓取新闻标题,并决定对其进行一些探索性分析。在这篇文章中,我将向你介绍我的发现、一些异常现象和一些有趣的见解。如果你想直接进入,你可以在找到代码

履带

爬虫使用 Scrapy 编写,这是一个用 Python 编写的开源网络爬行框架。有一个选项可以将数据转储到 csv 或 json 文件中,只需对命令稍作修改。你可以在我的 GitHub repo 中找到代码和命令。是时候深入分析了。

装载和清洗数据

第一步是加载数据,然后清理数据,为分析做好准备。

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
%matplotlib inlinedf = pd.read_csv('cnet_data.csv')df.head()

df.head()只输出数据帧的前 5 行。这里我们有 3 列:标题,链接和日期。这里明智的做法是将 date 列中的值转换为 datetime 对象。这将使访问年,月,日,工作日更容易。

df['date'] = pd.to_datetime(df.date, format='%Y-%m-%d')

注意:df.date 与 df['date']相同。只要列名是有效的变量名,就可以使用点(.),否则您将需要使用 df['列名']

数据集最常见的问题之一是空值。让我们从数据帧中删除标题为空的行。

df = df[pd.notnull(df['title'])]

现在我们可以开始分析了。

分析

让我们按日期分析文章发表的频率。

ax = df.groupby(df.date.dt.year)['title'].count().plot(kind='bar', figsize=(12, 6))ax.set(xlabel='Year', ylabel='Number of Articles', title="Articles Published Every Year")plt.show()

上面几行代码按年份对记录进行分组,并绘制计数。代码中的一切似乎都是不言自明的。我们可以将kind参数设置为其他值,如 line 表示线图,barh 表示水平条。查看文档了解更多详情。

我们可以为月份和工作日绘制类似的图表。

ax = df.groupby(df.date.dt.month)['title'].count().plot(kind='bar')
months = ['JAN',  'FEB', 'MAR', 'APR', 'MAY', 'JUN', 'JUL', 'AUG', 'SEP', 'OCT', 'NOV', 'DEC']ax.set_xticklabels(months)
ax.set(xlabel='Month', ylabel='Number of Articles', title="Articles Published Every Month")plt.show()

ax = df.groupby(df.date.dt.weekday)['title'].count().plot(kind='bar')days_of_week = ['MON', 'TUE', 'WED', 'THU', 'FRI', 'SAT', 'SUN']
ax.set_xticklabels(days_of_week)
ax.set(xlabel='Day of Week', ylabel='Number of Articles', title="Articles Published Every WeekDay")plt.show()

  • 2009 年发表的文章数量最多,1995 年最少。
  • 九月份发表的文章数量最多。
  • 除了九月,其他月份发表的文章数量几乎相同。
  • 星期三是一周中最忙的一天。
  • 不出所料,周末发表的文章数量很少。
df['date'].value_counts().head(10)

有趣的是,2009 年 9 月 2 日有 15000 多篇文章,前一天有 35000 多篇。这可能是为什么我们在之前的图表中看到 9 月和 2009 年以相当大的优势赢得比赛的原因。

让我们忽略前 5 个结果,绘制一个图表来显示按日期发布的文章的分布。

ax = df['date'].value_counts()[5:].plot(color='red', figsize=(12,6))
ax.set(xlabel='Date', ylabel='Number of Articles')
plt.show()

我仍然很好奇 2009 年 9 月 2 日发生了什么,导致如此大量的文章被发表。我们来看看当天出现在头条上的主导关键词。

from wordcloud import WordCloud
stopwords = set(open('stopwords.txt').read().split(','))
wc = WordCloud(stopwords=stopwords)
wordcloud = wc.generate(' '.join(df[df.date=='2009-09-02']['title'].apply(str)))plt.imshow(wordcloud, interpolation='bilinear')
plt.axis('off')
plt.show()

苹果似乎在当天的新闻中占据主导地位。我们可以在词云中看到 Mac,Apple,iTunes 这样的关键词。

wordcloud = wc.generate(' '.join(df['title'].apply(str)))
plt.imshow(wordcloud, interpolation='bilinear')
plt.axis('off')
plt.show()

纵观整个数据框架,头条新闻被谷歌、苹果、微软和脸书占据,这是意料之中的。

我们还可以统计一些热门关键词在头条中的出现次数。

keywords = ['microsoft', 'apple', 'facebook', 'google', 'amazon', 
            'twitter', 'ibm', 'iphone', 'android', 'window', 'ios']for kw in keywords:
    count = df[df['title'].str.contains(kw, case=False)].title.count()
    print('{} found {} times'.format(kw, count))microsoft found 12918 times
apple found 17762 times
facebook found 6342 times
google found 13409 times
amazon found 4162 times
twitter found 3340 times
ibm found 3178 times
iphone found 11543 times
android found 5801 times
window found 6063 times
ios found 3199 times

这是对 CNET 头条新闻的基本分析。你可以在我的 github repo 这里找到笔记本和数据。

随便玩玩,看看能不能在数据里找到什么有趣的东西,如果我漏掉了什么,就告诉我。

喜欢这篇文章吗?在我分享类似内容的 Twitter 上找到我。

使用聚类分析分析信用卡购买模式

原文:https://towardsdatascience.com/analyzing-credit-cards-kmeans-581565208cdb?source=collection_archive---------17-----------------------

使用各种聚类模型来评估信用卡购买模式,然后为客户提供建议

Photo by rupixen on Unsplash

问题简介

在深入研究各种聚类方法之前,让我们简短地看一下我们在这里试图解决的问题。随着时间的推移,一家信用卡公司支持其拥有的各种客户的数据。该公司收集了与客户相关的各种事实的数据,如他们的余额、购买量、预付现金、信用额度等。该团队的任务是从数据中获得有意义的见解,然后制定战略,使公司能够锁定客户并增加信用卡销售额,从而增加收入。

在绘制了简短的数据集描述后,我们注意到数据如下所示:

Partial Data Description of the Credit Card dataset

我们首先分析各种聚类方法,然后向客户提供我们的建议。让我们先简单了解一下聚类和 K 均值。

集群简介

聚类是对一组对象进行分组的任务,使得同一组(称为簇)中的对象比其他组(簇)中的对象更相似(在某种意义上)。聚类处理数据分组,将一对相似的数据点放在同一个聚类中。因此,数据点之间匹配的相似性的概念在聚类中起着重要的作用。集群是平面的或分层的,使用 scikit-learn 的集群包( sklearn.cluster )在 Python 中实现。
扁平聚类将帖子分成一组簇,这些簇之间没有关联。目标是创建内部相似但与其他集群不同的集群。在层次聚类中,聚类的数量不需要预先指定,而是取决于树状图。创建了一个集群层次结构。

让我们首先实现 K-Means 聚类方法,然后评估有哪些建议。

k 均值聚类

如上所述,K-Means 聚类是一种平面聚类,我们可以用一组聚类数来初始化模型。K-Means 模型的工作原理是选择 K 个质心,然后根据最小数据点对数据点进行分组,然后重新定位质心,直到实现收敛,前提是聚类是稳定的。

K-Means working. Source: Anirudh Sharma’s answer on Quora

现在,让我们绘制一个肘形图来评估最佳的集群数量应该是多少。肘形图,也称为 Scree 图,是一种给出关于簇的信息的图。肘图:

The Elbow Plot

所以,看上面的图,我们假设我们分析的最佳聚类数是 4。现在,使用 4 个聚类,并应用 K-Means 聚类,我们的结果是:

Clusters plotted against the various variables

对于上面的 K-Means 聚类,我们使用随机初始化方法。随机初始化的问题是,每次运行时,类内平方和都会改变,因为质心是随机选择的。这被称为 随机初始化陷阱 ,应该避免。为了避免这种情况,只需使用 k-means++初始化方法,该方法使用固定点作为质心,因此可以得到更好的结果。

K-Means++ Initialization

使用 K-Means init 方法的聚类可视化如下所示:

Visualization for K-Means Init Method

我们可以看到 K-Means++初始化方法确实比 random init 方法工作得更好。

分层聚类

转到其他类型的聚类方法,我们可以观察层次聚类方法。该方法不需要预先指定聚类,而是通过使用树状图来选择聚类。树状图是一种描述聚类分布方式的图表。分层聚类从其聚类中的每个数据点开始,并继续组合聚类,直到达到单个聚类。然而,为了阻止单个聚类的形成,通常使用树状图标准,该标准将不与水平线交叉的最长边作为最小距离标准。任何穿过这条线的聚类都将在最终模型中被选择。

这里需要注意的一点是,K-Means 聚类旨在减少距离,而层次聚类试图减少聚类中的方差。因此,HC 提供了更好和更清晰聚类,尽管它们不是最佳的,因为它们没有被距离分开。

Agglomerative HC Working Source: Machine Learning A-Z by Kirill Eremenko

通过使用 scikit-learn.cluster 包中的 AgglomerativeClustering(),可以在 python 中实现层次聚类。我们分析的树状图如下:

Dendrogram for the Credit Card dataset

从上面我们知道,我们可以选择集群的数量为 3。在这样做之后,使用上面的方法,我们可以观察到集群看起来像:

The behavior of various clusters across various variables

基于密度的聚类

基于密度的聚类方法基于根据聚类的不同密度来分布点。DBScan 聚类是一种聚类方法,它使用基于密度的方法,而不是 K-Means 和 HC 中基于距离的聚类。DBSCAN 的全称是带噪声应用的基于密度的空间聚类。将 DBSCAN 方法拟合到信用卡数据集,然后可视化聚类,我们得到:

Visualization for DBSCAN Clustering

通过查看上面的 DBSCAN 分析,可以更清楚地观察到,在这种情况下,聚类具有更非线性的形状,因此,当数据不是线性可分的时,应该使用这些类型的聚类方法。

来自数据的营销洞察

以下是营销策略的一些输入:

高余额,高购买量 —这些人购买了昂贵的东西,但他们也有更高的余额来支持这些购买。他们也支付了大笔款项,可能成为市场研究的目标。

高余额,低购买(较高的购买值)——这些人有较高的余额,但购买量较低,有中等或较高的信用额度,并提取大量现金预付款。

中等余额,中等购买量 —这些客户没有低余额或高余额,也没有大额或小额购买,但他们做的一切都处于中等水平。

节俭型客户(低余额、低购买量)——这些客户购买量最小,因为他们的信用额度也很低,这意味着他们不经常购买。因此,可以假设这些客户流失了,可以设计营销策略来减少这种流失。

因此,着眼于这四个群体的营销策略可以非常有效地解决这个问题。

聚类方法的利与弊

K-Means:这些方法简单易懂,适应性强,适用于小型或大型数据集,但是我们需要选择聚类的数量

HC 凝聚聚类:这些中的最优聚类数可以由模型本身获得,并且可以用树状图进行实际可视化,但是该模型不适用于大型数据集。'

请在我的 Github 上找到这个项目的完整实现。

分析神经网络中不同类型的激活函数——选择哪一种?

原文:https://towardsdatascience.com/analyzing-different-types-of-activation-functions-in-neural-networks-which-one-to-prefer-e11649256209?source=collection_archive---------9-----------------------

在构建神经网络时,我们需要做出的强制性选择之一是使用哪个激活函数。事实上,这是一个不可避免的选择,因为激活函数神经网络学习和逼近变量之间任何复杂和连续关系的基础。它只是增加了网络的非线性。

任何神经元(输入层神经元除外)计算输入的加权和,加上一些偏差,然后对其应用激活函数。在谈论更多关于激活函数之前,让我们先看看为什么需要它。

补充说明

本文假设读者对神经网络的概念、前向和后向传播、权重初始化、优化算法等有基本的了解。如果你不熟悉,我建议你关注我的其他关于这些主题的文章。

神经网络中的前向传播——简化的数学和代码版本

为什么更好的权重初始化在神经网络中很重要?

为什么梯度下降还不够:神经网络优化算法综合介绍

需要激活功能

参考下面的具有两个隐藏层的神经网络,输入层和输出层。该网络适用于三元类分类问题。

考虑在该网络中不使用激活函数的情况,则从隐藏层 1 计算的输入的加权和将被直接传递到隐藏层 2,它计算输入的加权和并传递到输出层,它计算输入的加权和以产生输出。输出可以表示为

因此,输出只是权重和输入的线性变换,不会给网络增加任何非线性。因此,这个网络类似于一个 线性回归模型 ,它只能处理变量之间的线性关系,即一个能力有限的模型,不适合图像分类、物体检测、语言翻译等复杂问题。

所以没有激活功能的神经网络

  1. 只能代表变量之间的线性关系。
  2. 不成立普适近似定理。

流行的激活功能

有许多可用的激活功能。因为激活函数只是一个数学函数,所以你也可以想出自己的激活函数。常用的激活功能有

  1. 物流的
  2. 双曲正切
  3. 整流线性单位
  4. 泄漏 ReLu

逻辑激活功能

这是一条带有等式的“S”形曲线

范围从 0 到 1。它也被称为乙状窦激活功能。输入的加权和作为输入应用于它。

对于一个大的正输入,它导致一个大的正输出,倾向于触发,对于大的负输入,它导致一个大的负输出,倾向于不触发。

激活函数的导数有助于反向传播期间的计算。在反向传播期间,计算损耗 w.r.t .参数的导数。逻辑函数的导数

物流激活功能的问题:

1.饱和问题

如果一个神经元达到其最大或最小峰值,则称其饱和。

f(x) = 0 或 1 时饱和,则 f'(x) = f(x)(1- f(x)) = 0

我们为什么关心饱和度?

参考下面的神经网络,其中假设权重 w211 需要在反向传播期间使用梯度下降更新规则来更新。

如果 h21 是 1,那么它的导数就是 0。所以权重 w211 没有任何更新,这个问题被称为消失梯度问题。重量梯度消失或降至零。

因此,使用逻辑激活函数,饱和神经元可能导致梯度消失,因此网络拒绝学习或以非常小的速率保持学习。

2.不是以零为中心的函数

零线(x 轴)两侧质量相等的函数称为零中心函数。换句话说,在以零为中心的函数中,输出可以是负的,也可以是正的。

在逻辑激活函数的情况下,输出总是正的,并且输出总是仅向一侧(正侧)累积,因此它不是以零为中心的函数。

为什么我们会关心以零为中心的函数?

让我们假设权重 w311 和 w312 需要在反向传播期间使用梯度下降更新规则来更新。

h21h22 由于逻辑激活功能将始终为正。w312 和 w312 的梯度值可以是正的或负的,这取决于公共部分的值。

因此,连接到同一神经元的所有权重的梯度要么是正的,要么是负的。因此,在更新规则期间,这些权重只允许在某些方向上移动,而不是在所有可能的方向上移动。这使得优化更加困难。

这就好比你只能向左和向前移动,不能向右和向后移动,那么你就很难到达你想要的目的地。

理解了这一点,让我们指出与逻辑激活功能相关的问题

  1. 饱和的逻辑神经元导致梯度 消失
  2. 它不是一个 以零为中心的 函数,
  3. 由于 e^x,它是高度 计算密集型 这使得收敛速度较慢。

2.双曲正切

它类似于逻辑激活功能,有一个数学方程

输出范围从-1 到 1,零轴两侧的质量相等,因此是 零居中 功能。所以 tanh 克服了逻辑激活函数的非零中心问题。因此,优化变得比逻辑相对容易,并且总是优先于逻辑

但是,一个 tanh 激活的神经元可能导致饱和并导致消失梯度问题

tanh 激活函数的导数

发布tanh 激活功能:

  1. 饱和的 tanh 神经元导致 渐变消失
  2. 因为 e^x,它是高度计算密集型的。

3.整流线性单位

由于其简单性,它是最常用的函数。它被定义为

如果输入是正数,函数返回数字本身,如果输入是负数,函数返回 0。

ReLu 激活函数的导数为

ReLu 激活功能的优点

  1. 容易 计算
  2. 对于输入的加权和的正值, 不饱和

因为简单, ReLu 在 CNN 中被用作标准的激活函数。

但是, ReLu 并不是一个以零为中心的函数。

ReLu 激活功能的问题

ReLu 定义为 max(0,w1x1 + w2x2 + …+b)

现在考虑一种情况 b(偏置)呈现(或初始化为)大的负值,然后输入的加权和接近 0,并且神经元未被激活。这意味着 ReLu 激活神经元 现在死亡 。这样, 多达 50%ReLu 激活神经元可能在训练阶段死亡。

为了克服 T21 的这个问题,有两个解决方案

  1. 偏置(b) 初始化为较大的正值。
  2. 使用 ReLu 的另一种变体,称为泄漏 ReLu

4。泄漏的 ReLu

提出修复 ReLu濒死神经元 问题。它引入了一个小斜率来保持神经元的更新有效,其中输入的加权和 。它被定义为

如果输入是一个数,函数返回该数本身,如果输入是一个数,那么它返回一个按 0.01 缩放的值(或任何其他小值)。

LeakyReLu curve

LeakyReLu 的导数为

leaky relu 的优点

  1. 正负区域都没有 饱和 问题
  2. 神经元 不会死 因为 0.01x 确保至少有一个小的梯度流过。虽然权重的变化很小,但经过几次迭代后,它可能会从其原始值出来。
  3. 容易 计算
  4. 接近零点功能。

Softmax 激活功能

对于分类问题,输出需要是包含不同类别的不同概率值的概率分布。对于二元分类问题,逻辑激活函数工作良好,但对于多类分类问题则不然。所以 Softmax 用于多类分类问题。

softmax 激活功能也是一种 s igmoid 功能。顾名思义,这是 max 函数的“软”风格,它不是只选择一个最大值,而是为最大元素分配分布的最大部分,其他较小元素获得分布的某一部分。

Softmax equation

Softmax 通常是输出层的首选,我们试图在输出中获得不同类别的概率。它应用于输出层中获得的输入加权和。

需要 Softmax 激活功能

考虑这样一种情况,对于一个三元分类问题,我们在输出层中有[2.4,-0.6,1.2]的预激活输出。预激活输出可以是任何实数值。

现在,如果我们通过取一个值并除以所有值的总和来直接计算每一类的概率。然后我们得到概率[0.57,-0.14,0.12]。因为概率永远不会是负的,所以这里不接受类别 2 的预测概率。因此,我们在输出层使用 softmax 激活函数来解决多类分类问题。

如果输入值为负,那么 softmax 也会返回正值,因为 e^x 总是给出正值。

结尾注释:现在更喜欢哪一个?

理解了所有的激活函数,现在有趣的问题是使用哪一个?

嗯,基于场景的激活功能选择没有硬性规定。决策完全取决于问题的性质,即你试图近似的关系具有一些性质,基于这些性质,你可以尝试不同的激活函数,并选择一个有助于更快收敛和更快学习过程的函数,或者可以根据你选择的不同评估参数。

  • 根据经验,您可以从 ReLu 开始作为通用近似器,如果 ReLu 不能提供更好的结果,则切换到其他函数。
  • 对于 CNNReLu 被视为标准激活功能,但如果它遭遇死神经元则切换到 LeakyReLu
  • 永远记住 ReLu 应该只用于隐藏 层。
  • 对于分类Sigmoid 函数(Logistic,tanh,Softmax) 及其组合工作良好。但同时可能会遭遇消失渐变问题
  • 对于 **RNN,**tanh**激活功能是首选的标准激活功能。

用 VAR 模型预测 Python 中的电价时间序列数据

原文:https://towardsdatascience.com/analyzing-electricity-price-time-series-data-using-python-time-series-decomposition-and-price-4cd61924ef49?source=collection_archive---------12-----------------------

向量自回归模型的时间序列分解和预测速成班

在过去的几年里,我处理过一些涉及时间序列分析和预测的项目,但是我总是发现这个主题对于初学者来说有些难以理解,因为缺乏全面的 Python 教程。因此,为了纠正这一点,这篇文章带领初学者通过时间序列分析,使用能源信息管理局的 API 提供的德克萨斯州每月电价数据。具体来说,本教程涵盖了时间序列分解和向量自回归(VAR)建模,以预测德克萨斯州的电价。

首先,简单介绍一下能源信息署(EIA)的背景。EIA 是美国能源部的一个分支,负责收集和分析能源相关数据,包括石油和天然气、煤炭、核能、电力和可再生能源。通过其开放数据应用编程接口(API) ,用户可以直接将 EIA 时间序列数据拉入 Python 进行分析。

关于在 Python 中设置 EIA API 访问的更多背景,请查看本教程:https://techrando . com/2019/06/26/how-to-use-the-energy-information-administration-EIA-application-programming-interface-API-and-pull-live-data-directly-into-Python-For-analysis/

在本分析中,我们将把德克萨斯州的电价时间序列放入 Python 进行分析,如下所示:

Snapshot of the time series data for electricity prices, pulled via the EIA API

首先,让我们看看月度电力数据是否显示了季节性和趋势。为此,我们使用 statsmodels.tsa.seasonal 包中的季节性分解()函数。该函数将时间序列分解为其核心部分:趋势、季节性和随机噪声。代码及其输出显示如下:

Time Series Decomposition: Monthly Electricity Prices in TX

那么上面的情节是什么意思呢?如果我们仔细观察分解的季节性成分,我们可以验证一个合乎逻辑的趋势:在德克萨斯州的夏季,电价飙升。对于任何一个在盛夏去过德克萨斯州的人来说,那里酷热难当,没有空调几乎无法居住(我知道,我住在休斯顿)。因此,更多的空调导致更多的用电量,从而导致更高的电价。

此外,每年年初左右,电价会出现第二次小幅上涨。这可能是由于天气足够凉爽,德州人求助于加热他们的家,办公室等。由于德州大部分地区冬天的天气相当温和,所以这种价格上涨明显不如夏天的电价上涨明显。

现在,我们已经使用时间序列分解进行了一些初步分析,我们希望确定是否可以使用另一个预测时间序列作为代理来预测电价。为了了解什么因素会影响电价,让我们先来看看德克萨斯州的电力是如何产生的。美国能源情报署在其网站上提供了德克萨斯州电力来源的分类,如下图所示:

Image courtesy of https://www.eia.gov/state/?sid=TX#tabs-4

根据上述图表,截至 2019 年 3 月,天然气似乎是德克萨斯州发电的主要来源,燃煤和可再生能源并列第二。

虽然我们分析的电力数据可以追溯到 2001 年,上面的细分数据是从 2019 年 3 月开始的,但为了简单起见,我们假设天然气是过去 15-20 年德克萨斯州发电的主要来源之一。因此,我们将通过 EIA API 提取天然气价格的时间序列,并与德克萨斯州电价时间序列进行对比:

Plotted Natural Gas Prices and Electricity Prices over Time

天然气价格时间序列似乎有更多的变化(高点特别高,低点特别低),但在大多数情况下,两个时间序列的趋势似乎非常相似。事实上,我们很有可能使用天然气价格作为代理来估算 TX 电价。

这提出了一个有趣的问题-使用一个时间序列的滞后值以及其他时间序列集的滞后值来预测未来值。解决此类问题的一种方法叫做向量自回归,或 VAR。VAR 是自回归(或 AR)模型的扩展,在生成预测时使用多个变量。VAR 模型因其在分析经济和金融时间序列时的灵活性而非常受欢迎,并且非常适合预测。

下图给出了带有两个变量和一阶动力学的 VAR 方程的分解。这是一个非常简单的线性方程,其中 t-1 时刻的 x 值和 y 值用于预测 t 时刻的 x 值和 y 值。由于变量 x 依赖于变量 y,反之亦然,因此使用一个方程组来共同考虑它们。基本上,VAR 模型通过使用多个相关时间序列的滞后数据来预测未来值。

VAR equation for two variables and first-order dynamics: Image courtesy ofhttp://www.ams.sunysb.edu/~zhu/ams586/VAR_Lecture2.pdf

如果你想了解更多的背景知识,华盛顿大学提供的以下讲义对 VAR 模型背后的数学进行了深入的描述:【https://faculty.washington.edu】

此外,芝加哥大学布斯商学院在以下演讲中对风险值建模进行了高度概括:https://faculty . Chicago Booth . edu/Jeffrey . Russell/teaching/time series/讲义/notes5.pdf

与大多数经济计量分析一样,VAR 模型的运行有几个要求。首先,过去的时间序列需要是静态的,即时间序列的统计属性,包括均值、方差和自相关,需要随时间保持不变。因此,显示季节性或趋势的时间序列不是静止的。

有几种方法可以让模型静止。它们如下:

  1. 差分时间序列。数据差分或多或少是计算每个数据点的瞬时速度,或时间序列从一个值到下一个值的变化量。
  2. 转换时间序列。这可以通过对数据应用对数或幂变换来实现。

接下来,为了使风险值模型发挥作用,采样频率(即每日、每月、每年的数据)需要相同。如果不是,则需要使用插补/线性插值等方法将数据转换成相同的频率。

在下面的代码中,每个时间序列都使用 numpy 自然对数函数进行转换,然后按一个间隔进行差分:

为了检验时间序列现在是否是平稳的,我们使用扩展的 Dickey Fuller 检验。扩展的 Dickey-Fuller 检验检验单位根存在于时间序列中的零假设(即,如果单位根存在于时间序列中,那么它不是平稳的)。要成功确定时间序列是平稳的,测试必须返回小于. 05 的 p 值。在下面的 Python 代码中,我们对转换后的差分时间序列运行了扩展的 Dickey-Fuller 测试,确定它们都是平稳的(对于电力和天然气时间序列,返回的 p 值分别为. 000299 和 0):

Outputs for the Augmented Dickey-Fuller Test for the electricity price time series and the natural gas price time series, respectively

现在,我们已经使我们的两个时间序列平稳,是时候将数据拟合到 VAR 模型中了。下面的 Python 代码成功构建了模型并返回了结果摘要,其中我们对训练/验证集使用了 95/5%的拆分:

VAR Model Summary, with y1=Electricity Price Time Series, and y2=Natural Gas Price Time Series

在上面的模型总结中,我们真正想要关注的是 y1 的等式,其中 y1 根据其自身的滞后值和滞后天然气价格来估计德克萨斯州的电价。

存在与滞后电价数据(L1.y1)和滞后天然气价格数据(L1.y2)相关联的 t 统计量和 p 值。t 统计将数据与零假设下的预期结果进行比较。如果样本结果正好等于零假设,则 t 统计量为 0。或者,t 统计值越高,我们就越有可能拒绝零假设。基本上,t 统计值越高,两个变量之间的相关性就越大。

每个 t 统计量都有一个相应的 p 值。p 值也用于拒绝零假设。p 值越低,反对零假设的证据越强。通常,小于 0.05 的 p 值用于确定统计显著性。

有关 t-统计和 p-值的更多信息,请查看以下链接:https://blog . minitab . com/blog/statistics-and-quality-data-analysis/what-are-t-values-and-p-values-in-statistics

记住所有这些信息,让我们来解释方程 y1 的模型总结的结果。

对于滞后电价变量,t 统计量为 3.002,p 值为 0.003-显然,电价时间序列的滞后值会影响时间序列的未来值,我们可以拒绝零假设。

天然气价格时间序列的滞后值也很有希望,t 统计值为 2.225,p 值为 0.026,远低于统计意义的临界值,并且明确表明天然气时间序列中的滞后值会影响电价时间序列中的未来值。

现在我们已经建立了一个模型,是时候生成预测并与测试/验证集中的实际数据进行比较了。需要注意的是,为了理解电价预测,数据必须是无差异的和反向转换的。以下代码执行非差分和反向转换操作,并计算与评估模型性能相关的预测指标,包括预测偏差、平均绝对误差、均方误差和均方根误差:

Actual electricity price vs. VAR-model predicted electricity price, predicted out 10 months (after un-differencing and back-transformation)

Accuracy metrics for the forecast: forecast bias, mean absolute error, mean squared error, and root mean square error

这里的结果看起来很有希望!VAR 似乎相当准确地估计了电价。预测偏差度量为-0.041638,表明模型有过度预测或预测过高的趋势。平均绝对误差、均方误差和均方根误差也相当低,这很好。根据平均绝对误差(MAE ),预测值和实际值之间的平均偏差为 0.22 美元。

有关时间序列预测模型指标的更多背景信息,请查看以下链接:https://machinelingmastery . com/time-series-forecasting-performance-measures-with-python/

本教程到此结束。感谢您的阅读!

此分析的完整脚本可通过 Github 获得:https://Github . com/kperry 2215/electricity _ price _ time _ series _ analysis/blob/master/analyze _ monthly _ electricity _ data . py

查看我的其他一些与能源相关的 Python 教程:

自动化油气递减曲线分析:https://techrando . com/2019/07/03/how-to-automate-decide-curve-analysis-DCA-in-python-using-scipys-optimize-curve _ fit-function/

分析开源 FracFocus 数据以获得完井见解:https://techrando . com/2019/07/14/using-public-available-frac focus-data-and-python-matplotlib-function-to-visualize-oil-and-gas-companies-completions-strategies-in-the-二叠纪盆地/

原载于 2019 年 7 月 19 日http://techrando.com

分析员工评论:谷歌 vs 亚马逊 vs 苹果 vs 微软

原文:https://towardsdatascience.com/analyzing-employee-reviews-google-vs-amazon-vs-apple-vs-microsoft-4dc3c036666b?source=collection_archive---------0-----------------------

值得为哪个公司工作?

概观

无论是因为他们提供高薪、奢侈津贴的能力,还是他们令人兴奋的使命宣言,很明显,像谷歌和微软这样的顶级公司已经成为人才磁铁。客观地说,仅谷歌每年就收到超过 200 万份工作申请。

为顶级科技公司工作是许多人的梦想,这当然是我很长一段时间的梦想,但我们不应该问自己“为这些公司工作真的值得吗?”有谁比他们自己的员工更能帮助我们回答这个问题呢?在这篇文章中,我将带你浏览我对谷歌、微软、亚马逊和苹果员工评价的分析,并试图发现一些有意义的信息,希望这些信息能在我们决定值得为哪家公司工作时有所启发。

我将从描述我如何清理和处理数据开始,然后借助一些可视化来谈谈我的分析。我们开始吧!!

[## 通过我的推荐链接加入 Medium-Andres Vourakis

阅读安德烈斯·沃拉基斯(以及媒体上成千上万的其他作家)的每一个故事。您的会员费直接支持…

medium.com](https://medium.com/@avourakis/membership)

数据

数据收集

用于这项分析的员工评论数据是从 Kaggle 数据集下载的,它来自 glass door——一个现任和前任员工匿名评论公司及其管理层的网站。该数据集包含超过 6.7 万条谷歌、亚马逊、脸书、苹果和微软的员工评论。

这些评论分为以下几类:

  1. 指数:指数
  2. 公司:公司名称
  3. 位置:该数据集是全球性的,因此它可能包括括号中的国家名称[即“安大略省多伦多(加拿大)”]。但是,如果位置在美国,那么它将只包括城市和州[即“洛杉矶,加利福尼亚州”]
  4. 发布日期:格式如下年月日
  5. 职位:该字符串还包括审核人在审核时是“现任”还是“前任”员工
  6. 总结:员工考核的简短总结
  7. 赞成:赞成
  8. 缺点:缺点
  9. 总体评分:1-5 分
  10. 工作/生活平衡评分:1–5 分
  11. 文化和价值观评分:1–5 分
  12. 职业机会评级:1–5
  13. 薪酬&福利等级:1–5
  14. 高级管理层评级:1–5
  15. 有帮助的评论统计:统计有多少人认为该评论是有帮助的
  16. 链接到评论:这将为您提供包含评论的页面的直接链接。然而,这种联系很可能会过时

以下是表格形式的数据:

Preview of data in tabular form (Not showing the last two columns)

数据清理

在做了一些基本的数据探索之后,我决定做以下事情来为我的分析准备数据:

  • 只包括谷歌,亚马逊,微软和苹果的员工评论。尽管脸书和网飞有大量的综述,但加在一起,它们只代表了不到 4%的数据集,所以为了简单起见,我决定将它们排除在分析之外。
  • “链接”和“给管理层的建议”专栏被删除了,因为我认为它们不会像其他专栏那样有见地。
  • 删除了“日期”列中缺少值的行。
  • 创建了一个名为“Year”的新列,包含进行评审的不同年份。
  • 以下各列中缺少值的行将被删除:“公司”、“年份”、“总体评分”和“职位”。
  • 删除了所有列中都缺少值的行。
  • 包含数值的列被转换为适当的数据类型。

洞察力和分析

哪家公司评论最多?

我从可视化我选择的 4 家公司的员工评价的分布开始我的分析。

解读:我们可以清楚地看到,亚马逊拥有最多的员工评论(超过 25000)。这很好,因为这可能意味着我们将看到各种观点的良好融合。虽然谷歌的员工评论数量最少,但它仍然足够大,足以让它与其他公司相比。

让我们来看看这些评价是如何在各个公司中分布的。

解释:如我们所见,有十年的员工评估可用,但它们只持续到 2018 年。

  • 微软:大多数评论都是过去 4-7 年的
  • 谷歌:大多数评论都是过去 4 年的
  • 亚马逊:大多数评论都是过去 3-4 年的
  • 苹果:大多数评论都是过去 2-4 年的

基于这些观察,并考虑到这些公司每年发展和变化的速度,我决定继续分析过去 4 年(2015 年至 2018 年)的员工评估,因为我认为它们是最相关的。

谁在复习?

现在我们已经知道我们要处理多少评论,让我们弄清楚是谁写的。这个问题可以用许多不同的方法来回答,我的第一个方法是找出评审者的职称,下面是前 5 名的样子:

Anonymous Employee               21910
Software Engineer                  930
Specialist                         648
Software Development Engineer      618
Warehouse Associate                585

不幸的是,大部分职位都被贴上了“匿名员工”的标签。考虑到很多时候公司对同一份工作的称谓略有不同,我决定不再深究。相反,让我们看看有多少评审者是现任和前任员工

正如我们所看到的,大多数评论来自当前的员工,但为了获得更多的洞察力,让我们看看每个公司的分布情况:

解读:再一次,我们看到大多数对每家公司的评论都是来自现在的员工。这些是在试图解读数据时想到的一些想法:有大量来自当前员工的评论是一件好事还是意味着更多的偏见?也许,有更多前员工的评论可以给我们一些我们不常读到的关于这些公司的见解。让我们继续…

哪家公司综合评分最高?

让我们来看看过去几年(2015 年至 2018 年)每家公司的平均总体评分是如何变化的

解读:我们可以看到,自 2015 年以来,除了苹果,每家公司的平均综合评分都没有下降。谷歌在这四家公司中拥有最高的平均综合评分,并且在过去的几年里一直保持这种状态。让我们来谈谈每家公司的趋势:

  • 谷歌:似乎从 2016 年开始略有减少。
  • 微软:从 2015 年开始缓慢增长
  • 苹果:好像在慢慢减少。
  • 亚马逊:从 2015 年到 2017 年急剧增长。

哪家公司能更好地平衡工作和生活?

让我们看看这些公司在允许员工拥有工作之外的生活方面做得有多好:

解读:谷歌的工作生活平衡评分最高(超过 4 星),微软紧随其后。在提供良好的工作生活平衡方面,亚马逊似乎有所欠缺。

哪家公司的文化价值观更好?

让我们看看员工如何评价他们公司的核心原则和理念:

解读:谷歌的文化价值观评分最高,苹果排名第二(超过 4 星)。亚马逊在 4 个等级中排名最低,但仅略高于 3.5 星。

哪个公司的职业机会比较好?

他们在帮助你推进职业发展方面有多出色?

解读:谷歌对职业机会的评分最高(超过 4 星)。考虑到这家公司有多大,他们正在使用多少种不同类型的技术,这并不奇怪。苹果的评分最低,仅略低于 3.5 星。

哪家公司福利待遇更好?

让我们看看这些公司在员工福利方面做得如何。

解读:谷歌的福利/津贴评分最高,超过 4.5 星。苹果和微软似乎也提供了很好的好处,但亚马逊有点不足。

哪个公司的高层管理比较好?

领导力是管理层的一项重要职能,让我们看看这些公司是如何评价高级管理层的领导力的:

解读:谷歌的高级管理层获得最高评级,但仅略低于 4 星,与其他评级相比是最低的。亚马逊对高级管理层的评价最低。

每个公司的优点是什么?

让我们用文字云来探索一下专业人士的评论:

以下单词在所有 4 家公司中都很常见(非常频繁),但不包括在单词云中:利益、公司、文化、环境、好、伟大、很多、机会、人、工作和工作。

这些词在试图找出这些公司的优秀之处时都很重要,但我决定省去它们,以便为其他频繁出现的关键词腾出空间,这些关键词可能对每个公司更独特/更有见解。以下是员工喜欢他们公司的几个方面:

  • 谷歌:额外津贴、聪明人、免费食物和高薪。
  • 亚马逊:学习的能力,他们的团队,聪明的人和管理。
  • 苹果公司:员工折扣、产品、团队、有趣的环境和良好的培训。
  • 微软:聪明的人、产品、薪酬、技术和他们的团队。

每个公司的缺点是什么?

让我们使用单词云来研究一下反对意见:

以下单词在所有 4 家公司中都很常见(非常频繁),但不包括在单词云中:company、get、lot、management、manager、people、time 和 work。

这些词在试图找出是什么让这些公司变得糟糕时都很重要,但我决定不考虑它们,以便为其他频繁出现的关键词腾出空间,这些关键词可能对每个公司更独特/更有洞察力。以下是员工不喜欢公司的几个方面:

  • 谷歌:他们的团队、艰苦的工作、项目、办公室政治以及缺乏工作与生活的平衡
  • 亚马逊:缺乏工作与生活的平衡,工作时间和文化。
  • 苹果:工作生活平衡的缺失,零售店,顾客,薪酬。
  • 微软:办公室政治、工作与生活缺乏平衡、他们的团队、努力工作和文化

结论

通过分析,我们发现谷歌不仅拥有最高的整体平均评分(低于 4.4 星)(截至 2018 年),而且在工作生活平衡、福利/津贴、文化价值观、高级管理和职业机会方面也排名第一。微软排名第二,总体平均评分略高于 4 星,但苹果似乎有更好的高层管理和文化价值观,并提供更好的福利/津贴。除了就业机会,亚马逊几乎在所有类别中都排在最后。

我们还了解到,尽管有评级,但总的来说,员工发现他们公司缺乏工作与生活的平衡是有问题的。此外,单词云显示,所有 4 家公司的首要缺点是管理、人员(其他员工)和工作本身。这三个缺点也是人们辞职的主要原因之一。

我们应该问自己的是,知道谷歌有多受欢迎,为什么在我们分析的 4 家公司中,它的评论最少?是因为它的员工数量最少还是我们遗漏了什么?

我当然想到了许多其他问题,但必须指出,这绝不是详尽的分析。

尽管如此,我希望这篇文章是有见地的,并且您会受到启发来扩展这一分析,或者使用您的数据科学技能来研究不同的感兴趣的主题。如果你想看代码,所有的代码都被仔细地记录在这个 Jupyter 笔记本上。

请在评论中告诉我你的想法和反馈。有什么事情你会做得不一样吗?我可以使用哪些其他数据作为分析的一部分?

此外,如果你希望支持我成为一名作家,可以考虑注册成为❤️的媒体成员

用 Python 分析英超数据及用 Tableau 可视化

原文:https://towardsdatascience.com/analyzing-english-premier-league-data-with-python-and-visualization-using-tableau-21d343bc57dd?source=collection_archive---------17-----------------------

Photo by Nathan Rogers on Unsplash

由 M.P.Karthick、 Janmejay SinghPritam Kumar Patro 出版

数据科学家和数据本身一样优秀。因此,为了获得可操作的见解,使用正确格式的数据集和正确的变量非常重要。体育分析是一个新兴领域,其中数据驱动的见解用于制定战略。在本教程中,我们将探索使用 Python 的数据分析和使用 Tableau 的可视化。我们将使用的 python 库是 pandas、os、glob 和 regex。

我们将使用的数据集是发布在 http://www.football-data.co.uk/的英超联赛数据集。我们分析了从 2009 年 10 月到 2018 年 19 月的 10 个 EPL 赛季的数据。使用这些数据集将帮助我们学习数据整理和转换过程,这在 iris 和 mpg 等内置数据集上是不可能的。

提问:

我们希望从数据集中了解并得出以下见解:

如何追加不同季节的数据,创建主数据集?

如何整理和转换主数据集?

曼联各个赛季的进攻表现如何?

曼联各个赛季的防守表现如何?

曼联在不同的主教练手下表现如何?

在穆里尼奥的领导下,曼联是一支防守型球队吗?

加载库和模块:

import pandas as pdimport osimport globimport re

Pandas 是一个开源库,为 python 编程语言提供了易于使用的数据结构和数据分析工具。python 中的 OS 模块提供了与操作系统交互的功能。这个模块属于 python 的标准实用程序模块。该模块有助于提供一种使用操作系统相关功能的便携方式

glob 模块根据 UNIX shell 使用的规则找到所有与指定模式匹配的路径名。但是,这些结果以任意顺序返回。正则表达式是构成搜索模式字符序列。Python 通过库支持正则表达式。正则表达式模式通过 Python 中的 re 模块导入。RegEx 可用于检查字符串是否包含指定的搜索模式。

数据整理和转换

在将数据集导入 Python 环境之前,我们将确保 CSV 格式的 10 个季节的数据表位于运行 Python 程序的同一个文件夹中。

我们发现数据集中缺少我们分析所需的两个重要变量。我们需要“赛季”变量来产生赛季洞察力,需要“经理”变量来理解曼联在不同经理下的表现。我们从英超网站上获得了这 10 个赛季的主教练名单,数据集已经按赛季排列好了。因此,我们将把这两列添加到数据集中,稍后将它们追加到一个数据表中。

man=["SAF","SAF","SAF","SAF","DM","VG","VG","JM","JM","OS"]a=glob.glob("season*.csv")b=[]for i in a:c=re.search(r"\d{2,}",i).group()b.append(c)

追加数据集:

EPL 的数据集是季节性的。当我们对数据集进行初步观察时,我们没有发现任何缺失值。当我们跨赛季匹配变量时,从 2012-13 赛季开始出现了新的变量。我们只保留了我们在分析和可视化方面感兴趣的变量。

count=0for i,j,k in zip(a,b,man):dataL=pd.read_csv(i)dataL.insert(0,"season",j)dataL.insert(0,"manager",k)if count==0:data.to_csv("dataL.csv",mode="a",index=False)count=count+1else:dataL.to_csv("dataL.csv",mode="a",index=False,header=False)

使用上面的代码,我们在工作文件夹中得到一个名为 dataL.csv 的数据表,其中包含所有 10 个赛季,包括赛季和经理列。

由于我们只分析与曼联相关的数据,我们删除了所有与其他俱乐部相关的数据。因此,我们已经使用 python 成功地清理和转换了数据,现在可以进行可视化了。

dataMU1=pd.read_csv(“dataL.csv”)dataMU2=dataMU1.loc[(dataMU1[‘HomeTeam’] == ‘Man United’) | (dataMU1[‘AwayTeam’] == ‘Man United’)]dataMU2.to_csv(“finaldataManUtd.csv”)

创建 Tableau 仪表板

Tableau 是一个强大的数据可视化工具,有助于以仪表板和工作表的形式创建可视化效果。tableau 的好处是它有点击和拖动的选项,这使得编程技能较低的人可以制作出令人惊叹的可视化效果。我们开发的 tableau 仪表板非常具有交互性,让您挑选感兴趣的见解。我们只分析了数据集中的一些变量。还有更多变数,比如犯规次数,黄牌数量等等。如果你感兴趣的话,可以去探索一下。

[## Tableau 公共

编辑描述

public.tableau.com](https://public.tableau.com/profile/pritam.kumar.patro#!/vizhome/ManUnitedComparison/Dashboard9)

对比曼联各个赛季的进攻表现

很多参数可以用来评估一支球队的进攻表现。我们使用进球数(主客场)、总射门数和目标变量进行分析。当我们绘制跨赛季的进球时,我们可以看到,自从 2012-13 赛季结束弗格森爵士退役以来,曼联的进攻表现已经不一样了。弗格森爵士执教下(2009-10 赛季至 2012-13 赛季)的平均主场进球是 49.5 个,相比之下,范加尔和穆里尼奥分别为 34.0 和 32.0 个。类似的趋势也可以在客场进球中观察到。

投篮命中率(命中目标的投篮次数/总投篮次数)是决定一个队能否赢得比赛的重要因素之一。另一项分析显示,与那些仅仅比对手创造更多投篮机会的球队相比,命中率更高的球队获胜的概率明显增加。我们的分析表明,自从弗格森爵士退役以来,曼联的射门准确率明显下降,从未越过 50%。

对比曼联各个赛季的防守表现

与进攻表现不同的是,防守表现对于不同主帅手下的曼联来说差别并不大。上赛季(2018–19)出现了近 10 个赛季以来最差的防守表现。

曼联在不同主帅手下表现如何?

毫无疑问,曼联在弗格森爵士手下的表现是最好的。比较整个赛季的联赛积分和联赛排名给了我们清晰的叙述。在弗格森爵士之后,下一个最佳教练是穆里尼奥,81 分,2017-18 赛季亚军。

曼联在穆里尼奥手下是防守型球队吗?

何塞·穆里尼奥的足球哲学与其他顶级教练不同。他的比赛风格已经被证明能够在对抗最好的球队时取得好成绩。但它也被认为是防御性的和无聊的。这篇博客还认为,随着职业生涯的发展,他变得更加具有防御性。如爆炸图所示。在穆里尼奥的带领下,曼联的防守表现比其他教练都要好。当我们比较进攻表现的时候,这和其他曼联经理类似,比如大卫·莫耶斯和路易斯·范加尔。

希望这能帮助你对你喜欢的体育相关数据进行基本的分析和可视化。Python 语法非常简明易懂。Tableau 是最好的用户友好的可视化工具之一。上面给出的所有可视化都可以用 python 来完成,但是我们想讨论一下这两个神奇的工具,并展示使用它们是多么容易!

分析数据和人工智能初创公司的特征和全球分布

原文:https://towardsdatascience.com/analyzing-global-distribution-of-data-science-and-ai-startups-through-angellist-database-30a89168a6b2?source=collection_archive---------24-----------------------

我喜欢初创公司,也喜欢人们可以做什么来让这个世界变得更好。而且,由于我在数据和人工智能领域工作,我对探索 AngelList 上的数据和人工智能初创公司更感兴趣。从 AngelList 收集数据并不简单,因为它不会让您一次导出超过 100 条记录。因此,我应用了多个过滤器,如 Type="Startup "," Market="Big Data Analytics "," Data Science "," Big Data "," Machine Learning,Predictive Modeling "," Computer Vision "," Natural language Processing "," Neural Networks "," Deep Learning "," Reinforcement Learning ",然后排除了重复的过滤器,因为这些过滤器的结果在一些操作中有重叠。我 26 次得到不到 100 条记录,因此创建了 26 条。csv 文件。最后,我合并了这些。csv 文件合二为一。csv 文件,并随后在数据帧中添加了标题。

sed 1d companies*.csv > startup.csv

这是对初始数据集的一瞥。

df=pd.read_csv("startup.csv",names=["Name","Profile URL","Signal","Joined","Location","Market","Website","Employees","Stage","Total Raised"])

我对该数据集进行了处理,将“Joining”拆分为“Joining_Year”和“Joining_Month ”,并删除了“Joining ”,在 Year 前面附加了“20 ”,使用以下命令删除了重复的行。

df.drop_duplicates(keep=False,inplace=True)
df[['Joining_Month','Joining_Year']]=df.Joined.str.split("'",expand=True)
df.drop(['Joined'], axis=1, inplace=True)
df['Joining_Year'] = ('20' + df['Joining_Year'])
df.head()

使用 python 的计数器,我用下面的代码找出了 10 大创业市场。

from collections import Counter
c=Counter(df.Market)
histo=c.most_common(10)
freq={}
for item,count in histo:
    freq[item]=count
explode = (0.05,0.05,0.05,0.05,0.05,0.05,0.05,0.05,0.05,0.05)
plt.pie([float(v) for v in freq.values()], labels=[(k) for k in freq],
           autopct='%.2f',startangle=90, pctdistance=0.85, explode = explode,radius=3,textprops={'fontsize': 14})centre_circle = plt.Circle((0,0),0.90,fc='white')
fig = plt.gcf()
fig.gca().add_artist(centre_circle)
plt.tight_layout()
plt.show()

Top 10 Startup Markets in Data/AI. We see SaaS is the leader followed by ‘Big Data Analytics’, ‘Predictive Analytics’ and ‘IoT’.

类似地,我努力寻找这些创业公司的多种属性,你可以找到如下的环形图。

Distribution of number of employees across startups. ‘nan’ indicates that number was not specified in the AngelList database for these companies.

Top 10 cities across the world for DS/AI startups, note 7 are in the USA with the exception of Berlin and London. ‘nan’ indicates that city was not specified in the AngelList database for these companies.

Distribution of funds raised across the startups. ‘nan’ indicates that funds raised was not specified in the AngelList database for these companies.

Distribution of the stages of the startup. As we see majority are in ‘nan’ stage, this indicates that stage was not specified in the AngelList database for these companies. Amongst the valid stages, most startups are in seed stage, which makes sense, as initially startups struggle to get funded.

贴完这篇文章,我想到了在 2013 年之前和之后的时代描绘全球各地的创业公司。为此,我使用了以下代码。我从 IGIS 地图上下载了“continentsshp31.shp”。此外,为了在地图上绘制这个数据帧,我需要每个城市的经度和纬度,这是我使用 geopandas 计算的。

#install the following libraries# !pip3 install geopandas
# !pip3 install descartes
# !pip install geopyimport matplotlib.pyplot as plt
import geopandas
from geopy.geocoders import Nominatim
world = geopandas.read_file("continentsshp3147/continentsshp31.shp")
geolocator = Nominatim(user_agent="ds")# code to retrieve latitude and longitude
from geopy.extra.rate_limiter import RateLimiter# 1 - convenient function to delay between geocoding calls. I did this in groups of 100 as the service was getting timed out. Later, I combined all slices.geocode = RateLimiter(geolocator.geocode, min_delay_seconds=1)# 2- - create location column
df_100=df[:100]
df_100['location'] = df_100['Location'].apply(geocode)# 3 - create longitude, latitude, altitude from location column (returns tuple)
df_100['point'] = df_100['location'].apply(lambda loc: tuple(loc.point) if loc else None)# 4 - split point column into latitude, longitude and altitude columns
df_100[['latitude', 'longitude', 'altitude']] = pd.DataFrame(df_100['point'].tolist(), index=df_100.index)# combine the slices with latitude and longitude
df_new = pd.concat([ df_100,df_101_200,df_201_300,df_301_400,df_401_497])
df_new = df_new.sample(frac=1).reset_index(drop=True)
df_new.head()

产生的数据帧如下所示。

下一步是获取几何格式的数据。方法是将 Pandas 数据框架转换为 geo-data 框架,这需要原始数据框架、坐标参考系统(CRS) 和新数据框架的几何参数。为了适当地格式化几何图形,我们需要将经度和纬度转换成(我们从上面的 shapely 中导入点),所以让我们传递熊猫数据帧,并使用 EPSG:4326 CRS 获得经度和纬度。

from shapely.geometry import Point, Polygon
crs={'init': 'epsg:4326'}
geometry=[Point(xy) for xy in zip(df_new["longitude"],df_new["latitude"])]geo_df=gpd.GeoDataFrame(df_new,crs=crs,geometry=geometry)
fig, ax = plt.subplots(figsize=(20, 20))
world.plot(ax=ax,alpha=0.4,color='grey')geo_df[(geo_df['Joining_Year']).astype(str).astype(int)>2013].plot(ax=ax,markersize=20,color='green',marker="o",label="2014-2018")geo_df[(geo_df['Joining_Year']).astype(str).astype(int)<=2013].plot(ax=ax,markersize=20,color='red',marker="^",label="2010-2013")plt.legend(prop={'size':15})plt.title("Global distribution of DS/AI Startups joining AngelList before and after 2013")

结果图如下所示。我们看到(如右边绿色部分)在 2014-2018 年间,很少有创业公司出现在非黄金创业区。此外,世界上大多数人看起来缺乏创业精神。创业文化主要集中在美国、英国和欧洲的一些地方。

我还绘制了另一个 geopandas 地图,以查看筹集资金的全球分布和密度。

从这个数据集中可以得出更多的见解。如果你对使用这个数据集感兴趣,我已经在 kaggle 链接上上传了这个(https://www . ka ggle . com/shilpbhattacharyya/data ai-startups-dataset-from-angellist)——敬请访问。

分析被撤回的生物医学文献中隐藏的主题

原文:https://towardsdatascience.com/analyzing-hidden-themes-in-the-retracted-biomedical-literature-15314a150d9d?source=collection_archive---------30-----------------------

在我之前的博客文章中,我讨论了生物医学和生命科学文献中涉及撤稿的各种参与者。有一个问题引起了我的兴趣,但没有得到回答——这些被撤回的出版物中有哪些研究主题?在这篇博文中,我试图用主题建模来回答这个问题。

主题建模是从语料库或文档集中发现、组织和理解文本信息。这是一种无监督的学习方法,其中主题模型学习未标记文档中的主题。它基于这样的假设,即每个主题都由单词组组成,每个文档都是主题的集合。因此,语料库中潜在的或隐藏的主题可以通过收集频繁共现的词来发现。

有许多主题建模技术可用。这里,我使用了一种最流行的技术,潜在狄利克雷分配(LDA)。

LDA 是文档集合的生成概率模型。它基于狄利克雷分布,这是一种多项式分布的分布,并假设文档是潜在主题的概率分布,主题是单词的概率分布。LDA 回溯并发现构成语料库的不同主题以及每个主题在文档中出现的数量。

从数学上讲,这种生成过程可以解释如下:

这样的图表被称为图版符号。由于媒介不允许下标,请遵循图表或提供的等式中的符号,或者在我的 网站 上阅读这篇帖子。从具有参数λ的狄利克雷分布中,我们获得了主题𝑘∈1 的单词分布..𝐾,这代表了𝛽𝑘。这里,每个主题是一个𝑁-dimensional 向量(𝑁是词汇量的大小),根据𝛽.分布,它具有主题𝑘中每个单词的概率根据具有参数𝛼的第二狄利克雷分布,我们绘制了每个文档𝑑∈1 的主题分布..𝑀,这代表了𝜃𝑑.因此,对于每个文档,我们有一个𝐾-dimensional 向量,根据主题的分布,它具有每个主题的概率(𝐾是主题的数量)。为每个单词定位𝑛∈1..𝑁在文件中给来自𝜃.的𝑧𝑛画了一个题目然后,我们使用与主题赋值𝛽𝑧𝑛相对应的𝛽来生成单词。由于 LDA 知道这些词,它打算找到𝑧、𝛽和𝜃.

简而言之,LDA 工作如下:首先,我们指定语料库中我们期望的主题𝐾的数量。然后 LDA 为每个文档中的每个单词随机分配主题。接下来,它查找语料库中的每个单词,并检查该特定主题在文档中出现了多少次,以及该特定单词在指定主题中出现了多少次。根据结果,它为这个特定的单词指定一个新的主题,这样反复下去,直到主题有意义为止。最终还是由用户来解读题目。

这篇博文将描述从我的撤稿文献语料库中提取潜在主题的以下步骤。

  1. 数据预处理
  2. 构建 LDA 模型
  3. 形象化

正如我在之前的博客文章中提到的,这些数据是从 PubMed 获得的,包含 6485 篇被撤稿的出版物。对于当前的分析,我只使用了这些出版物的摘要。关键词可用于确定任何摘要的主题,但在可用的数据集中,84%的摘要没有关键词,这促使我从摘要中提取主题。

数据预处理:

这一步涉及数据清理,在任何文本挖掘任务中都至关重要。我将此细分为 3 个步骤:

一.词汇化

这一部分涉及词性(POS)标记,以过滤名词、专有名词或形容词。我忽略了其他词类,如动词和副词,因为它们似乎对我当前的任务不重要。产生的单词然后被词条化,这意味着只有单词的词根形式被保留。我使用了非常棒的 Python 库 spaCy 来做这个处理。

*# load spacy and return english language object*
nlp**=**spacy**.**load('en_core_web_sm')

**def** **lemmatization**(doc, allowed_pos**=**['NOUN','ADJ','PROPN']):

    ``` filtering allowed POS tags and lemmatizing them```

    retracted_corpus**=**[]
    **for** text **in** doc:
        doc_new **=** nlp(text) 
        retracted_abstract**=**[]
        **for** token **in** doc_new:
            **if** token**.**pos_ **in** allowed_pos:
                retracted_abstract**.**append(token**.**lemma_)
        retracted_corpus**.**append(retracted_abstract)
    **return** retracted_corpus

abstract_lemmatized **=** lemmatization(doc,allowed_pos=['NOUN','ADJ','PROPN'])

这些是科学文档,有时仅用空格断句并不是最佳选择(例如,公式或等式可能使用=或+等其他字符)。因此,在一个额外的步骤中,我使用了一个不同的文本分割实现,它使用了 NLTK 的一些功能,NLTK 是另一个用于自然语言处理(NLP)的 Python 库。

**from** nltk.tokenize **import** RegexpTokenizer
*# tokenizer that splits only in the selected symbols or space*
tokenizer**=**RegexpTokenizer('\s+|[<>=()-/]|[±°å]',gaps**=**True)

**def** **remove_punctuation**(text):
    updated_abstract**=**[]
    **for** doc **in** text:
        sent**=**' '**.**join(doc)
        updated_abstract**.**append(tokenizer**.**tokenize(sent))
    **return**(updated_abstract)

abstract_processed **=** remove_punctuation(abstract_lemmatized)

二。删除停用词

在自然语言处理中,一个相当常规的任务是去除停用词,或者没有足够含义来区分一个文本和另一个文本的常用词,例如“a”、“the”、“for”等等。为此,我使用了 NLTK 的停用词库。它包含 179 个单词。因为在生命科学和生物医学研究语料库中有更多的词,如“证明”、“记录”、“研究者”等。,没有区分单词,我将额外的单词(我在当前语料库中找到的)添加到停用词表中,使其长度为 520 个单词。此外,在这一步,我把所有的字母都小写了,这是为了避免算法把“read”和“Read”当成两个不同的单词。

**def** **remove_stopwords**(doc):
    retracted_corpus**=**[]
    **for** text **in** doc:
        retracted_abstract**=**[]
        **for** word **in** text: 
            word**=**word**.**lower()
            **if** word **not** **in** nltk_stopwords:
                retracted_abstract**.**append(word)
        retracted_corpus**.**append(retracted_abstract)
    **return** retracted_corpus

abstract_no_stop **=** remove_stopwords(abstract_processed)

三。制作二元模型

生命科学文献经常包含诸如“细胞周期”和“蛋白磷酸酶”的二元模型。当单独考虑两个单词时,这些双字表达的意思并不明显。因此,我决定使用 python 库 Gensim 来收集二元模型,这是另一个用于自然语言处理的伟大的 python 库。该步骤提供二元模型和单元模型,其中二元模型是根据语料库中出现频率的特定条件来选择的。

*#using gensim to construct bigrams*
**from** gensim.models.phrases **import** Phrases, Phraser
bi_phrases**=**Phrases(abstract_processed, min_count**=**5, threshold**=**10)
bigram **=** Phraser(bi_phrases)

*#provides unigrams and bigrams*
**def** **dimers**(doc):
    updated_abstract**=**[]
    **for** text **in** doc:
        di **=** bigram[text]
        updated_abstract**.**append(di)
    **return** updated_abstract

abstract_bigram **=** dimers(abstract_no_stop)

在这之后,我删除了所有只有数字或者少于 2 个字符的内容。

**def** **abstract_bigram_clean**(doc):
    retracted_corpus**=**[]
    **for** text **in** doc:
        retracted_abstract**=**[]
        **for** word **in** text:
            **if** **not** word**.**isdigit() **and** len(word)**>**1:
                retracted_abstract**.**append(word)
        retracted_corpus**.**append(retracted_abstract)
    **return** retracted_corpus

abstract_clean **=** abstract_bigram_clean(abstract_bigram)

从这些处理步骤中,我获得了列表的列表,每个列表包含来自单个摘要的单词。为了说明语料库的复杂性,在语料库中有 35,155 个独特的单词,语料库本身包含 6,000 多个摘要。

构建 LDA 模型

在构建模型之前,我们需要将我们的语料库(所有文档)以矩阵形式呈现。为此,我准备了一本字典,其中每个独特的单词都被分配了一个索引,然后用它来制作一个文档术语矩阵,也称为单词袋(BoW)。我使用 Gensim 来执行所有这些任务。此外,有 11,998 个单词只出现一次。我删除了它们,因为它们不表示模型将检测到的任何模式。此外,在超过 20%的文档中出现的任何单词都被删除,因为它们似乎不局限于少数主题。

*# create a dictionary* 
**from** gensim.corpora **import** Dictionary
dictionary **=** Dictionary(abstract_clean)
dictionary**.**filter_extremes(no_below**=**2, no_above**=**0.2)

*# convert the dictionary into the bag-of-words (BoW)/document term matrix*
corpus **=** [dictionary**.**doc2bow(text) **for** text **in** abstract_clean]

为了构建 LDA 模型,我们需要提供语料库中我们期望的主题数量。这可能很棘手,需要多次反复试验,因为我们不知道有多少主题。估计这个数字的一种方法是通过计算一致性度量,这是一种对主题模型计算的主题质量进行评级的分数,从而区分好的主题模型和坏的主题模型。

相干性度量按以下四个步骤计算:

  • 分割——其中单词集 t 可以被分割成单词子集 S
  • 概率计算——其中基于参考语料库计算单词概率 P
  • 确认措施—确认措施使用两组 SP 来计算成对 S 的协议𝜙
  • 汇总—最后,所有确认汇总成一个一致性值 c

为了找到语料库中主题的最佳数量,可以用不同数量的主题建立多个 LDA 模型。从这些模型中,人们可以选择具有最大分数的主题值,并结束一致性值的快速增长。进一步增加主题的数量可能会导致许多关键字出现在不同的主题中。Gensim 库提供了一致性度量的实现。

*# instantiating an lda model*
LDA **=** gensim**.**models**.**ldamodel**.**LdaModel 

*#computing coherence for different LDA models containing different number of topics* 
**def** **calculate_coherence**(dictionary, corpus, texts, start, stop, step):
    coherence_scores**=**[]
    **for** num_topics **in** range(start,stop,step):
        model**=**LDA(corpus**=**corpus, id2word**=**dictionary,    num_topics**=**num_topics)
        coherence_lda**=**CoherenceModel(model**=**model, texts**=**texts, dictionary**=**dictionary, coherence**=**'c_v')
        coherence**=**coherence_lda**.**get_coherence()
        coherence_scores**.**append(coherence)
    **return** coherence_scores

coherence_scores **=** calculate_coherence(dictionary**=**dictionary, corpus**=**corpus, texts**=**abstract_clean, start**=**2, stop**=**40, step**=**3)

在相干值图中,我们可以观察到高度几乎相同的多个峰。第一个高峰出现在 14 点。

我决定用 14 个主题建立我的 LDA 模型。

lda_model_abstract **=** LDA(corpus**=**corpus,id2word**=**dictionary, num_topics**=**14, random_state**=**10,chunksize**=**6485,passes**=**100)

形象化

这是阅读和理解从 LDA 和 pyLDAvis 那里获得的主题的关键一步。pyLDAvis 是用于主题的交互式可视化的 python 包。它源自 LDAvis,LDAvis 是一个基于 web 的可视化工具,用于使用 LDA 估计的主题。

pyLDAvis 提供了两个可视化面板:左边的面板以二维圆圈的形式显示主题。通过计算主题间的距离来确定圆圈的中心,然后使用多维标度将它们投影到二维上。因此,密切相关的主题更接近。此外,圆圈区域代表主题的总体流行程度。因此,圆圈越大,语料库中的主题越普遍。右侧面板显示了左侧面板中所选主题的关键术语的条形图。重叠的条形用红色表示各种术语的特定主题频率,用灰色表示语料库范围内的频率。因此,右边的面板帮助我们找到主题的含义。两个面板的链接方式是,在左侧面板中选择一个主题会在右侧面板中显示其重要术语。此外,选择右侧面板上的术语时,会显示其在所有主题中的条件分布。pyLDAvis 中一件有趣的事情是它在一个叫做相关性的主题中对术语进行排序的方法。相关性是一个词的概率及其提升的对数的加权平均值。提升被定义为术语在主题中的概率与其在语料库中的边际概率的比率。带有权重参数 λ 的术语 w 与主题 k 的相关性可以数学定义为:

其中𝜙𝑘𝑤是𝑤∈1 项的概率..𝑉代表话题𝑘∈1..𝐾,其中𝑉是语料库的词汇中的术语数量;𝑝𝑤是语料库中术语𝑤的边际概率。𝜆介于 0 和 1 之间。它决定了相对于与𝑤.相关联的提升,给予主题𝑘中的术语𝑤的概率的权重当𝜆=1 出现时,术语按照其主题特定概率的降序排列。当𝜆=0 时,术语根据它们的寿命排列在一个主题中。pyLDAvis 提供了一个用户界面来调整𝜆.对于解释主题,我保留了𝜆=0.6,这也是从用户研究中获得的最优值。

您可以在下面查看当前分析的可视化效果。请查看我的博客来看看和玩互动可视化。

获得了以下主题(按其流行程度降序排列):

结论:

首先,使用 LDA 的主题建模显示了主题 1-9 和 12 的主题特定术语的良好解析/分离,除了主题 5,我发现主题解释相当容易。但是对于其他主题的解释是困难的,因为许多不相关的术语出现在一个主题中,这表明主题模型在语料库中拾取了噪声或特殊的相关性。选择更多的主题并没有给主题解释带来任何改进。重要的是,由于语料库不大(只有大约 6000 篇文章),只包含摘要(短文本)和 23,157 个词汇,这可能是为什么在某些情况下主题模型会产生噪音的原因。

第二,主题 1 至 7 显示了相似的主题流行度,范围从 10.2%到 7.9%的令牌。因此,表明这些主题中的大部分在收回文献的语料库中是同等重要或普遍的。

总之,尽管数据集很小,但 LDA 可以在收回的文献中找到 14 个主题,主要包括医学、细胞周期和增殖、癌症、免疫学、氧化应激、遗传学、中枢神经系统和认知。可以说 LDA 是一个非常强大的工具,它提供了一种简单快速的方法来探索语料库中的模式或主题。

这个分析的源代码可以在我的 Github 存储库中找到。这篇文章最初发表在我的博客。请随意参观。

  1. 布雷博士、Ng 博士和乔丹博士,2003 年。潜在狄利克雷分配。机器学习研究杂志,第 3 期(一月),第 993–1022 页。
  2. 罗德,m .,两者,a .和欣内堡,a .,2015 年 2 月。探索话题连贯性测量的空间。《第八届 ACM 网络搜索和数据挖掘国际会议论文集》(第 399-408 页)。ACM。
  3. 西沃特和雪莉,2014 年。LDAvis:一种可视化和解释主题的方法。交互式语言学习、可视化和界面研讨会论文集(第 63-70 页)。

使用亚马逊转录和理解分析历史演讲

原文:https://towardsdatascience.com/analyzing-historical-speeches-using-amazon-transcribe-and-comprehend-636f39a0726a?source=collection_archive---------22-----------------------

使用 Python 和 AWS 服务的快速简单的 NLP 教程

FIgure 1. From left to right: Winston Churchill, Ronald Reagan, John F. Kennedy, Martin Luther King and General Douglas MacArthur.

1.介绍

半个多世纪前,试图让计算机理解我们的语言是人工智能(AI)研究人员面临的首批挑战之一。最近几年,它在一个被广泛称为自然语言处理(NLP)的领域里大受欢迎。翻译、语音识别、boots 和许多其他工具和应用程序是我们生活的一部分,并且以某种方式利用了与 NLP 相关的某种算法或模型。如果你正在做一个软件项目,你可能需要使用工具来处理 NLP。学习基本理论和如何使用传统库需要时间,所以我们在这里介绍一种使用 AWS 提供的服务分析音频文件的简单方法。

目标:

本文的目标是使用 Python 和 boto3 展示两个 AWS NLP 工具,Amazon transcriptor 和 Amazon understand。我们将使用 Youtube-dl 从 Youtube 下载一些历史演讲,将其转录为文本并进行情感分析。我们还将音频转录与原始转录进行比较,以评估亚马逊转录所用模型的相似性和一致性。

2.选择演讲

我们将使用从 Youtube 上下载的五篇历史演讲来说明上述工具的潜力。你可以在这篇由 Brett & Kate McKay 发表的关于男子气概艺术的文章中找到历史和演讲的原始转录。选定的演讲如下:

A) 温斯顿·丘吉尔《我们将在沙滩上战斗》 :

1940 年 7 月 4 日,温斯顿·丘吉尔去下议院发表了历史上最勇敢也是最重要的演讲之一。德国军队迅速征服了欧洲,法国已经落入希特勒的控制之下,英国军队不得不从敦刻尔克战役中撤退。通过这次演讲,丘吉尔号召英国人民放弃一切投降的机会,抗击纳粹的威胁,成为第二次世界大战历史的转折点。

Figure 2. Winston Churchill ““We Shall Fight on the Beaches”

B) 罗纳德·里根,《在勃兰登堡门的演讲》 :

1987 年 6 月 12 日,美国前总统罗纳德·里根在勃兰登堡门前与苏联领导人米哈伊尔·戈尔巴乔夫并肩呼吁结束冷战,向世界展示了他的领导力和自由。

Figure 3. Ronald Reagan, “Remarks at the Brandenburg Gate”

C) 马丁·路德·金《我有一个梦想》 :

马丁·路德·金部长是美国五六十年代民权运动的主要领导人。在 1963 年的华盛顿游行中,他发表了著名的“我有一个梦想”的演讲,呼吁白人和黑人之间的和平与尊重。

Figure 4. Martin Luther King Jr., “I Have a Dream”.

D) 道格拉斯·麦克阿瑟将军,“职责、荣誉、国家” :

历史上很少有美国人能在军事生涯成就方面接近道格拉斯·麦克阿瑟将军。他参加过三次战争,体现了军事领袖的责任和荣誉。他在西点军校的最后演讲是一首爱国主义颂歌,是对为自由而牺牲的士兵的敬意。

Figure 5. General Douglas MacArthur, “Duty, Honor, Country”.

E) 约翰·肯尼迪《登月决定》 :

美国前总统约翰·肯尼迪是现代史上最伟大的演说家之一,1961 年 5 月 25 日在休斯顿的一次活动中,他向全国和全世界传达了美国和人类登月的目标。在我们的历史上,很少有项目像太空竞赛和登月这样对科学和现代社会产生如此大的影响。

Figure 6. John F. Kennedy, “The Decision to Go to the Moon”.

3.分析的要求和工具

要遵循本教程,您需要以下内容:

a)安装了以下库的 python 3:boto 3pandasmatplotlibseabornspacywmd

AWS 上的活跃账户;

c)安装并配置好 AWS 命令行界面()AWS CLI);

d)Youtube-DL安装。

重要提示

为了增加这篇文章的可读性和理解性,我决定只展示分析中最重要的代码块,但是你可以在我的GitHubrepository上的 Jupyter 笔记本上找到所有细节,包括完成这些情节的代码。****

Youtube-DL

为了从 Youtube 下载音频文件,我们将使用一个名为Youtube-DL的命令行工具。安装之后,你可以在终端上输入下面描述的命令,并输入任何 Youtube 视频的 URL 来下载它。Youtube-DL 是用 Python 开发的,GitHub 上的社区正在积极开发。

**# To download the video file to your local folder **youtube-dl <youtube_video_url>**# To download the audio file in mp3
**youtube-dl -x --audio-format "mp3" <youtube_video_url>`****

boto3 和 AWS 服务

Boto3 是 AWS 为用户访问其服务而开发的 Python SDK。它调用 AWS API,有两种类型的服务访问:客户端资源。客户端是低级服务访问,响应是 JSON 格式(Python 字典)。资源是以面向对象的方式构造的高级服务访问。基本上,您可以使用两种类型的服务访问中的任何一种,而与您需要在 AWS 上执行的任务无关,但是一般来说,可以使用较少的代码行来使用 Resource。有关 boto3 的更多信息,请查看 Ralu Bolovan 的精彩文章。我们将在 Jupyter 笔记本上使用 Python 进行所有的分析,boto3 对于工作流来说是必不可少的。

亚马逊转录

为了将我们的音频转换成文本,我们将使用亚马逊转录,这是一项 AWS 服务,为位于 S3 桶上的音频文件提供自动语音识别。它支持 9 种不同的语言和一些变体:美国英语、英国英语、澳大利亚英语、法语、加拿大法语、美国西班牙语、es 西班牙语、意大利语、巴西葡萄牙语、德语、韩语、印地语、印度口音英语和现代标准阿拉伯语。Amazon transcribe 接受 4 种格式的文件(mp3、mp4、wav 和 flac ),并能够识别音频中的多个扬声器,为每个扬声器返回相应的转录。如果您在 S3 存储桶上有一个音频文件,您可以简单地使用它的 URL 在 AWS 转录控制台上创建一个转录作业。但是当我们用 Python 进行分析时,我们将使用 boto3 调用 AWS API 来调用转录作业。

亚马逊理解

亚马逊理解是在 AWS ML/AI 套件上找到的服务,它为你提供了各种各样的功能,让你从你的文本中获得洞察力,像情感分析、标记化和实体识别以及文档分类。我们将使用这一工具对我们的文稿进行情感分析,试图捕捉在上述每一篇演讲中发现的全球信息。

空间

Spacy 是一个 Python 的 NLP 库,提供了一组已经为 9 种不同语言训练好的模型。它建立在 Cython 的基础上,可以轻松地与其他机器和深度学习库集成,如 TensorFlow,PyTorch,scikit-learn 和 Gensim,所以它真的很高效,很容易使用。Spacy 被不同的公司和项目广泛使用,并在全球拥有越来越多的用户。

4.执行分析

从 Youtube 下载视频

我们分析的第一步是从 Youtube 下载引言中提到的五个演讲的音频文件。为了组织我们的分析并使其可重复,我们将创建一个 Pandas 数据框架来存储分析过程中生成的数据。

首先,我们创建了一个字典,将每个发言者的名字作为关键字,将各自的 Youtube URLs video 作为值 (1) 。接下来,我们遍历这些值并执行 youtube-dl 命令,使用 os.system 将每个文件下载到我们的本地文件夹 (2) 。在步骤 (3) 中,我们从字典中创建 Dataframe,并用每个下载文件的名称创建一个新列 (4)

亚马逊转录音频转录

现在我们已经有了用于分析的音频文件,我们只需要把它上传到一个 S3 桶中,然后转录成文本。在步骤 (5) 中,我们使用 boto3 创建了一个新的 S3 桶,并将音频文件上传到其中 (6) 。为了启动自动语音识别,我们需要位于新 S3 存储桶上的每个文件的路径。因此,通过使用 S3 路径约定,我们为每个文件定义了路径,并将其保存到我们的数据帧 (7) 。在步骤 (8) 中,我们创建了一个名为 start_transcription 的函数来使用 boto3 调用 AWS API,并为每个语音迭代调用它 (9) 。我们还在函数 start_transcription 上定义了将结果作为 JSON 文件输出到我们的 S3 桶上。

使用 spaCy 将音频转录与原文进行比较

当亚马逊转录工作完成后,你可以通过读取保存在 S3 桶 (10) 上的 JSON 文件来访问结果。为了评估 Amazon Transcribe 生成的转录的质量,我们将使用存储在 JSON 文件 (11) 中的原始文本。最初的文字记录是从男子气概的艺术文章上提供的链接复制的,新的行字符被删除。原始文本的一些部分被删除,以与音频内容完全匹配,因为一些部分不是完整的语音。在进行任何文本比较之前,我们将删除停用词、标点符号、代词,并对标记进行词条化 (12) 。为了建立文本之间的相似性,我们将使用空间方法进行语义相似性 (13) 。这不是文本的字面比较,因为它是基于 Word2vec 的,这意味着我们在比较每个单词在整个句子/文本中的百分比。

单词向量相似性的结果绘制在图 7 中。我们可以看到,根据这一指标,我们可以说亚马逊转录在将音频转录为文本方面做得很好,因为所有转录与原始转录的相似度超过 99%。

Figure 7. Word Vectors similarity for the speeches.

由于词向量的相似性是基于文本上每个词的表示,所以它会给我们一种两个文本相似的错觉。为了更好地衡量文本差异,我们将使用单词移动距离来比较原始转录和使用 Amazon Transcribe 生成的转录。为了估计这个距离,我们需要库 wmd ,它可以与空间 (14) 集成。有关评估文本相似性的更多信息,请看看阿德里安·锡格河的伟大的文章

Figure 8. Word Movers Distance for each analyzed speech.

正如我们在图 8 中看到的,有一些转录显示原始和音频转录之间的距离更大,丘吉尔和麦克阿瑟的演讲是最明显的。

为了将原始抄本的结构与 Amazon Transcribe 生成的结构进行比较,我们将使用名为 displacy (15) 的 spaCy 可视化工具进行实体识别。

Displacy 提供了单词及其各自类别的可视化标识,使得比较文本的结构更加容易(图 9)。

Figure 9. SpaCy entity recognition visualizer. On the left Kennedy’s original transcription, and on the right the one generated using Amazon Transcribe.

通过查看 displacy 创建的可视化效果,我们发现了一些不一致之处,尤其是在丘吉尔和麦克阿瑟演讲的音频转录上。似乎音频的质量和演讲者的措辞对转录的质量有影响。当我们听里根和肯尼迪的演讲时,我们可以注意到音频的质量更高,文字更清晰,因此原始和自动转录之间的 WMD 更小,这意味着亚马逊转录模型可以显示更好的性能。

使用亚马逊理解进行情感分析

在我们分析的最后一部分,我们将使用 Amazon understand 对演讲进行情感分析。如前所述,AWS 提供了一个预先训练的模型,您可以使用它来返回 4 种不同情绪的百分比:积极、消极、混合或中性。为了执行情感分析,我们只需要提供字符串形式的文本和语言。Amazon understand 强加的一个限制是可以分析到 5000 字节的文本大小(翻译成包含 5000 个字符的字符串)。由于我们要处理大于这个限制的文本副本,我们创建了 start _ intensive _ job 函数,该函数将输入文本分割成更小的块,并使用 boto3 为每个独立的部分调用情感分析。然后将结果汇总并作为字典返回 (16) 。因此,我们在每个扬声器的音频转录上使用了这个功能,并保存在我们的数据帧上以供进一步分析 (17)。

Figure 10. Barplot for Sentiment Analysis for each historical speech.

Figure 11. Radarplot for Sentiment Analysis for each historical speech.

图 10(柱状图)和 11(雷达图)显示了对每个所选语音的情感分析结果。似乎中性句子在所有演讲中是最普遍的,其次是肯定、混合和否定。丘吉尔的演讲似乎是负面百分比最高的一个,而肯尼迪的演讲是最正面的。

5.结论

AWS 提供了一组 ML/AI 工具,使用 boto3 进行 API 调用可以轻松访问和集成这些工具。

当音频质量良好时,亚马逊转录似乎是一致的,如里根和肯尼迪的演讲,但当音频不清晰时,表现往往不好,如丘吉尔的演讲。

Amazon understand 提供了一种从文本中提取情感的简单方法,如果能看到它与其他 NLP 工具和其他模型相比的结果,那就太好了。

非常感谢你阅读我的文章!

  • 你可以在我的个人资料页面 找到我的其他文章🔬
  • 如果你喜欢并且想成为中级会员,你可以使用我的 推荐链接 来支持我👍

更多资源

**** [## 自然语言处理的简史

在这篇文章中,我们将了解一个非常有趣的研究领域,叫做自然语言处理…

medium.com](https://medium.com/datadriveninvestor/the-brief-history-of-nlp-c90f331b6ad7) [## 历史上最伟大的 35 次演讲|男子气概的艺术

这些著名的演讲在黑暗时期振奋人心,在绝望中给人希望,精炼人的性格,激励勇敢的人…

www.artofmanliness.com](https://www.artofmanliness.com/articles/the-35-greatest-speeches-in-history/) [## Python、Boto3 和 AWS S3:揭秘——真正的 Python

亚马逊网络服务(AWS)已经成为云计算的领导者。其核心组件之一是 S3,即对象存储…

realpython.com](https://realpython.com/python-boto3-aws-s3/) [## Python 中的自然语言处理简介

自然语言处理(NLP)是数据科学最有趣的子领域之一,数据科学家是…

towardsdatascience.com](/a-short-introduction-to-nlp-in-python-with-spacy-d0aa819af3ad) [## 单词嵌入之间的单词距离

单词移动距离(WMD)被提出用于测量两个文档(或句子)之间的距离。它利用了 Word…

towardsdatascience.com](/word-distance-between-word-embeddings-cc3e9cf1d632) [## 文本相似度:估计两个文本之间的相似程度

读者注意:Python 代码在最后是共享的

medium.com](https://medium.com/@adriensieg/text-similarities-da019229c894)****

分析贾斯廷·特鲁多的演讲

原文:https://towardsdatascience.com/analyzing-justin-trudeaus-speeches-3ba2690ad57a?source=collection_archive---------22-----------------------

Photo by sebastiaan stam on Unsplash

基本原理

加拿大正在进入 2019 年选举季,有迹象表明这将是一个有争议的事件。

一方面,总理特鲁多的自由派在过去 4 年里推动了几项改革,从大麻合法化到买断管道。另一方面,在过去的一年中,反对派驱逐自由党的能量显著增加。保守派和 NDP 选择了新的领导人,绿党的支持率也在上升。

然而,当加拿大人反复思考选举谁担任国家最高职位时,只有几种方法可以分析候选人是否适合担任总理:

  • 社交媒体:候选人的账户有多活跃?它们诱人吗?
  • 辩论:候选人与其他政党平台的互动如何?他们对手的政治策略有哪些重大漏洞?
  • 第三方分析:候选人提出的哪些政策客观上是最好的?

这些分析候选人的方法对于维护加拿大的民主至关重要;他们为个人选择符合他们理想的最佳候选人提供了一种方法。

在很大程度上,这些分析渠道运行良好,并且非常容易使用。不幸的是,政客们的一个方面,尤其是在职者,往往被这些更受欢迎的分析平台所忽略。

演讲。首相的官方讲话是了解政府政策和首相总体情绪的绝佳窗口。这些演讲可以用来全面理解首相的动机和首相自上次选举以来提出的政策。

作为一个刚刚年满 18 岁的人,我终于有幸在联邦选举中投票。由于没有主要的工具来分析贾斯廷·特鲁多总理的演讲,我被激励去创建自己的工具。

方法

网页抓取

总理办公室发布了总理在 https://pm.gc.ca/en/news/speeches演讲的所有文字记录。我必须克服的第一个挑战是将所有的演讲下载成一种格式,以便用于进一步的分析。

输入网页抓取。Web 抓取脚本以编程方式解析来自特定网站的文本,并将其呈现为可通过附加代码进一步操作的格式。对我来说,这是收集特鲁多总理所有演讲的最佳方式。

最初,我决定使用 Selenium,它允许用户控制一个可以与 Javascript 交互的浏览器驱动程序。在下面的代码示例中,我指示 Chrome 驱动程序遍历列表中的所有文章,并通过 CSS 选择器和 XPATHS 的组合来提取日期、标题和语音副本。

**for** article **in** article_list:
   article.click()

   time.sleep(3)

   # Getting title
   title = article.find_element_by_xpath("//h1[@class = 'field-content']")
   print(title.text)  

   # Getting date
   date = article.find_element_by_class_name("date-display-single")
   print(date.text)

   # Getting place
   place = article.find_element_by_xpath("//div[@class = 'inline-date']")
   print(place.text)

   # Getting speech
   speech_div = browser.find_elements_by_xpath("//span[@lang = 'EN-CA']")

   **for** p **in** speech_div:
      print(p.text)

不幸的是,我遇到了硒的问题。在演讲网站上,每份文稿都隐藏在一个可扩展的 HTML div中。上面的 Selenium 脚本无法处理这个问题。

相反,我决定采用 AJAX 抓取方法。首先,我注意到每个演讲都是使用 AJAX 下载的,并带有唯一的 ID。其次,我发现这个 ID 可以在可扩展的 div 上的 teaser 中找到。使用来自 teaser 的 ID,我使用 requests 库以编程方式下载了所有演讲,使用 BeautifulSoup 解析了文本中的重要信息,并将所有信息保存在 MongoDB 数据库中。以下是 AJAX 抓取脚本的一部分,它使用 AJAX 请求来下载演讲:

**def fetch_speech_details**(speech_id: str) -> str:

    # AJAX requests link. Replaced ID with speech_id collected from teaser
    url = 'https://pm.gc.ca/eng/views/ajax?view_name=news_article&view_display_id=block&view_args={id}'
    url = url.format(id = speech_id)

    # Get the speech
    res = requests.get(url, headers=headers)
    res.raise_for_status()

    # Convert to proper form using BeautifulSoup
    data = res.json()
    html = data[1]['data']
    soup = BeautifulSoup(html, 'html.parser')

    # Select the speech content
    body = soup.select_one('.views-field-body')
    speech_text = body.get_text()

    **return** str(speech_text)

清洁

我采取了几个步骤来清理这些支离破碎的演讲稿:

  • 记号化:记号化是指将文本分成称为记号的片段的实践。在这个特别的项目中,我将演讲标记成单个的单词,但是我也可以将演讲标记成句子。此外,我将每个标记转换成小写以确保一致性。这是使用 spacy 库完成的。

An example of tokenization

  • ngram:ngram 是指文本样本中的一系列 n 项。在这个项目中,我尝试将上述标记转换为单字(一个单词)、双字(两个单词)和三字(三个单词)。ngram 函数在 NLTK 库下可用。
  • 词汇化:这个过程移除单词的屈折词尾,以到达词根或词汇。比如‘学习过’和‘正在学习’都有‘学习’的引理。通过单词的词条化,我们能够到达基础并减少句子之间的差异。同样重要的是要注意,词汇化并没有粗暴地砍掉动词的词尾(也称为词干);相反,它使用语法规则来获得基本单词。这个步骤使用了 NLTK 库中的 WordNet lemmatizer 函数。

Examples of lemmatization. Note how grammar rules are used to arrive at the stem of the word rather than simply cutting off the end of the word (‘ed’, ‘es’, ‘ing’).

  • 停用词移除:在任何语言中,都有一些极其常见的词,它们不会给句子带来任何额外的意义。例如,句子“Billy 在上学前吃煎饼”可以转换为非停用词句子“Billy 在上学前吃煎饼”。删除停用词有助于简化后面模型的计算,如词袋,同时仍保留句子的含义。停用字词的移除是使用 NLTK 库执行的。

情绪分析

情感分析是指破译一个给定句子是肯定的、否定的还是中性的过程。如果有足够的标签数据可用,朴素贝叶斯模型可以用来预测一个句子是否有总体积极或消极的情绪;然而,缺乏情感的标记语音语料库阻止了这种方法。

相反,我使用了 Vader perspection 库,它优雅地提供了一个用于自动情感分析评分的 API。复合分数与积极、中性和消极分数一起提供;复合分数有助于确定文章的整体情绪。

以下是用于分析演讲中情绪的代码示例:

# Getting sentiment score of each speech
**def sentiment_score**(speech):
    # Initializing analyzer object
    analyzer = SentimentIntensityAnalyzer()

    # Outputting and returning speech sentiment score
    score = analyzer.polarity_scores(speech)
    print("Speech: ", speech)
    print("Score: ", score)

    **return** score

话题分析

主题分析采取了几个步骤,因为我必须训练自己的模型,而不是利用 API:

  • 创建单词袋模型:机器学习算法有一个共同的缺点——模型只能对向量或数列起作用。当然,这不是文本的自然表示,因此将文本转换为特征向量是自然语言处理中不可或缺的任务。将文本转换为特征向量的一种方式是通过单词袋模型。这个机制需要几个步骤。首先,必须创建一个语料库或词典;在我的项目中,我使用了特鲁多总理的演讲令牌的全部集合作为字典。第二,模型必须记录字典中所有不同类型的词汇,并给每个单词一个特定的 ID。最后,每篇演讲都要根据词汇表进行评分。为这个项目的每个演讲打分是一个相对简单的任务:我只是简单地计算每个单词-ID 组合出现的次数。这里有一个简单的图表来解释单词袋模型的创建。

An example of a bag-of-words representation

  • 潜在狄利克雷分配(LDA)模型的创建:LDA 模型是目前存在的最有用的主题模型之一。本质上,LDA 基于文本序列在每个主题中的特定出现的概率来确定文档属于特定主题的概率。例如,如果单词“环保主义”和“管道”在主题 1 中出现的概率很高,并且如果文档包含“环保主义”和“管道”的多次出现,则该文档成为主题 1 文档的概率很高。关于 LDA 模型工作原理的更漂亮、更深入的解释,请访问这篇文章。在我的项目中,这个模型是基于所有演讲的单词袋模型建立的。

Each topic has a few words that contribute to a high probability of having that topic. Finding those words in a document increases the probability of the document having that topic (source)

  • 预测:有了最终构建的模型,我们可以通过单词袋模型将每个语音转换为特征向量,并使用 LDA 预测主题。与 k-means 不同,LDA 给出的是文档属于某个主题的概率,所以肯定比 k-means 更模糊。这意味着预测输出是主题及其各自概率的列表。

最后,所有的观点和话题都存储在 MongoDB 数据库中。

结果和分析

由于这个项目是我的第一个 NLP 项目,我尝试了许多分析技术。其中一个是单词云:它代表了在演讲中发现的所有单词,每个单词的大小与其频率相对应。这里有几个单词云的例子:

Wordcloud for speech on National Inquiry into Missing and Murdered Indigenous Women and Girls

Wordcloud for remarks on New Zealand mosque shooting

Wordcloud for all speeches

虽然它们看起来很吸引人,但是这些文字云是一个很好的分析来源。例如,最终的 wordcloud 给了我们一些启示:

  • 强调自己是加拿大人:当然,作为加拿大总理,提到“加拿大”或“加拿大人”的次数并不奇怪。
  • 土著人:鉴于加拿大与土著人交往的历史充满了悲剧和特鲁多总理的和解政策,与土著人有关的词语的出现频率表明,特鲁多一直在集中努力试图纠正过去的错误。
  • 《时代》杂志:有趣的是,特鲁多的讲话表明,他的政策更关注“今天”和过去(“几年前”),而不是未来,特别是考虑到特鲁多竞选时对未来持乐观态度。他的官方演讲和竞选承诺可能不会像预期的那样一致!

我还研究了平均每场演讲的代币数量。这是所有演讲的标记数量的直方图(x 轴是标记数量,y 轴是演讲数量)

这种分布大致正常,平均约为 1750 个单词。平均语速为 150 字/分钟,也就是说平均发言时间大约为 12 分钟。对于大多数官方演讲来说,这个长度是合理的,但竞选演讲肯定会更短,大约 5-7 分钟。

我还想检查各种情感分数的分布。以下是我使用情感分析脚本编译的直方图集合:

在很大程度上,这些演讲似乎有一种中立评分的趋势。然而,正如在复合分数分布中所看到的那样,还有几个正分数超过负分数的例子。此外,似乎有更多的积极意义大于消极意义的演讲。

总的来说,特鲁多的演讲风格反映了他在政府中乐观的竞选承诺。

我想分析的情绪的另一个方面是情绪随着时间的变化。我创建了一个小线图来研究任何趋势:

这里有几点需要注意:

  • 在很大程度上,特鲁多总理的讲话是积极的,这可以从绿色积极情绪线相对于红色消极情绪线的优势看出。
  • 从 3 月到 4 月,特鲁多演讲中的负面性明显增加。此时总理办公室卷入SNC-拉瓦林事件,可能间接影响了特鲁多的讲话风格
  • 随着选举的临近,乐观情绪增加了。这可能表明,随着选举的临近,特鲁多正在回归他之前对加拿大积极前景的战略。

最后主要分析特鲁多演讲中的主题。在一个 5 主题的 LDA 结构中,我的脚本输出了以下主题:

主题 0-2 似乎更倾向于一个土著主题,主题 3 与加拿大身份更相关,主题 4 与环境保护主义相关。

然后,脚本系统地检查每篇演讲,并记下每篇演讲出现这些话题的概率。例如,关于失踪和被谋杀的土著妇女和女孩的全国调查的演讲有 0.997 的概率有主题 0,这从直觉上讲是有道理的。

总的来说,结果非常成功。

结论

这是我参与过的最复杂的项目之一,通过它我学到了很多东西。在这个项目之前,自然语言处理和 LDA 是我一无所知的术语;然而,分析总理的演讲帮助我将我的知识扩展到机器学习的这个领域。

此外,我通过 MongoDB 学习了大量新技术和技能,从 NLTK 这样的包到非关系数据库管理。老实说,如果不是这样一个深入的项目,这些技术我永远也学不会。

正是通过像语音分析这样高度复杂的项目,我受到启发,学习新的技术和技能。此外,这个项目是巩固我已经知道的技能的一个极好的方式。在探索新技能时,我强烈推荐基于项目的学习。

只有一个月的时间来完成这个项目,优先顺序迫使我放弃了以下组件,这些组件可以将这个项目向前推进一步:

  • 创建一个脚本,用一个命令运行所有功能
  • 收集更多的演讲:出于某种原因,我的脚本很难收集到超过 10 个演讲。这可能是因为“显示更多”按钮会拉更多的发言。
  • 用二元模型和三元模型做更多的实验:我真的对二元模型和三元模型如何影响我的 LDA 模型的准确性很感兴趣,所以我会继续用它做实验。

总的来说,这是一个非常有趣和具有挑战性的项目,我将继续尝试。该项目的源代码可以在这里找到如果你想试验我的分析。加拿大的任何人,请在十月投票!

伦敦犯罪数据分析

原文:https://towardsdatascience.com/analyzing-london-crimes-data-in-r-aee4658f79fe?source=collection_archive---------12-----------------------

我在研究伦敦的犯罪数据集。分析和可视化比我预期的要好得多,所以我想我还不如写一篇关于它的文章。我在试验 bigquery 时获得了这些数据,但是你也可以从 Kaggle 上的这里下载。让我们从加载库和数据开始。

library(tidyverse) ## For data wrangling and visualization 
library(lubridate) ## To work with dates
library(ggpubr)    ## Extra visualizations and themes
library(patchwork) ## Patch visualizations together
library(hrbrthemes)## extra themes and formatting
library(scales)    ## For formatting numeric variables
library(tidytext)  ## Reordering within facets in ggplot2
library(pier)      ## Make interactive piecharts in R
library(ggalt)     ## Extra visualizationslondon_crimes <- read_csv("C:\\Users\\ACER\\Downloads\\bq-results-20190830-212006-dh1ldd1zjzfc.csv",trim_ws = TRUE) %>% 
  mutate(Date_Column = dmy(Date_Column))

加载完库之后,我使用了 read_csv 函数,并给了它一个文件在我电脑上的路径,设置 trim_ws 为 TRUE 以防有任何空白并删除它,然后使用 mutate 函数将 Date_Column 更改为 Date 类型,使用的是Lubridate包中的 dmy 函数。

为了得到一个概览,我将想象一下这些年来整体犯罪事件是如何变化的。让我们浏览一下代码:

london_crimes %>% 
  group_by(Year = floor_date(Date_Column,unit = "year")) %>%   
  summarise(Incidents=sum(total_incidents,na.rm = TRUE)) %>%   
  ungroup() %>%                                                 mutate(pct_change= (Incidents-lag(Incidents))/lag(Incidents),
         pct_change=replace_na(pct_change,0)) %>%   
  ggplot(aes(Year,Incidents))+               
  geom_bar(stat="identity",fill="firebrick",color="black")+        
  geom_line(color="steelblue",size=1.5,linetype="dashed")+     
  geom_text(aes(label=percent(pct_change)),vjust=-1,color="black",face="bold")+  geom_text(aes(label=comma(Incidents)),vjust=1,fontface="bold",color="white")+ 
  scale_y_comma(expand = c(0,0),limits = c(0,800000))+         
  scale_x_date(breaks = "year",date_labels ="%Y")+             
  theme_classic()+                                             
  labs(title = "Total Incidents over the years")
  • 为了获得年度分析,我们按日期列分组,并使用 floor_date 函数将其四舍五入,然后使用summary函数获得每年的事件总数
  • 每次 group_by 操作后,取消分组总是一个好的做法,以删除分组上下文
  • 然后,我们使用 mutate 函数创建一个新列— pct_change ,它基本上是使用 lag 函数计算每年之间的百分比变化
  • 整理好数据后,我们使用 ggplot2 制作一个标准的条形图。由于 ggplot2 不允许组合图表显示百分比增长线图,我只是使用了 geom_line 函数来绘制趋势线,并用百分比变化值对其进行注释

如果我们只是比较 2008 年和 2016 年,你会认为犯罪事件几乎没有变化,但实际上这是 2014 年的最低水平,此后一直在增长。现在让我们在区一级分析我们的数据。

让我们来看一个简单的柱状图,看看区一级的事故总数。如果你熟悉 Tidyverse 元包,那么下面这些应该不难理解。

london_crimes %>%                                     
  group_by(borough) %>% 
  summarise(Incidents=sum(total_incidents)) %>% 
  ungroup() %>% 
  ggplot(aes(reorder(borough,Incidents),Incidents))+
  geom_bar(stat = "identity",aes(fill=borough),color="black")+
  coord_flip()+
  scale_y_comma()+
  geom_text(aes(label=comma(Incidents)),hjust=1)+
  theme_classic()+
  theme(legend.position = "none")+
  labs(x=" ",y=" ",title = "Total Incidents for boroughs from 2008-2016 ")

我不熟悉伦敦的地理,但 Westminister 遥遥领先。我谷歌了一下,发现 Westminister 是伦敦人口最密集的地区之一。

这些年来这些区的犯罪率有什么变化?

为此,我将 2016 年的数据与 2014 年的数据进行比较,而不是与 2008 年进行比较,因为 2014 年的犯罪事件最低,与 2016 年进行比较可能会显示一些有趣的变化。

london_crimes %>% 
  group_by(borough) %>%  summarise(Incidents_2014=sum(total_incidents[year(Date_Column)==2014]),         Incidents_2016=sum(total_incidents[year(Date_Column)==2016])) %>% 
  ungroup() %>% 
  mutate(Pct_Change=(Incidents_2016-Incidents_2014)/Incidents_2016)    %>%      
  ggplot(aes(reorder(borough,Pct_Change),Pct_Change))+                       
  geom_bar(stat = "identity",aes(fill=borough),color="black")+               
  coord_flip()+
  scale_y_continuous(labels = percent_format())+                             
  geom_text(aes(label=percent(Pct_Change)),hjust=1)+
  theme_classic()+
  theme(legend.position = "none")+                                           
  labs(x=" ",y="Percentage Change ",title = "Percentage Change in Incidents from 2014-2016")
  • 我们再次按区对数据进行分组,并计算两个条件和——Incidents _ 2004 和 Incidents_2016,并计算两者之间的百分比差异,以查看每个区的变化
  • 然后,像以前一样,按照标准程序绘制柱状图,根据从最高到最低的百分比变化重新排序

  • 伦敦金融城的最高比例有点失真,因为它的犯罪事件数量很少
  • 令人惊讶的是,Westminister 是倒数第二名,尽管它在所有事故中排名第一。至少,它没有经历相当大的增长。

我想知道每一个行政区在哪一年经历了有史以来最高的犯罪事件数量,以及哪一年有最多的行政区经历了最高的犯罪事件数量。

london_crimes %>% 
  group_by(borough,Yearly=floor_date(Date_Column,unit = "year")) %>% 
  summarise(Incidents=sum(total_incidents)) %>%
  ungroup() %>% 
  group_by(borough) %>%
  filter(Incidents==max(Incidents)) %>%  
  ungroup() %>% 
  mutate(borough_max_year = paste0(borough,"-","(",year(Yearly),")")) %>%                                                                    
  ggplot(aes(reorder(borough_max_year,Incidents),Incidents))+
  geom_col(aes(fill=borough_max_year),color="black")+
  scale_y_comma()+
  coord_flip()+
  geom_text(aes(label=comma(Incidents)),hjust=1)+
  theme_classic()+
  theme(legend.position = "none")+
  labs(title = "Max Incidents for each Borough",x="Borough and year of max Incidents ",y="Incidents")
  • 我们首先按照年份和行政区进行分组,然后根据行政区和相应年份的每个组合获得事故总数
  • 因为我想根据事件筛选每个区的最大年份,所以我按区对数据进行分组,然后筛选每个区的事件值等于其最大值的地方。这也将显示该值的年份
  • 为了直观起见,我创建了一个新列— borough_max_year ,它基本上是使用 paste0 函数将yearIncidents 列串联起来的版本。剩下的是我用来可视化柱状图的相同代码。

现在,我们可以看到每一个区在哪一年经历了最高数量的犯罪事件,但我现在将制作另一个可视化效果,以查看哪一年最多的区经历了最高数量的犯罪事件。

london_crimes %>% 
  group_by(borough,Yearly=year(floor_date(Date_Column,unit = "year"))) %>% 
  summarise(Incidents=sum(total_incidents)) %>%
  ungroup() %>% 
  group_by(borough) %>%    
  filter(Incidents==max(Incidents)) %>%  
  ungroup() %>% 
  count(Yearly,sort = TRUE,name = "Boroughs_with_max_incidents") %>%  ggplot(aes(reorder(Yearly,Boroughs_with_max_incidents),Boroughs_with_max_incidents))+
  ggalt::geom_lollipop(aes(color=factor(Yearly)),point.size = 10)+
  scale_y_comma()+
  coord_flip()+
  geom_text(aes(label=Boroughs_with_max_incidents),hjust=0.5,color="white",fontface="bold")+
  theme_classic()+
  theme(legend.position = "none")+
  labs(title = "Number of boroughs that experienced their highest ever incidents",x="Year",y=" ")
  • 使用和以前一样的代码,我增加了一个额外的步骤,计算每年的行政区数量
  • 厌倦了条形图,我使用了 ggalt 包中的 geom_lollipop 函数来绘制棒棒糖图

  • 因此,2016 年拥有最多的行政区,尽管 2016 年在 2008 年和 2012 年之前的犯罪事件总数方面排名第三

我现在要检查每个区的犯罪事件的总体趋势。

london_crimes %>% 
  group_by(Year=floor_date(Date_Column,unit = "year"),borough) %>% 
  summarise(Incidents=sum(total_incidents,na.rm = TRUE)) %>% 
  ggplot(aes(Year,Incidents))+
  geom_line(aes(color=borough),size=0.75,style="--")+
  theme_pubclean()+
  scale_y_comma()+
  expand_limits(y=0)+
  facet_wrap(~borough,scales = "free")+
  labs(y="Total Incidents",x=" ")+
  theme(legend.position = "none",strip.background = element_rect(fill="firebrick"),strip.text=element_text(color = "white",face="bold"))

我原以为这将是一个非常混乱的图表,但结果比我预期的要好很多。从 2014 年到 2016 年,我们可以大致看到大多数行政区的总体增长趋势。

让我们来看看每个主要类别在犯罪事件总数中所占的比例,以及它们的长期趋势。

**# Piechart**london_crimes %>% 
  group_by(major_category) %>% 
  summarise(Incidents=sum(total_incidents,na.rm = TRUE)) %>% 
  ungroup() %>% 
  mutate(color=RColorBrewer::brewer.pal(9, 'Spectral')) %>%
  select(label=major_category,value=Incidents,color) %>%
  pier() %>% 
  pie.size(inner=70, outer=100, width = 600, height = 450) %>%
    pie.header(text='Crimes', font='Impact', location='pie-center') %>%
    pie.subtitle(text='by major category')%>%
    pie.tooltips()**# Trend over time**london_crimes %>% 
  group_by(Yearly=floor_date(Date_Column,unit = "year"),major_category) %>% 
  summarise(Incidents=sum(total_incidents,na.rm = TRUE)) %>% 
  ggplot(aes(Yearly,Incidents))+
  geom_line(aes(color=major_category),size=0.75)+
  theme_pubclean()+
  scale_y_comma()+
  expand_limits(y=0)+ # making sure that the yaxis for every facet starts at 0 otherwise the trend may look misrepresentitive
  facet_wrap(~major_category,scales = "free")+
  labs(y="Total Incidents",x=" ")+
  theme(legend.position = "none",strip.background = element_rect(fill="firebrick"),strip.text=element_text(color = "white",face="bold"))
  • 我在这里使用了 pier 包来绘制一个交互式饼图,因为我总是发现在 ggplot2 中绘制像样的饼图比实际需要的要复杂一些
  • pier 要求栏目只需标注“标签”、“数值”和“颜色”
  • 趋势图的代码与行政区的代码相同。唯一的区别是我用 major_category 变量替换了 borough 变量
  • 请注意,我使用了 expand_limits(y=0) 参数来确保每个线图中的 y 轴都从 0 开始,否则,它们看起来会有点失真

  • 从 2014 年到 2016 年,盗窃和处理以及针对人身的暴力等主要贡献者出现了显著增长
  • 似乎奇怪的是,2008 年后就没有发生过性犯罪欺诈或伪造。可能是因为这些罪行后来被记录在不同的类别下

现在我想看看不同的行政区在每个主要类别中的排名。我将只关注前 40%的地区,因为在一个多面图中可视化所有的行政区看起来非常混乱。

london_crimes %>% 
  group_by(major_category,borough) %>% 
  summarise(Incidents=sum(total_incidents)) %>% 
  filter(Incidents>quantile(Incidents,0.6)) %>% #filtering for only the top 40% to make the plot more readable
  ungroup() %>% 
  mutate(borough=reorder_within(borough,Incidents,major_category)) %>%                                                            ggplot(aes(borough,Incidents))+
  geom_bar(aes(fill=borough),stat = "identity",color="black")+
  coord_flip()+
  scale_x_reordered()+       
  scale_y_comma()+
  geom_text(aes(label=comma(Incidents)),hjust=1)+
  theme_classic()+
  theme(legend.position = "none")+
  facet_wrap(~major_category,scales ="free")+
  labs(x=" ",y=" ",title = "Top 40% Boroughs by Incidence",subtitle = "Segmented by Major Category")+
  theme(legend.position = "none",strip.background = element_rect(fill="firebrick"),strip.text=element_text(color = "white",face="bold"))
  • 在分组和总结之后,我保留分组上下文,使用分位数函数过滤每个主要类别下前 40%的行政区
  • 然后,我使用 tidytext 包中的 reorder_within 函数,根据犯罪事件对每个主要类别下的行政区进行重新排序。这样做的原因是为了在每个主要类别方面内对条形图进行排序

另外,我想看看每个大类中哪些是主要的小类。

london_crimes %>% 
  group_by(major_category,minor_category) %>% 
  summarise(Incidents=sum(total_incidents)) %>%
  ungroup() %>% 
  mutate(minor_category=reorder_within(minor_category,Incidents,major_category)) %>%
  ggplot(aes(minor_category,Incidents))+
  geom_bar(aes(fill=minor_category),stat = "identity",color="black")+
  coord_flip()+
  scale_x_reordered()+
  scale_y_comma()+
  geom_text(aes(label=comma(Incidents)),hjust=1)+
  theme_classic()+
  theme(legend.position = "none")+
  facet_wrap(~major_category,scales ="free")+
  labs(x=" ",y=" ",title = "Incidents by Minor Category",subtitle = "Segmented by Major Category")+
  theme(legend.position = "none",strip.background = element_rect(fill="firebrick"),strip.text=element_text(color = "white",face="bold"))

  • 所以大部分都是骚扰、袭击和盗窃案件。我猜在 2008 年后,性犯罪被归入对人身的暴力。
  • 看起来商业和个人财产相对来说被抢劫了很多。虽然盗窃和处理有很多潜在的重叠,但是抢劫入室盗窃

结论

尽管数据集性质严峻,但我在探索它的过程中获得了很多乐趣。也有可能进行更多的探索性分析。你可以对伦敦最安全的行政区进行分析,或者深入挖掘小类事故。

分析纽约市的交通方式

原文:https://towardsdatascience.com/analyzing-modes-of-transportation-in-new-york-city-dfb4a1726ac4?source=collection_archive---------12-----------------------

这项工作由坎贝尔·韦弗、吴宇舟和雷汉·拉苏尔完成,是康奈尔理工大学数据科学课程的一部分。****

简介

对大都会运输管理局(MTA)来说,预测给定纽约市地铁站的乘客数量是一个关键挑战。
因此,我们旨在解决以下挑战:给定一周中的某一天、一个站点位置和附加数据(例如天气、特殊事件),他们预计会有多少人?

这种分析和预测的目的是让 MTA 为不可预见的情况做好准备。例如,在罗斯福岛最近举行的樱花节期间,地铁站出现了大拥堵,这使许多人面临窒息或踩踏的危险。

使用我们的机器学习模型,MTA 将能够预测不同天气条件下每个地铁站的预期人数,并考虑到特殊事件。这将允许他们先发制人的安排,以避免任何危险的情况。

这项工作侧重于 2018 年的数据。

分析

数据选择

****地铁数据来自 MTA 十字转门数据。尽管这些数据比我们需要的更复杂,但是我们能够执行彻底的数据清理,使其对我们的分析有用。

该数据由所有纽约地铁站十字转门的入口和出口计数器组成,每 4 小时采集一次。

我们使用这个数据集来分析天气和特殊事件对地铁使用的影响。

数据集大小:1000 万行,11 列

****从谷歌地图 API 获得的位置数据。这被用来提取从 MTA 数据获得的台站的纬度和经度,因为这些数据只包含台站名称,而不包含它们相应的位置坐标。

****从城市自行车出行历史中获得的城市自行车数据。数据集由 2018 年期间每次骑自行车的信息组成,包括行程持续时间、开始&结束时间、日期和车站、车站位置(纬度/经度)和一些用户信息。

我们使用这个数据集来分析天气和特殊事件对自行车骑行的影响。

数据集大小:1100 万行,7 列

****从国家环境信息中心获得的天气数据。数据集由 2018 年纽约市不同站点的气候数据组成,包括站点位置(纬度/经度)和各种气候参数,例如,温度、降水量和降雪量。

数据集大小:28000 行,33 列

活动数据:吸引大量人群(从而导致地铁乘客高峰)的特殊活动有许多不同的形式。因此,很难找到包含所有这些事件的历史信息的现有数据集。在我们分析事件对交通数据的影响时,我们集中在 161st St. Yankee Stadium 站的乘客量和 Yankee 主场时间表之间的关系。为了获得扬基队的赛程信息,我们使用开源 python 包装器来访问 MLB 的 API。

数据清理

****地铁数据使用以下步骤进行清理:

  • 每天每个十字转门的总进出数据
  • 每天每个站点的总进出数据
  • 使用 z 得分> 3 移除异常值

这产生了一个干净的数据集,包含 136000 行,比我们开始时的 1000 万行减少了很多。

****位置数据用于使用站名填写每个站的位置坐标(纬度/经度)。

****CitiBike 数据非常大,因为每行仅代表一次骑行记录。为了节省时间和空间,我们把数据过一遍,收集每个站的数据。我们将站名、id 和位置存储到字典中以备后用。此后,我们通过计算每日乘车人数和平均乘车时长来压缩数据。因此,我们获得了每天每个站点的自行车使用数据。

****天气数据使用以下步骤进行清理:

  • 仅提取纽约市数据
  • 填写 TAVG
  • 将缺失值填写为 0
  • 小写列保持一致

这产生了一个干净的数据集,从 28000 行减少到 365 行,一年中每天一行。

数据分析

下雨会影响地铁的使用吗?

distribution of subway usage for rainy vs non-rainy days

零假设(H0):
雨天和非雨天的地铁使用量没有区别

交替假设(HA):
雨天和非雨天的地铁使用量是有区别的

每个类别有两个分布,我们猜测这与周末和工作日有关。我们用下面的图来证实。

看起来有两种不同的多雨和不多雨的分布,但是我们不能确定这种差异是偶然的还是有统计学意义的。因此,我们对该数据执行非参数 Mann Whitney U-test ,因为样本是独立且非正态分布的。

p 值出来是 0.0218,小于我们 p 临界值的 0.05。因此,我们可以拒绝零假设,并得出结论雨天和非雨天的地铁使用存在差异。****

我们通过绘制雨天和非雨天的地铁使用热图来证实这种差异。

下雨会影响 CitiBike 的使用吗?这是一个更简单的问题,因为人们本能地不太可能在雨天骑自行车。我们通过绘制雨天和非雨天的 CitiBike 使用热图证实了这一点。

地铁和城市自行车的乘客量每月都有变化吗?为了回答这个问题,我们绘制了 subway 和 CitiBike 每月的使用情况。

看起来在炎热的月份,地铁乘客量是最低的,因为人们在那些日子里避免乘坐地铁,而更喜欢骑自行车或步行。

特殊事件对地铁使用有何影响?在体育比赛或音乐会等受欢迎的活动当天,靠近活动场地的地铁站的乘客量会增加,这是很直观的。在许多情况下,这种影响很难量化,因为许多地铁站可以服务于同一个场地,从而将这种影响分散到不同的交通枢纽。此外,许多一次性事件,如音乐会,只产生一天的数据,并且很少重复,留给我们的样本量很小,无法建立我们的直觉。最后,收集纽约市许多不同类型的活动和场所的历史数据是一项艰巨的任务。我们选择通过关注 161 ST . Yankee Stadium(Yankee Stadium 附近唯一方便的地铁站)Yankee 主场比赛对地铁乘客量的影响来分析乘客量和事件之间的关系。

通过绘制该车站一年的乘客数据,一些事情立即变得显而易见。首先,有一个规律周期,即工作日的客流量较高(每天约 10,000 人),周末的客流量较低(约 5,000 人)。突然,大约在 4 月 2 日,在洋基主场揭幕战的当天,每天的乘客量开始变成穿插着超过 15,000 名乘客的常规高峰。这种情况会持续到洋基的球季在 10 月结束,届时上座率会回复到先前的水平。

通过把我们的电视台数据分成有洋基主场比赛的日子和没有主场比赛的日子,我们立刻看到了不同。当有主场比赛时,平均每天的观众人数是 18,000,当没有主场比赛时,观众人数下降到 10,000。通过观察当有洋基主场比赛时和没有比赛时车站乘客的分布,很明显这些来自不同的分布。

同样,我们分析了 2018 年罗斯福岛地铁交通。2018 年 4 月 21 日地铁使用量有一个明显的峰值,对应的是罗斯福岛樱花节。

预测模型

我们使用了两种机器学习模型来根据位置和天气信息预测车站的客流量:

  • 线性回归
  • 随机森林

我们使用以下测量技术来评估性能:

Performance of different models

从表中我们可以看出,与线性回归模型相比,随机森林模型具有更好的性能。由于站点位置对客流量的影响不能用线性表示,因此线性模型很难准确预测。

为了可视化这些预测,我们创建了预测值与实际值的热图。我们可以清楚地看到,随机森林模型优于线性回归模型:

我们还研究了不同特征对乘客量的重要性。

****

经度和纬度对日客流量影响最大。这是有道理的,因为不同的社区有不同的人口,这是公共交通使用的最重要的因素。

平均温度表明了一个普遍的天气状况和一年中的季节。所以也是一个重要的特点。

在工作日和周末,运输使用情况不同,显示为一周中的某一天。

降水也会影响乘客量,但与其他因素相比,它的影响较小。

进一步的改进

可以采取以下步骤来改进这项工作:

  • 使用具有更丰富特征的更高级的机器学习模型,例如,我们可以将事件信息作为特征的一部分,以获得更好的预测结果
  • 包括出租车和优步/Lyft 数据,以分析它们如何受到天气和事件的影响
  • 使用多年的数据捕捉年度趋势

用 Python 分析电影对话速度

原文:https://towardsdatascience.com/analyzing-movie-dialog-speed-with-python-79a8a8a286e8?source=collection_archive---------27-----------------------

当大卫·芬奇在执导《社交网络》时,他带着秒表去了阿伦·索尔金的家,记录了索尔金阅读剧本的时间。然后,他记下了每个场景的时间,并在拍摄这部杰作时严格遵守这些场景时间。听到这个轶事后,我决定自己从分析的角度来看看这部电影的对话。

为了开始我的调查,我首先收集数据。我发现了一个叫做 YIFY 字幕(https://yts-subs.com/)的网站,它提供电影编辑用来给电影添加字幕的文件。这些特定的文件称为 SRT 文件,甚至有自己独特的。srt 扩展。看一些例子。srt 文件,很明显它们遵循一种严格的格式,包含:
1。字幕编号
2。格式为 START_TIME → END_TIME 的场景时间,时间格式为 hh:mm:ss:ffff
3。副标题的文本

我需要删除文本中的一些元素(html 标签、圆括号和方括号中的场景描述符、音乐符号),所以我编写了函数 clean_text 来帮助清理文件。

def clean_text(line):

    clean = line.strip().replace('</i>', '').replace('<i>','').replace('- ', '')
    clean = re.sub('\(.*\)','', clean)
    clean = re.sub('\[.*\]','', clean)
    clean = re.sub('♪', '', clean)

    return clean

通过几个辅助函数,我遍历了文件中的每一行,获得了以秒为单位的累积电影时间和说话的字数。解析每个的最终输出。srt 文件是一个具有两列的数据帧,一列用于累计时间,一列用于累计说出的单词。

为了有一个比较《社交网络》的电影基础,我还收集了一些波士顿同行的数据:
善意狩猎
狂热程度
战士
消失的婴儿
爱国者日
逝者
乡野圣徒
神秘河
小镇

所有的。srt 文件被解析,数据在干净、统一的数据帧中,然后我继续进行可视化。随着时间的推移,绘制每部电影的字数突出了社交网络,因为它具有最多的单词和最陡的斜率(对应于每秒的单词数)。

据传,芬奇花了 99 次拍摄才对《社交网络》的开场感到满意。将窗口缩小到前 600 秒会进一步提高对话速度。

利用每部电影的最终长度和字数,我还计算了每秒的平均字数。

最后,我又添加了 15 部电影来增加样本量,并绘制在下面。即使像《超级坏蛋》和《婚礼傲客》这样有大量对话和快嘴演员的电影,社交网络仍然保持领先。

感谢阅读!对于那些感兴趣的人,我已经把我用来进行这种分析的笔记本和。我的 GitHub 页面上的 srt 文件(https://github.com/eonofrey/movie_word_counts)。谢了。要获得所有媒体文章的完整访问权限,请点击此处

用机器学习分析我的减肥

原文:https://towardsdatascience.com/analyzing-my-weight-loss-journey-with-machine-learning-b74aa2e170f2?source=collection_archive---------8-----------------------

个人健康

我如何用 Python 从头开始构建一个逻辑回归分类器来预测我的体重减轻

要看我为这个项目写的代码,可以看看它的 Github 回购

背景

我在 2018 年初开始了我的减肥之旅,遵循着人们常说的“减肥=饮食+运动”的建议。在饮食方面,我开始跟踪我每天的食物消耗量(使用食物秤并通过 Loseit 应用程序记录卡路里)。在锻炼方面,我开始遵循“沙发到 5 公里”计划,到目前为止已经完成了四个 5 公里,一个 10K,还有几周前的一个半程马拉松。最后,每天早上,我醒来后马上称体重,并在同一个 Loseit 应用程序中记录我的体重。

问题

任何试图减肥的人都不可避免地会遇到减肥平台期,最初快速的减肥开始放缓。就我个人而言,我在五月初的假期后达到了一个主要的平台期。在那之后,我放弃了追踪我的进度,持续了近三个月。只有在我用一个 Amazfit Bip 取代了快要报废的 Pebble 智能手表后,我才重新获得了一些按下恢复按钮的动力,部分原因是我可以用新手表开始记录我的步数。然而,我的体重持续稳定,在经历了两个月令人沮丧的体重波动后(见下面的虚线区域),我完全停止了追踪我的体重和卡路里。那是去年的 11 月。

Left: Progress report of my weight in 2018. Right: time window for my data (when steps were tracked)

现在是 2019 年,随着 Tet(越南新年)最近接近尾声,我决定更仔细地研究在这两个月期间收集的数据,希望发现我的减肥和跟踪的卡路里/步数之间的有趣关系,以便我可以制定比以前更有效的减肥计划。

数据

数据收集

Calories (budget & consumed) and steps for September 6th, 2018

卡路里:从我的 Loseit 账户导出为 CSV 文件。出于某种奇怪的原因,Loseit 只允许一次导出一周的卡路里数据,但是将它们连接在一起是快速 Python 脚本所不能做到的。每个日期都有我当天记录的所有食物的相应卡路里计数,以及应用程序根据我当天的体重和我最初指定的减肥目标(每周减肥 0.75 公斤)为我计算的卡路里“预算”。

步骤:我的 Amazfit Bip 智能手表的 Android 应用程序不允许数据导出,除非有人使用第三方工具使用一些令人毛骨悚然的变通方法。因此,获得我的步骤数据的最快方法是手动滚动手机上的几十个日期(在这两个月内),并将每个日期的步骤输入到一个 CSV 文件中。一点也不优雅,但是,嘿,这很有效!

体重:谢天谢地,Loseit 网站允许我将我所有记录的体重——以及它们的拍摄日期——导出为一个 CSV 文件。

在按日期将这 3 个数据源连接在一起后,我最终得到了这两个月中只有 46 个日期的卡路里+步数+体重数据。显然,我在相当多的日子里(出于显而易见的原因,很多日子是周末)忽略了记录这三个数据中的至少一个。

数据转换

根据这三个原始数据源,计算三个附加数据字段:

剩余=消耗的卡路里-卡路里预算。正剩余意味着我吃了比那天允许的预算更多的卡路里,反之亦然。我选择使用卡路里盈余而不是消耗的原始卡路里,因为应用程序的卡路里预算会随着我体重的上升和下降而自然变化,所以卡路里盈余(考虑了上述预算)比卡路里本身更能准确地衡量我的饮食习惯。

增重=明天体重-今天体重。给定日期的正体重增加意味着我在那一天增加了体重(咄!),反之亦然。

体重增加状态:正的体重增加标记为 1,负的或零体重增加标记为 0。我决定使用二元体重增加状态——无论我是否增加了体重——而不是更具体的体重增加量,因为纠结于增加 0.5 公斤还是 0.3 公斤是非常适得其反的,尤其是因为体重增加量会受到除卡路里和步骤之外的许多因素的影响(如饮水量、进食时间等)。

First few rows of my final data table

数据可视化

当绘制卡路里剩余量和每天的步数与我当天体重增加状况的关系图时(见下面的前两个图),这两个据说很重要的因素如何预测我是否会增加体重似乎没有明显的模式。

Left & middle: plot of weight gain status against calories surplus and steps separately. Right: plot of weight gain status against surplus and steps together

然而,当绘制卡路里剩余量和步数时(上图右侧),非常有趣的模式出现了!例如,我马上就能看出,根据我的步数,有两组截然不同的日期:那些低于 5000 步的日期(我的“基线”懒惰日)整齐地围绕着一条水平线,而那些高于 5000 步的日期(我的活跃日),这主要归功于我的跑步。就卡路里过剩而言,有三个主要观察结果:

1。在我懒惰的日子里,如果我吃的超过了我的卡路里预算限制,第二天当我走上体重秤时,这将是个坏消息。有一些奇迹,比如有一天我吃了超过限量的 1500 卡路里,但第二天体重并没有增加,但这种情况很少。

2。另一方面,如果我在懒惰的日子里吃得低于我的卡路里预算限制,我也不完全清楚:有好几天我是个好孩子,吃我的沙拉(打个比方),但仍然增加了体重。这表明我应该在懒惰的日子里更加保守地饮食。

3。然而,在我活跃的日子里,我似乎可以吃得比我的卡路里限量还多,因为有几天我吃得比限量还多,但体重却没有增加。

这些观察表明,我应该考虑我的日常活动(以步数的形式),而不是使用 Loseit 应用程序的默认限制。

  • 例如,在上面的剩余步骤图上,我可以画一条直线,将我体重增加的天数(红色)和体重减少的天数(绿色)很大程度上分开。
  • 然后,我可以使用该线性边界来告知我的减肥策略,即我如何保持在边界的减肥一侧,而不是另一侧。
  • 用机器学习的说法,这相当于建立一个线性分类器对我的数据进行二进制分类(对体重增加和体重减少进行分类)。

使用哪个线性分类器?

从数据构建线性分类器有几种常见的方法,如逻辑回归、[线性判别分析](http://linear discriminant analysis)或支持向量机。但是,对于这个项目,我将使用逻辑回归,因为:

  • 这很容易解释:例如,分类边界的方程可以很容易地从逻辑回归系数中获得。
  • 易于实现:这是一个非常重要的原因,因为这个项目的另一个目标是让我实现一个机器学习项目,而不使用预先存在的库(如 scikit-learn)。正如我将在后面展示的,逻辑回归学习算法的核心只需要 3 行代码就可以完成!

选择模型后,让我们看看如何使用我的数据实现和解释逻辑回归。然而,这需要我们回顾一些关于逻辑回归分类器如何工作以及如何从数据中学习的数学知识。

数学评论

请注意,这个数学复习主要是为了建立一个通用的符号,以便在从数学方程实现算法之前,我们在同一页上。如果你想了解这些方程是如何推导出来的,以及它们背后的直觉,我在这篇博文的末尾链接了更多的资源,这些资源可以比我做得更好。

根据特征预测体重增加的概率

在逻辑回归中,我在某一天体重增加的预测概率是应用于我的特征(卡路里剩余量和步数)的加权线性组合的 sigmoid 函数加上常数截距项。这种关系在数学上表示为:

Superscript (i) denotes a a single data point/date

在哪里

  • y(i): 日期 I 的体重再次状态(1 =体重增加,0 =体重减少)
  • P(y(i)=1) :我在第一天体重增加的预测概率
  • x(i): 在日期 i*时各个特征(卡路里剩余量和步数)的观察值
  • θ :各个特征的回归系数/权重(从数据中学习)*

*请注意,我添加了一个额外的特征( x_intercept ),该特征将始终等于 1,以便可以学习截距项( θ_intercept )以及两个现有特征的系数。

因此,一旦从数据中学习到θ,就可以使用逻辑回归来分类我是否会在任何给定的一天增加体重——给定我的卡路里剩余量和步数——通过检查我在那一天增加体重的概率是否高于某个阈值(通常为 50%)。

如何学习 θ值

回归系数(θ)是通过最大化观察我的训练数据的概率的对数(也称为对数似然)来学习的。对数似然的公式是:

Log-likelihood of m training data points/dates

在哪里

  • L :训练数据的对数似然(m 个数据点)
  • y(i): 日期 I 的真实体重增加状态(1 =体重增加,0 =体重减少)
  • P(y(i)=1) :我在第一天体重增加的预测概率(从之前的 sigmoid 函数中获得)

根据 sigmoid 函数,不同的θ值将产生不同的体重增加预测概率(P(y(i)=1),从而产生不同的对数似然性。因此,我们的目标是找到最大化我的训练数据的对数似然性的一组θ,即最好地“解释”我的训练数据的θ。

使用批量梯度上升最大化对数似然

找到使我的训练数据的对数似然最大化的θ的一个简单算法是批量梯度上升,如下所述:

第 0 步:初始化θ的一些值(θ_ 截距,θ_ 剩余,θ_ 步长)

步骤 1: 对于每个训练数据点 I,使用该数据点的特征值(x_intercept*,x_surplus,x_step)和步骤 0 中初始化的θ的值,计算体重增加的概率。这是使用熟悉的 sigmoid 函数完成的:

*回忆 x_intercept = 1

步骤 2: 对于每个特征 j——截距/剩余/步长——使用下面的等式找到对数似然性相对于该特征θ的偏导数:

在哪里

  • ∂L/∂θⱼ: 对数似然相对于特征 j 的θ的偏导数
  • y(i): 日期 I 的真实体重再次状态(1 =体重增加,0 =体重减少)
  • P(y(i)=1): 第一天体重增加的预测概率(来自步骤 1)
  • xⱼ(i): 特性 j(截距/剩余/步长)在日期 I 的观测值,其中 x _ 截距(i) = 1,对于任何 I

步骤 3: 对于每个特征 j,通过对数似然性相对于θ的偏导数(来自步骤 2)乘以一个小常数(也称为学习率 α )来更新其θ:

这种学习速率控制算法收敛到对数似然最大值的速度,甚至控制算法是否收敛(有关更多详细信息,请参见后面的可视化算法收敛一节)。

步骤 4: 用这些更新的θ,重复步骤 1 到步骤 3,直到收敛。测试收敛的一种方法是查看对数似然是否已经收敛到稳定值,即它是否已经达到可能的最大值。

批量与随机梯度上升

步骤 2 中的求和符号——对所有数据点 I 求和 (y(i) - P(y(i)=1)) * xⱼ(i) 以计算偏导数——是该梯度上升算法属于批次种类的原因,因为每个偏导数是使用训练数据中的所有数据点计算的。没有这个求和符号,即偏导数仅使用一个数据点计算;假设数据点是随机选择的,梯度上升算法称为随机

对于这个项目,我选择实现批量梯度上升,因为我的训练数据非常小(只有 46 个数据点),所以一次使用整个训练数据集来计算偏导数没有问题。另一个原因是使用 numpy 的矢量化运算可以更容易地实现批量梯度上升(请参考下面的实现来了解如何实现)。

模型实现

数据预处理

Features & labels for 6 dates out of 46 in my training data

根据我之前的数据表,我使用剩余卡路里和步数列作为我的特征,体重增加状态列作为标签(见左)来训练我的逻辑回归分类器。

但是,在对该数据实施批量梯度上升算法之前,我首先需要:

  1. 在我的训练数据中添加一列 1 的来表示 x_intercept 特性的值。
  2. 通过(a)减去每个特征列的平均值和(b)除以其标准偏差,重新调整我的卡路里剩余量和步数特征。这样做有两个原因:

Sigmoid function

  • 回想一下,sigmoid 函数(左)涉及 x 的线性组合的指数,因此 x 的非常小/大的值将使该指数内爆/爆炸。事实上,在我重新调整我的特征之前,我有可怕的趋同性,我不知道为什么。只有当我偶然看到 Jupyter 终端(而不是 Jupyter 笔记本输出)时,我才看到 numpy 默默产生的下溢/上溢警告页面!在我重新调整我的特征后,这些警告消失了,我的算法能够收敛了。
  • 通过将我的特征缩小到相同的比例,我可以使用这些特征的回归系数(θ)来衡量它们在我体重增加/减少中的相对重要性。这将在我的模型的解释部分详细阐述。

在以上两个步骤之后,我的特征矩阵(X)被转换成维数为(46,3)的二维 numpy 数组,我的标签向量(y)被转换成维数为(46)的一维 numpy 数组。

Left: feature matrix X (46, 3). Columns (L to R): x_intercept, x_surplus, x_step. Right: label array y (46)

实施批量梯度上升

步骤 0:初始化θ的

theta = np.array([0.5, 0.5, 0.5])

我将所有θ初始化为 0.5。结果是一个维度为(3)的一维 numpy 数组theta

步骤 1:对于每个数据点,使用步骤 0 中的θ和 sigmoid 函数计算体重增加的概率

prob = 1 / (1 + np.exp(-X @ theta))

这就是 numpy 的矢量化运算派上用场的地方,因为 numpy 不是计算每个数据点的体重增加概率,而是一次计算所有数据点的体重增加概率:

  • X @ theta:通过将矩阵X与向量theta相乘,numpy 实质上是通过将X的每一行与theta列进行点积来计算每个数据点的 x 和θ的线性组合(见图中加粗的单元格)。
  • 1 / (1 + np.exp(-X @ theta)):在计算了所有数据点的 x 和θ的线性组合后,将 sigmoid 函数应用于它们中的每一个,以获得所有数据点的体重增加的最终概率。注意,这个 sigmoid 函数中的操作(/+-np.exp)都表示 numpy 在后台运行的矢量化函数。这最终输出了概率向量prob,一个维数为(46)的一维 numpy 数组。

步骤 2:对于每个特征,使用步骤 1 中计算的概率,计算对数似然对相应θ的偏导数

gradient = (y - prob) @ X

这也是 numpy 的矢量化运算的亮点:

  • y - prob:对所有数据点的真实标签和预测概率进行直接的逐个元素的减法,得到表示差异的一维 numpy 数组(46 维)。
  • (y - prob) @ X:在y - prob差向量(46)与特征矩阵X相乘之前,由 numpy 在幕后转置成一个维数为(1,46)的行向量,使其维数与X (46,3)的维数对齐。这种转置在 numpy 中也称为列向量的“向维度添加 1”。
  • 一旦尺寸对齐,y - probX之间的向量矩阵乘法可以发生:点积在y - prob的行向量和X的每个特征列之间进行(见图中加粗的单元)。这实际上是对所有数据点 I 的(y(I)-p(y(I)= 1))* xⱼ(i)求和,以获得特征 j 的对数似然的偏导数(等式 2)。更令人印象深刻的是,在这种向量矩阵乘法下,可以同时计算所有三个特征的偏导数,从而产生一个称为gradient的偏导数向量。
  • 从技术上讲,这个向量应该是(1,46)向量乘以(46,3)矩阵所得的维数(1,3)。但在幕后,numpy 在乘法后“去掉了(乘法前的)前置 1”,最后的gradient向量是一个维数为(3)的一维数组。numpy 在乘法前后应用于其数组的这些幕后“扭曲”可以参考[numpy.matmul](https://docs.scipy.org/doc/numpy/reference/generated/numpy.matmul.html)的文档,它实现了矩阵乘法运算符@

如果第一个参数是一维的,则通过在它的维数前加上 1,将它提升为矩阵。在矩阵乘法之后,前置的 1 被移除。

— numpy.matmul 文档

步骤 3:对于每个特征,用步骤 2 中的偏导数乘以学习率α来更新其θ

alpha = 0.01
theta = theta + alpha * gradient

这再简单不过了:我们可以通过将偏导数的gradient向量乘以某个预定义的学习速率alpha,并将乘积加到theta向量,来一次更新所有 3 个θ,而不是更新每个θ。

步骤 4:重复步骤 1 至 3,直到收敛

这可以通过将前面的 3 行代码嵌套到一个多次迭代的for循环中来轻松实现——每一步一行(见下面加粗的代码块)。下面展示的是运行 100 次迭代的批量梯度上升的完整算法(实现如此简单,难道不令人惊讶吗?!):

theta = np.array([0.5, 0.5, 0.5])
alpha = 0.01for _ in range(100):
 **prob = 1 / (1 + np.exp(-X @ theta))
    gradient = (y - prob) @ X
    theta = theta + alpha * gradient**

检查收敛

检查算法收敛性的一种方法是查看对数似然性的差异在循环的过去几次迭代中是否保持在某个小容限水平以下,这表明对数似然性可能已经达到其最大值。使用yprob(及其各自补码)的点积,对数似然可以简单地计算为:

log_likelihood = y @ np.log(prob) + (1 - y) @ np.log(1 - prob)

另一种(也许更有趣)方法是运行算法一定次数的迭代,并观察对数似然性是否达到了可能的最大值。下面是学习率α = 0.01 的批量梯度上升算法的 60 次迭代的可视化:

Left: convergence of θ’s. Middle: convergence of average log-likelihood. Right: convergence of decision boundary

  • 从上面的动画中可以看出,平均对数似然性(对数似然性除以训练数据的数量,见中间的面板)在前 10 次迭代中快速上升,但之后开始趋于平稳。在第 60 次迭代时,迭代之间的平均对数似然的差异在 10^-5 的数量级,这表明足够好的收敛。这也对应于左图中回归系数(θ)的收敛。
  • 另一种可视化这种收敛的方法是通过分类边界(见右图)。分类边界,也称为决策边界,代表体重增加的预测概率为 50%的线:其上的每个点的预测概率低于 50%,因此被分类为体重下降,其下的每个点的预测概率高于 50%,因此被分类为体重增加。在这 60 次迭代中,决策边界似乎稳定在一个合理的边界上,该边界将大多数体重减轻的日子(绿色)与体重增加的日子(红色)分开。

现在我们有了一个融合的逻辑回归模型,可以很好地对我的训练数据进行分类(至少通过目测决策边界),让我们看看如何改进它。

模型改进

选择合适的学习速度

给定固定的迭代次数,学习率(α)的值可以确定算法在这些迭代之后是否会收敛,或者是否会收敛:

  • 当α减少到 0.001(从最初的 0.01)时,θ的学习发生得更慢,并且在 60 次迭代之后,平均对数似然性仍然显示出增加的迹象。因此,在这个小的学习速率下,迭代次数应该增加,或者学习速率本身应该提高。

Dotted line represents the respective values at α = 0.01 for comparison

  • 然而,如果学习率太高,θ可能会被“过度修正”,并在每次更新后在最佳点附近反弹。这一点从下面的α = 1 时的收敛动画可以看出,60 次迭代后似乎并没有收敛。因此,在这些情况下,应该降低学习率。

Dotted line represents the respective values at α = 0.01 for comparison

当α = 0.01 作为我们学习率的最佳点时,我们当然可以增加迭代的次数,以确保我们的模型很好地收敛到最大对数似然。事实上,在 1000 次迭代时,迭代之间的平均对数似然的差异实际上为零。

使用岭回归减少过度拟合

尽管我的逻辑回归模型已经收敛到我的训练数据的最大对数似然,但它可能会过度拟合训练数据,即它从数据中学习得有点太好了。因此,该模型可能会对我在 2018 年收集的过去数据进行很好的预测,但如果我用它来预测我在 2019 年的体重增加,可能会很糟糕。

减少逻辑回归过度拟合的一个解决方案是使用回归的 L2 正则化版本(也称为岭回归),它通过一个由θ的平方组成的项减去原始对数似然:

m: number of training data points, n: number of features

因此,最大化上述函数相当于尽可能最大化训练数据的对数似然,同时保持θ较低(因为较高的θ将降低 L)。λ符号(λ)表示θ保持较低的程度(通常称为模型的正则化超参数)。当λ = 0 时,岭回归精确地返回到原始的、非正则化的逻辑回归。

在岭回归的实现方面,与原始逻辑回归的唯一区别在于批量梯度上升的偏导数(等式 2)的计算,其中从每个特征 j 的偏导数中减去 λ*θⱼ 正则化项:

需要注意的是,这种正则化并不经常用于截距θ,因此θ_intercept 的偏导数的计算与非正则化版本相同,即不减去λ*θ项。

该实现可以通过以下方式轻松集成到我们现有的 Python 代码中:

  1. theta乘以正则化超参数lambda_reg得到reg_term——维数(3)的λ*θ正则化项。
  2. reg_term的第一个元素设置为零,表示θ_intercept 没有被正则化
  3. (y - prob) @ X中减去reg_term得到gradient

以下是λ = 10 的岭回归代码,对原始算法的修改以粗体显示:

theta = np.array([0.5, 0.5, 0.5])
alpha = 0.01
lambda_reg = 10for _ in range(100):
    prob = 1 / (1 + np.exp(-X @ theta))    
 **reg_term = lambda_reg * theta
    reg_term[0] = 0**
    gradient = (y - prob) @ X **- reg_term**
    theta = theta + alpha * gradient

当在 60 次迭代中监测该岭回归的收敛时,我们可以看到:

Dotted line represents the respective values at λ = 0 (non-regularized logistic regression) for comparison

  • 在λ = 10 时,我的两个主要特征(卡路里剩余量和步数,见左图)的θ收敛到更接近于零的值,即与非正则化版本(λ = 0)相比幅度更低。然而,截距θ的收敛基本不受影响。
  • 岭回归的平均对数似然比非正则化版本收敛到更低的值(见中间面板),这表明岭回归对我的训练数据提供了不太完美的拟合,但这也可能意味着它对我的训练数据的过度拟合更少。
  • 岭回归的决策边界稍微偏离非正则化边界(见右图)。然而,它似乎仍然能够很好地区分我的训练数据点(红色和绿色)。

随着λ的增加,学习回归系数(θ)进一步向零压缩,截距除外(见下图)。此外,从决策边界可以看出,岭回归在对我的训练数据进行分类时变得越来越不有效:λ = 1 时的决策边界非常接近非正则化边界,而在λ = 100 时,边界实际上不可用(见右图)。

How θ’s and decision boundary changes at different λ values

然而,岭回归的目的不是改善对训练数据的拟合(因为如果是这样,它的表现将总是比非正则化版本差,如上所述)。更确切地说,它是为了改进对新数据的预测,即没有训练过岭回归的数据。

为了比较岭回归和它的非正则化对应物,我使用了双重交叉验证,如下所示:

1。 46 个数据点随机分成 2 等份:A & B(各 23 个数据点)

2。 在部分 A——训练集——上训练岭回归,并在训练集上记录回忆(正确预测体重增加的天数/部分 A 中真实体重增加的天数)

3。使用在 A 部分训练的θ来预测我是否会在 B 部分(验证集)增加体重,并在验证集上记录回忆(正确预测体重增加的天数/B 部分中真实体重增加的天数)

4。 交换零件,重复步骤 2 和 3,即零件 B 现在是训练集,零件 A 是验证集

5。 对两次试验中的训练集召回进行平均,验证集召回也是如此

为什么要用回忆?

有两个基本的度量标准来衡量分类器工作的好坏:精确度和召回率。在这方面:

  • 就我个人而言,如果分类器预测我会增加体重,而事实证明我不会,我不会在意;事实上,这甚至会是一个受欢迎的惊喜!所以在预测的增重天数中,我并不是太在意假阳性。换句话说,精度对我来说没那么重要。
  • 另一方面,我更可能纠结于分类器是否会标记出我真正增重的所有日子,以免它们被误报为假阴性(分类器预测我会减肥,而事实恰恰相反)。换句话说,我会尽可能提高召回率。

以下是不同正则化水平下的平均训练和验证召回,λ范围从 0(非正则化)到 10:

Average train & validation set recall (across 2 folds) at different λ values

  • 从左图来看,随着λ从 0 开始增加,平均训练集召回率保持在恒定水平,并且仅在λ接近 10 时开始下降。这与早期的观察结果一致,即岭回归对训练数据的性能随着λ的增加而变差。
  • 另一方面,对于λ在 0.1 和 1 之间,平均验证集召回具有明显的隆起,这表明在这些λ处的岭回归在新的验证数据上比其非正则化对应物表现得更好,即使两者在训练数据上表现得一样好。
  • 通过进一步的检查,发现在一个验证组中,真实的体重增加日(红色带黑边,见下图)被非正则化回归错误地归类为体重减少:它停留在(实)决策边界之上。另一方面,当λ = 0.5(介于 0.1 和 1 之间)时,决策边界会略微扭曲。因此,该点保持在该(虚线)决策边界之下,并且被正确分类。这是岭回归在λ = 0.5 时比其非正则化对应物在验证集上具有更好召回率的唯一原因。

Left: Decision boundary on one validation set (with training set faded in background). Right: dotted region on left panel enlarged

尽管这些结果表明我应该选择具有最高平均验证集召回率(λ = 0.5)的λ值,但验证集(23)中的少量数据点(其中甚至有更少数量的重量增加点(红色))表明这种性能的提高可能只是由于运气。这也解释了为什么对于一些λ,在相同的λ下,验证集的性能高于训练集的性能,即使通常发生相反的情况;我可以有一个“幸运的”验证集。

也就是说,选择λ = 0.5 没有害处,因为当在我的 46 个点的整个数据上训练时,它的决策边界实际上与λ = 0 的决策边界没有什么区别,正如前面不同λ(从 0 到 100)的决策边界图所示。因此,对于我的最终模型,我选择保持λ = 0.5。

选择决策边界的阈值

在调整我的模型时,选择λ并不是最有影响的决定。相反,选择我的决策边界的阈值是:

  • 对于我到目前为止建立的所有回归模型,分类阈值,也就是决策边界,被设置为 50%(或 0.5)。这是一个合理的阈值,因为预测体重增加概率高于 50%的日子自然应被归类为体重增加的日子,反之亦然。
  • 然而,当这个体重增加阈值降低时,越来越多的数据点将被归类为体重增加(正确与否)。回忆,也被称为真阳性率,当然会增加,但是假阳性率——在真正体重减轻的日子里被错误地预测为体重增加的日子——会同步增加(见左图,以及下面中间图中的 ROC 曲线)。然而,如前所述,由于我不太担心假阳性,我可以容忍许多体重减轻日被错误地归类为体重增加,即高假阳性率,如果这意味着我的真实体重增加日被更好地检测,即高真阳性率/回忆。

Left: True/False Positive Rate at different classification threshold. Middle: ROC curve. Right: decision boundary at different thresholds

如果是这样的话,门槛是不是应该定得越低越好,甚至到 0%?不,因为:

当阈值降低时,决策边界上移。

  • 例如,为了使回忆增加到最近的较高水平,阈值必须从 50%减少到 44%(在左侧面板中从黑色减少到棕色)。结果,决策边界上移,以捕捉更多的体重增加点(右侧面板中带有棕色边框的红点)。这相当于向左移动了 107 千卡。换句话说,如果我以前在 50%的界限,我必须在相同的步数下少吃 107 千卡,才能保持在 44%界限的良好减肥侧。
  • 在阈值接近 0%的极端情况下(左侧面板中的橙色点),边界向上移动,以便捕捉所有体重增加点,包括带有橙色边框的最高红色点(右侧面板)。这个决策界限决定了在我懒惰的一天,我平均走了将近 2500 步,我应该比我的预算少吃 1740 千卡来保持健康。鉴于我的数据中的平均预算约为 1715 千卡,这转化为在那些懒惰的日子里的上限 -25 卡路里(是的,你没看错)。当然,在这个物理极限下,我的回忆会是惊人的,但是我会死的!
  • 那么我到底该不该降低自己的门槛呢?鉴于从我的数据中学到的 50%决策界限已经相当保守了——在懒惰的日子里,这表明我应该比通常的 1700+千卡预算少吃大约 140 千卡——我决定坚持默认的 50%阈值。将这个阈值降低到下一个可能的水平 44%会让我在回忆中多得几分,但额外的 107 千卡限制不值得我失去理智。

模型解释

概括地说,我们通过梯度上升算法训练了一个逻辑回归分类器,使用我的每日卡路里盈余和步数作为特征,我的体重增加状态作为标签。我们模型的参数是:

  • 学习率: α = 0.01
  • 正则化参数: λ = 0.5
  • 阈值: 50%

在整个数据集上训练分类器后,学习的回归系数(θ)得出:

优势比分析

  • 逻辑回归系数的一个常见解释是通过 优势比 :特征的一个单位变化,结果变化的几率是多少倍。对于一个特征 j,那个特征的比值比正好是它的θ的指数。

  • 回想一下,逻辑回归是对卡路里盈余的标准化值进行的(通过减去盈余平均值并除以盈余标准偏差得到)。因此,θ_surplus = 0.9 意味着在任何步数下,剩余卡路里的标准差减少(约 420 千卡)对应于 e^0.9,或者我体重增加的几率减少 2.5 倍。
  • 另一方面,在θ_step = -1.2 的情况下,我步数的标准差增加——大约 5980 步——对应于 e^1.2,或者我体重增加的几率减少 3.3 倍(在任何卡路里剩余量的情况下)。在我最近的 10 次锻炼中,我的平均步频是 1366 步/公里。因此,这 5890 步相当于大约 4.4 公里。
  • 换句话说:

步数的标准差增加(5980 步)比卡路里消耗量的标准差减少(420 千卡)更能有效减少我体重增加的几率。

当然,我愿意跑 4.4 公里而不是不吃那碗 420 千卡的河粉完全是另一回事!

尽管比值比为我应该如何制定减肥策略提供了一些见解,但从我的逻辑回归分类器的决策边界中可以得出一个更可行的计划。

决策边界分析

回想一下我们之前可靠的 sigmoid 函数:

Superscript (i) removed for simplicity

很容易看出,体重减轻的概率为 50%(其中分类阈值为),θ和 x 的线性组合必须为零*(我还用 1 代替了 x_intercept):

50% decision boundary formula for normalized features

*对于其他概率阈值,θ和 x 的线性组合可以通过取阈值的 logit 得到:ln(p/(1-p))

然而,在我们的逻辑回归中使用的 x 是我们原始特征的标准化值。因此,我们可以将上面的等式改写为:

***** denotes the original feature value. μ: feature mean, and σ: feature standard deviation

重新排列,我们有:

50% decision boundary formula for original features

将θ和特征均值(μ)和标准偏差(σ)代入上述方程,得到原始卡路里剩余量和步数特征之间的线性方程:

从图形上看,这个方程代表了原始剩余步骤图中的决策边界(见下面的左图)。根据这个决策界限,我应该记住 3 个重要数字(见右图):

Left: surplus-step plot with decision boundary. Right: dotted region from left panel enlarged

1) -140 千卡

这是我在懒惰的日子里(平均 2480 步)应该吃的低于 Loseit 应用程序卡路里预算 的量。平均预算刚刚超过 1700 千卡,这意味着在那些日子里,我应该平均摄入低于 1560 千卡的热量。这个数字听起来确实很严格。****

130 千卡

然而,一个可取之处是,根据决策边界,对于我超出正常活动范围的任何 1 公里,我都可以将这个限制增加 130 千卡。例如,如果我计划在某一天跑 5000 米,我可以负担得起比应用程序当天的卡路里预算多吃 140 + 130 * 5 = 510 千卡。希望这能鼓励我坚持我的跑步计划。

3) 1070 步

另一方面,当我试图吃得超过卡路里限制时(如前两条规则所规定的),我吃的任何超过限制的 100 千卡必须通过至少 1070 步来获得。这可以通过以下方式实现:

  • 绕着街区走 1070 步,然后去吃那家 banh bao ,或者
  • 意识到我太懒了,把食物从我愚蠢的嘴里拿出来(嘿,我刚刚做了我自己的掌掴厨师!)

Hit me with that number baby!

结论

我希望用以上的指导方针,让我 2019 年的减肥之旅比 2018 年更成功。当然,即使有数字支持,我也不会总是成功,但我从这个项目中学到的最重要的一课是:

我应该善待自己。

例如,我减肥,即使我在活跃的日子里吃得比预算多,所以我不应该为这样做感到内疚。希望有了这种结合饮食和锻炼的新模式,在我持续的减肥旅程中,我可以感觉到更少的罪恶感和羞耻感(就像我以前一样)。

其他课程

我着手这个项目的另一个重要原因是实现一个机器项目,而不使用预先存在的库,如 scikit-learn。以下是我从这个过程中学到的一些经验:

  • 一年多前,当我第一次学习 Python(或者任何严肃的编程)时,我不确定为什么会有人使用类。嗯,在这个项目中(a)使用全局变量theta , (b)得到一些奇怪的结果,比如不收敛,以及(c)意识到所述的theta属于我许多个月前运行的其他模型,我现在意识到为什么类中的封装是如此重要:一个模型对象可以有它自己的属性(thetaalphalambda_reg)和方法(fitpredict),这些属性和方法不会与其他模型对象的属性和方法冲突,我可以在下次需要它的时候愉快地把它完整地捡起来。

我真的对如何使用类来建模数据科学问题很感兴趣,并且我认为通过更多相关的例子,我可能能够更好地理解面向对象编程的强大功能(现在我仍然不太确定我应该何时或者如何使用它们)。

—初学 Python 时的我

  • 这个项目还允许我实现和理解一些我从未有机会使用的简洁编程概念的实际好处,例如使用生成器yield语句一次返回一个训练和验证文件夹。这允许我仅在这些折叠上评估我的模型,然后返回并生成更多的折叠,而不是一次将所有折叠存储在内存中(尽管对于我的数据大小来说,这几乎没有区别)。甚至像编写清晰的伪代码这样的事情也被证明是非常重要的,尤其是在实现像逻辑回归这样的数学算法时;令人尴尬的是,我不得不承认我花了很长时间进行调试,因为我没有事先编写明确的伪代码,并且错误地交换了alphatheta
  • 最后,这个项目帮助我更详细地研究了我经常使用的一些机器学习库的实现,例如偶尔警告我在训练 scikit-learn 模型时必须指定max_itertol:前者指定让模型收敛的迭代次数,后者指定迭代停止的容差水平——这正是我在为自己的模型检查收敛性时面临的两个选择。
  • 另一个例子是,我现在了解到一些 scikit-learn 模型的行为不像我期望的那样:SGDClassifier(loss=’log’, penalty=’l2', learning_rate=’constant’)似乎没有缩小截距的θ,并给了我的模型类似的θ,而LogisticRegression(penalty=’l2')在默认设置下缩小截距的θ,除非有人篡改了intercept_scaling参数。因此,我在将来使用第三方库分析我的数据时会更加小心,并在必要时验证结果。

更多资源

  • 我从 CS229讲义视频 讲座(我极力推荐的吴恩达教授讲授的机器学习课程)中获取了逻辑回归及其梯度上升法的大部分推导。注释提供了随机梯度上升的公式,但是批量版本可以很容易地修改(如前面的数学回顾部分所示)。
  • 一个更容易理解的解释可以在他在 Coursera 上的第三周机器课程中找到。本课程也涵盖岭回归在逻辑回归上的应用,这是 CS229 课程所没有的。一个小细节:Coursera 课程将逻辑回归称为使用随机梯度下降最小化对数损失。然而,这与我实现的使用随机梯度上升最大化对数似然性是一样的,对数损失只不过是对数似然性的负值(有一些小的修改)。
  • 对逻辑回归和岭回归的另一个很好的解释来自华盛顿大学 Coursera 关于分类方法的课程。幸运的是,本课程使用对数似然最大化来解释逻辑回归,所以它应该与 CS229 和我的符号一致。
  • 最后但并非最不重要的是,我在网上找到的两个减肥分析项目真正启发了我自己的项目:一个来自威尔·科尔森,他只使用他过去的体重来预测未来的减肥,另一个来自阿里尔·费根,他使用几十个因素来预测他每天增加或减少多少体重,并得出非常有趣的结果:显然睡眠是他减肥的最重要因素!我的方法介于两者之间,仅使用两个特征来预测我是否会减肥,这使得我可以在我的减肥旅程中带走简单的可视化和简单可行的见解

我希望我的项目可以启发其他人使用机器学习和数据科学来帮助他们更多地了解自己,完成减肥等个人目标。如果您有任何问题或反馈,请不要犹豫通过媒体联系我!

分析网易音乐-第一部分:播放列表

原文:https://towardsdatascience.com/analyzing-netease-music-part-i-playlist-968f43fc7fc5?source=collection_archive---------30-----------------------

中国人听什么样的音乐?

Netease Music Logo

网易音乐(https://music.163.com/),一个中国版的 Spotify,是一个音乐应用程序,允许用户播放、下载和参与来自世界各地的音乐。网易的月活跃用户数超过 7000 万,与酷狗音乐、酷我音乐和 QQ 音乐并列中国音乐应用前四。此外,它是四款应用中唯一一款非腾讯的应用。

网易音乐的受众呈现出一些有趣的特征。根据该公司的报告以及 QuestMobile 的数据,该应用的用户更年轻,男性比例更高,并经常与社区互动。用户不仅比其竞争对手更频繁地打开和使用该应用,而且他们也倾向于留下大量评论。事实上,网易音乐中的评论已经成为其一大看点。人们会发布有趣的笑话、心碎的故事,甚至向他们的秘密情人表达自己的感受,并要求其他听众竖起大拇指,这样他/她就可以看到了。在网易音乐的一次推广活动中,它在杭州的地铁站和火车上发表了点赞数最高的评论。这一创意活动是该应用程序的巨大成功,并进一步确立了其作为最具“社交”属性的音乐应用程序的地位。

The comment promotional campaign

与西方同行类似,大多数听众将使用播放列表作为存储他们喜爱的歌曲以及发现新事物的方式。在网易音乐中,用户可以“播放”该列表,“收藏”该列表以供将来收听,“评论”该播放列表,并在应用程序内或微信/微博中“分享”该播放列表。在本文中,我将单独查看播放列表的一些指标。在接下来的几篇文章中,我还将探索关于单首歌曲的指标以及这些歌曲的评论。

如何获取数据

所有的数据都可以在网站上公开获得,并使用我个人构建的爬虫收集。爬虫基本遵循从主页发现播放列表,从播放列表发现歌曲,然后从播放列表和歌曲下载评论的逻辑。爬虫仍在积极开发中。如果你对学习如何爬行感兴趣,请在下面留下评论,我会写一篇关于爬行的文章。

数据大小

下面进行的分析使用了 6000 个播放列表的样本。这些列表要么是在主页上推荐的,要么与那些热门播放列表有些关联,所以这些列表往往有更多的参与。

探索数字变量

首先,我们将查看数据集的数值。如前所述,参与度指标是“收藏”、“评论”、“分享”和“播放”。数据集还有一个“song_num”变量,它描述了播放列表中歌曲的数量。由于默认的 Pandas describe()使用 float 类型并在表中留下许多 0,我们可以使用 applymap()函数更改输出的格式,使它更漂亮。

df[['comment_num', 'fav_num', 'share_num', 'play_num','song_num']]
.describe()
.applymap(lambda x: format(x, '.0f'))

describe() result

从这里我们可以看到,评论和分享的中位数是 10。“fav”的号码是 663,播放号码是 36k。粗略地说,一个播放列表需要播放 4000 次才能获得“分享”或“评论”。这表明评论和分享功能并不常用。请注意,这里的“评论”适用于整个播放列表,它不同于评论一首更受欢迎的歌曲。

为了直观地显示这些指标,我们可以使用一个方框来绘制这些列。然而,由于所有四列的数据都有很大的偏差,直接绘制它们不会产生好的结果。下图并没有真正告诉我们什么,因为 x 轴非常大,没有显示足够多的“长尾”播放列表的细节。

sns.boxplot(data = df[['comment_num', 'fav_num', 'share_num', 'play_num']], orient='v')

Boxplot without normalization

为了使这种偏斜数据正常化,我们可以使用对数函数来做一个快速而肮脏的把戏。如果你想了解更多细节,请阅读这篇文章。

https://becoming human . ai/how-to-deal-with-skewed-dataset-in-machine-learning-AFD 2928011 cc

sns.boxplot(
data = df[['comment_num', 'fav_num', 'share_num', 'play_num']]
       .applymap(lambda x: math.log(x+1)), orient='v')

Boxplot with normalization

归一化后,我们可以看到所有四个指标都遵循相对正态分布。

变量之间的相关性

播放次数多的播放列表也有很多评论吗?这似乎是一个明显的正相关,但看看这个数字如何滚动出来仍然很有趣。

corr = df[['comment_num', 'fav_num', 'share_num', 'play_num']].corr()
sns.heatmap(corr, 
        xticklabels=corr.columns,
        yticklabels=corr.columns,
        cmap = 'Blues',
        annot = True)

我们可以使用 pandas 的 corr()函数来获得相关图,并使用 seaborn 来绘制相关图。注意,您可以使用 cmap 参数来改变图形的颜色。对于关联热图,基于单一颜色的图表会更有效,因为它更清楚地显示了数字比较。

有意思的是,播放号和收藏号的相关性最强。这是有意义的,因为在他们可以保存播放列表之前,需要有大量的人在听它,收藏它意味着他们将来会听它。评论与其他指标的相关性较弱。由于评论数和分享数与其他两个相比要小得多,很可能这些指标中有较高比例的“噪声”,因此导致相关性较弱。

另一方面,股票数量的相关性更弱。尽管仍有很强的正相关性,但这个数字并不那么确定。也许一个原因是,共享播放列表的意义不同于播放它或喜欢它。通过演奏或收藏,听众可以独立地欣赏音乐。通过对播放列表进行评论,听众可以与作者和喜欢该播放列表的其他人进行互动。然而,通过共享播放列表,这意味着听众在社交上参与音乐,并致力于向他们的朋友推荐该列表。也许一个人会在白天分享一个经典的摇滚播放列表,然后在晚上循环播放“我知道你是个麻烦”?

探索其他变量

我们可以看的另一个有趣的列是“tag_list”。当用户创建播放列表时,用户最多可以选择 3 个标签。这些标签包括语言、流派、合适的场合、情感和主题。对于那些不懂中文的人,我创建了一个翻译文件来将这些标签翻译成英文。

Tag selection page at Netease Music App

在将标签列表展开成一个带标签的标签列表后,我们可以绘制每个标签的直方图。虽然样本量很小,但数据也许能显示出网易音乐听众音乐偏好的一些有趣趋势。

语言

Language count plot

在语言方面,中国音乐仍然是最主要的类别,但西方音乐(主要是英语)紧随其后。日语也占据了播放列表的相当一部分。

流派

Genre count plot

就流派而言,除了很难精确定义的“世界音乐”之外,流行音乐是最受欢迎的一类,因为人们不知道还能选择什么。“新时代”和“轻音乐”都很放松,占据了第三和第四位。这可能会令人惊讶,因为这些音乐在西方世界并不流行。尽管 EDM 和 Rap 最近在年轻一代中很受欢迎,但它们在播放列表中所占的比例仍然相对较小。

场合

Occasion count plot

对于场合,夜晚和午休是两个占主导地位的标签。这与我们上面确定的“轻音乐”趋势相一致,因为人们在这两个时间段倾向于听到更多的“舒缓”音乐。同样值得注意的是,对于“流行”列表,列表创建者可能不会为其选择“场合”标签。

情感

Emotion count plot

Theme count plot

排在前两位的情绪是“怀旧”和“开心”。与“悲伤”和“孤独”列表的低数量相比,人们似乎更倾向于制作积极情绪的播放列表。就主题而言,由于数量很少,很难确定一个趋势。值得注意的是,动画和游戏具有很强的代表性,表明“动漫”文化在中国仍然蓬勃发展。

总体而言,与西方世界相比,网易音乐听众的口味更“清淡”。观众作为一个整体已经接受了一套不同的音乐。

有趣的事实

  • 播放次数最多的播放列表播放次数达 1.48 亿,是一个收录了最佳 intros 的英文歌曲集。榜单第一首是《五百里》。
  • 评论最多(10k)的播放列表是 90 年代中国动画片的配乐集。

好了,这一次到此为止。下一篇文章,我会在播放列表数据上探索一些机器学习的方法,尝试基于文本数据和歌曲数据来预测类别。

分析曼哈顿一百万选民的记录

原文:https://towardsdatascience.com/analyzing-one-million-voter-records-in-manhattan-3a4787b8a83b?source=collection_archive---------26-----------------------

对曼哈顿选民构成的独特观察

如果你能立即想象整个城市的政治归属,下至每一个公寓和登记投票的人,会怎么样?有点令人惊讶的是,纽约市在 2019 年初将这一点变成了现实,当时纽约市选举委员会决定在网上发布460 万选民记录,由 《纽约时报》 报道。这些记录包括全名,家庭住址,政治派别,以及你在过去 2 年中是否登记过。根据此的原因是:

委员会官员表示,他们的印刷供应商无法及时制作足够的选民登记册,供候选人在 2 月份开始收集请愿书签名,这就是他们在网上发布信息的原因。

所以这成了其间的‘权宜之计’。尽管正如纽约市 BOE 发言人瓦莱丽·瓦兹奎·迪亚兹在同一篇文章中所说:

不管你有没有意识到,纽约的选民数据是公开的。

虽然一个城市心血来潮公开 460 万份选民个人记录的想法令人深感不安,我打算在另一篇文章中讨论这一点,但可视化这些数据的机会引起了我的兴趣。对于大多数公共数据集,你可能能够访问的最细的数据集可能是人口普查区级别,但是纽约市刚刚展示了世界上最独特的数据集之一!现在第一次有了一个数据集来可视化大量超粒度选民数据,包括按地区划分的政治派别集中度,在某些地区是否有协调一致的努力来登记新选民,以及占主导地位的政党在多大程度上是人们可以理解的。

最终我决定尝试并发表这篇文章,原因有二:

1。公共官员需要更好地考虑在线发布这样一个大规模数据集的潜在后果

在这种情况下,一个半技术人员花了几个周末的空闲时间来下载、转换和搜索数百万条记录。我不仅做到了这一点,而且在谷歌上获得积分后,我能够以大约 30 美元的价格对超过 100 万条记录进行地理编码。在这个数字时代,隐私需要放在首位,而不是事后才想到。

。总的来说,这些数据提供了新的、独特的见解,对很多人都很有价值

我确实相信这个数据集(在建筑层面可视化/分析)可以提供独特的见解,同时维护我自己和其他纽约居民的隐私。

总的来说,我发现确实存在政党主导的集中区域,而且政党主导的集群遍布整个城市。我还发现,新选民登记高度集中在字母城和上东区等地区,一些集群的登记人数比其他集群高 5 倍。本文的其余部分将涵盖将大约 600 个 pdf 转换成可用数据集的方法、观察到的独特比较的三种可视化,以及对进一步研究提出建议的结论。

方法学

现在,仅仅因为数据可用并不意味着它是可访问的,数据发布的方式证明了这一点。让我们来看看下面经过编辑的原始 PDF:

Redacted sample of the PDF pages

从数据科学的角度来看,这绝对是一场噩梦。许多原因中的几个:

  1. 它在 PDF 中显示为每页三个“表格”,因此 excel/其他程序不会像您预期的那样使用它。它或多或少会爆炸,并在随机单元格中生成随机条目,因此不适合简单的复制/粘贴
  2. 数据重叠(街道名称与名称重叠),因此没有简单的方法来分隔列
  3. 像街道号这样的数据点最初只陈述一次
  4. 列/新页面可以从没有数据开始(例如,第二列没有街道号码),因此需要有一种方法来记住“最近”的元素
  5. 它只有地址,为了在地图上可视化,您需要纬度/经度数据

由于我是 Python 爱好者,我立即开始尝试使用各种现有的库,如 PyPDF2 来尝试读取数据,但是很明显 PDF 的格式不允许这样做。在陷入死胡同的最初几个小时后,我陷入了困境,开始重新思考我的策略。如果我不能使用页面上现有的数据结构,我需要找到一种方法来完全隔离和重建页面上的每个单词。

输入光学字符识别(“OCR”)。使用 Pytesseract 库,我改变了策略,告诉我的程序每一页都是图像而不是 PDF 页面。事实上,只需要一行代码:

text = pytesseract.image_to_data(第页)

为您提供页面上几乎每个元素的坐标:

Output of Pytesseract using image_to_data

一旦我确认了这一点,接下来的问题就是如何使用这些位置来构造一个自定义的分隔符来遍历每一页。不幸的是,由于 Pytesseract 选择的分组方式,前几列中的大部分都不起作用,但据我所知,“左”、“上”、“宽”和“高”的信息是准确的。所以对于我的程序,我基本上利用了以下逻辑:

  • 将页面作为图像阅读
  • 隔离左侧的数据表
  • 使用左/上位置来确定行/列分组
  • 制作一个数据框架,其中包含街道号、姓名、邮政编码等单独的列。
  • 对中间和右侧的数据表执行上述步骤
  • 移到下一页

公平地说,我不得不处理许多细微差别和边缘情况,OCR 的结果并不完美(我将在结论中详细讨论)。然而,经过一两天的修补,我能够在大约 30 分钟内成功地迭代通过我的第一个 250 页的 PDF,并将其转换成一个完全可利用的数据表!

Sample view of our newly converted dataset

现在是有趣的部分,我如何把它翻译成实际的地图?我有地址,但是我不能实际映射它们,除非我能以某种方式找到每个地址的纬度/经度坐标。当我查看我成功转换的唯一曼哈顿地址时,它达到了近 100,000 个唯一地址,因此手动完成这一部分是不可能的。幸运的是,谷歌不仅有一个反向地理编码 API,而且我发现了一个名为 Geopy 的奇妙的 python 库,它让我可以轻松地创建一个函数,用不到 20 行代码对地址列表进行地理编码。

About 20 lines of code can geocode nearly any address

由于我从未使用过谷歌的云平台,我从 300 美元的免费信用开始,这有助于抵消大约 330 美元的总成本。在我的免费积分和奇思妙想的鼓舞下,我让我的程序在接下来的 12 个小时内执行,为几乎所有相应的地址返回一组漂亮的经纬度坐标。在将它与聚合数据集连接起来并进行一些数据清理之后(见结论),是时候决定如何可视化它了。

可视化大规模数据集不是一件容易的事情,除了找到一个可以处理几十万行的可视化库之外,您还需要考虑可视化数据集的技术,以便最终结果对底层数据来说是有意义和真实的。我最初开始在机器学习社区使用一个奇妙的新项目,名为 Streamlit ,但最终决定我不想创建一个仪表板,因为太多的杂物会分散注意力(绘制数据)。

First Attempt with Streamlit, Great for Creating Dashboards for Active Analysis!

最终,我选择了优步可视化团队制作的名为 Kepler.gl 的图形库。开普勒使用 Mapbox 作为底层地图提供商,不仅在处理大型数据集方面做了惊人的工作,而且即使对于不编码的人也非常容易访问。在尝试了一些不同的技术、滤镜和图层设计后,我决定选择下面三个最有影响力的。

选民的绝对优势

我想看的第一件事是'孤立地看每个聚会浓度是什么样的'?我想这样做有两个原因:

  1. 为了看看我提取的数据是否大致接近报道的党派优势(民主党已经占了大约 68%的投票人口)
  2. 为了清楚地识别集中区域,没有一方由于偏斜而控制地图

为了做到这一点,我在地图上创建了每个政党的双重视图,根据给定区域中的点的集中程度(该区域中注册选民的密度)创建了半径宽度,然后根据 avg 创建了连续的量化色标。双方所占面积中的建筑百分比。

Democratic (left) concentrations compared to Republican (right)

正如我们在地图对比中看到的那样,曼哈顿确实是压倒性的民主,许多倍数更集中在像哈莱姆区(曼哈顿北部)这样的地区。毫不奇怪,他们往往也是大多数建筑中的大多数选民,正如你在地图上看到的深蓝色。从共和党方面来看,很明显,从原始数据来看,他们占少数,而在他们拥有大量集群的地区,民主党人通常仍占主导地位(由浅红色和深红色显示)。与其他地区相比,上东部地区,如鲁诺山、海龟湾和约克维尔确实显得高度集中。林肯广场和金融区周围的人群似乎也较少,尽管要稀疏得多。

选民的混合优势

现在我们已经检查了原始的政党优势,让我们试着合并到一张地图上。这里的想法是试图显示政党集中的主导领域,同时也保持人口的相对规模。为了做到这一点,我创建了一个网格样式的层,使用了 0.2 公里(约 0.06 英里)半径内的聚会总数。然后我会为每个网格创建一种颜色,基于在该区域找到的最频繁的聚会。我的假设是,即使民主党控制了曼哈顿,也可能有共和党控制的地区。下面是结果:

Party dominance in clustered areas

正如我们所看到的,这并不令人惊讶,因为民主党主导了地图,即使是在上东区这样的共和党人最集中的地区。似乎确实有一些主题区域,如中央公园的东南区域,但最终在同等规模的民主集中度下,几乎没有优势。

新选民登记

我特别好奇的一件事是,曼哈顿的选民登记是否集中在某些地区。pdf 包括 2017 年和 2018 年登记的选民数据,所以我决定看看可以收集到哪些见解。总的来说,我能够捕获大约 55,000 名新注册的选民,所以我决定将新选民聚集在 0.2 公里(~0.12 英里)的集群中。曼哈顿本身只有大约 2.3 英里宽,所以选择一个对你所代表的区域有意义的比例尺是很重要的。起初,我试图像上面的双地图一样将政党分开,但令人惊讶的是,在新民主党人和共和党人登记的地区,我看到的变化很小。相反,我决定将两党的新登记者结合在一起,并从总体上看 2017 年与 2018 年的新选民。

2017 New Voters (left) compared to 2018 New Voters (right)

正如我们所看到的,有两个新选民登记非常集中的地区——上东区的鲁诺山/约克维尔地区,东村的字母城周围地区。很难从中收集到任何明确的见解,但这种集中很有趣,因为地图上红色区域的新选民集中程度几乎是绿色区域的 5 倍。有几种方法可以潜在地解释这一点——也许这些地区相对于其他地区来说,由更多的新移民组成;或者,这可能反映了社区集中努力鼓励选民登记。

结论

这是一个非常有趣的项目,但是我还需要强调一些关于分析的免责声明。首先也是最重要的,像我这样使用 OCR 在准确性方面有很大的折衷。我的最终数据集被精简为大约 750,000 条聚合记录,其中大部分是由于 OCR 读取错误而不得不丢弃的数据(例如/“100 Orange Street”可能会读作“T0O 0range $treet”)。

因为像街道号码和名称这样的数据在某些情况下只出现一次,程序以这种方式误读它们最终会导致纬度/经度坐标找不到或不正确。我尽我最大的判断,试图扔掉明显不正确的大量数据,但我知道这个数据集并不完美,可能无法 100%代表现实。虽然数据可能是准确的,但我没有完美的验证方法,因为这是一个人的操作。

我很乐意看到城市思考如何创建像这样更开放的数据集。虽然我对纽约市发布数据集的方式感到失望,但我认为汇总层面的基础数据对许多相关方来说都有巨大的价值。这不仅有助于研究人员更好地了解选民趋势,还可能极大地促进与选区划分选区划分等问题相关的研究。

进一步的研究可以纳入其他数据集,如美国人口普查数据,以了解诸如地区选民参与度或刺激选民登记的社会经济混合等情况。我也没有想象像布鲁克林或共和党或民主党以外的其他政党这样的地区,所以这些地区也仍然是未开发的领域。我相信,深入研究这些领域会发现更多关于纽约选民构成的独特发现。我希望这能有所帮助,并给每个人提供思考的食粮——感谢您花时间通读,并在下面自由发表您的想法或问题!

分析在线活动和睡眠模式

原文:https://towardsdatascience.com/analyzing-online-activity-and-sleep-patterns-10c997591e76?source=collection_archive---------15-----------------------

让数据科学变得有趣

分析你的脸书朋友的网上活动和睡眠模式

社交网络上有大量公开的信息,有时我们甚至会忘记它们的存在。像我们的脸书朋友在的在线活动这样的小信息能让我们推断出他们什么时候睡觉,或者他们什么时候在脸书最活跃。

在本帖中,我们将学习分析脸书好友的在线活动,并找出使用统计和睡眠模式。该员额由两部分组成。

  1. 展示在线活动和睡眠模式
  2. 使用 Python 分析在线活动和睡眠模式(带代码)

在第一部分,我将向你展示一些我用我脸书朋友的数据制作的有趣的图表,在第二部分,我将向你解释如何用 Python 创建一些展示的图表。

本帖完整代码的 Jupyter 笔记本可以在 这里 找到。

1.展示在线活动和睡眠模式

从一个人的脸书朋友的在线状态数据中可以得出一系列有趣的见解。在这一节中,我将向你展示一些有趣的见解,这些见解来自我通过爬行脸书收集的两周数据。

首先,我非常有兴趣找出我的朋友们在一天中的不同时间以及一周中的不同日子使用脸书/Messenger 的模式。

给定一个时间戳列表和相应的当时在线的朋友列表,我们不仅可以找出一天中最多和最少数量的朋友在线的高峰时间,还可以对 睡眠模式 有一个相当好的估计。

这些统计数据也提醒我们,我们在网上留下了多少公共信息和痕迹,以及它们是如何被以不同方式利用的。

虽然数据收集非常简单,但是与收集的数据样本及其预处理相关的一些要点值得一提,如下所示:

  1. 两周 的过程中,每周 7 天,每天 24 小时,每 4-5 分钟收集一次样本。仅仅两个星期的短时间跨度可能导致有偏差的数据集,但是正如我们将在后面看到的,它给了我们一个很好的模式估计。
  2. 我的大多数朋友都是穆斯林,数据也是在神圣的斋月收集的,在不同的时区(包括欧洲、美国、亚洲和非洲)都有朋友。这可能会导致睡眠模式与平时不同。
  3. 当比较朋友的相对在线活动时,使用了每个朋友的当地时区例如,当地时间晚上 8:00(GMT+2)斯德哥尔摩的一个朋友的在线状态与当地时间晚上 8:00(GMT-4)纽约州的另一个朋友的在线状态进行比较。
  4. 因为我的大多数朋友都来自巴基斯坦,默认时区被假定为 GMT+5,对于我碰巧记得的朋友,我相应地调整了他们的时区。然而,由于时区设置错误,汇总数据中可能存在一些不准确性(约 5-10%)。

背景信息已经够多了,现在让我们来看看第一周和第二周在线朋友的平均数量。图 1 描绘了一天中不同时间线上朋友的数量。

Figure 1: Average number of online friends over the day for two different weeks

  • 这两周的曲线高度略有不同,但这两周曲线模式在一天不同时间的变化非常一致。
  • 两周后曲线的峰值非常一致。

如果您想知道如何创建这些图表,请继续,您可以在本文的下一部分中了解到这一点。

从图 1 中可以明显看出,一周的数据通常是对模式的足够好的估计,我们可以继续绘制一周中不同日子的在线朋友数量图。

Figure 2: Number of online friends over the day for whole week

让我们列出图 2 中的一些观察结果:

  1. 一天中在线朋友数量的模式在一周中不同的日子里惊人地一致,高度几乎没有变化。
  2. 当地时间下午 5:00 为每个好友记录了最多的在线好友数量。
  3. 凌晨 4:00 记录的在线好友数量最低(可能是因为大多数好友都在睡觉)。

我们还可以绘制一个条形图,显示一周中不同日子的平均在线时间。

Fig 3: Average number of hours spent online for each day of the week

  • 朋友们平均每天在脸书呆 3.5 个小时。
  • 周六和周一被发现是一周中最忙的一天,同时也是上网时间最多的一天。

如本节开头所述,出于某些原因,每个用户都被视为基于其当地时间在线。但是,如果我们想知道一天中最大限度地扩大帖子覆盖范围和浏览量的最佳时间,这可能会产生误导性的统计数据。

让我们根据我的时区(恰好是中欧时间)调整每个朋友的时区,然后绘制一天中在线朋友的数量图,以确定一天中发布新帖子的最佳时间。

Figure 4: Number of online friends over the day for whole week (relative to my local time)

到目前为止,我们只使用了用户的汇总数据,但是个人朋友的在线活动呢?我们能从中获得什么样的见解?

假设用户倾向于把查看脸书作为晚上的最后一件事,也是早上的第一件事,我们可以发现在脸书上不活跃的一些非常一致的模式,这表明用户正在睡觉。

让我们画出我的一个朋友的睡眠模式。从图 5 中可以观察到,我的朋友从午夜 12:00 到早上 9:00 平均每天睡眠 6.5 小时,非常规律。

Figure 5: Sleep times of a particular user over days

仅通过可视化一天中用户在线/离线的时间,就可以很好地估计用户的睡眠模式。

很有趣,不是吗?嗯,这是 迷人的 同时也是 令人担忧的 ,让我们意识到这么小的一条信息能透露多少关于我们日常生活的信息。

这些都是通过分析脸书朋友的在线活动得出的见解。如果您有兴趣了解如何使用 Python 创建本节中呈现的图表,可以继续阅读下一节。否则,你可能会有兴趣阅读【即将推出】分析社交网络图。

使用 Python 可视化脸书朋友的在线活动

先决条件:

  1. Python 3.5
  2. 钟摆
  3. Matplotlib
  4. Numpy

为了简单和隐私起见,我不会在这里展示我朋友的真实数据。在本教程中,我们将使用具有相同结构的样本虚拟数据

让我们看看数据集的结构。收集的数据集是一个简单的字典列表,其中包含“在线朋友列表”“时间戳”(当列表被获取时),作为 JSON 存储在一个文件中。**

*[
    {
        "timestamp": "2019-05-14T08:12:52.313921+02:00",
        "friends": [
            "John Doe",
            "John Roe"
        ]
    },
    {
        "timestamp": "2019-05-14T08:13:49.449888+02:00",
        "friends": [
            "Jane Roe",
            "Jane Doe"
        ]
    },
    ...
    ...
]*

加载数据

让我们加载样本数据并执行一些初始处理:

上面的代码将为我们提供“时间戳”,这是一个(friend_name,times)对的 Python 字典,其中 times 是一个列表,其中的pendulum . datetime对象表示特定朋友在线时记录的时间戳。

下一步是将 dict 转换成嵌套的 dict,每个朋友的时间戳按天分组。下面的代码可以做到这一点:

上述代码执行以下操作:

  1. 它按照唯一的日期对每个朋友的 pendulum.datetime 对象列表进行分组,并将其转换为(day,times)对的字典,其中 times 是按时间顺序排列的时间戳列表。
  2. 创建一个名为“activities”的嵌套有序字典,其中包含一个嵌套字典对(day,times)。

结果是以下格式的嵌套字典:

*{
    "Jane Roe": {
        "We 15/05/19": [DateTime,...,],
        "Th 16/05/19": [DateTime,...,]
    },
    "Jane Doe": {
        "We 15/05/19": [DateTime,...,],
        "Th 16/05/19": [DateTime,...,]
    },
    ...
}*

给定上面的字典,我们想要做的是创建一个二进制地图来表示每个朋友每天的在线状态。就这么办吧。

如果您觉得它看起来吓人,请不要担心,我还在代码片段后提供了代码摘要。

上面的代码实质上是将每个朋友每天的时间戳列表转换成一个二进制映射,1 表示在线,0 表示离线,时间间隔为 5 分钟,时间间隔为一天 24 小时。它执行以下操作:

  1. 一天创建 289 个垃圾箱。每个时间戳被放入适当的容器中(但是不计算频率)。
  2. 创建一个名为 online_maps 的 shape (4,2,289)的 Numpy 数组,因为有 4 个朋友和 2 天。创建阵列的日期按时间顺序排列。

为了熟悉箱的概念,假设我们将一天分成 24 个部分/间隔,即箱,每小时一个部分。如果用户在从午夜 12:00 到凌晨 1:00 的任何时间在线,我们将把第一个 bin 的值设置为 1,否则为 0。对所有 24 个时间间隔执行此操作将产生一个整数列表(我们称之为二进制映射,因为每个整数的值为 0 或 1 ),表示一天中每个小时用户在线或离线的状态。

我们现在有一个非常好的数据格式,即每个朋友几天的活动地图。让我们使用格式化的数据绘制一些图表。

绘图活动状态

我们可以画出一个朋友在不同日子不同时间的在线活动。下面的代码描绘了数据中第一个朋友的活动。

这将绘制下图,其中蓝色竖线表示在线,不在线表示离线。

Figure 6: Online status of a friend across different days of the week

有趣到目前为止?

让我们绘制另一个图表,在这个图表中,我们可以看到一天中不同时间的在线好友总数。

在线好友的数量

通过计算 online_maps 数组第一维的总和,我们可以得到一天中在线的朋友数量,即朋友数量:

*>>> online_count = np.sum(online_maps, axis=0)
>>> print(online_count.shape)
(2, 289)*

下面的代码绘制了一个折线图,显示不同日子在线的朋友数量。为了视觉效果,我们也将高斯平滑应用于每条曲线。

运行上面的代码会产生下面的图:

Figure 7: No. of online friends of different hours of multiple days in the week

利用这组简单的信息,我们还可以做更多的事情(其中一些我将在本系列的后面部分讨论),但是本教程应该可以帮助您从基础开始。本帖完整代码的 Jupyter 笔记本可以在这里找到。

我希望这篇文章对你的工作和研究有所帮助。如果你有任何问题,欢迎在下面写评论。

阅读相关故事:

  1. 抓取你脸书朋友的数据
  2. 分析在线活动和睡眠模式
  3. ****【即将推出】:分析我的社交网络图

分析招聘数据

原文:https://towardsdatascience.com/analyzing-recruiting-data-4bf6c580f0a9?source=collection_archive---------50-----------------------

无需提及统计学或机器学习就能获得洞察力

Photo by Clem Onojeghuo on Unsplash

上周,我发现自己在和一位同事谈论我们多年来参与的各种分析项目。不用说,对话冒险进入了复杂的统计分析、技术术语和超级有趣的发现的兔子洞。在谈话结束时,我肯定会提起我几年前进行的一项具体分析,该分析揭示了一系列可操作的见解,但没有提到统计意义。没有提到相关或混淆矩阵。没有提到张量流或递归神经网络。

搭建舞台

大约两年前,我的一个朋友参加了一个 SuccessFactors 会议,会上我展示了 SuccessFactors 平台自带的分析工具的强大功能。会议结束后,他吸引了我几分钟的注意力,问我是否可以帮助他解决他遇到的招聘问题。尽管尽了最大努力,他还是很难将高潜力的候选人转化为雇员。这个问题是短期公司战略的一个重大障碍,因为随着公司准备进入一个新产品市场,它需要多样化的技能组合。我已经让他把他的数据发过来,我会看一看。

分析/结果

收到数据后,我决定将招聘过程分成三个独立的部分;申请、申请人和征用。

应用程序

首先,我通过得出“申请完成率”、“申请退出率”和“完成申请的平均时间”等指标来检查申请流程。令我惊讶的是,完成率超过 80%,脱落率极低,提交申请平均需要 3 分钟。问题当然不在于申请过程。

申请人

接下来,我把注意力转向了申请人。哪些来源推动了申请人群体?哪些来源产生了高质量的申请人?拥有庞大的申请人才库大大增加了聘用高质量候选人的可能性。分析的结果产生了混合的结果,因为申请人才库是足够的,但高度倾斜。17 个候选来源中的 3 个驱动了 80%的申请人和大多数优质申请人(即进入招聘经理面试阶段的候选人)。这些结果并不一定会给我指出任何可能解决潜在招聘问题的方向,但我发现了潜在的效率和成本节约因素。这些较小的见解在数据挖掘实践中非常常见。

征用

接下来,我开始更仔细地分析征用数据。首先,我检查了完成一个申请平均需要多长时间(完成时间定义为申请完成日期—申请发布日期)。我特别关注技术需求,因为它们对业务战略有最直接的影响。令我惊讶的是,填写一份申请表平均需要 50 多天。需求与头寸的 1:1 比率)这一指标在过去六个月中没有逐月波动。更令人不安的是,同一时期的招聘率低于 5%。这些结果肯定证实了我朋友提出的担忧,但是是什么导致了这些问题呢?在需求技术候选人往往可以有两个或三个报价,时间是至关重要的。我发现这家公司雇佣了 8 名招聘人员,他们管理着 15 到 25 个职位需求,这不一定是很大的工作量,但是当时间非常重要时,这肯定是问题的一部分。

我把注意力集中在招聘过程本身,以更好地理解是什么导致了如此激烈的时间填补时代。通过候选人漏斗分析,我发现了一个 12 步招聘流程!在候选人进入“评估”阶段之前,阶段之间的候选人退出率和阶段中的平均时间都在正常范围内。在进入这一阶段的候选人中,只有 4%的人进入了下一阶段“创建录用通知”。此外,绝大多数被处分的候选人都自愿终止了申请过程!审查阶段的平均时间从候选人被评估到进入“创建录用通知”阶段平均需要 16 天,实际收到录用通知又需要 6 天。我发现了影响招聘对话率的最后一块拼图。

推荐

最终的罪魁祸首是候选人的满意度。招聘人员不得不处理太多的申请,这意味着他们对候选人的数量负担过重。雇佣更多精通技术的招聘人员可以分散工作量,让候选人更快地接受面试,最终让他们更高效地通过面试。此外,我建议改进申请流程,以减少候选人在获得聘用之前必须经历的阶段。这将加快招聘过程,而不会显著影响候选人的质量。为招聘人员提供培训和标准化的行为评估将有助于消除选拔过程中的偏见,产生质量相似的候选人,并加快候选人的选拔过程。接下来,我建议详细审查聘用创建工作流程,以简化流程并减少候选人收到聘用的天数。最后,出于节约成本的考虑,我建议公司进一步检查来源预算分配,因为绝大多数候选人都来自少数来源。最有效的来源渠道之一,推荐,并没有得到充分利用。

拿走

我们经常偶然发现一些鼓舞人心的文章,这些文章讲述了一些公司利用先进的技术和统计知识来获得对组织产生巨大影响的见解。其中一些分析所需的知识、技能和大量数据简直令人难以置信。这并不意味着不能从单一数据源和使用 Microsoft excel 的精明分析师那里收集可操作的见解。对数据、度量设计、技术诀窍和问题的背景知识有敏锐的理解会大有帮助。

Youtube 数据上的文本分类技术分析

原文:https://towardsdatascience.com/analyzing-text-classification-techniques-on-youtube-data-7af578449f58?source=collection_archive---------13-----------------------

文本分类是自然语言处理所要解决的一个经典问题,它指的是分析原始文本的内容并确定其所属的类别。这类似于有人读了罗宾·夏尔马的书,把它归类为‘垃圾’。它有广泛的应用,如情感分析,主题标记,垃圾邮件检测和意图检测。

今天,我们将进行一项相当简单的任务,使用不同的技术(朴素贝叶斯、支持向量机、Adaboost 和 LSTM)并分析其性能,根据视频的标题和描述将视频分类为不同的类别。这些类别被选择为(但不限于):

  • 旅游博客
  • 科学与技术
  • 食物
  • 制造业
  • 历史
  • 艺术和音乐

事不宜迟,就像一个刚刚开始园艺的中年父亲会说,“让我们把手弄脏吧!”。

收集数据

当处理像这样的定制机器学习问题时,我发现收集自己的数据非常有用,如果不是简单地令人满意的话。对于这个问题,我需要一些关于属于不同类别的视频的元数据。如果你有点笨,我欢迎你手动收集数据并构建数据集。然而我不是,所以我会用 Youtube API v3 。它是由谷歌自己创建的,通过一段专门为我们这样的程序员编写的代码与 Youtube 进行交互。前往谷歌开发者控制台,创建一个示例项目并开始。我选择这样做的原因是,我需要收集成千上万的样本,我发现使用任何其他技术都不可能做到这一点。

注意:Youtube API,像谷歌提供的任何其他 API 一样,基于配额系统工作。根据你的计划,每封邮件每天/每月都有固定的配额。在我的免费计划中,我只能向 Youtube 发出大约 2000 次请求,这造成了一点问题,但我通过使用多个电子邮件帐户克服了这个问题。

API 的文档非常简单,在使用了超过 8 个电子邮件帐户来补偿所需的配额后,我收集了以下数据并将其存储在一个. csv 文件中。如果你想在你的项目中使用这个数据集,你可以在这里 下载

Collected Raw Data

注意:你可以自由探索一种被称为网络抓取的技术,它被用来从网站中提取数据。Python 有一个名为 BeautifulSoup 的漂亮库用于同样的目的。然而,我发现在从 Youtube 搜索结果中抓取数据的情况下,对于一个搜索查询,它只返回 25 个结果。这对我来说是一个障碍,因为我需要大量的样本来创建一个准确的模型,而这并不能解决问题。

数据清理和预处理

我的数据预处理过程的第一步是处理丢失的数据。因为丢失的值应该是文本数据,所以没有办法估算它们,因此唯一的选择是删除它们。幸运的是,在总共 9999 个样本中,只存在 334 个缺失值,因此它不会影响训练期间的模型性能。

“视频 Id”列对于我们的预测分析并不真正有用,因此它不会被选为最终训练集的一部分,所以我们没有任何预处理步骤。

这里有 2 个重要的栏目,即— 标题描述,但它们都是未经加工的原文。因此,为了过滤掉噪声,我们将遵循一种非常常见的方法来清理这两列的文本。这种方法分为以下几个步骤:

  1. 转换成小写:执行这一步是因为大写对单词的语义重要性没有影响。“travel”和“Travel”应该被同等对待。
  2. 删除数值和标点:数值和标点中使用的特殊字符($,!等等。)无助于确定正确的类别
  3. 删除多余的空格:这样每个单词都由一个空格分隔,否则在标记化过程中可能会出现问题
  4. 记号化成单词:这指的是将一个文本串分割成一个“记号”列表,其中每个记号是一个单词。例如,句子“我有巨大的二头肌”将转换为[“我”、“有”、“巨大”、“二头肌”]。
  5. 去除非字母单词和“停用词”:“停用词”指的是 and、the、is 等单词,这些单词在学习如何构造句子时很重要,但对我们的预测分析没有用处。
  6. 词汇化:词汇化是一种非常棒的技术,可以将相似的单词转换成它们的基本含义。例如,单词“flying”和“flyed”都将被转换成它们最简单的意思“fly”。

Dataset after text cleaning

“现在文字干净了,万岁!让我们开一瓶香槟庆祝吧!”

不,还没有。即使今天的计算机可以解决世界问题,玩超逼真的视频游戏,但它们仍然是不懂我们语言的机器。因此,我们无法将文本数据原样提供给我们的机器学习模型,无论它有多干净。因此,我们需要将它们转换成基于数字的特征,这样计算机就可以构建一个数学模型作为解决方案。这就构成了数据预处理步骤

Category column after LabelEncoding

由于输出变量(' Category ')也是分类的,我们需要将每个类编码为一个数字。这叫做标签编码

最后,让我们关注一下每个样本的主要信息—原始文本数据。为了从文本中提取数据作为特征并以数字格式表示它们,一种非常常见的方法是将它们矢量化。Scikit-learn 库包含用于此目的的“TF-IDF 矢量器”。 TF-IDF (词频-逆文档频率)计算每个词在多个文档内部和跨文档的频率,以识别每个词的重要性。

数据分析和特征探索

作为一个额外的步骤,我决定显示类的分布,以便检查样本数量的不平衡。

此外,我想检查使用 TF-IDF 矢量化提取的特征是否有意义,因此我决定使用标题和描述特征为每个类找到最相关的单字和双字。

# USING TITLE FEATURES# 'art and music':
Most correlated unigrams:
------------------------------
. paint
. official
. music
. art
. theatre
Most correlated bigrams:
------------------------------
. capitol theatre
. musical theatre
. work theatre
. official music
. music video# 'food':
Most correlated unigrams:
------------------------------
. foods
. eat
. snack
. cook
. food
Most correlated bigrams:
------------------------------
. healthy snack
. snack amp
. taste test
. kid try
. street food# 'history':
Most correlated unigrams:
------------------------------
. discoveries
. archaeological
. archaeology
. history
. anthropology
Most correlated bigrams:
------------------------------
. history channel
. rap battle
. epic rap
. battle history
. archaeological discoveries# 'manufacturing':
Most correlated unigrams:
------------------------------
. business
. printer
. process
. print
. manufacture
Most correlated bigrams:
------------------------------
. manufacture plant
. lean manufacture
. additive manufacture
. manufacture business
. manufacture process# 'science and technology':
Most correlated unigrams:
------------------------------
. compute
. computers
. science
. computer
. technology
Most correlated bigrams:
------------------------------
. science amp
. amp technology
. primitive technology
. computer science
. science technology# 'travel':
Most correlated unigrams:
------------------------------
. blogger
. vlog
. travellers
. blog
. travel
Most correlated bigrams:
------------------------------
. viewfinder travel
. travel blogger
. tip travel
. travel vlog
. travel blog# USING DESCRIPTION FEATURES# 'art and music':
Most correlated unigrams:
------------------------------
. official
. paint
. music
. art
. theatre
Most correlated bigrams:
------------------------------
. capitol theatre
. click listen
. production connexion
. official music
. music video# 'food':
Most correlated unigrams:
------------------------------
. foods
. eat
. snack
. cook
. food
Most correlated bigrams:
------------------------------
. special offer
. hiho special
. come play
. sponsor series
. street food# 'history':
Most correlated unigrams:
------------------------------
. discoveries
. archaeological
. history
. archaeology
. anthropology
Most correlated bigrams:
------------------------------
. episode epic
. epic rap
. battle history
. rap battle
. archaeological discoveries# 'manufacturing':
Most correlated unigrams:
------------------------------
. factory
. printer
. process
. print
. manufacture
Most correlated bigrams:
------------------------------
. process make
. lean manufacture
. additive manufacture
. manufacture business
. manufacture process# 'science and technology':
Most correlated unigrams:
------------------------------
. quantum
. computers
. science
. computer
. technology
Most correlated bigrams:
------------------------------
. quantum computers
. primitive technology
. quantum compute
. computer science
. science technology# 'travel':
Most correlated unigrams:
------------------------------
. vlog
. travellers
. trip
. blog
. travel
Most correlated bigrams:
------------------------------
. tip travel
. start travel
. expedia viewfinder
. travel blogger
. travel blog

建模和培训

我们将分析的四个模型是:

  • 朴素贝叶斯分类器
  • 支持向量机
  • Adaboost 分类器
  • LSTM

数据集被拆分为训练集和测试集,拆分比例为 8:2。标题和描述的特征被独立计算,然后被连接以构建最终的特征矩阵。这用于训练分类器(除了 LSTM)。

对于使用 LSTM,数据预处理步骤与前面讨论的非常不同。这是它的流程:

  1. 将每个样本的标题和描述组合成一个句子
  2. 将组合句子标记为填充序列:将每个句子转换为标记列表,为每个标记分配一个数字 id,然后通过填充较短的序列并截断较长的序列,使每个序列具有相同的长度。
  3. 对“Category”变量进行一次性编码

LSTM 的学习曲线如下所示:

LSTM Loss Curve

LSTM Accuracy Curve

分析性能

以下是所有不同分类器的精度-召回曲线。要获得额外的指标,请查看 完整代码

在我们的项目中观察到的每个分类器的等级如下:

LSTM > SVM >朴素贝叶斯> AdaBoost

LSTMs 在自然语言处理的多个任务中表现出了优异的性能,包括这个任务。LSTMs 中多个“门”的存在允许它们学习序列中的长期依赖性。深度学习 10 分!

支持向量机是高度鲁棒的分类器,它们尽最大努力寻找我们提取的特征之间的相互作用,但是学习到的相互作用与 LSTMs 不一致。另一方面,朴素贝叶斯分类器认为特征是独立的,因此它的性能比支持向量机稍差,因为它没有考虑不同特征之间的任何交互作用。

AdaBoost 分类器对超参数的选择非常敏感,因为我使用了默认模型,所以它没有最佳参数,这可能是性能差的原因

我希望这对你和对我一样有益。完整的代码可以在我的 Github 上找到。

[## agrawal-rohit —概述

拥有 3 年以上项目工作经验的初级数据科学家和软件开发人员。高度熟练的机器…

github.com](https://github.com/agrawal-rohit)

再见

使用熊猫分析疾病控制中心(CDC)的癌症数据,第 1 部分

原文:https://towardsdatascience.com/analyzing-the-center-for-disease-control-cdc-cancer-data-using-pandas-part-1-64e30fdeb1fb?source=collection_archive---------37-----------------------

Photo by Miguel Á. Padriñán on Pexels

虽然癌症药物开发和治疗的研究多年来取得了进展,但癌症每年仍夺去成千上万人的生命。尽管如此,随着对数据的访问、计算能力和最先进的机器学习工具的增加,癌症研究进展的潜力继续增长。

在本帖中,我们将探索疾病控制中心癌症数据集。该数据集包括脑瘤、各州癌症类型、种族、年龄等信息。在这篇文章中,我们将探索“大脑旁站点”。' TXT '数据。

我们从导入熊猫图书馆和阅读开始。TXT '文件转换成熊猫数据帧。每一列都用“|”分隔,所以我们也适当地设置分隔参数“sep”。我们还可以指定需要分析的列,并显示前五行数据,以了解列类型和值:

df = pd.read_csv("BRAINBYSITE.TXT", sep="|")
df = df[['AGE', 'BEHAVIOR', 'COUNT', 'POPULATION', 'SEX', 'YEAR', 'SITE"]]
print(df.head())

“计数”列包含一些我们可以删除的缺失值:

df = df[df['COUNT'] != '~']
df.reset_index(inplace=True)
print(df.head())

为了开始我们的分析,我们可以生成“计数”列的直方图,以可视化所有类别的肿瘤分布:

import seaborn as sns
import matplotlib.pyplot as plt#settings for the histogram plot
sns.set(font_scale = 2)
plt.ylim(0, 80)
plt.xlim(0, 10000)df['COUNT'] = df['COUNT'].astype(int)
df['COUNT'].hist(bins=1000)

Distribution in Tumor Counts

我们还可以在重叠图上查看女性和男性肿瘤数量的直方图:

#define female and male data frames
df_female = df[df['SEX'] == 'Female']
df_male = df[df['SEX'] == 'Male']#overlay histograms
df_female['COUNT'].hist(bins=1000)
df_male['COUNT'].hist(bins=1000).set_title('Male and Female')

Overlay of distributions in tumor counts for males and females

我们可以进行更细致的分析,观察给定年份(假设“年份”=2004 年)女性和男性的肿瘤数量分布:

df_female = df[df['SEX'] == 'Female']
df_female = df_female[df_female['YEAR'] ==  '2012-2016']
df_female.loc[:, 'COUNT'] = df_female['COUNT'].astype(int)
df_female['COUNT'].hist(bins=1000).set_title('Female ')

Distribution in tumor counts for females between 2012–2016

df_male = df[df['SEX'] == 'Male']
df_male = df_male[df_male['YEAR'] == '2012-2016']
df_male.loc[:, 'COUNT'] = df_male['COUNT'].astype(int)
df_male['COUNT'].hist(bins=1000).set_title('Male')

Distribution in tumor counts for males between 2012–2016

接下来,我们可以生成“原油价格”与“年份”的散点图。在这里,我们还将调整散点图点的大小,以便大小和色调与“计数”成比例。我们还过滤数据帧以获得对应于 0.1 以上的“部位”=“间变性星形细胞瘤”、“行为”=“恶性”和“粗制率”的行。对于女性,我们有:

df_female = df[df['SEX'] == 'Female']
df_female = df_female[df_female['SITE'] == 'Anaplastic astrocytoma']
df_female = df_female[df_female['BEHAVIOR'] == 'Malignant']#remove baseline value present in each year
df_female = df_female[df_female['CRUDE_RATE'] > 0.1]sns.scatterplot(df_female["YEAR"], df_female["CRUDE_RATE"], sizes = (1000, 1500), size =  df_female["COUNT"], alpha = 0.8,hue = df_female["COUNT"])

Scatter plot of ‘CRUDE_RATE’ vs ‘YEAR’ of Anaplastic astrocytoma in females

我们也可以看看这个雄性的图:

df_male = df[df['SEX'] == 'Male']
df_male = df_male[df_male['SITE'] == 'Anaplastic astrocytoma']
df_male = df_male[df_male['BEHAVIOR'] == 'Malignant']#remove baseline value present in each year
df_male = df_male[df_male['CRUDE_RATE'] > 0.1]
sns.scatterplot(df_male["YEAR"], df_male["CRUDE_RATE"], sizes = (1000, 1500), size =  df_male["COUNT"], alpha = 0.8,hue = df_male["COUNT"])

Scatter plot of ‘CRUDE_RATE’ vs ‘YEAR’ of Anaplastic astrocytoma in males

如你所见,2004 年至 2016 年间,女性和男性间变性星形细胞瘤的粗发病率都有所上升。还值得注意的是,男性患这种脑瘤的比率高于女性。尝试生成其他肿瘤类型的散点图,看看女性和男性之间是否有任何有趣的差异。

接下来,我们可以从这些数据列中生成一些统计数据。我们可以定义一个函数,输出分类变量的唯一值集,并计算该值在数据中出现的次数:

from collections import Counter
def get_unqiue_values(feature):
    print("{} Unique Set: ".format(feature), set(df[feature]))
    print("{} Count: ".format(feature), dict(Counter(df[feature])))get_unqiue_values('SEX')

当我们使用“性别”字段调用“get_unqiue_values”函数时,输出显示每个“性别”类别的唯一值列表以及每个值在数据中出现的次数。

Uniques set of ‘SEX’ values and their frequencies

我们可以对“行为”做同样的事情:

get_unqiue_values('BEHAVIOR')

输出是“行为”类别的唯一值的列表,以及每个值在数据中出现的次数。

Uniques set of ‘BEHAVIOR’ values and their frequencies

对于“站点”类别:

get_unqiue_values('SITE')

输出显示了“SITE”列的唯一值列表以及每个值在数据中出现的次数。

Unique set of ‘SITE’ values and their frequencies

与该数据集中的其他分类变量相比,存在相对更多的唯一“位置”值。我们可以通过查看五个最常见(最频繁出现)的值来缩小范围:

from collections import Counter
def get_unqiue_values(feature):
    print("{} Unique Set: ".format(feature), set(df[feature]))
    print("{} Count: ".format(feature), dict(Counter(df[feature]).most_common(5)))
get_unqiue_values('SITE')

Most common ‘SITE’ values

将这些数据可视化可能比盯着字典更有用一些。为此,我们可以更新函数“get_unqiue_values ”,使其返回 10 种最常见脑瘤的字典:

def get_unqiue_values(feature):
    print("{} Unique Set: ".format(feature), set(df[feature]))
    print("{} Count: ".format(feature), dict(Counter(df[feature]).most_common(5)))
    result = dict(Counter(df[feature]).most_common(10))
    return result

接下来,我们迭代“站点”频率字典,并将键和值存储在数据框中:

key_list = []
value_list = []
for key, value in get_unqiue_values('SITE').items():
    key_list.append(key)
    value_list.append(value)
site_df = pd.DataFrame({'SITE': key_list, 'Count':value_list} )

最后,我们使用 seabon 定义一个条形图对象,并设置 x 轴标签:

ax = sns.barplot(x=site_df.SITE, y=site_df.Count)
ax.set_xticklabels(site_df.SITE, rotation=30)

The frequency of tumor types

在‘BRAINBYSITE’有更多值得探索的地方。TXT '数据,但现在我们将结束我们的分析。在接下来的几篇文章中,我将继续探索疾病控制中心癌症数据集中提供的一些其他数据集。在那之前,你可以自己在其他数据集上重复这个分析。这篇文章中显示的代码可以在 GitHub 上找到。祝好运,机器学习快乐!

分析美国地震以确定可能的地震风险。

原文:https://towardsdatascience.com/analyzing-the-earthquakes-in-usa-to-determine-the-possibly-risky-to-quakes-hotels-2a9ff162e747?source=collection_archive---------14-----------------------

Photo by Sunyu Kim on Unsplash

曾经想过,如果有一个预测系统,可以在地震袭击我们脚下的地面之前准确地预测地震,死亡人数和几座摩天大楼、住宅、酒店的破坏将大幅减少,因此我们可以逃离自然的最大灾难之一,地震将不再成为一个人死亡的原因。

假设,你去了美国太平洋沿岸的一个海滨城市,并入住了一家酒店。现在,你正在欣赏海景,突然你感觉到一个脆弱的震动,酒店,可能是一座摩天大楼像玩具一样倒塌了,现在你想知道如果你知道在这些地震严重的地方哪些酒店需要仔细检查和升级抗震设备,你不会只受用户评级的影响而选择这家酒店入住。

但是,通过当今非常强大的数据科学工具的进步,有可能确定发生地震的可能性很高的地方,通过那个地方,人们可以很容易地获取附近商业场所的数据,包括商业场所、公寓或任何东西,以测量风险因素和结构强度,为它们配备抗震设备并升级它们,从而确保居民和游客的安全。

那么,我们要做什么?高层次概述:

所以,现在,问题对我们来说是清楚的。我们需要分析地震记录,必须确定地震发生率较高的地点,并确定因其位置而可能处于危险中的酒店。考虑到这个问题,让我们采取有条不紊的方法来解决这个问题。我们将按照约翰·罗林斯博士提出的方法来解决这个问题。

首先,让我们从某个数据提供商那里获取一个包含美国地震数据的数据集,开始处理这些数据。在获取阶段完成后,让我们继续清理获取的数据集,方法是删除不必要的列,用有意义的内容替换空值或无效值,并通过用不规则范围规范化值来使所有列同等重要。

现在我们分析数据框的不同列以及它们与其他列的关系。简而言之,为了便于分析,我们现在试图找到列值之间的关系。在这个过程中,我们使用了几个 Python 可视化库和包来支持我们的发现。

现在,我们对整个数据框进行分组,以搜索出现频率独特的位置。

接下来,我们将继续收集记录地震事件最频繁的地方的地理编码纬度和经度。我们将把这个纬度和经度数据传递给我们的街道级信息提供程序,以获取一个包含不同商业场所信息的结果集,包括记录的场所附近的酒店信息。

选择地震和街道级数据提供商并请求数据:

在我们深入分析之前,我们需要大量的数据和信息。在数据科学领域,选择可靠且价格合理的数据提供商是至关重要的。我们必须确保提供给我们的数据是高效、可靠、使用灵活、可修改和定制的。事实上,如果是人工审核,而不是自动生成,准确性和可靠性会提高。

所以,考虑到所有的事情,我决定和美国地质调查局(USGS)一起收集地震数据。 USGS 提供了非常直观、易用、可靠的 API 和 web 门户服务,在输出格式、指定感兴趣的区域等方面提供了灵活性。美国地质勘探局是一个政府运营的研究中心,他们提供的数据是免费的,非常可靠,因为大多数数据在注册前都经过了人工审查。API 请求链接不需要任何身份验证。

因此,我们指定我们感兴趣的地区为美国,选择我们感兴趣的时间段为 2010 年至 2019 年,输出格式为逗号分隔值(CSV ),然后点击搜索以获得结果。我们可以使用 API 来请求数据。请求 URL 的格式如下所示。

import requests
usgs_request_url = ‘[https://earthquake.usgs.gov/fdsnws'](https://earthquake.usgs.gov/fdsnws')
usgs_request_url+=’/event/1/query.geojson?starttime=2010–04–20%2000:00:00&endtime=2019–04–27%2023:59:59'
usgs_request_url+=’&maxlatitude=50&minlatitude=24.6&maxlongitude=-65&minlongitude=-125&minmagnitude=2.5&orderby=time&limit=2000'requests.get(usgs_request_url).json()
requests

我已经下载了一个格式化的 CSV 数据框架来使用。可以按照链接:https://S3 . Amazon AWS . com/swastiknath group/seismic _ results . CSV下载文件,在自己的笔记本或其他任何 python 环境下使用。

获取数据后,我们使用 pd.read_csv()函数从 CSV 文件创建一个 Pandas Dataframe,并使用 pd.drop()函数删除所有不必要的列,该函数提供要作为 list 对象删除的列,作为 drop 函数的输入参数。

我还决定使用 Foursquare API 来获取美国各地商业场所的街道信息,包括我感兴趣的地方。他们的 API 使用起来非常便宜,有很好的文档记录并且可靠。每次连接到 Foursquare 服务器并请求数据时,您都必须验证您的 API 请求 URL。身份验证的格式如下:

#credentials for communicating with Foursquare API:
CLIENT_ID= 'your client id'
CLIENT_SECRET = 'your client secret'
VERSION = integer date of version.

一旦我们提取完地震数据,我们将定义一个 python 函数,将 USGS 地震数据集返回的纬度和经度列表作为输入,并使用该数据搜索易受地震影响的地方附近的酒店。自定义函数 whats _ nearby 也从 JSON 响应和 Pandas 数据框中检索数据,以更好地表示这些值。

#custom function for requesting street-level business information #from foursquarefrom progressbar import ProgressBar, Bar, Percentage
pbar = ProgressBar(widgets=[Percentage(), Bar()], maxval=300).start()

import requests
def whats_nearby(latitudes, longitudes, radius = 15000):
  nearby_places_list1 = []

  status = 'EXECUTION STARTED, PLEASE WAIT ->'
  for lat, lng in zip(latitudes, longitudes):
    for i in range(len(latitudes)):
        pbar.update(i+1)
    pbar.finish()
    query_url = '[https://api.foursquare.com/v2/venues/search?&query=hotel&client_id={}&client_secret={}&v={}&ll={},{}&radius={}&limit={}'.format(](https://api.foursquare.com/v2/venues/search?&query=hotel&client_id={}&client_secret={}&v={}&ll={},{}&radius={}&limit={}'.format()
            CLIENT_ID,                       
            CLIENT_SECRET, 
            VERSION, 
            lat, lng, 
            15000, 
            100)
    response = requests.get(query_url).json()['response']['venues']

    nearby_places_list1.append([(r['name'], 
                          r['location']['lat'], 
                          r['location']['lng'],
                          r['location']['formattedAddress']) for r in response])
  vulnerable_places = pd.DataFrame(item for nearby in nearby_places_list1 for item in nearby)
  vulnerable_places.columns = ['Venue', 'Venue Latitude', 'Venue Longitude', 'Address']

  return vulnerable_places

分析变量和它们之间的关系曲线:

现在让我们尝试理解特征集的变量之间的关系,以理解单个变量对地震测量的影响。

想象一下,尽管机器学习、监督、非监督和深度强化学习过程取得了很大进步,但是什么一直在机器学习模型和完全准确的地震预测之间建立障碍?自然和由自然生成的数据是非常不规则的,并且不能被精确地映射成数学关系,尽管自然的每个元素都是由算法驱动的,但是它们理解起来非常非常复杂,并且对于机器学习模型来说是不规则的、不可靠的。每个训练有素的机器学习模型都试图以最简单的方式将特征集与目标细胞进行映射。我们建立了一个深度神经网络来正确预测地震,但仍然没有预期的那么好。

让我们想象一下地震能量波的均方根速度与震级之间的关系。我们使用 Seaborn 包,它是基于 Matplotlib 构建的,可以自动生成具有最高可信度的线性回归图。这是一个很大的特点,它根据回归线显示了曲线的偏差。在均方根与幅度的关系中,我们看到两者之间存在线性关系,尽管线的两侧存在极小的偏差。由于自然的不规则性,这些偏差可以忽略。

sns.regplot(x= earth_quake_encoded['rms'], y= earth_quake_encoded['mag'], data = earth_quake_encoded, color = 'purple')

Regression plot between Root Mean Square Speed and Magnitude

现在,让我们想象地震波破裂的深度与震级之间的关系。由于自然的不规则性导致的偏差量很小的回归线。

import seaborn as sns
reg_plot_depth_mag = pd.DataFrame(columns =['Depth', 'Magnitude'])
reg_plot_depth_mag['Depth'] = earth_quake_encoded['depth'].values
reg_plot_depth_mag['Magnitude'] = earth_quake_encoded['mag'].valuessns.regplot(x=reg_plot_depth_mag['Depth'], y = reg_plot_depth_mag['Magnitude'], data = reg_plot_depth_mag, color = 'blue')

Regression plot between Magnitude and Depth.

现在是时候将从记录到震中的水平距离与震级之间的关系曲线可视化了。回归图显示了具有高偏差的线性回归线,基本上意味着两个变量之间的非线性。

sns.regplot(x= earth_quake_encoded['dmin'], y = earth_quake_encoded['mag'], data = earth_quake_encoded, color = 'crimson')

Regression plot between Horizontal distance vs. Magnitude

现在让我们通过可视化来验证数据集。让我们看一下测量星等误差与星等之间的散点图,以获得对数据集的信心,我们决定也绘制回归线。结果是我们所期望的。回归线就其斜率而言是负的,并且具有最小的偏差,这确实意味着,如果测量量值的误差增加,则实际量值减小。

sns.regplot(x = earth_quake_encoded['magError'], y=earth_quake_encoded['mag'], color = 'orange')

Negative Regression plot between Magnitude and error in measuring magnitude

我们现在想看一下时间框架,基本上是相对于时间连续绘制震级。我们使用 Pandas Series.from_csv 创建一个系列对象,并使用 Matplotlib 的 pyplot 脚本层直接绘制它。在绘制之前,我们确保正确理解了每一列的数据类型。脚本层足够智能,可以相对于选定的时间段以较小的比例(为了更好的可视化)绘制幅度。

time_vs_mag_bar = pd.DataFrame(columns = {'time', 'mag'})
time_vs_mag_bar['time'] = usa_earthquakes['time']
time_vs_mag_bar['mag'] = usa_earthquakes['mag']
time_vs_mag_bar.to_csv('time_vs_mag.csv')dates = mpl.dates.date2num(time_vs_mag_bar['time'].values)
plt.plot_date(dates, usa_earthquakes['mag'])

Time-frame representation of magnitude vs. time

from pandas import Series
series = Series.from_csv('usa_earth_quakes.csv', header=0)
series.plot(style='-')
plt.show()

Pandas Series plotting of continuous time-frame plotting of magnitude(in a smaller scale) vs. time.

我们现在希望在三维空间中可视化数据集,以便更好地反映沿每个轴的变化。因此,我们使用 Matplotlib 的 mpl_toolkits.mplot3d 包的 Axes3D 函数绘制深度、均方根、震级和记录站之间的角度间隙、记录事件所需的站数和震级的三维示意图。

from mpl_toolkits.mplot3d import Axes3D
fig = plt.figure(figsize = (8, 6))
ax = fig.add_subplot(111, projection = '3d')
ax.set_xlabel('Depth')
ax.set_ylabel('RMS')
ax.set_zlabel('Magnitude')
ax.scatter(usa_earthquakes['depth'], usa_earthquakes['rms'], usa_earthquakes['mag'])
plt.show()

3-dimensional representation of Depth vs. RMS vs. Magnitude

fig = plt.figure(figsize = (8, 6))
ax = fig.add_subplot(111, projection = '3d')
ax.scatter(usa_earthquakes['gap'], usa_earthquakes['nst'], usa_earthquakes['mag'])
ax.set_xlabel('Gap')
ax.set_ylabel('Nst')
ax.set_zlabel('Magnitude')
plt.show()

3-dimensional representation of angular gap vs. number of stations vs. magnitude

看看代表美国易受地震影响地区的不同地图:

从检索到的地震数据中,我们获取纬度、经度和地名(使用 Regex 模式获得)。我们使用一个叫做 Folium 的 python 映射库。Folium is 使用 Leaflet.js 创建高度交互式的地图。因此,此时我们在以美国为中心的地图中绘制纬度和经度,并使用一个名为 HeatMap 的 folio 插件来生成一个热图,沿地图显示整个美国的漏洞频率。由于是交互式的,热图会随着缩放级别而变化。我们还可以使用另一个名为 FastMarkerCluster 的功能,以一种整洁的方式可视化地震重灾区。FastMarkerCluster 也是交互式的。它们随着缩放级别折叠和展开。

heat_quake_map = folium.Map(location=[usa_earthquakes['latitude'].mean(), 
                                usa_earthquakes['longitude'].mean()], 
                                zoom_start=4)
latlons = usa_earthquakes[['latitude', 'longitude']].values.tolist()
from folium.plugins import HeatMap
HeatMap(latlons).add_to(heat_quake_map)
heat_quake_map

Heat map showing earthquake heavy regions around USA.

from folium.plugins import MarkerCluster
from folium.plugins import FastMarkerCluster
usa_quake_map = folium.Map(location=[usa_earthquakes['latitude'].mean(), 
                                usa_earthquakes['longitude'].mean()], 
                                zoom_start=4)usa_quake_map.add_child(FastMarkerCluster(usa_earthquakes[['latitude', 'longitude']].values.tolist()))
usa_quake_map

Map showing the clusters of recorded earthquakes and their location in USA.

分析酒店数据:

前面我们看到了如何使用 Foursquare 获取街道级别的数据。因此,在我们获取完酒店数据后,现在是分析从 Foursquare API 返回的附近酒店数据集的时候了。现在,我们删除空值,只需使用'就可以按唯一的酒店名称对值进行分组。数据框的酒店名称列上的“unique()”方法。我们通过简单地使用“获得每个记录位置附近酒店的发生频率(“易受攻击事件”)。“value_counts()”方法。首先,我们返回显示酒店及其易受攻击事件的数据框。

num = fx['Venue'].value_counts()
vulnerables = num.rename_axis('business_name').reset_index(name='Vulnerable Occurrence')
vulnerables

Pandas Dataframe showing the hotel names returned by Foursquare API which are frequently nearby to the recorded earthquake events.

Hotels with their respective Vulnerable occurrences in a horizontal bar chart.

needs_attention = vulnerables
needs_attention.set_index('business_name', inplace = True)
needs_attention.plot(kind = 'barh', width = 0.8, edgecolor = 'black', color = 'tomato')
fig = plt.figure(figsize = (20, 10))
plt.show()from folium.plugins import MarkerCluster
from folium.plugins import FastMarkerCluster
vulnerable_business_map = folium.Map(location = [usa_earthquakes['latitude'].mean(), 
                                usa_earthquakes['longitude'].mean()], tiles = 'OpenStreetMap',
                                zoom_start=4)
vulnerable_business_map.add_child(FastMarkerCluster(fd_grouped[['Venue Latitude', 'Venue Longitude']].values.tolist()))folium.Circle([usa_earthquakes['latitude'].mean(),usa_earthquakes['longitude'].mean()], radius=1500000, color='red', opacity = 0.6, fill=False).add_to(vulnerable_business_map) 
folium.Circle([usa_earthquakes['latitude'].mean(),usa_earthquakes['longitude'].mean()], radius=2000000, color='red', opacity = 0.6, fill=False).add_to(vulnerable_business_map) 
folium.Circle([usa_earthquakes['latitude'].mean(),usa_earthquakes['longitude'].mean()], radius=2500000, color='red', opacity = 0.6, fill=False).add_to(vulnerable_business_map)from folium.plugins import HeatMap
latlons = usa_earthquakes[['latitude', 'longitude']].values.tolist()
HeatMap(latlons).add_to(vulnerable_business_map)
vulnerable_business_map

Hotels that requires attention and nearby to the earthquake events on the heat map validating the result.

聚集酒店:

聚类是一种无监督的学习过程,它基于某些相似性分割或聚集未标记的数据集。因此,这里我们将使用 KMeans 作为一种聚类算法,它功能强大但使用简单。它基本上从数据集中选取 k 个质心,并根据距质心的平均 Minkowski 距离将它们动态分配到一个聚类中,直到算法收敛。

这里,我们将数字 5 指定为要将数据分割成的簇的数量。我们像这样使用 ScikitLearn 包:

from sklearn.cluster import KMeans
cluster_list = fx.set_index('Venue')
cluster_list
num_clusters = 5
clusters = cluster_list.drop('Address', 1)
kmeans_cls = KMeans(n_clusters = num_clusters, random_state = 0).fit(clusters)
kmeans_cls.labels_

我们现在删除 hotels 数据集的标签,并将其作为输入提供给 KMeans,以获得聚类标签。最后,我们将聚类标签与它们各自的酒店名称连接起来,并使用颜色索引将它们绘制在叶子地图上,以便更好地可视化聚类。

cluster_list['Cluster Labels'] = kmeans_cls.labels_
cluster_list.reset_index(inplace = True)
cluster_list

Dataframe showing the hotels, their location data and above all, cluster labels.

import matplotlib.cm as cm
import matplotlib.colors as colors
lat_usa = 37.09
lng_usa = -95.71
mapping_earthquake_cluster = folium.Map(location = [lat_usa, lng_usa], zoom_start = 4)

cluster_in = [int(i) for i in cluster_list['Cluster Labels']]

x = np.arange(num_clusters)
ys = [i + x + (i*x)**2 for i in range(num_clusters)]
colors_array = cm.rainbow(np.linspace(0, 1, len(ys)))
rainbow = [colors.rgb2hex(i) for i in colors_array]markers_colors = []
for lat, lon, poi, cluster in zip(cluster_list['Venue Latitude'], cluster_list['Venue Longitude'], cluster_list['Venue'], cluster_in):
    label = folium.Popup(str(poi) + ' Cluster ' + str(cluster), parse_html=True)
    folium.CircleMarker(
        [lat, lon],
        radius=10,
        popup=label,
        color=rainbow[cluster-1],
        fill=True,
        fill_color=rainbow[cluster-1],
        fill_opacity=0.7).add_to(mapping_earthquake_cluster)
mapping_earthquake_cluster

Folium Map showing the clustered hotels.

商业方法:

从商业的角度来说,我们可以说,这个项目将有助于政府城市管理部门,如市政公司或不同的测量师。另一方面,该项目对于不同酒店或企业的利益相关者来说非常有用,以确定他们的酒店或企业是否需要注意抗震设备的升级或结构强度的评估。

要查看完整的代码和它是如何实现的,请点击这里查看我的谷歌合作笔记本

结束。和平!

“我们是我们的思想造就了我们;所以小心你的想法。文字是次要的。思想活着;他们旅行很远。”

~斯瓦米·维威卡难达。

posted @ 2024-10-13 15:25  绝不原创的飞龙  阅读(361)  评论(0)    收藏  举报