TowardsDataScience-博客中文翻译-2019-六十九-

TowardsDataScience 博客中文翻译 2019(六十九)

原文:TowardsDataScience Blog

协议:CC BY-NC-SA 4.0

理解 ul fit——自然语言处理向迁移学习的转变

原文:https://towardsdatascience.com/understanding-ulmfit-and-elmo-the-shift-towards-transfer-learning-in-nlp-b5d8e2e3f664?source=collection_archive---------19-----------------------

了解什么是 ULMFiT 它做什么和如何工作;以及它在 NLP 中引起的根本性转变

Image by Hitesh Choudhary from Unsplash

自然语言处理在过去十年中加快了步伐,随着实现深度学习越来越容易,该领域已经有了重大发展。然而,它落后于计算机视觉领域的专业水平。

主要原因是迁移学习使许多计算机视觉任务比实际简单得多——像 VGGNet⁸或 AlexNet⁹这样的预训练模型可以微调以适应大多数计算机视觉任务。这些预训练的模型是在像 ImageNet 这样的大型语料库上训练的。它们被用来捕捉图像的一般特征和属性。因此,经过一些调整,它们可以用于大多数任务。因此,不必为每一项计算机视觉任务从头开始训练模型。此外,由于它们是在一个巨大的语料库上训练的,许多任务的准确性或结果都是非常出色的,并且会胜过为特定任务从头开始训练的较小模型。

另一方面,对于每个 NLP 任务,模型必须被单独地和逐个地训练。这非常耗时,并且限制了这些模型的范围。“最近的方法(2017 年和 2018 年)将来自其他任务的嵌入与不同层的输入连接起来,仍然从头训练主任务模型,并将预训练的嵌入视为固定参数,从而限制了它们的有用性。”缺乏关于如何为各种 NLP 任务适当微调语言模型的知识。

通用语言模型微调

2018 年,霍华德和鲁德等人。艾尔。为归纳迁移学习的神经模型微调提供了一种新方法——给定一个训练模型的源任务,相同的模型将用于在其他任务(NLP 任务)上获得良好的性能。

Figure 2: Main Stages in ULMFiT — Figure from Analytics Vidya

选择基础模型 理想的源任务被视为语言建模,并被视为类似于自然语言处理任务的 ImageNet。这是因为以下原因:“它捕获了与下游任务相关的语言的许多方面,例如长期依赖、等级关系和情感。与机器翻译(MT)和蕴涵等任务相比,它为大多数领域和语言提供了近乎无限量的数据。”此外,语言建模可以被训练以适应特定的目标任务的独特特征,并且语言建模是各种其他 NLP 任务的组成部分。通常,像 AWD-LSTM⁷这样的好的语言模型(LM)被选作基础模型。一般认为,基础模型越好,最终模型在微调后在各种 NLP 任务上的性能就越好。

通用领域语言模型预训练
预训练是在一个大规模的语言语料库上进行的,该语料库能有效地捕捉语言的主要属性和方面。这有点像图像网络语料库,但是对于语言来说。该阶段只需执行一次。得到的预训练模型可以在所有任务的下一阶段重复使用。
预训练已经完成,因此模型已经理解了语言的一般属性,必须稍加调整以适应特定的任务。事实上,发现预训练对于小数据集和中等大小的数据集特别有用。

目标任务 LM 微调当使用预训练模型时,那么,在这个阶段的收敛更快。在这个阶段,判别微调倾斜三角学习率用于微调语言模型。

区别性微调
“由于不同的层捕捉不同类型的信息,所以应该对它们进行不同程度的微调。”因此,对于每一层,使用不同的学习速率。最后一层的学习,ηᴸ是固定的。然后,用ηˡ⁻ = ηˡ/2.6 来获得其余的学习率。

Figure 3: Weight update for each layer where l=1, 2, …, L is the layer number, ηˡ is the learning rate for the lᵗʰ layer, L is the number of layers, θˡₜ is the weights of the lᵗʰ layer at iteration t and ∇(θˡ) [ J(θ) ] is the gradient with regard to the model’s objective function. — Image and Equation for ULMFiT Research Paper

倾斜三角形学习率 在整个微调过程中,学习率并不保持恒定。最初,对于一些时期,它们以陡峭的斜率线性增加。然后,对于多个时期,它们以逐渐的斜率线性降低。发现这给出了模型的良好性能。

Figure 4: Slanted Triangular Learning Rates — Change of learning rate with each iteration — Image from Wordpress

目标任务分类器微调
“最后,为了微调分类器,我们用两个额外的线性块来扩充预训练的语言模型。”每个块有以下
1。批量正常化
2。辍学
3。中间层
4 的重新激活。softmax 激活输出层以预测类别

进一步改进模型的一些附加步骤

Concat Pooling 一般来说,在文本分类中,重要的词只有几个词,可能是整个文档的一小部分,尤其是文档比较大的时候。因此,为了避免信息丢失,隐藏状态向量与隐藏状态向量的最大汇集和平均汇集形式连接。
逐步解冻
当所有层同时微调时,存在灾难性遗忘的风险。因此,最初除了最后一层之外的所有层都被冻结,并且微调在一个时期内完成。一个接一个的层被解冻,微调完成。重复这一过程直到收敛。
使用双向模型 组合前向和后向 LM 分类器进一步提高了性能。

Figure 5: Block Diagram of ULMFiT in Text Analysis — Image from by HU-Berlin from GitHub

ULMFiT 的优势 与在相应数据集上从头开始训练的模型相比,基于 ulm fit 的模型(已经过预训练)即使在中小型数据集上也表现得非常好。这是因为他们已经在前期训练中掌握了语言的特性。
新提出的微调 LM 和分类器的方法证明比使用传统的微调模型的方法给出更好的精度。

Figure 6: ULMFiT Performance Comparison on IMDB Dataset — Image from FastAI

ULMFiT 彻底改变了 NLP 领域,提高了 NLP 中深度学习的范围,并使在比以前少得多的时间内为各种任务训练模型成为可能。这为自然语言处理的迁移学习奠定了基础,并为埃尔莫、GPT、GPT-2、伯特和 XLNet 铺平了道路。

如何使用 ULMFiT 进行文本处理

附加教程链接:https://www . analyticsvidhya . com/blog/2018/11/Tutorial-text-classification-ulm fit-fastai-library/

注意:我最初写这篇文章是作为我的自然语言处理课程的作业。

在我的 YouTube 频道上观看解释机器学习、人工智能和数据科学概念的视频。

参考

[1]霍华德,j .,&鲁德,S. (2018)。用于文本分类的通用语言模型微调。 arXiv 预印本 arXiv:1801.06146 。*
【2】图一:【https://miro.medium.com/proxy/0*2t3JCdtfsV2M5S_B.png】
【3】图二:
https://cdn . analyticsvidhya . com/WP-content/uploads/2018/11/ulm fit _ flow _ 2 . png
【4】图四:https://yashuseth . files . WordPress . com/2018/06/stlr-formula 2 . jpg?w=413 & h=303 2017 年 b。指针哨兵混合模型。2017 年国际学习代表会议论文集。
[8]西蒙扬,k .,&齐塞曼,A. (2014)。用于大规模图像识别的非常深的卷积网络。 arXiv 预印本 arXiv:1409.1556
[9]克里热夫斯基,a .,&辛顿,G. E. (2012)。基于深度卷积神经网络的图像网分类。在神经信息处理系统的进展(第 1097-1105 页)。

*本文中的许多短语、句子和段落都是表格[1]中句子或段落的总结。图 3 也取自[1]。

理解理解:事物如何有意义

原文:https://towardsdatascience.com/understanding-understanding-how-anything-has-meaning-4613da9d72e2?source=collection_archive---------28-----------------------

我们的理解是我们如何认识我们的世界。它是我们的“心灵之眼”,是我们思考的地方,也是唯一赋予任何事物意义的东西。理解之外的其他体验都是通过感觉来感知的。

你将要读到的描述了无意识理解的过程。支配有意识理解的机制是未来文章的主题。

为了清楚起见,理解和觉察是说类似事情的两个角度。理解是用知识从基础上重建现实,而觉知指的是被重建的对象。

知识是理解的必要条件。知识是识别模式并将其抽象为信号的能力。一个有知识的人是能识别很多模式的人。当多个信号能够告知一个更高层次的模式时,理解就形成了。

如果你看到你下面有一艘船,周围都是水,你知道你在一片水域中的一艘船上。

虽然可能不明显,但这种理解是一种基本的模拟。例如,如果你认识到船在水面上没有摇晃,这个新的信号会改变你的理解。你可以模拟水很浅,船停在水下的地面上。

理解是一个模拟的场景,而意识是指场景中的对象。

现在,你正在用你的理解能力来阅读这句话。你正试图模拟用特定顺序排列的单词来产生这篇文章的思维。

你读的每一个单词都在激活你大脑中该单词的语义表征。“语义”意味着激活代表多维思维空间中的特定位置。我会详细说明这是什么意思:

每个词都可以在很多属性或“维度”上识别。例如,考虑“温度”维度:“火”因为高温而具有较大的正值,“冰”因为低温而具有较大的负值,“云”则接近于零,因为我们通常不认为云具有温度属性。

同时,考虑“硬度”维度:“冰”将具有大的正值,因为冰是硬的,“云”将具有大的负值,因为云是软的,“火”将接近于零,因为火通常不被认为具有硬度属性。

总的来说,所有用来描述每个单词的各种属性最终创造了一个想象的多维思维空间,每个单词都存在于其中的特定位置。

在大脑中,给定维度上的正值是连接到该属性的兴奋性神经连接,负值是连接到该属性的抑制性神经连接,零值是缺乏与该属性的连接。

在人工智能神经网络中,程序使用向量(一系列数字)来表示每个单词,这些数字是该单词在多维思维空间中所处位置的坐标。向量中的每个数字可以是正的、负的或接近于零的,并表示该单词如何与给定的维度属性相关。

理解“语义”真的很重要,因为语义是思维的基础。当你阅读每个单词时,你在大脑中激活该单词的语义表示(识别为信号的模式),同时使用语法来修改表示,并以特定的方式将它们联系在一起。“阅读”的结果是在多维思维空间中创建一条导航路径。给你几个特定的位置,对应于代表,并告诉他们连接。

为了理解你所读到的,你必须利用你大脑中的连接来重现同样的路径。所以,文字就成了被复制的模板。为了完成这种复制,你修改神经连接来连接由模板指示的思想空间中的特定位置。这个过程就是前面提到的模拟。

一旦你的模拟与通过阅读获得的模板相匹配,你就明白了我想要传达的意思。而且,你的模拟和我的模拟的差异是我们的沟通错误。

“在多维思维空间中生成路径的能力”与“对思维的理解”是同义词。当有人说“我懂”的时候,其实是在说“我会模拟”。

了解变分自动编码器(VAEs)

原文:https://towardsdatascience.com/understanding-variational-autoencoders-vaes-f70510919f73?source=collection_archive---------0-----------------------

逐步建立导致 VAEs 的推理。

Credit: Free-Photos on Pixabay

这篇文章是与巴蒂斯特·罗卡共同撰写的。

介绍

在过去的几年里,由于(并暗示)该领域的一些惊人的改进,基于深度学习的生成模型已经获得了越来越多的兴趣。依靠大量的数据、精心设计的网络架构和智能训练技术,深度生成模型显示出令人难以置信的能力,可以生成各种类型的高度逼真的内容,如图像、文本和声音。在这些深度生成模型中,有两个主要家族引人注目,值得特别关注:生成对抗网络(GANs)和变分自动编码器(VAEs)。

Face images generated with a Variational Autoencoder (source: Wojciech Mormul on Github).

在今年 1 月发表的前一篇文章中,我们深入讨论了生成对抗网络(GANs) ,并特别展示了对抗训练如何对抗两个网络,一个生成器和一个鉴别器,以推动它们改进一次又一次的迭代。在这篇文章中,我们现在介绍另一种主要的深度生成模型:变分自动编码器(VAEs)。简而言之,VAE 是一个自动编码器,其编码分布在训练期间被正则化,以确保其潜在空间具有良好的属性,允许我们生成一些新数据。此外,术语“变分”来源于统计学中正则化和变分推断方法之间的密切关系。

如果最后两句很好地总结了 VAEs 的概念,它们也可以提出许多问题。什么是自动编码器?什么是潜在空间,为什么要规范它?如何从 VAEs 生成新数据?VAEs 和变分推理有什么联系?为了尽可能好地描述 VAEs,我们将尝试回答所有这些问题(以及许多其他问题!)并为读者提供尽可能多的见解(从基本的直觉到更高级的数学细节)。因此,这篇文章的目的不仅是讨论变分自动编码器所依赖的基本概念,而且是一步一步地建立,并从最开始的推理开始,导致这些概念。

事不宜迟,让我们一起(重新)发现 VAEs 吧!

概述

在第一部分中,我们将回顾一些关于降维和自动编码器的重要概念,它们将有助于理解 VAEs。然后,在第二部分中,我们将说明为什么自动编码器不能用于生成新数据,并将介绍各种自动编码器,它们是自动编码器的规范化版本,使生成过程成为可能。最后,在最后一节中,我们将基于变分推理给出一个更数学化的 VAEs 表示。

注。在上一节中,我们试图使数学推导尽可能完整和清晰,以弥合直觉和方程之间的差距。然而,不想深入 VAEs 的数学细节的读者可以跳过这一节,而不会影响对主要概念的理解。还要注意,在这篇文章中,我们将滥用符号:对于一个随机变量 z,我们将 p(z)表示这个随机变量的分布(或密度,取决于上下文)。

降维、PCA 和自动编码器

在第一部分中,我们将首先讨论一些与降维相关的概念。特别是,我们将简要回顾主成分分析(PCA)和自动编码器,显示这两个想法是如何相互关联的。

什么是降维?

在机器学习中, 降维 就是减少描述某些数据的特征数量的过程。这种缩减可以通过选择(仅保留一些现有特征)或提取(根据旧特征创建数量减少的新特征)来完成,在许多需要低维数据的情况下(数据可视化、数据存储、大量计算……)非常有用。虽然存在许多不同的降维方法,但我们可以建立一个全局框架来匹配大多数(如果没有的话!)的这些方法。

首先,我们称编码器为从“旧特征”表示(通过选择或提取)产生“新特征”表示的过程,称解码器为相反的过程。维数减少可以被解释为数据压缩,其中编码器压缩数据(从初始空间到编码空间,也称为潜在空间,而解码器解压缩它们。当然,取决于初始数据分布、潜在空间维度和编码器定义,这种压缩可能是有损的,这意味着一部分信息在编码过程中丢失,并且在解码时无法恢复。

Illustration of the dimensionality reduction principle with encoder and decoder.

降维方法的主要目的是在给定系列中找到最佳编码器/解码器对。换句话说,对于给定的一组可能的编码器和解码器,我们正在寻找这样一对编码器和解码器:当对进行编码时,保持最大的信息量,因此,当对进行解码时,具有最小的重建误差。如果我们分别用 E 和 D 表示我们所考虑的编码器和解码器的族,那么降维问题可以写成

在哪里

定义输入数据 x 和编码-解码数据 d(e(x))之间的重构误差度量。最后注意,在下文中,我们将表示 N 为数据数量,n_d 为初始(解码)空间的维数,n_e 为缩减(编码)空间的维数。

主成分分析

谈到降维,首先想到的方法之一是 主成分分析(PCA) 。为了展示它如何符合我们刚刚描述的框架,并与自动编码器建立联系,让我们对 PCA 的工作原理做一个非常全面的概述,把大部分细节放在一边(注意,我们计划就这个主题写一篇完整的帖子)

PCA 的思想是建立 n_e 个新的独立的特征,这些特征是 n_d 个旧特征的线性组合,这样由这些新特征定义的子空间上的数据投影尽可能接近初始数据(根据欧几里德距离)。换句话说,PCA 正在寻找初始空间(由新特征的正交基描述)的最佳线性子空间,使得通过数据在该子空间上的投影来近似数据的误差尽可能小。

Principal Component Analysis (PCA) is looking for the best linear subspace using linear algebra.

在我们的全局框架中,我们在 n_e 乘 n_d 矩阵(线性变换)的族 E 中寻找一个编码器,其行是正交的(特征独立),并且在 n_d 乘 n_e 矩阵的族 D 中寻找相关的解码器。可以看出,对应于协方差特征矩阵的 n_e 个最大特征值(范数形式)的酉特征向量是正交的(或者可以被选择为正交的),并且定义了 n_e 维的最佳子空间,以最小的近似误差将数据投影到该子空间上。因此,这些 n_e 特征向量可以被选为我们的新特征,因此,降维问题可以表示为一个特征值/特征向量问题。此外,还可以看出,在这种情况下,解码器矩阵是编码器矩阵的转置。

PCA matches the encoder-decoder framework we described.

自动编码器

现在让我们讨论一下自动编码器,看看我们如何使用神经网络进行降维。自动编码器的一般想法非常简单,包括将编码器和解码器设置为神经网络,以及使用迭代优化过程学习最佳编码-解码方案。因此,在每次迭代中,我们向自动编码器架构(编码器后接解码器)提供一些数据,我们将编码-解码输出与初始数据进行比较,并通过架构反向传播误差,以更新网络的权重。

因此,直觉上,整个自动编码器架构(编码器+解码器)为数据创建了一个瓶颈,确保只有信息的主要结构化部分能够通过并被重构。查看我们的一般框架,所考虑的编码器族 E 由编码器网络架构定义,所考虑的解码器族 D 由解码器网络架构定义,并且通过在这些网络的参数上的梯度下降来完成最小化重构误差的编码器和解码器的搜索。

Illustration of an autoencoder with its loss function.

让我们首先假设我们的编码器和解码器架构都只有一个没有非线性的层(线性自动编码器)。这样的编码器和解码器是简单的线性变换,可以用矩阵表示。在这种情况下,我们可以看到与 PCA 的明确联系,就像 PCA 一样,我们正在寻找最佳的线性子空间来投影数据,同时尽可能少地丢失信息。用 PCA 获得的编码和解码矩阵自然地定义了我们将满意地通过梯度下降达到的解决方案之一,但是我们应该概述这不是唯一的一个。实际上,可以选择几个基来描述同一个最佳子空间,因此,几个编码器/解码器对可以给出最佳重建误差。此外,对于线性自动编码器,与 PCA 相反,我们最终得到的新特征不必是独立的(在神经网络中没有正交约束)。

Link between linear autoencoder and PCA.

现在,让我们假设编码器和解码器都是深度非线性的。在这种情况下,架构越复杂,自动编码器就越能在保持低重建损失的同时进行高维数缩减。直观上,如果我们的编码器和解码器有足够的自由度,我们可以将任何初始维数减少到 1。事实上,具有“无限能力”的编码器理论上可以将我们的 N 个初始数据点编码为 1、2、3…直到 N(或者更一般地,作为实轴上的 N 个整数),并且相关联的解码器可以进行相反的变换,在该过程中没有损失。

在这里,我们应该记住两件事。首先,在没有重建损失的情况下进行重要的维度缩减通常是有代价的:在潜在空间中缺乏可解释和可利用的结构(缺乏规律性)。其次,在大多数情况下,降维的最终目的不仅仅是减少数据的维数,而是减少这个维数,同时将数据结构信息的主要部分保留在简化的表示中。由于这两个原因,潜在空间的维度和自动编码器的“深度”(定义压缩的程度和质量)必须根据降维的最终目的仔细控制和调整。

When reducing dimensionality, we want to keep the main structure there exists among the data.

可变自动编码器

到目前为止,我们已经讨论了降维问题,并介绍了自动编码器,它是可以通过梯度下降来训练的编码器-解码器架构。现在让我们把内容生成问题联系起来,看看当前形式的自动编码器在这个问题上的局限性,并介绍变化的自动编码器。

用于内容生成的自动编码器的局限性

在这一点上,一个很自然的问题浮现在脑海中:“自动编码器和内容生成之间有什么联系?”。事实上,一旦自动编码器被训练,我们就有了编码器和解码器,但仍然没有真正的方法来产生任何新的内容。乍一看,我们可能会认为,如果潜在空间足够规则(在训练过程中由编码器“组织得很好”),我们可以从潜在空间中随机选取一个点,并对其进行解码以获得新的内容。然后,解码者的行为或多或少会像一个生成性对抗网络的生成器。

We can generate new data by decoding points that are randomly sampled from the latent space. The quality and relevance of generated data depend on the regularity of the latent space.

然而,正如我们在上一节中讨论的,自动编码器的潜在空间的正则性是一个难点,它取决于初始空间中的数据分布、潜在空间的维度和编码器的架构。因此,很难(如果不是不可能的话)事先确保编码器会以一种与我们刚刚描述的生成过程兼容的智能方式组织潜在空间。

为了说明这一点,让我们考虑之前给出的例子,其中我们描述了一个编码器和一个解码器,其功能强大到足以将任意 N 个初始训练数据放到实轴上(每个数据点被编码为一个实值)并对它们进行解码,而没有任何重建损失。在这种情况下,自动编码器的高自由度使得无信息损失地编码和解码成为可能(尽管潜在空间的维度低)导致严重的过拟合,这意味着潜在空间的一些点一旦解码将给出无意义的内容。如果这个一维的例子被自愿选择为非常极端的,我们可以注意到自动编码器潜在空间正则性的问题比它更普遍,值得特别注意。

Irregular latent space prevent us from using autoencoder for new content generation.

仔细想想,潜在空间中的编码数据缺乏结构是很正常的。事实上,在任务中,自动编码器没有被训练来强制实现这样的组织:自动编码器被单独训练来以尽可能少的损失进行编码和解码,不管潜在空间是如何组织的。因此,如果我们不仔细考虑架构的定义,很自然地,在训练过程中,网络会利用任何过度拟合的可能性来尽可能好地完成它的任务…除非我们明确地将其规范化!

变分自动编码器的定义

因此,为了能够将我们的自动编码器的解码器用于生成目的,我们必须确保潜在空间足够规则。获得这种规律性的一个可能的解决方案是在训练过程中引入明确的规律性。因此,正如我们在这篇文章的介绍中简要提到的,一个变分的自动编码器可以被定义为一个自动编码器,它的训练是正则化的,以避免过拟合,并确保潜在空间具有支持生成过程的良好属性。

就像标准的自动编码器一样,变分自动编码器是由编码器和解码器组成的架构,并且被训练来最小化编码-解码数据和初始数据之间的重构误差。然而,为了引入潜在空间的一些正则化,我们对编码-解码过程进行了轻微的修改:不是将输入编码为单个点,而是将其编码为潜在空间上的分布。然后,该模型被训练如下:

  • 首先,输入被编码为在潜在空间上的分布
  • 第二,从潜在空间中的一个点对该分布进行采样
  • 第三,对采样点进行解码,并且可以计算重建误差
  • 最后,重构误差通过网络反向传播

Difference between autoencoder (deterministic) and variational autoencoder (probabilistic).

在实践中,编码的分布被选择为正态分布,使得编码器可以被训练以返回描述这些高斯分布的均值和协方差矩阵。将输入编码为具有一些方差的分布而不是单个点的原因是,它使得非常自然地表达潜在空间正则化成为可能:由编码器返回的分布被强制接近标准正态分布。我们将在下一小节中看到,我们通过这种方式确保了潜在空间的局部和全局正则化(局部是因为方差控制,全局是因为均值控制)。

因此,当训练 VAE 时被最小化的损失函数由“重建项”(在最终层上)和“正则化项”(在潜在层上)组成,所述“重建项”倾向于使编码-解码方案尽可能有性能,所述“正则化项”倾向于通过使编码器返回的分布接近标准正态分布来正则化潜在空间的组织。正则化项表示为返回分布和标准高斯分布之间的 Kulback-Leibler 散度,将在下一节中进一步证明。我们可以注意到,两个高斯分布之间的 Kullback-Leibler 散度有一个封闭的形式,可以直接用两个分布的均值和协方差矩阵来表示。

In variational autoencoders, the loss function is composed of a reconstruction term (that makes the encoding-decoding scheme efficient) and a regularisation term (that makes the latent space regular).

关于规范化的直觉

为了使生成过程成为可能,期望从潜在空间中得到的规律性可以通过两个主要属性来表达:连续性(潜在空间中两个接近的点一旦被解码就不应该给出两个完全不同的内容)和完全性(对于选定的分布,从潜在空间中采样的点一旦被解码就应该给出“有意义的”内容)。

Difference between a “regular” and an “irregular” latent space.

VAEs 将输入编码为分布而不是简单的点这一事实不足以确保连续性和完整性。如果没有明确定义的正则化项,为了最小化其重建误差,模型可以学习来“忽略”分布被返回的事实,并表现得几乎像经典的自动编码器(导致过拟合)。为此,编码器可以返回具有微小方差的分布(趋于为点分布),或者返回具有非常不同的平均值的分布(在潜在空间中彼此相距非常远)。在这两种情况下,分配的使用方式都是错误的(取消了预期收益),连续性和/或完整性都得不到满足。

因此,为了避免这些影响,我们必须调整协方差矩阵和编码器返回的分布均值。在实践中,这种规范化是通过强制分布接近标准正态分布(集中和减少)来实现的。通过这种方式,我们要求协方差矩阵接近恒等式,以防止准时分布,并且要求均值接近 0,以防止编码分布彼此相距太远。

The returned distributions of VAEs have to be regularised to obtain a latent space with good properties.

通过这个正则化项,我们防止模型在潜在空间中对相距很远的数据进行编码,并鼓励尽可能多的返回分布“重叠”,以这种方式满足预期的连续性和完整性条件。自然地,对于任何正则化项,这是以训练数据上更高的重建误差为代价的。然而,可以调整重建误差和 KL 散度之间的折衷,并且我们将在下一节中看到如何从我们的形式推导中自然地出现平衡的表达式。

总结这一小节,我们可以观察到通过正则化获得的连续性和完整性倾向于在潜在空间中编码的信息上创建一个“梯度”。例如,在来自不同训练数据的两个编码分布的平均值之间的潜在空间的点应该被解码为在给出第一分布的数据和给出第二分布的数据之间的某处,因为在两种情况下它都可以被自动编码器采样。

Regularisation tends to create a “gradient” over the information encoded in the latent space.

注。顺便提一下,我们可以提到,我们提到的第二个潜在问题(网络使分布彼此远离)实际上几乎等同于第一个问题(网络倾向于返回正点分布),直到尺度发生变化:在两种情况下,分布的方差相对于它们的均值之间的距离变小。

VAEs 的数学细节

在前面的部分中,我们给出了以下直观的概述:vae 是自动编码器,其将输入编码为分布而不是点,并且其潜在空间“组织”通过将编码器返回的分布约束为接近标准高斯分布而被正则化。在这一节中,我们将给出一个更加数学化的 VAEs 视图,这将允许我们更加严格地证明正则化项。为此,我们将建立一个清晰的概率框架,并将特别使用变分推理技术。

概率框架和假设

让我们首先定义一个概率图形模型来描述我们的数据。我们用 x 表示代表我们的数据的变量,并假设 x 是从一个潜在的变量 z(编码表示)中产生的,这个变量不能被直接观察到。因此,对于每个数据点,假设以下两步生成过程:

  • 首先,从先验分布 p(z)中采样潜在表示 z
  • 第二,从条件似然分布 p(x|z)中采样数据 x

Graphical model of the data generation process.

有了这样一个概率模型,我们可以重新定义编码器和解码器的概念。事实上,与考虑确定性编码器和解码器的简单自动编码器相反,我们现在将考虑这两个对象的概率版本。“概率解码器”自然由 p(x|z)定义,它描述了给定编码变量时解码变量的分布,而“概率编码器”由 p(z|x)定义,它描述了给定解码变量时编码变量的分布。

在这一点上,我们已经可以注意到,我们在简单的自动编码器中缺乏的潜在空间的正则化自然地出现在数据生成过程的定义中:潜在空间中的编码表示 z 实际上被假设为遵循先验分布 p(z)。另外,我们还可以想起著名的贝叶斯定理,它将先验 p(z)、似然性 p(x|z)和后验 p(z|x)联系起来

现在让我们假设 p(z)是标准高斯分布,并且 p(x|z)是高斯分布,其均值由 z 的变量的确定性函数 F 定义,并且其协方差矩阵具有乘以单位矩阵 I 的正常数 c 的形式。因此,我们有

现在让我们考虑,f 是明确定义的,固定的。理论上,我们知道 p(z)和 p(x|z),就可以用贝叶斯定理计算 p(z|x):这是一个经典的贝叶斯推理问题。然而,正如我们在上一篇文章中讨论的,这种计算通常是难以处理的(因为分母上的积分),并且需要使用近似技术,例如变分推理。

注。这里我们可以提到 p(z)和 p(x|z)都是高斯分布。因此,如果我们有 E(x|z) = f(z) = z,这将意味着 p(z|x)也应该遵循高斯分布,并且在理论上,我们可以“仅仅”尝试相对于 p(z)和 p(x|z)的均值和协方差矩阵来表达 p(z|x)的均值和协方差矩阵。然而,在实践中,这一条件并不满足,我们需要使用一种近似技术,如变分推理,使这种方法相当普遍,对模型假设的某些变化更加稳健。

变分推理公式

在统计学中,变分推断(VI)是一种近似复杂分布的技术。想法是设置一个参数化的分布族(例如高斯分布族,其参数是平均值和协方差),并在该族中寻找我们的目标分布的最佳近似。该族中的最佳元素是最小化给定近似误差测量(大多数情况下近似和目标之间的 Kullback-Leibler 散度)的元素,并且通过描述该族的参数的梯度下降来找到。更多细节,我们参考我们关于变分推理的帖子和其中的参考资料。

这里,我们将通过高斯分布 q_x(z)来近似 p(z|x ),其均值和协方差由参数 x 的两个函数 G 和 H 来定义。这两个函数分别属于函数 G 和 H 的族,函数 G 和 H 将在后面详细说明,但应该是参数化的。因此,我们可以表示

因此,我们以这种方式定义了一族用于变分推理的候选项,现在需要通过优化函数 g 和 h(实际上是它们的参数)来找到这一族中的最佳近似值,以最小化近似值和目标 p(z|x)之间的 Kullback-Leibler 散度。换句话说,我们在寻找最优的 g和 h使得

在倒数第二个方程中,我们可以观察到在最大化“观察”的可能性(最大化预期对数似然,对于第一项)和保持接近先验分布(最小化 q_x(z)和 p(z)之间的 KL 散度,对于第二项)之间存在折衷。这种权衡对于贝叶斯推理问题来说是很自然的,并且表达了需要在我们对数据的信心和我们对先验的信心之间找到的平衡。

到目前为止,我们已经假设函数 f 是已知的和固定的,并且我们已经表明,在这样的假设下,我们可以使用变分推理技术来逼近后验 p(z|x)。然而,在实践中,定义解码器的这个函数 f 是未知的,并且也需要被选择。为了做到这一点,让我们提醒一下,我们的最初目标是找到一个性能编码-解码方案,其潜在空间足够规则以用于生成目的。如果正则性主要由在潜在空间上假设的先验分布决定,则整个编码-解码方案的性能高度依赖于函数 f 的选择。实际上,由于 p(z|x)可以由 p(z)和 p(x|z)近似(通过变分推断),并且由于 p(z)是简单的标准高斯函数,因此在我们的模型中,我们可用于进行优化的仅有的两个杠杆是参数 c(其定义了似然性的方差)和函数 f(其定义了似然性的均值)。

因此,让我们考虑,正如我们先前所讨论的,我们可以为 F 中的任何函数 F(每个函数定义一个不同的概率解码器 p(x|z))得到 p(z|x)的最佳近似,记为 q_x(z)。尽管它是概率性的,我们正在寻找一种尽可能有效的编码-解码方案,然后,当 z 从 q_x(z)中被采样时,我们想要选择最大化给定 z 的 x 的期望对数似然的函数 f。换言之,对于给定的输入 x,当我们从分布 q_x(z)中采样 z,然后从分布 p(x|z)中采样 x̂时,我们希望最大化 x̂ = x 的概率。因此,我们寻找最优的 f,使得

其中 q_x(z)取决于函数 f,并如前所述获得。将所有的部分集合在一起,我们寻找最优的 f,g和 h使得

我们可以在这个目标函数中识别在前面部分中给出的 VAEs 的直观描述中引入的元素:x 和 f(z)之间的重构误差以及由 q_x(z)和 p(z)之间的 KL 散度给出的正则化项(这是一个标准高斯)。我们还可以注意到,常数 c 决定了前两项之间的平衡。在我们的模型中,c 越高,我们就越假设概率解码器在 f(z)附近的方差高,因此,我们就越倾向于正则化项而不是重建项(如果 c 低,则相反)。

将神经网络引入模型

到目前为止,我们已经建立了依赖于三个函数 f、g 和 h 的概率模型,并且使用变分推理来表达要求解的优化问题,以便获得 f、g和 h*,它们给出了利用该模型的最佳编码-解码方案。由于我们无法在整个函数空间内轻松优化,我们限制了优化域,并决定将 f、g 和 h 表示为神经网络。因此,F、G 和 H 分别对应于由网络体系结构定义的函数族,并且对这些网络的参数进行优化。

实际上,g 和 h 不是由两个完全独立的网络定义的,而是共享它们的一部分架构和权重,所以我们有

因为它定义了 q_x(z)的协方差矩阵,所以 h(x)应该是一个方阵。然而,为了简化计算和减少参数的数量,我们额外假设我们的 p(z|x),q_x(z)的近似是具有对角协方差矩阵的多维高斯分布(变量独立性假设)。在这种假设下,h(x)仅仅是协方差矩阵的对角元素的向量,并且具有与 g(x)相同的大小。然而,我们用这种方法减少了我们考虑的变分推论的分布族,因此,得到的 p(z|x)的近似值可能不太精确。

Encoder part of the VAE.

与模拟 p(z|x)的编码器部分相反,我们考虑的是具有 x (g 和 h)的函数的均值和协方差的高斯,我们的模型假设 p(x|z)是具有固定协方差的高斯。定义高斯平均值的变量 z 的函数 f 由神经网络建模,并可表示如下

Decoder part of the VAE.

然后通过连接编码器和解码器部分获得整体架构。然而,我们仍然需要非常小心在训练期间从编码器返回的分布中采样的方式。采样过程必须以允许误差通过网络反向传播的方式来表示。一个简单的技巧,称为重新参数化技巧,用于使梯度下降成为可能,尽管随机采样发生在架构的中途,并且在于使用以下事实:如果 z 是一个随机变量,遵循具有均值 g(x)和协方差 H(x)=h(x)的高斯分布。h^t(x)那么它可以表示为

Illustration of the reparametrisation trick.

最后,以这种方式获得的变分自动编码器架构的目标函数由前一小节的最后一个方程给出,其中理论预期被或多或少精确的蒙特卡罗近似所代替,该近似在大多数时间包含在单次绘制中。因此,考虑到这种近似并表示 C = 1/(2c),我们恢复了在前面部分中直观导出的损失函数,该函数由重建项、正则化项和定义这两项的相对权重的常数组成。

Variational Autoencoders representation.

外卖食品

这篇文章的主要观点是:

  • 降维是减少描述某些数据的特征数量的过程(或者通过仅选择初始特征的子集,或者通过将它们组合成数量减少的新特征),因此,可以被视为编码过程
  • 自动编码器是由编码器和解码器组成的神经网络架构,其产生数据通过的瓶颈,并且被训练为在编码-解码过程中丢失最少量的信息(通过梯度下降迭代训练,目的是减少重建误差)
  • 由于过拟合,自动编码器的潜在空间可能非常不规则(潜在空间中的接近点可能会给出非常不同的解码数据,潜在空间中的某个点一旦解码可能会给出无意义的内容……),因此,我们无法真正定义一个生成过程,该过程只是简单地从潜在空间中采样一个点,并使其通过解码器以获得新数据
  • 变分自动编码器(VAEs)是通过使编码器返回潜在空间上的分布而不是单个点,并通过在损失函数中添加返回分布上的正则化项以确保潜在空间的更好组织来解决潜在空间不规则问题的自动编码器
  • 假设一个简单的潜在概率模型来描述我们的数据,由重建项和正则化项组成的 VAEs 的非常直观的损失函数,可以特别使用变分推断的统计技术(因此称为“变分”自动编码器)仔细地导出

总之,我们可以概括说,在过去的几年里,GANs 比 VAEs 从更多的科学贡献中受益。除了其他原因之外,社区对 GANs 表现出的更高兴趣可以部分地解释为 VAEs 理论基础(概率模型和变分推理)的复杂程度高于支配 GANs 的对抗性训练概念的简单程度。通过这篇文章,我们希望我们能够分享有价值的直觉以及强大的理论基础,使 VAEs 更容易为新人所接受,正如我们今年早些时候为 GANs 所做的那样。然而,现在我们已经深入地讨论了他们两个,还有一个问题…你更像 gan 还是 VAEs?

感谢阅读!

巴蒂斯特·罗卡一起写的其他文章:

[## 推荐系统简介

几种主要推荐算法综述。

towardsdatascience.com](/introduction-to-recommender-systems-6c66cf15ada) [## 整体方法:装袋、助推和堆叠

理解集成学习的关键概念。

towardsdatascience.com](/ensemble-methods-bagging-boosting-and-stacking-c9214a10a205)

理解各种 MDM 实现风格

原文:https://towardsdatascience.com/understanding-various-mdm-implementation-styles-5b4c8fcbbecf?source=collection_archive---------7-----------------------

最近,我有机会为一家金融监管机构写了一些关于主数据管理(MDM)的报告,在那里我学到了很多关于 MDM 的知识。我一直对 MDM 主题的复杂性感到惊讶,我了解的越多,我就越意识到我以前不知道的事情。虽然我可能距离成为 MDM 专家还有千里之遥,但是有些方面我已经开始有了很好理解。其中之一是人们可以选择不同的实现方式来满足他们的需求。

大多数情况下,决定 MDM 实现风格的是与数据管理相关的业务情况。虽然在整个组织中创建和维护单一版本的 truth 是最终目标,但在实现该目标的过程中可以有不同的关注点,例如提高数据质量、维护遗留系统和提供数据可访问性,等等。

这些因素中的每一个都可以通过实现特定的实现风格来获得。在这里,我们看一下 4 种常见的 MDM 实现方法,您可以选择它们来满足您的业务需求。我已经按照从最少打扰到最多打扰的方式进行了安排。

登记处

如果您有大量的源系统,每个系统都有自己的规则和复杂性,很难修改,那么您可能希望考虑以注册方式实现 MDM。有了几个源系统之后,可能很难立即建立权威的源,所以您只需从源中提取所有数据,将其放在 MDM hub 上,让它发挥魔力。MDM 将筛选数据并运行清洗和匹配算法,为重复记录分配唯一的全局标识符,并最终建立单一版本的 truth。

这种方法的美妙之处在于 MDM 永远不会触及您的源系统,这意味着尽管下游应用程序(如您的企业数据仓库(EDW)和报告系统)现在可以使用经过清理和标准化的主数据,但源系统中不会发生任何变化。这对于那些修改源系统会导致大量成本和资源的组织来说是非常有益的,更不用说法规限制了。

总而言之,注册表风格是实现 MDM 成本最低的方式,但是当然也有一些缺点,比如延迟。

合并

脱离了低成本和非侵入式的注册风格,我们现在有了整合方法,它仍然是非侵入式的,但是在 MDM hub 中增加了功能:管理。什么是管家?嗯,基本上就是在整个 MDM 流程中引入人的因素。因此,在您的 MDM 运行对收集的数据进行清理、匹配、链接和合并的算法,并建立单一来源的真相/黄金记录之后,有些人可以调整黄金记录,使其更加黄金。这些人被称为数据管家,他们所做的活动值得另一个专门的媒体职位。

整合方法及其管理功能是集中存储主数据并将其用作分析和报告参考点的一种很好的方式。下游应用程序可以享受可信的黄金记录,而源系统仍然可以照常维持业务。

共存

如果您已经有了整合风格,那么您可以通过将循环添加回您系统来发展成共存风格。这意味着,将黄金记录发送回各个源系统,这样您现在就可以享受 MDM hub 和源系统之间的实时同步了。此外,主数据的更新可以在两者中进行,这意味着主数据质量的显著提高。请记住,这种方法更具侵入性,并且允许更新发生在您的源系统中,您需要确保源系统具有数据清理功能,以便与中心保持一致。

交易/集中

这是 MDM 实现风格的顶峰,在这种风格中,中心成为主数据的单一提供者。在这种方式下,可以简单地说,所有主数据都被转移到 hub,任何外部系统都不能再创建或修改主数据,而是必须向 hub 订阅任何更新。

这种方法需要耗费大量的资源和时间来实现,但幸运的是,这只是前面介绍的实现方式的另一种演变。因此,组织可以花时间,如果他们确定他们的业务需要事务风格提供的优势,那么他们应该去做。

虽然这个解释并不详尽,但我希望这个简短的解释能够对 MDM 的复杂世界有一些初步的了解,尤其是实现风格。幸运的是,每种实现风格都不是惩罚性的,人们可以根据自己的需要从一种风格发展到另一种风格。只要人们选择了支持各种实现风格的正确的 MDM 平台,那么他们就处于非常有利的地位。

祝 MDM-ing 快乐!

理解简单和多元线性回归何时给出不同的结果

原文:https://towardsdatascience.com/understanding-when-simple-and-multiple-linear-regression-give-different-results-7cf6c787766c?source=collection_archive---------8-----------------------

Taken from pexels

简单和多元线性回归通常是用于调查数据关系的第一个模型。如果你和他们玩得够久,你最终会意识到他们可以给出不同的结果。

使用简单线性回归时有意义的关系在使用多元线性回归时可能不再有意义,反之亦然,简单线性回归中不重要的关系在多元线性回归中可能变得有意义。

认识到为什么会发生这种情况,将有助于提高你对线性回归的理解。

快速回顾一下简单的线性回归,它试图以下列形式对数据进行建模:

如果斜率项很重要,那么 x 每增加一个单位,y 就会平均增加β_ 1,这不可能是偶然发生的。

假设我们是一家冰淇淋企业,试图找出推动销售的因素,我们测量了两个独立变量:(1)温度和(2)我们观察到的 10 分钟内走在街上的穿短裤的人数。

我们的因变量是:我们销售的冰淇淋数量。

首先,我们绘制温度与冰淇淋销量的关系图

并做一个简单的线性回归,找出销量和温度之间的显著关系。这是有道理的。

然后我们绘制观察到的卖空数量与销售额的关系图

再做一个简单的线性回归,找出我们在 10 分钟内观察到的穿短裤的人数和冰淇淋销量之间的显著关系。有意思…也许这没什么意义。

然后我们转向多元线性回归,多元线性回归试图以下列形式对数据建模:

多元线性回归与简单线性回归有点不同。首先要注意的是,我们可以包含任意多的独立变量,而不是只有一个独立变量。解释也不同。如果其中一个系数(比如β_ I)很重要,这意味着 x_i、每增加 1 个单位,而所有其他独立变量保持不变,则 y 平均增加β_ I,这不太可能是偶然发生的。

我们做多元线性回归,包括温度和短路进入我们的模型,看看我们的结果

温度仍然是显著相关的,但短裤不是。它已经从简单线性回归中的显著变为多元线性回归中的不再显著。

为什么?

通过绘制短路和温度可以找到答案。似乎有关系。

当我们检查这两个变量之间的相关性时,我们发现 r =0.3,短路和温度往往一起增加。

当我们进行简单的线性回归并发现短裤和销售之间的关系时,我们实际上是在检测温度和销售之间的关系,这种关系会传递到短裤上,因为短裤会随着温度而增加。

当我们进行多元线性回归时,我们在保持温度不变的情况下研究了卖空和销售之间的关系,这种关系消失了。然而,温度和销售之间的真实关系依然存在。

相关数据经常会导致简单和多元线性回归,从而得出不同的结果。每当你用简单的线性回归发现一个重要的关系时,确保你用多元线性回归跟踪它。你可能会对结果感到惊讶!

(注意:这个数据是我们在 R 中使用 mvrnorm()命令生成的)

欢迎在下面的评论中留下任何想法或问题!

用 TF-IDF 和 GloVe 理解单词嵌入

原文:https://towardsdatascience.com/understanding-word-embeddings-with-tf-idf-and-glove-8acb63892032?source=collection_archive---------16-----------------------

它们是如何工作的,你能用它们做什么?

单词嵌入是自然语言处理中最流行的技术之一。因此,理解它们是如何工作的以及它们可以用来做什么,对于任何愿意投身自然语言处理领域的数据爱好者来说都是至关重要的。

为了向你展示它们有多重要,请考虑以下情况:我们都使用过谷歌搜索来找到数以千计或更多的与我们的查询相匹配的结果。但是你有没有想过计算机是如何理解你指的是苹果公司而不是水果?同样,如果你输入“巴拉克·奥巴马的妻子”,它如何返回“米歇尔·奥巴马”?

上面的答案是:单词嵌入。这种技术允许以一种捕捉单词的含义、语义关系和使用它们的上下文的方式来表示单词。

“从一个人和什么样的人交往,你就可以知道他是什么样的人。”——弗斯。

词语嵌入清晰解释

单词嵌入是将单词转换成实数向量的过程。

我们为什么需要它?嗯,机器学习中的大多数算法都无法处理原始形式的字符串或纯文本。相反,它们需要数字作为输入才能发挥作用。通过将单词转换为向量,单词嵌入因此允许我们处理大量的文本数据,并使它们适合机器学习算法。

它是如何工作的?将单词转换成数字的最基本方法之一是通过一键编码法。考虑这个句子:“我正在学习单词嵌入是如何工作的”。这个句子中的词是“学习”、“嵌入”等。由此,我们可以创建一个字典,它是句子中所有独特单词的列表。在这种情况下:["我","我","学习","如何","词","嵌入","工作"]。一个字的独热编码矢量表示可以以这样的方式编码,1 代表该字存在的位置,而 0 代表其它任何位置。例如,“学习”的向量表示如下:[0,0,1,0,0,0,0]。因此,每个单词都有其独特的维度。

此外,它们被映射到一个向量空间 。为什么?其背后的思想是,上下文相近的词占据相近的空间位置。换句话说,在向量空间中,在相似上下文中使用的单词彼此靠近,而不靠近的单词彼此远离。这就是这一切的美妙之处!

在本文中,我将展示将单词转换成数字的两种不同方法:使用 TF-IDF 转换和 GloVe。虽然 TF-IDF 依赖于稀疏向量表示,但 GloVe 属于密集向量表示。

稀疏向量:TF-IDF

TF-IDF 遵循与上述独热码编码向量相似的逻辑。然而,它不是只计算一个单词在单个文档中的出现次数,而是计算整个语料库的出现次数。这允许我们检测一个单词对语料库中的文档有多重要。

这是什么意思?嗯,像“the”或“a”这样的常用词在几乎每个文档中都会非常频繁地出现。然而,其他单词可能只在一个或两个文档中频繁出现,而这些单词可能更能代表它们所在的文档。

TF-IDF 的目标是揭示这一点:降低在几乎每个文档中出现的常用词(例如“the”或“a”)的权重,并赋予那些只在少数文档中出现的词更多的重要性。

详细地说,TF IDF 由两部分组成: TF ,它是单词的词频,即该单词在文档中出现的次数;以及 IDF ,它是逆文档频率,即对只在少数文档中出现的单词给予较高权重的权重分量。

密集向量:手套

密集向量分为两类:矩阵分解和神经嵌入。GloVe 属于后一类,旁边是另一种流行的神经方法 Word2vec。

简而言之,GloVe 是一种无监督的学习算法,它强调单词-单词共现对提取意义的重要性,而不是其他技术,如 skip-gram 或单词包。其背后的想法是,某个词通常比另一个词更频繁地与一个词同时出现。例如,单词更有可能与单词一起出现。

手套在 R 中非常容易使用,带有 text2vec 包。

应用中的单词嵌入:我能用它们展示什么?

理解单词嵌入是关键,但掌握如何使用它们也同样重要。单词嵌入如此重要的原因不仅在于它们在数据科学中的应用,还延伸到了政治、通信、营销或决策领域。

1/寻找两个单词之间的相似度

一旦将单词转换成数字,就可以使用相似性度量来查找单词之间的相似程度。

一个有用的度量是余弦相似度,它测量两个向量之间角度的余弦。重要的是要理解,它测量的是方向而不是幅度,即相似的矢量将具有相似的矢量方向。更详细地说,这意味着具有相同方向的两个向量将具有 1 的余弦相似度,相对于彼此成 90°方向的两个向量将具有 0 的相似度,并且直径上相对的两个向量具有-1 的相似度。这完全与它们的大小无关。

找到单词之间的相似性可以带来强大的洞察力。在市场营销中,这可以帮助营销人员了解消费者将特定产品与哪些词语联系在一起。因此,这有助于通过有针对性的搜索查询开展更高效的广告活动。以类似的方式,这也可以通知传播专家或政治家在制定针对受众的活动。

2/比较一个词在不同语料库中的使用

与上述相关,人们还可以关注特定单词的使用,并使用余弦相似性的度量来理解该单词在不同的语料库中是如何不同地使用的。例如,你可以比较“气候”一词在各种联合国演讲中的用法,或者“移民”一词在共和党和民主党宣言中的上下文。你可以从中提取政党甚至政策的差异。

根据你想要分析的文本,由单词嵌入给出的研究可能性是无限的。

[## 自然语言处理如何帮助你通过词语理解党派差异

用词汇嵌入法分析民主党和共和党政纲的异同

medium.com](https://medium.com/data-social/natural-language-processing-word-embeddings-e0b2edc773d2)

3/分析像女人+国王-男人=王后这样令人惊奇的事情

单词类比是单词嵌入真正有趣的部分!他们允许你以“a 对 b”和“x 对 y”的形式进行扣除。

举个例子:国王——男人+女人=王后。换句话说,将向量 king 和 woman 相加,同时减去 man,得到与 queen 相关的向量。简单地说,这意味着:国王对于男人就像女王对于女人一样。

作为人类,我们知道国王指的是男性,而女王指的是女性。单词嵌入让计算机也能理解这一点,它利用了 king 和 man 的向量表示之间的差异。如果一个人试图把女性向量投射到同一个方向,他就会得到 queen 这个词。女王是国王的女性的信息从未被直接提供给模型,但是模型能够通过单词嵌入来捕捉这种关系。

再比如:巴黎—法国+德国=柏林。换句话说,巴黎对于法国就像柏林对于德国一样!

在这里, text2vec 是 R 中一个易于使用的包,用于使用上述余弦相似性度量从 GloVe 算法中执行这些单词类比。

始终小心道德方面的考虑!

尽管单词嵌入非常有用,并且应用广泛,但是应该仔细考虑它们的实现。

不幸的是,语言是一种强有力的手段,通过它,种族、性别歧视和刻板偏见得以复制。因此,考虑这些偏见对基于处理人类语言的自动化任务的影响是至关重要的。

这怎么会成为问题,为什么会成为问题?

考虑在工作招聘流程或翻译服务等环境中实现基于单词嵌入的机器学习算法。在这些情况下,陈规定型观念会影响并实际上隐含对某一群体的歧视。在这种情况下给出的一个流行的例子是男人:程序员=女人之间的关系,这将产生结果家庭主妇。嵌入模式将看到程序员与男性比女性更亲密,因为我们自己对这份工作的社会认知反映在我们使用的语言中。

另一个例子是 cv 扫描的自动化。让我们假设公司决定在一个大数据集上训练单词嵌入,比如维基百科。在一封激励信中找到积极的形容词,如狡猾、聪明和聪明的机会很高,但我们也发现,在预先训练的嵌入空间中,这些术语更接近男性而不是女性。因此,这种性别偏见将在自动化任务中重现。

性别不平等、种族歧视和其他刻板偏见在我们的社会和语言使用中根深蒂固。因此,在这种语言上应用机器学习算法有传播和放大所有这些偏见的风险。因此,算法从来都不是“中性”的,因为我们的语言本身就不是中性的。

因此:永远要小心你的模型的伦理含义!

结论

在我们与计算机的日常互动中,词语嵌入无处不在。他们可以提供超越数据科学应用的见解,触及营销、通信、政治和政策制定领域。识别单词的相似性和相似性是其强大应用的例子。尽管如此,它们的应用从来都不是中立的,就像任何算法一样,一定要考虑它们的伦理含义!

我定期撰写关于数据科学和自然语言处理的文章。关注我的 Twitter Medium查看更多类似的文章或简单地更新下一篇文章!

理解自然语言处理中的单词 N 元语法和 N 元语法概率

原文:https://towardsdatascience.com/understanding-word-n-grams-and-n-gram-probability-in-natural-language-processing-9d9eef0fa058?source=collection_archive---------1-----------------------

快速文本系列

这并没有听起来那么难。

最初发表于我的博客

N-gram 大概是整个机器学习领域最容易理解的概念了吧,我猜。一个 N-gram 意味着 N 个单词的序列。举例来说,“中型博客”是一个 2-gram(二元模型),“中型博客文章”是一个 4-gram,而“写在介质上”是一个 3-gram(三元模型)。嗯,那不是很有趣或令人兴奋。没错,但是我们还是要看看 n-gram 使用的概率,这很有趣。

为什么是 N-gram 呢?

在我们继续讲概率的东西之前,让我们先回答这个问题。为什么我们需要学习 n-gram 和相关的概率?嗯,在自然语言处理中,简称 NLP,n-grams 有多种用途。一些例子包括自动完成句子(如我们最近在 Gmail 中看到的),自动拼写检查(是的,我们也可以这样做),在一定程度上,我们可以检查给定句子的语法。我们将在后面的文章中看到一些例子,当我们谈论给 n 元文法分配概率的时候。

n 元概率

让我们以一个句子完成系统为例。这个系统建议在给定的句子中接下来可以使用的单词。假设我给系统一句话“非常感谢你的”,并期望系统预测下一个单词是什么。现在你我都知道,下一个词是“救命”的概率非常大。但是系统怎么知道呢?

这里需要注意的一点是,与任何其他人工智能或机器学习模型一样,我们需要用庞大的数据语料库来训练模型。一旦我们做到了这一点,系统或 NLP 模型将对某个单词在某个单词之后出现的“概率”有一个非常好的了解。因此,希望我们已经用大量数据训练了我们的模型,我们将假设模型给了我们正确的答案。

我在这里讲了一点概率,但现在让我们在此基础上继续。当我们建立预测句子中单词的 NLP 模型时,单词在单词序列中出现的概率才是最重要的。我们如何衡量呢?假设我们正在使用一个二元模型,我们有以下句子作为训练语料:

  1. 非常感谢你的帮助。
  2. 我非常感谢你的帮助。
  3. 对不起,你知道现在几点了吗?
  4. 我真的很抱歉没有邀请你。
  5. 我真的很喜欢你的手表。

让我们假设在用这些数据训练了我们的模型之后,我想写下句子“我真的很喜欢你的花园。”因为这是一个二元模型,该模型将学习每两个单词的出现,以确定某个单词出现在某个单词之后的概率。例如,从上面例子中的第二句、第四句和第五句,我们知道在单词“really”之后,我们可以看到单词“appreciate”、“sorry”或单词“like”出现。所以模型会计算这些序列中每一个的概率。

假设我们正在计算单词“w1”出现在单词“w2”之后的概率,则公式如下:

*count(w2 w1) / count(w2)*

其是单词在所需序列中出现的次数,除以该单词在预期单词在语料库中出现之前的次数。

从我们的例句中,让我们来计算“like”这个词出现在“really”这个词之后的概率:

count(really like) / count(really)
= 1 / 3
= 0.33

同样,对于另外两种可能性:

count(really appreciate) / count(really)
= 1 / 3
= 0.33count(really sorry) / count(really)
= 1 / 3
= 0.33

因此,当我键入短语“我真的”,并期望模型建议下一个单词时,它只会在三次中得到一次正确答案,因为正确答案的概率只有 1/3。

作为另一个例子,如果我对模型的输入句子是“谢谢你的邀请”,并且我期望模型建议下一个单词,它将会给我单词“你”,因为例句 4。这是模型知道的唯一例子。你可以想象,如果我们给模型一个更大的语料库(或更大的数据集)来训练,预测将会改善很多。同样,我们在这里只使用二元模型。我们可以使用三元模型甚至四元模型来提高模型对概率的理解。

使用这些 n 元语法和某些单词在某些序列中出现的概率可以改进自动完成系统的预测。同样,我们使用 can NLP 和 n-grams 来训练基于语音的个人助理机器人。例如,使用 3-gram 或 trigram 训练模型,机器人将能够理解句子之间的差异,如“温度是多少?”和“设定温度”

我希望这是一个足够清晰的解释,可以理解自然语言处理中 n 元语法这个非常简单的概念。我们将使用这种 n 元语法的知识,并使用它来优化我们的机器学习模型用于文本分类,我们在早些时候的介绍 fastText 库帖子中构建了该模型。

Twitter 上关注我,了解更多数据科学机器学习,以及通用技术更新。还有,你可以关注我的个人博客

如果你喜欢我在 Medium 或我的个人博客上的帖子,并希望我继续做这项工作,请考虑在 Patreon 上支持我。

在实践中理解 Word2vec 嵌入

原文:https://towardsdatascience.com/understanding-word2vec-embedding-in-practice-3e9b8985953?source=collection_archive---------4-----------------------

单词嵌入,向量空间模型,Gensim

这篇文章旨在用 Python 中的 Gensim 实现 Word2vec 嵌入的同时,以直观的方式解释 Word2vec 的概念以及概念背后的数学原理。

Word2vec 的基本思想是,不是在高维空间将单词表示为一键编码(count vectorizer/tfidfvectorizer),而是在稠密的低维空间中以相似单词得到相似单词向量的方式来表示单词,从而映射到附近的点上。

Word2vec 不是深度神经网络,它把文本变成深度神经网络可以作为输入处理的数值形式。

word2vec 模型是如何训练的

  • 使用滑动窗口浏览训练语料库:每个单词都是一个预测问题。
  • 目标是使用相邻单词来预测当前单词(反之亦然)。
  • 预测的结果决定了我们是否调整当前的单词向量。渐渐地,向量收敛到(希望)最优值。

比如我们可以用“人工”来预测“智能”。

Source: https://www.infoq.com/presentations/nlp-practitioners/?itm_source=presentations_about_Natural-Language-Processing&itm_medium=link&itm_campaign=Natural-Language-Processing

然而,预测本身并不是我们的目标。它是学习向量表示的代理,以便我们可以将它用于其他任务。

Word2vec 跳跃式网络架构

这是 word2vec 模型架构之一。它只是一个简单的隐藏层和一个输出层。

Source: http://mccormickml.com/2016/04/19/word2vec-tutorial-the-skip-gram-model/

数学

下面是 word2vec 嵌入背后的数学。输入层是独热编码向量,因此它在单词索引中得到“1”,在其他地方得到“0”。当我们将这个输入向量乘以权重矩阵时,我们实际上拉出了对应于该单词索引的一行。这里的目标是提取重要的行,然后,我们丢弃其余的行。

Source: http://mccormickml.com/2016/04/19/word2vec-tutorial-the-skip-gram-model/

这是 word2vec 工作的主要机制。

当我们使用 Tensorflow / Keras 或者 Pytorch 来做这件事的时候,他们有一个专门的层用于这个过程,叫做“嵌入层”。所以,我们不打算自己做数学,我们只需要传递一个热编码向量,“嵌入层”做所有的脏工作。

预处理文本

现在我们将为一个 BBC 新闻数据集实现 word2vec 嵌入。

  • 我们用 Gensim 来训练 word2vec 嵌入。
  • 我们使用 NLTK 和 spaCy 对文本进行预处理。
  • 我们使用 t-SNE 来可视化高维数据。

clean_text.py

  • 我们使用空间来进行引理化。
  • 禁用命名实体识别以提高速度。
  • 去掉代词。

lemmatize.py

  • 现在我们可以看看最常用的 10 个单词。

word_freq.py

在 Gensim 中实现 Word2vec 嵌入

  • min_count:语料库中要包含在模型中的单词的最小出现次数。数字越大,语料库中的单词就越少。
  • window:句子内当前词和预测词之间的最大距离。
  • size:特征向量的维数。
  • workers:我知道我的系统有 4 个内核。
  • model.build_vocab:准备模型词汇。
  • model.train:训练词向量。
  • model.init_sims():当我们不打算进一步训练模型时,我们使用这一行代码来提高模型的内存效率。

word2vec_model.py

探索模型

  • 找出与“经济”最相似的单词
w2v_model.wv.most_similar(positive=['economy'])

Figure 1

  • 找出与“总统”最相似的单词
w2v_model.wv.most_similar(positive=['president'])

Figure 2

  • 这两个词有多相似?
w2v_model.wv.similarity('company', 'business')

请注意,如果我们改变min_count,上述结果可能会改变。例如,如果我们设置min_count=100,我们将有更多的单词可以使用,其中一些可能比上面的结果更接近目标单词;如果我们设置min_count=300,上面的一些结果可能会消失。

  • 我们使用 t-SNE 来表示低维空间中的高维数据。

tsne.py

Figure 3

  • 很明显有些词彼此接近,比如“球队”、“进球”、“伤病”、“奥运”等等。这些词往往被用在与体育相关的新闻报道中。
  • 其他聚集在一起的词,如“电影”、“演员”、“奖项”、“奖品”等,它们很可能在谈论娱乐的新闻文章中使用。
  • 又来了。剧情看起来如何很大程度上取决于我们如何设定min_count

Jupyter 笔记本可以在 Github 上找到。享受这周剩下的时光。

参考:https://learning . oreilly . com/videos/oreilly-strata-data/9781492050681/9781492050681-video 327451?自动播放=假

了解模型的结果

原文:https://towardsdatascience.com/understanding-your-models-results-b0d7c5170603?source=collection_archive---------20-----------------------

数据分析和数据科学生命周期包括理解我们正在处理的数据,以及从模型提供的结果中解释和提取价值的关键步骤。

对于这些关键步骤,我们需要一个解决方案来帮助我们探索数据并与之交互,同时通过提出隐藏的见解来增强我们的发现能力。

在本文中,我们将评估预测模型的结果,找出它在哪些方面表现得更好和更差,了解某些变量是否以及为什么比其他变量更重要,以及如何改进模型。

我们将使用一个由 https://cloud.google.com/bigquery/public-data/的 BigQuery 托管的公共数据集的例子。谷歌团队发布了一个信用卡客户数据集,用来预测信用卡违约。它们提供算法给出的分数,以及默认值的真实值(1/0)。那些得分较高的客户,将有更多的违约概率。

使用 Graphext 来可视化数据,我们可以了解分数在数据拓扑中的分布情况,以及预测模型忽略了哪些区域或客户端组。这是分数分布的热图:

这是真实目标的分布图:

看起来 50%的真实违约者(黄色,1 代表 default_payment_next_month)预测得分很高,但其余的得分很低,这意味着他们是假阴性。

让我们比较这两组,看看为什么我们的算法在检测这些模式方面较弱。我们将为这两个组创建两个“集合”,或标签:真阳性(高分的违约者)和假阴性(低分的违约者)。

我们的比较界面将自动建议最能区分我们各组的变量。最有区别的变量是 Pay_0(最后一次支付延迟)。算法似乎对这个变量过度拟合,将所有 Pay_0 大于 1 的客户归类为高风险,而忽略了这个变量小于 1 的违约者。

进一步分析,我们还可以观察到假阴性比真阴性具有更高的极限平衡。这意味着,我们遗漏的违约者可能比我们正在捕获的违约者更危险,意味着他们可能拖欠更多的钱。

为什么模型过度拟合这个变量而忽略了其他危险的违约者?让我们来看看这个特殊的变量。如果我们在数据集中过滤那些 Pay_0 值大于 0 的客户,我们会看到目标利率上升到 50%以上,当我们过滤该变量值大于 2 的客户时,目标利率上升到 75%。

我们应该做的第一件事,是审查该变量是如何在数据库中建立的,并验证是否建立良好,它没有未来的信息。

检查后,很明显我们需要建立两个独立的模型,一个不需要为那些超过 Pay_0 的客户进行细分,因为目标水平很高,另一个更细分的模型用于那些 Pay_0 小于 0 的客户,因为他们更难用这个初始数据集捕获,他们的模式可能会隐藏在其他类型的变量中。

这只是一个示例,说明数据探索如何帮助您更好地理解模型的结果,并指导您如何改进和推进您的分析。

如果您想了解更多,请向我们索取演示

UNet —逐行解释

原文:https://towardsdatascience.com/unet-line-by-line-explanation-9b191c76baf5?source=collection_archive---------0-----------------------

UNet 实施示例

UNet 由传统的卷积神经网络演变而来,于 2015 年首次设计并应用于处理生物医学图像。由于一般卷积神经网络将其任务集中在图像分类上,其中输入是图像,输出是一个标签,但在生物医学情况下,它要求我们不仅要区分是否存在疾病,还要定位异常区域。

UNet 致力于解决这一问题。它能够定位和区分边界的原因是通过对每个像素进行分类,因此输入和输出共享相同的大小。例如,对于尺寸为 2x2 的输入图像:

[[255, 230], [128, 12]]  # each number is a pixel

输出将具有相同的大小 2x2:

[[1, 0], [1, 1]]  # could be any number between [0, 1]

现在让我们来看看 UNet 的具体实现。我会:

  1. 显示 UNet 的概述
  2. 逐行分解实现并进一步解释它

概观

这个网络的基本基础看起来像是:

UNet architecture

乍一看,它呈“U”形。该架构是对称的,由两大部分组成—左边部分称为收缩路径,由一般的卷积过程构成;右边部分是扩展路径,由转置的 2d 卷积层构成(你现在可以认为它是一种上采样技术)。

现在让我们快速看一下实现:

代码引用自 Kaggle 竞赛的一个内核,一般来说,大多数 UNet 遵循相同的结构。

现在让我们一行一行地分解实现,并映射到 UNet 架构映像上的相应部分。

逐行解释

收缩路径

收缩路径遵循以下公式:

conv_layer1 -> conv_layer2 -> max_pooling -> dropout(optional)

所以我们代码的第一部分是:

哪一个符合:

注意每个过程构成两个卷积层,通道数从 1 → 64 变化,因为卷积过程会增加图像的深度。向下的红色箭头是最大池化过程,它将图像的大小减半(大小从 572x572 → 568x568 减少是由于填充问题,但这里的实现使用 padding= "same ")。

该过程重复 3 次以上:

带代码:

现在我们到达了最底部:

仍然构建了 2 个卷积层,但是没有最大池化:

这时的图像已经调整到 28x28x1024。现在让我们走上宽阔的道路。

宽阔的道路

在扩展路径中,图像将被放大到其原始大小。公式如下:

conv_2d_transpose -> concatenate -> conv_layer1 -> conv_layer2

转置卷积是一种扩大图像大小的上采样技术。这里有一个可视化演示和一个解释这里。基本上,它在原始图像上做一些填充,然后进行卷积运算。

在转置卷积之后,图像从 28×28×1024→56×56×512 被放大,然后,该图像与来自收缩路径的相应图像连接在一起,并且一起形成大小为 56×56×1024 的图像。这里的原因是组合来自先前层的信息,以便获得更精确的预测。

在第 4 行和第 5 行中,添加了 2 个其他卷积层。

与之前相同,该过程重复 3 次以上:

现在我们已经达到了架构的最上层,最后一步是重塑图像,以满足我们的预测要求。

最后一层是卷积层,有 1 个大小为 1x1 的滤波器(注意整个网络没有密集层)。剩下的神经网络训练也一样。

结论

UNet 能够通过逐个像素地预测图像来进行图像定位,UNet 的作者在他的论文中声称,该网络足够强大,可以通过使用过多的数据增强技术,基于甚至很少的数据集来进行良好的预测。使用 UNet 进行图像分割有很多应用,也出现在很多比赛中。一个人应该尝试一下自己,我希望这篇文章可以成为你的一个好的起点。

参考:

不幸的结局

原文:https://towardsdatascience.com/unhappy-endings-36e5fd157703?source=collection_archive---------27-----------------------

《权力的游戏》有没有电视史上最差的大结局?

A Song of Ice and Ire (Image: HBO)

《权力的游戏》是一种文化现象,这对任何人来说都不是新闻。以任何标准衡量,这都是过去十年中最大的电视节目,尤其是就其预算而言,根据综艺节目的报道,该节目最后一季每集的预算达到了惊人的 1500 万美元(T2)。

然而,这并不是第八季唯一令人惊讶的特征。尽管开头几集很有希望,但作为《权力的游戏》同义词的出色写作开始下滑。而且不是一点点。到了节目的高潮,情节漏洞被打开了。一英寸厚的情节装甲消除了电视史上最大的战斗序列的所有紧张气氛。错综复杂的人物弧线就像被龙焰点燃的铁王座一样消失了。犯罪记录还在继续。

粉丝们对这一切毫无兴趣。一份请愿书要求“与有能力的作家一起”翻拍最后一季,已经有 170 万人签名,并且人数还在增加。当然,节目主持人面临着一个几乎不可能完成的任务。鉴于前几季的高质量和由此产生的巨大期望,很难想象一个结局不会让至少一些人失望。

但是电视史上最差的?好吧,这是一个数据科学博客,所以要回答这个问题,现在是时候让一些数字参与进来了…

“I drink and I mung things,” — Tyrion Lannister, probably… (Image: HBO)

不出所料,我们将用于这一分析的数据集来自 IMDb。特别是,我们将使用几个电视连续剧统计数据的数据集,可以直接从 IMDb 这里下载,以及另一个特定于剧集的统计数据的数据集。这第二个数据集需要一点网络搜集来生成(从 IMDb 并不容易获得特定剧集的数据——稍后会有更多)。

将来自 IMDb 的所需数据集连接在一起,并将其加载到熊猫数据帧中,我们看到我们有 951,196(!)行,每一行代表一个唯一的“标题”,以下列:

The index of this dataframe has been set to ‘tconst’, which is a unique identifier for each title on IMDb. This is a very useful field — especially in cases when two shows have the same name, for example, the original BBC ‘House of Cards’, and the Netflix remake, which should be analysed as two separate shows.

我们可以使用这些列来过滤标题:

  • 标题类型告诉我们正在讨论的标题是电影、电视短片、电视电影等。我们可以删除任何不是'电视剧'的行。
  • isAdult 是 1 还是 0,取决于……嗯,你大概能猜到。假设这里的 get 计数为 0,那么删除带有 1 的行可能是安全的。
  • endYear 告诉我们这部剧在哪一年结束,而 NaN 则代表仍在制作中的剧集。鉴于我们正在分析节目的结局,我们应该删除这里带有 NaN s 的行。
  • 平均分是一个介于 0 和 10 之间的浮动值,表示给予整个系列的平均分(10 分)。这一点很重要——在 IMDb 上,人们既可以对一个系列进行评级(这在本专栏中有所考虑),也可以对单个剧集进行评级。正如我们将在后面看到的,这些评级并不总是像人们预期的那样紧密相关。如果我们在分析剧集的结局,那么只包括总体上至少还过得去的标题是合理的(一个糟糕的剧集也有一个糟糕的结局并不是一个特别有启发性的观点)。因此,我们过滤掉任何没有 7.5/10 或以上系列评分的节目。
  • numVotes 告诉我们有多少张选票进入了平均投票。我们应该有一个较低的门槛,以确保我们只处理(相对)主流系列。我用 2 万张选票作为截止日期。
  • 一旦我们有了特定剧集的数据,我们也将排除任何少于 12 集的剧集。这样的集数是必要的,以便从整个系列的整体质量中理清一个节目“结局”的质量。

令人难以置信的是,应用这些过滤器让我们从 951,000 本书减少到 305 本。这些是 305 个展示,将形成以下分析的基础。

如前所述,要获得单集的收视率,我们需要直接从 IMDb.com 那里获取。

这就是那些“tconst”标识符派上用场的地方——IMDb 在每个标题的 URL 中使用的正是这些字符串。比如《权力的游戏》就有一个 tt0944947 的‘t const’。因此,系列 1 的 IMDb 网页采用以下形式:

www.imdb.com/title/TT 0944947/剧集?季节=1

考虑到这一点,我们可以使用一个函数遍历一个节目的不同季节,并存储每一集的收视率。通过这个函数传递一个“tconst”代码列表,我们可以为给定的节目列表(在我们的例子中,我们上面确定的 305 个标题)创建一个剧集评级数据库。

有了这些新数据,我们就可以开始分析了。

让我们先看一些非常简单的东西,来测试一下我们的数据集。在我们的“已完成”电视节目数据库中,哪些节目的整体收视率最高?

即使结局令人不快,《权力的游戏》仍然享有 9.4 的健康收视率,周围是你预计会在这样的排名中看到的剧集(《绝命毒师》、《火线》(The Wire)和《黑道家族》(The Sopranos),以及一些你可能甚至没有听说过的剧集(《蕾拉和梅克纳》(Leyla and Mecnun)是土耳其剧,目前在网飞可以看到,而《阿凡达》(Avatar)、《死亡笔记》(Death Note)和《钢之炼金术士》(Fullmetal Alchemist)都是日本动漫)。

让我们更深入地了解排名前五的剧集,追踪每一集的收视率。

正如我们可能预料的那样,第一个跳出来的是《权力的游戏》结尾时收视率的急剧下降。我们还应该注意到,这种下降并不是不可避免的——有很多高质量节目在最后一刻没有出错的例子。事实上,这里的其他剧集在最后几集几乎达到了各自的巅峰(黑道家族的轻微下滑可能是由臭名昭著的“切换到黑色”结局造成的)。

这里出现的另一个不太明显的东西是总的剧集评级(如原始数据集中所定义的)和剧集评级的平均值之间的关系。我们会认为它们非常相似,如果不是完全相同的话,尽管事实似乎并非如此。例如,虽然《连线》的剧集收视率一直很高,但平均下来仍比其整个系列的收视率低一个百分点(分别为 8.25 和 9.30)。

事实上,如果我们比较整个数据集的这两个指标,我们会发现剧集收视率和平均剧集收视率之间的相关性实际上相当弱。

The purple line here represents x = y. Very few titles sit on (or indeed especially near) it

奇怪的是,我们看到总系列和剧集评分差异最大的七个节目中有六个是动画,其中五个是日本动画(火影忍者、星际牛仔、死亡笔记和两份龙珠 Z)。

查看具有最大差异的剧集跟踪记录,我们看到很高的标准偏差(在《蝙蝠侠》和《龙珠 Z》的情况下,每集的质量相当不一致)。

我们可以猜测,这里有某种“怀旧因素”在起作用——人们可能对十多年前播出的一部电视剧有着美好的“整体”记忆,这将导致该剧整体的高收视率。

然而,时间可能会抹去对无用剧集的记忆,从而降低单集收视率(我们可以假设,逐集评分的人更有可能最近以更客观的眼光观看了这些剧集)。

数据在一定程度上证实了这一点。一部电视剧的年终与其整体剧集评分和平均剧集评分之间存在负相关关系。

The further towards the top of the chart a title is, the higher its series rating is compared to the average rating of its individual episodes. Older shows are likelier to have such discrepancies.

那么,鉴于我们已经看到了剧集收视率差异很大的不一致的剧集,哪些剧集能够在整个播出过程中保持一致的质量呢?我们可以通过绘制一部剧的剧集收视率均值和标准差来回答这个问题。

Consistently good shows highlighted in yellow: The Wire, Leyla and Mecnun, Firefly, Oz, Blackadder, Mr. Bean, Ezel, Pushing Daisies, The Killing, The Inbetweeners, Happy!, Studio 60 on the Sunset Strip, ‘Allo ‘Allo!, Into the Badlands, Agent Carter, Almost Human, Pinky and the Brain, The Alienist, Nikita, Rizzoli & Isles, Kyle XY, and Witches of East End

让我们回到系列赛决赛的话题上来。

回答片名问题的一个非常简单的方法是——“权力的游戏有电视史上最差的结局吗?”—就是简单的把每个剧集的最后一集隔离出来,按照收视率从上到下排序。让我们来看看这个列表的极端情况:

我们不应该对《绝命毒师》出现在顶部感到惊讶,尽管除了《阿凡达》,其他的标题对这个博客来说都是新的。让我们更详细地看看这些达到 9.8 分的其他节目。

至于天平的另一端,我们看到《权力的游戏》并不(完全)拥有最差最后一集的荣誉——这个可疑的荣誉属于网飞改编的《纸牌屋》。

“For those of us climbing to the top of the IMDb rankings, there can be no mercy” (Image: Netflix)

现在,我们将看到《纸牌屋》突然出现在这些“最差”的名单中,所以让我们马上处理这个特定的房间里的大象。《纸牌屋》在接近尾声时的衰落是毋庸置疑的。对其最后一集的一星评论既多又严厉。然而,该剧在最后一季确实不得不应对其首席演员和执行制片人的职业内爆——这是《权力的游戏》的主持人戴维·贝尼奥夫和 D·B·威斯(或者用术语来说是“D&D”)不必承受的。

除此之外,我们还能如何判断一部剧结局的好坏呢?单看最后一集似乎有点狭隘。有人可能会说,以这种方式比较不同长度的序列是不公平的。对于 12 集的节目,最后一集代表其总播放量的 8%,但是对于 150 集的节目,最后一集代表不到 1%。

此外,很多对《权力的游戏》结局的批评是因为它的前 95%的质量——我们应该在剩余剧集的背景下看待一部剧的结局。

因此,让我们来看看一部剧集在最后 5%的平均收视率(以获得一个更一致的跨标题“结尾”定义),并将其与该剧的中值剧集收视率进行比较。

《纸牌屋》再次占据榜首,但网飞的另一部作品《血统》将《权力的游戏》挤到了倒数第二名。尽管如此,如果我们比较他们的剧集收视率,我们可以看到《血统》和《纸牌屋》都没有达到《权力的游戏》盛况下的高度。

那么,我们能得出什么结论呢?《权力的游戏》可能没有电视史上最差的大结局。但肯定是在上面(或下面)。当然,尽管粉丝们可以为有史以来最伟大的电视节目之一的不光彩的消亡而悲伤,但我们应该记住,在它运行的大部分时间里,它恰恰是电视有史以来最伟大的节目之一。

对泰温·兰尼斯特来说,我们必须接受 D & D 的决定,并感谢我们还有《权力的游戏》——D&D 并不完美,但没有人是完美的。

让我们只希望五年后我不会坐在这里,写一篇关于他们如何击败星球大战的博客…


注意:截至 2019 年 7 月 14 日,本文中的所有评级均正确

R 中的单元测试

原文:https://towardsdatascience.com/unit-testing-in-r-68ab9cc8d211?source=collection_archive---------0-----------------------

为什么单元测试真的是一个好主意——即使对于非包。为创建健壮的软件编写测试,节省时间,并从中获得乐趣!

你会问:“为什么要进行单元测试?我的代码起作用了!”。单元测试有助于创建健壮的代码。在简短地介绍了什么是健壮代码之后,我给出了基本单元测试思想的概述。最后,我展示了如何在 R 中快速使用它们,甚至是简单的脚本(没有创建 R 包的负担)。

Entangled software breaks upon tiny changes — like these wirings (Photo by Pexel on Pixabay)

健壮代码

  • 不会因变更(如新的 R 版本、包更新、错误修复、新特性等)而轻易中断。)
  • 可以简单地重构
  • 可以将延长而不破坏其余部分
  • 可以进行测试

单元测试对于编写健壮的代码是很重要的——它们可以让我们更加确信一些变化不会破坏代码——至少代码可以比紧耦合的代码库更快地修复。

有很多关于单元测试的精彩文献。在这篇文章中,我想分享单元测试背后的基础知识,并把它们应用到 R 脚本语言中,同时推荐一些包和概念,用于您的日常 R 编程。

确信:在不断增长的代码库中,你需要单元测试。有时候,即使很小的脚本有时也会产生很多苦恼。我保证在没有测试的情况下在调试器中花很多时间。在长期的单元测试中会节省你很多宝贵的时间,即使你认为这可能是额外的工作。我不喜欢测试驱动设计(TDD)——在我看来,测试应该只是支持你编程的一个工具。他们不应该统治你!

动机

单元测试在 R 和 Python(以及其他动态类型的脚本语言)中特别有用,因为没有编译器的帮助来告诉你在哪里可以用无效的参数调用函数。有一些帮助器包,比如 R 的 lintr 或 Python 的 pylint,试图减轻这一点。

然而,在过去我经常遇到困难——代码崩溃,例如,一些中间列表突然变空,或者只包含一个项目,而一个列表包含多个项目。在这些地方,测试将有助于防止将来出现这种问题。在数据科学中,一些计算会持续很长时间。如果计算在几个小时后由于错误而中止,则为坏。

单元测试基础

测试简单功能

一个简单的函数接受一个输入并生成一个输出,如下所示

在单元测试中,我们希望在调用函数 f 时,验证输出 y 是否具有特定输入 x 的期望值。通常测试不同的( x,y )对。

一个例子可以是按升序对向量值进行排序的函数。边界测试非常重要。在这个例子中,我们可以测试

  • 作为输入的空列表
  • 只有一个值的列表
  • 已经排序的列表
  • 未排序的列表
  • 如果提供了无效的参数,将引发函数错误。
  • 该函数是否正确处理了所有这些情况?
  • 当创建一个复杂的应用程序时,对可能失败的功能或者过去发生错误的地方进行单元测试是一个好习惯。为 bug 编写一个测试,修复 bug,看看单元测试是否成功。

测试有副作用的功能

事情并不总是像上一节那样简单。有时一个函数会有副作用,可能是文件的读/写、数据库的访问等等。

在这种情况下,考试的准备就更加复杂了。它可以只包含一堆用于模拟数据库访问的函数的模拟对象。这正在影响编程风格——抽象层可能会变得必要(参见 R 数据库接口——DBI)。在某些情况下,需要在执行测试之前生成输入文件,并在测试之后检查输出文件。

测试类别

面向对象编程( OOP )在 R 里有点奇怪,感觉很别扭。如果你曾经有机会用其他语言编写软件:我强烈建议,为了更好地理解什么是面向对象——比如说尝试一下kot Lin——这很有趣。

面向对象背后的基本思想是你把数据(成员变量)和处理这些数据的代码(称为方法)放在一起。这是在一个类定义中声明的。面向对象的主要思想是,你可以通过继承从另一个类派生出类,从而扩展它的功能和数据。一个简单的例子:一个图形形状可以从原点偏移(x,y)。由此,我们得到一个矩形,除此之外,它还有一个宽度和一个高度(w,h)。

类定义只是由构造器生成的具体对象实例的蓝图。然后,实例的状态(成员变量)通过调用如下类方法逐步修改:

在 R 中有不同的面向对象系统,如 S3 和 S4。大部分旧功能都是用 S3 写的。summary()或 print()之类的函数就是这样的例子。这些“函数”实际上是方法,它们被分派给作为参数输入的不同对象类型的相应类方法。参见 R 教程章节。16 凯利·布莱克如果你想了解更多这方面的情况。因此,测试通常由对对象实例的一系列操作组成,从而验证某些步骤后的结果是否符合预期。

R 中的单元测试

这里我们使用 testthat package⁴,它有一个从其他语言(Java、C#、Python)派生的 xUnit 测试中已知的概念。这个例子展示了第一个基本功能测试。因为我经常发现自己创建了更多的脚本而不是 R 包(这要乏味得多),所以这个例子展示了如何使用 testthat 而不必创建包。

举例:一个简单的函数

假设我们编写了一个函数,它在 my_code 中将其参数(可能是一个数字向量)加 1。R 文件。那似乎是原始的。但是你会在续集里看到,连这个功能都可能失效。

创建一个名为 tests 的目录,并将一个或多个以 test_ 作为文件名的 R 脚本放在那里。

在这之后,您可以通过在 R 中调用 testthat::test_dir("tests ")来启动单元测试代码,您将会看到类似这样的输出。

The output is shown after calling the tests. So the function did not work with an empty list c().

因为它不是一个包,所以测试文件必须包含一个 source()命令来导入您的脚本。

测试是使用 testthat::test_that(name,expression)函数声明的。第一个参数为测试指定一个名称,以便识别它。第二个参数是一个 R 表达式,它将使用 expect_*断言。每当断言不成立时,测试被中止并标记为失败。

好的一面是:无论何时你决定继续创建你的 R 包,你都可以让你的测试就位。然后只需要从 test_xxx 中删除那些 source() 命令。R 文件。

  • 参见我的 GitHub 获取这个基本片段。

结论

单元测试让你不再害怕修改源代码。当你在写代码的时候心里想着可测试性,你的编程风格就会改变。如果函数不能被简单地测试,那就说明你有纠缠不清的代码!在这种情况下,准备环境(变量、文件、数据库连接等)的工作可能会过多。)做一个测试。对于有明确目的的函数,单元测试应该很容易!

我建议从福勒和马丁的伟大著作中获得灵感。

解开你的代码,编写单元测试,享受其中的乐趣!花更多时间开发有趣的功能,少花时间调试。

参考文献

[1]: G. J. Myers,T. Badgett,T. M. Thomas 和 C. Sandler,软件测试的艺术,第 2 卷(2004),威利在线图书馆

[2]: M .福勒,重构:改进现有代码的设计(2000),艾迪生-卫斯理专业版

[3]: R. C. Martin,干净代码,敏捷软件工艺手册(2009),普伦蒂斯霍尔

[4]:test tha:R的单元测试。哈德利·韦翰。

单元测试 Python 数据可视化

原文:https://towardsdatascience.com/unit-testing-python-data-visualizations-18e0250430?source=collection_archive---------10-----------------------

对与 matplotlib 接口的 Python 代码进行单元测试可能具有挑战性。测试有多大帮助,最好的方法是什么?

在为数据科学工具包 Triage、进行开发时,这种情况经常出现,该工具包包括大量使用 matplotlib 或其他相关 Python 库绘制图表的代码。这些情节经常在 Jupyter 笔记本中使用,这些笔记本有自己的设施来显示情节。

过于详细地测试可视化代码没有太多意义。对于一个情节应该是什么样子的期望很难用一种易于单元测试的方式来表达。将尽可能多的绘图数据生成与绘图分开,并像测试任何其他生成的数据一样测试绘图数据生成通常是有意义的。但是图数据不是图。我们想确保绘图代码正常工作。我们如何定义“作品”?一个有用的定义是测试是否能回答这个问题:

我们策划了什么吗?

这是一个很好的开始。任何应该绘制某些东西的代码可能都应该绘制某些东西,并且希望它应该足够容易地自动解决这个问题。

方法一:修补

我过去经常使用的方法是模仿“plt.show”并断言它被调用了。一个例子:

这通常是有效的。因为“plt.show”通常在绘制代码的末尾被调用,所以如果在 plt.show(通常是您要测试的内容)之前出现了问题,这个模拟就不会被调用,测试就会失败。

但是也有一些缺点:

  • 如果 plt.show 没有被调用怎么办?对于经常从 Jupyter 笔记本(或任何其他可能在自己的层上处理显示的显示引擎)调用的代码。您可以尝试制定内部准则,强制所有绘图代码都调用 plt.show,但在这一点上,您只是在测试您的内部准则,而不是代码工作。
  • 如果调用了 plt.show,但不是在您正在导入的模块中调用,该怎么办?以 seaborn 地块为例。他们使用 matplotlib,但是包装了它,所以你不太可能在你的代码中看到 plt.show。如果有人将笨拙的 matplotlib 图形重构为漂亮的 seaborn 图形会怎样?我不希望我的测试在这种情况下失败。
  • 如果调用了 plt.show 但是没有任何内容怎么办?这个可能性不是超级大,但还是有可能的。

方法二:plt.gcf

幸运的是,matplotlib 有另一个接口,我们可以用它来克服 patch 的这些缺点:plt.gcf()(获取当前数字)。

我不确定这是不是 Jupyter 的内联绘图魔法的工作方式,但是它非常有用。gcf 返回对当前(最后绘制的)图形的引用。更好的是,它包括一个数字(plt.gcf()。number),它可以让您跟踪绘制了多少个。在我们的绘图代码运行之后,我们可以检查当前的图形,以便对它做出我们想要的任何级别的断言。所以它不关心是否调用了 plt.show,只要在某个地方创建了图形,它就工作,甚至是内部使用 matplotlib 的一些高级库。

当我第一次发现 gcf 时,很容易在调用代码之前“重置”绘图编号,以尝试并断言当前图形的确切编号。在这样做之前,我试图用 plt.close()来“清除”这个情节:

这在本地有效。然而,当我推给 Travis 时,“close”似乎没有做任何事情,gcf()的值。数字受到其他测试用例的影响。我认为这与我的笔记本电脑有一个真正的显示器/窗口和 Travis 是无头的有关。也许有一种更好的方式来进行“清理”,但我不想进入显示器的杂草中,所以我想出了一种替代方式来使它具有确定性:

断言数字的数量比你开始测试时要多

这在 Travis 和我的笔记本电脑上是一样的。另一个不同之处是,我没有断言绘制的具体数字。不管你是否想在你的代码中这样做(最终我认为它可能会深入到 matplotlib 内部处理事情的方式),你都可以使用这个方法。但是这本身就是一个方便的情节断言工具。我甚至最终把它变成了一个上下文管理器感知的方法,以便于重用:

这种方法可能存在哪些缺点?

我们断言,无论我们调用什么代码来绘图,都会创建 matplotlib 图形。这个易碎吗?理论上。这听起来肯定违反了“不要测试实现”的指导方针。但事实上,我认为

matplotlib 是一个通用的后端,许多我可能会在其中切换的前端都会用到它

是一个比

seaborn 是最好的前端,我会一直使用它,也许它会从 matplotlib 切换后端

我的团队将一个图表重做到一个新的、非 matplotlib 支持的绘图库中当然是可能的,但可能性不大。因此,作为一个相当通用的 Python 数据可视化断言,我对此相当满意。你怎么想呢?我是否遗漏了其他缺点,或者测试 Python 绘图的更好方法?

单元测试 Apache Spark 应用程序

原文:https://towardsdatascience.com/unittesting-apache-spark-applications-b9a46e319ce3?source=collection_archive---------13-----------------------

PySpark 案件

对 Spark 应用程序进行单元测试并不是那么简单。对于大多数情况,您可能需要一个活跃的 spark 会话,这意味着您的测试用例将需要很长时间来运行,并且可能我们正在所谓的单元测试的边界附近踮着脚尖。但是,这绝对值得去做。

那么,我应该吗?
嗯,是的!测试你的软件总是一件好事,它很可能会让你免除许多麻烦,此外,你将被迫把你的代码实现成更小的片断,这样更容易测试,从而获得可读性和简单性。

好的,那么我需要做些什么呢?嗯,我认为我们可以从pip install spark-testing-base开始,然后从那里开始。为此,我们还需要pyspark(当然)和unittest(单元测试 2)和pytest——尽管pytest是个人偏好。

[## 霍尔登克/火花测试基地

用 Spark 编写测试时使用的基类。您已经在 Spark 中编写了一个很棒的程序,现在是时候编写了…

github.com](https://github.com/holdenk/spark-testing-base)

Spark testing base 是一个帮助 Spark 测试的基类集合。对于这个例子,我们将使用继承自SparkTestingBaseReuse的基础[SQLTestCase](https://github.com/holdenk/spark-testing-base/blob/master/python/sparktestingbase/sqltestcase.py),它创建并重用了一个 SparkContext。

SparkSessionSparkContext上:

[## 火花会议和火花背景的故事

我已经有了 Spark 上下文、SQL 上下文、Hive 上下文!

medium.com](https://medium.com/@achilleus/spark-session-10d0d66d1d24)

从个人经验来说(使用目前最新的 spark 版本。+),我发现我需要对SQLTestCase做一些小的调整,这是我在当前项目中经常使用的一个测试用例。因此,这里有一个我为适应自己的需要而做的调整的例子:

Example of a base spark test case, based on Spark testing base’ s SQLTestCase

总结一下我所做的改变:

  • 为了一致性,我添加了一个配置,将时区设置为UTC。时区一致性是贯穿你的代码的一个非常基本的东西,所以请确保你总是设置spark.sql.session.timeZone
  • 在配置中设置的另一个重要的事情是spark.sql.shuffle.partitions对于将要运行测试的机器来说是合理的,比如<= cores * 2。如果我们不这样做,那么 spark 将使用默认值,即 200 分区,这将不必要地、不可避免地减慢整个过程。<= cores * 2是一个普遍适用的好规则,不仅仅适用于测试。
  • 还添加了一种在比较之前对要比较的数据帧进行排序的方法。在一个基类中有一个compareRDDWithOrder方法,但是我认为使用 dataframes 更容易。
  • schema_nullable_helper方法应该谨慎使用,因为它可能最终破坏你的测试用例,这取决于你需要测试什么。这种情况的用例是在没有指定模式的情况下创建数据帧(目前不推荐使用),因为 spark 试图推断数据类型,有时要比较的两个数据帧之间的可空标志不一致,这取决于用于创建它们的数据。该方法将两个数据帧的模式之一更新为另一个的模式,该模式仅与可空值相关。
  • 最后,我为appNameconfig添加了一个稍微调整过的版本。在最新的 pyspark 版本中,session实例化也有所不同。(对于 2.2 的支持,有一个待定的版本。+和 2.3。+ spark 版本仍然开放这里这里,所以,我们将子类化来解决这个问题)

注意getOrCreate()将创建一次 spark 会话,然后在整个测试套件中重用它。

现在让我们创建一个要测试的简单特性:

An example of a feature calculation class

这个特性只是计算a/b,其中ab是输入数据帧中的列。非常简单明了。我在这里没有包括列检查,因为如果ab丢失,我们需要计算过程失败到足以停止一切。但一般来说,这取决于您希望如何处理应用程序中的错误情况,以及这种计算对您的过程有多重要。

这里需要注意的是:即使您模拟了对calculate dataframe 的输入,spark 会话也是需要的,因为在我们特性的calculate实现中,我们使用了像F.col('a')这样的pyspark.sql.functions,这需要您有一个活动的会话。如果我们没有会话,我们会得到这样的错误:

Attribute error when using pyspark sql functions without an active session

如果出于某种原因,我们需要在特性的__init__体(构造函数)中声明计算,这就更明显了,例如:

**class** FeatureAToBRatio(object):
    feature_name = **'a_to_b_ratio'** default_value = 0.

    **def** __init__(self):
        self.calculation = F.col(**'a'**).cast(**'float'**) / F.col(**'b'**).cast(**'float'**)

然后我们会在特性实例化期间得到错误feature = FeatureAToBRatio()

现在让我们继续添加一些测试用例。

An example test suite for testing feature a to b ratio

我们正在测试:

  • 正常情况下,ab存在,并有数值
  • 其中一个例外,例如b不存在于数据帧中
  • 分母为 0 的情况。

这些只是人们可以为测试的一些基本测试用例。我想到了许多其他的例子,例如,如果a为空或者不同类型的数据类型会发生什么,但是为了这个例子,让我们保持它简单明了。

要运行测试套件:

python -m pytest test_feature_a_to_b_ratio.py

Example output of tests execution

Example output of tests execution — ran with PyCharm

就是这样!请注意,它运行了 7.58 秒(当 shuffle 分区设置为默认的 200 时,运行了 14.72 秒),这对于单元测试来说有点多,而且它只有 3 个测试用例—想象一下,有一个 CI/ CD 在每次合并或提交时运行测试套件…

当然,spark / pyspark 还有很多复杂的测试要做,但我认为这是一个很好的基础。如果有更好的方法,请告诉我。

我希望这有所帮助。任何想法,问题,更正和建议都非常欢迎:)

如果您想了解更多关于 Spark 的工作原理,请访问:

[## 用非技术性的方式解释技术性的东西——Apache Spark

什么是 Spark 和 PySpark,我可以用它做什么?

towardsdatascience.com](/explaining-technical-stuff-in-a-non-techincal-way-apache-spark-274d6c9f70e9) [## 向 Spark 数据帧添加顺序 id

怎么做,这是个好主意吗?

towardsdatascience.com](/adding-sequential-ids-to-a-spark-dataframe-fa0df5566ff6)

对逻辑回归(python)的直观理解

原文:https://towardsdatascience.com/univariate-logistic-regression-example-in-python-acbefde8cc14?source=collection_archive---------21-----------------------

二元例子

Source: Anne Spratt

逻辑回归是一种用于预测目标变量“非此即彼”的模型。我们将研究的例子是:

  • 目标变量:学生将通过或未通过考试。
  • 自变量:每周学习时间

逻辑模型本质上是带有额外步骤的线性模型。在逻辑模型中,线性回归通过“sigmoid 函数”运行,该函数将其输出压缩成二分的 1 和 0。

如果我们想预测实际的考试成绩,我们会使用线性模型。如果我们想预测“通过”/“失败”,我们将使用逻辑回归模型。

线性(预测数值测试分数):

y = b0 + b1x

逻辑(预测“通过/失败”):

p = 1 / 1 + e ^-(b0 + b1x)

可视化:

下图中,直线是线性的,“S”形线是逻辑的。由于其形状,逻辑回归在用于“非此即彼”模型时具有更高的准确性。

Logistic Regressions are “S” shaped. Linear Regressions are straight.

理解数据:

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
%matplotlib inline
df = pd.read_excel(r”C:\Users\x\x\Log_test.xlsx”)
x = df[‘W_hours’]
y = df[‘Y’]plt.scatter(x,y)
plt.show()

df.info()
x.plot.hist()
y.plot.hist()

数据集中有 23 行。以下是学习时间的分布情况:

下面是通过(1)/失败(0)的分布情况:

数据准备/建模

接下来,我们将使用 sklearn 库导入“LogisticRegression”。关于参数的详细信息可以在这里找到

我们把我们的双变量模型转换成二维的。shape()函数。我们定义了 1 列,但是我们将行数保留为数据集的大小。所以我们得到 x 的新形状为(23,1),一个垂直数组。这是使 sklearn 功能正常工作所必需的。

使用“logreg.fit(x,y)”来拟合回归。

from sklearn.linear_model import LogisticRegression
logreg = LogisticRegression(C=1.0, solver=’lbfgs’, multi_class=’ovr’)#Convert a 1D array to a 2D array in numpy
x = x.reshape(-1,1)#Run Logistic Regression
logreg.fit(x, y)

使用和可视化模型

让我们写一个程序,通过学习的小时数,我们可以得到通过和失败的预测概率。我们在下面的代码中输入学习时间:学习 12、16 和 20 小时的例子。

print(logreg.predict_proba([[12]]))
print(logreg.predict_proba([[16]]))
print(logreg.predict_proba([[20]]))

左边的输出是失败的概率,右边的输出是通过。

为了形象化模型,让我们做一个循环,将每半小时的学习时间放入从 0 到 33 的回归中。

hours = np.arange(0, 33, 0.5)
probabilities= []
for i in hours:
    p_fail, p_pass = logreg.predict_proba([[i]])[0]
    probabilities.append(p_pass)plt.scatter(hours,probabilities)
plt.title("Logistic Regression Model")
plt.xlabel('Hours')
plt.ylabel('Status (1:Pass, 0:Fail)')
plt.show()

在这组虚构的数据中,如果一个学生学习超过 20 个小时,他/她就一定会通过,如果不到 10 个小时,他/她就一定会不及格。17 小时是 50/50 的界限。

感谢阅读,

通用变压器

原文:https://towardsdatascience.com/universal-transformers-782af05095ee?source=collection_archive---------23-----------------------

本文将讨论 Universal Transformer,它结合了原始的 Transformer 模型和一种叫做自适应计算时间的技术。通用变形器的主要创新是对每个符号应用不同次数的变形器组件。

纸张参考

德加尼·M、古乌斯·S、维尼亚尔斯·O、乌兹科雷特·J、凯泽·日。万能变形金刚。ICLR 2019。

背景及变压器回顾

如果你还不熟悉变形金刚模型,你应该通读一下“变形金刚:注意力是你所需要的。”万能变压器是对变压器的简单改造,所以先了解变压器型号很重要。

如果您已经熟悉了 Transformer 模型,并且想要快速回顾一下,那么可以这样做:

Figure modified from Transformer paper

基本变换器由编码器和解码器组成:

编码器:

  • 6 个编码器层
  • 每个编码器有 2 个子层:(1)多头自关注;(2)前馈

解码器:

  • 6 个解码器层
  • 每个解码层有 3 个子层:(1)掩蔽多头自注意;(2)编解码多头注意;(3)前馈

以下是对多头注意力的一个数字回顾,这是 Transformer 模型的关键创新之一:

多头关注用于编码器自关注(其将先前的编码器层输出作为输入)、解码器自关注(其将先前的解码器层输出作为输入)以及编码器-解码器关注(其将密钥和值的最终编码器输出以及先前的解码器输出用作查询)。)在上图中,模型中使用多头注意力的部分在左侧用红色方框标出。在右侧,示出了多头注意力计算的每个部分的张量的维度。

最后,快速回顾一下编码器子层和解码器子层中使用的位置式全连接前馈网络:

通用变压器的动机

最初的 Transformer 是一种自然语言处理模型,它并行处理输入序列中的所有单词,同时利用注意机制来合并上下文。它的训练速度比 RNN 快,后者必须一个接一个地处理输入令牌。它在语言翻译方面取得了良好的性能。然而,它在诸如字符串复制的算法任务上性能较差(例如,给定“abc”作为输入,输出“abcabc”。)

神经 GPU 和神经图灵机(不同种类的模型)在语言翻译上性能较差,但在算法任务上性能良好。

Universal Transformer 的目标是只用一个模型就能在语言翻译和算法任务上获得良好的性能。通用变压器的作者还指出,这是一个图灵完全模型。(“图灵完备”是指它可以模拟任何图灵机,这是计算机的正式定义。)

概述

在 Universal Transformers 的论文中,作者提供了一个新的图表来描述他们的模型:

Figure 4 from Universal Transformer paper

然而,我认为相对于原始的 Transformer 文件使用不同的图形样式掩盖了模型之间的关键差异。因此,我修改了原始变形金刚论文中的图,以更清楚地强调变形金刚和通用变形金刚模型的相似性和差异性。关键差异用红色强调:

Modified from original Transformers paper figure

变压器和通用变压器的主要区别如下:

  1. 通用转换器为每个输入令牌应用可变数量的步骤(T 个步骤)的编码器,而基本转换器恰好应用 6 个编码器层。
  2. 通用变换器将解码器应用于每个输出令牌的可变数量的步骤(T 个步骤),而基本变换器恰好应用 6 个解码器层。
  3. 通用转换器使用稍微不同的输入表示:除了“位置编码”之外,它还包括“时间步长嵌入”

差异(1)和(2),步骤的可变数量,通过使用“自适应计算时间”来实现,这将在后面更详细地描述。简而言之,自适应计算时间是一种动态的每位置暂停机制,允许对每个符号进行不同量的计算。

通用转换器是一种“时间并行自关注递归序列模型”,它可以在输入序列上并行化。像基本变压器一样,它有一个“全局感受野”(意味着它一次看很多单词。)主要的新思想是,在每个循环步骤中,通用变换器使用自关注迭代地改进其对序列中所有符号的表示,随后是跨所有位置和时间步骤共享的“转换函数”。

这里有一个来自Oriol Vinyals(@ OriolVinyalsML 在 Twitter 上)的很酷的动画,演示了通用变压器:

通用变压器的参数,包括自我关注和过渡权重,与所有位置和时间步长相关联。如果通用变换器运行固定数量的步骤(而不是可变数量的步骤 T),那么通用变换器相当于在所有层上具有绑定参数的多层变换器。

这是通用变形金刚的另一个很酷的动画,来自谷歌人工智能博客:

通用变压器的更多细节

通用变压器输入

如上图所示,通用转换器的输入是一个长度为 m 的序列,表示为 d 维嵌入。在每个时间步,“坐标嵌入”被添加。这些“坐标嵌入”包括位置嵌入(与原始变换器的位置嵌入相同)和时间步长嵌入(与位置嵌入类似的概念,除了它基于时间 t 而不是位置 I)

通用变压器编码器

通用变形金刚编码器的第一部分是多头自关注,和原变形金刚编码器的第一部分一模一样。

通用转换器编码器的第二部分是一个转换函数。转换函数可以是全位置全连接神经网络,在这种情况下,它与原始变压器编码器的第二部分完全相同。或者,转换函数可以是可分离的卷积。作者没有讨论他们何时使用位置全连接网络而不是可分离卷积,但这种选择可能会影响通用转换器在不同任务上的性能。

什么是可分卷积?可分离卷积将卷积核分割成两个独立的核,这两个核进行两次卷积:

Figure modified from “Separable Convolutions” by Chi-Feng Wang

如果你对可分卷积的更多细节感兴趣,可以看看这篇论文: Francois Chollet。例外:具有深度可分卷积的深度学习。arXiv 2016

这就是通用变压器编码器!如果选择位置前馈网络作为转换函数,通用变压器编码器与原始变压器编码器相同。

通用变压器解码器

同样,如果选择位置式前馈网络作为转换函数,通用变压器解码器与原始变压器解码器相同。有三个解码器子层:

  • 子层 1:多头自我关注(在先前的解码器输出上)
  • 子层 2:多头编解码注意。通过投影先前的解码器输出来获得查询。通过投影最终编码器输出来获得键和值。
  • 子层 3:过渡函数。

通用变压器解码器培训

通用变压器论文的一个优点是,它提供了更多关于如何训练解码器的背景知识。这也适用于最初的 Transformer,但在最初的 Transformer 论文中没有详细讨论。

Transformer 解码器(原始和通用)是“自回归”的,这意味着它一次生成一个输出符号,解码器消耗其先前生成的输出。

它使用“教师强制”来训练,这意味着在训练期间,嵌入目标符号的地面真相被馈入(而不是解码器自己可能不正确的预测。)目标符号被右移(因此模型看不到它应该预测的当前单词)并被屏蔽(因此模型看不到未来的单词。)

在通用变换器中,每个符号的目标分布如下获得:

自适应计算时间(ACT)

这是 Universal Transformers 论文的主要贡献:他们将最初在 RNNs 中开发的自适应计算时间应用于 Transformer 模型:

Graves A .递归神经网络的自适应计算时间。arXiv 预印本 arXiv:1603.08983。2016 年 3 月 29 日。

这是一种允许编码器应用可变次数和解码器应用可变次数的机制。

ACT 根据模型在每一步预测的标量“暂停概率”,动态调整处理每个输入符号所需的计算步骤数(“思考时间”)。通用变压器分别对每个位置(例如每个字)应用动态动作停止机制。一旦一个特定的循环块停止,它的状态就被复制到下一步,直到所有的块都停止,或者直到达到最大的步数。编码器的最终输出是以这种方式产生的最终表示层。

以下是 ACT 工作原理的快速总结:

在每一步,我们都会得到:

  • 停止概率和先前状态(初始化为零)
  • 介于 0 和 1 之间的标量暂停阈值(超参数,即我们自己选择暂停阈值)

首先,我们使用通用转换器计算每个位置的新状态。

然后,我们使用一个全连接层来计算“思考”值,该层将状态降低到 1 维,并应用 sigmoid 激活来使输出成为介于 0 和 1 之间的类似概率的值。这就是思考的价值。“思考”值是模型对每个输入符号需要多少额外计算的估计。

我们决定停止任何超过停止阈值的仓位:

  • 刚停止到这一步:(停止概率+思考) >停止阈值
  • 仍在运行:(暂停概率+思考)≤暂停阈值

对于仍在运行的仓位,更新暂停概率:暂停概率+=思考。

我们更新其他位置的状态,直到模型停止所有位置或达到预定义的最大步数。

关于自适应计算时间的实现,参见这个 Github 库

图灵完备性

Universal Transformer 论文的作者解释说,Universal Transformer 是图灵完全的,就像神经 GPU 是图灵完全的一样。如果你不熟悉图灵完备性或者模型之间相互“还原”的证明,可以跳过这一节。

简而言之,作者通过将神经 GPU 简化为通用转换器来证明通用转换器是图灵完全的:

  • 忽略解码器
  • 使自我关注模块成为身份功能
  • 假设转移函数是卷积
  • 将循环步骤的总数 T 设置为等于输入长度
  • 我们已经从 UT 获得了一个神经 GPU

结果

我们现在已经讨论了通用变形金刚中的所有关键概念。万能变形金刚擅长什么?

通用变压器白皮书中有五项任务,总结如下:

在 bAbi 问答上,通用转换器比原始转换器获得了更好的性能。此外,对于更困难的任务变体(需要更多支持事实来回答问题的变体),在测试数据中所有样本的所有位置上的平均思考时间(通用转换器对一个符号计算多少次)更长。)这意味着当任务更难时,通用变压器“想得更多”。

在 Universal Transformers 的论文中,有几个在 bAbi 任务的不同时间步骤中注意力权重的可视化。视觉化是基于一个芭比故事和一个问题中所有事实的不同观点。四种不同的注意力头对应四种不同的颜色:

Figure 5 from the Universal Transformers paper.

更多这样的数字,可以看论文附录。

Universal Transformer 在主谓一致和 LAMBADA 上也取得了不错的成绩。在 LAMBADA 上,作者注意到通用转换器平均走 8-9 步;然而,他们比较的基础变压器只有 6 层。因此,他们运行了一个 8-9 层的基本变压器,但发现通用变压器仍然优于这种更深层次的变压器变体。这表明更多的计算并不总是更好,在输入和输出序列中的某些符号上减少计算是有价值的。作者推测,自适应计算时间可能具有正则化效果,例如,通过帮助模型忽略(“较少计算”)对解决任务不重要的信息。

最后,作者表明,通用转换器在几个算法任务上取得了良好的性能,包括复制、反转和加法。通用转换器在英德机器翻译方面也优于基本转换器。

总结

  • 通用转换器=原始转换器+自适应计算时间
  • 通用转换器允许每个符号隐藏状态的同时演化,这些隐藏状态是通过关注前一步骤中的隐藏状态序列而生成的。
  • 通用变压器在各种任务上实现了改进的性能。

演讲

对于这篇通用变形金刚博客文章的 PowerPoint 演示版本,请点击链接

特色图片

特色图像是约翰·威廉姆·沃特豪斯的画作“水晶球”的一部分,结合维基百科的“宇宙”(各种星系)图像和卡通太阳。

原载于 2019 年 9 月 7 日http://glassboxmedicine.com

无标签数据的股票正在上涨

原文:https://towardsdatascience.com/unlabelled-datas-stock-is-rising-71ed1cf909b7?source=collection_archive---------34-----------------------

Facebook’s latest Semi-Weak Supervised Learning framework is a novel approach to leveraging unlabelled datasets for Computer Vision. https://ai.facebook.com/blog/billion-scale-semi-supervised-learning/

脸书大学的研究人员一直在探索使用 Instagram 标签作为 ImageNet 分类模型的弱监督预训练手段。在这项研究中,“弱监督”学习描述了使用有噪声的标签进行监督学习,即 Instagram 图片上的标签。这是有利的,因为大数据是计算机视觉中的王者,他们能够利用10 亿张这些 Instagram 图片进行预训练(ImageNet 包含 120 万张图片,以供参考)。

他们基于这种弱监督学习范式的模型已经记录了最先进的 ImageNet 分类结果,准确率高达 85.4%。他们目前通过使用分辨率增强扩展弱监督学习,以 86.4% 的成绩获得 ImageNet 奖杯。

脸书的最新框架半弱监督学习是这种思想的最新体现,取得了令人印象深刻的结果,并自然产生了高效的模型。随着数据量持续爆炸,脸书的半弱监督学习等研究正在寻找新的方法利用大规模未标记数据集并解决图像网络分类等计算机视觉任务。

半监督和弱监督学习

脸书在这项研究中对“半监督学习”提出了独特的观点。他们将模型提取描述为半监督学习任务,这不是不正确的,只是不符合文献的常规。模型提取指的是使用更大容量的教师网络来产生类标签上的 softmax 分布。然后,较低容量的学生网络在该分布上被训练。模型提取是模型压缩中最强大的技术之一,为像 HuggingFace 的 DistilBERT 这样的模型提供动力。

半监督学习描述了从未标记数据中构造监督学习信号的范例。这是 Word2Vec、DeepWalk 或 Wav2Vec 等技术的想法,其中一部分输入被屏蔽掉,模型的任务是预测哪些被删除了。这种扩展到图像的想法被称为“修复”。然而,更常见的是做一些像人工旋转图像,然后让模型预测旋转角度。这就是驱动诸如“自监督 GAN”的自监督模型的机制。

在脸书的“半弱监督学习”框架中,教师模型最初用弱监督数据集(Instagram hashtags 的监督学习)训练,在 ImageNet 上微调,然后教师模型预测原始弱监督数据集上的班级分布,学生模型训练自己预测相同的分布,最后,学生模型在 ImageNet 数据集上微调。

未标记数据集中的类别不平衡

类别不平衡描述了在训练数据中严重偏向一个类别的数据集。例如,包含 80%狗和 20%猫的训练集将产生偏向于将图像标记为狗的模型。Instagram 图片等海量无标签数据集自然包含类别不平衡和长尾分布。比如 Instagram 上有成吨的狗图片,有多少叶甲?

脸书大学的研究人员通过使用教师网络预测标签的 top-K 评分系统来解决这个问题,并使用该参数来平衡图像的数量。随着 K 变大,接近分布末端的图像相对于它们的类别标签变得更有噪声。在叶甲虫的情况下,可能只有 8K 甲虫图像,因此如果 K 被扩展到 16 或 32K,则从 8001 到 16000 的图像将被错误地标记。然而,这个想法是教师模型对 bettle 图像有足够的感觉,使得不是甲虫的图像 8001 在语义/视觉上仍然是相似的。

大规模模型蒸馏的推理加速

High-level idea of NVIDIA’s TensorRT inference accelerator. https://developer.nvidia.com/tensorrt

从这个框架中产生的另一个有趣的部分是,当教师在未标记的数据集上预测标签时,推理加速的重要性。教师网络必须进行大约 10 亿次预测,以产生学生网络的精选标签。通常,用模型提取训练的模型不会解决推理瓶颈,但是在以这种方式标记 10 亿张图像的情况下,这显然是重要的。这提供了推理加速器的额外贡献,如 NVIDIA 的 TensorRT 和针对小推理延迟优化的模型。

弱监督数据集的最佳来源是什么?

Photo by NeONBRAND on Unsplash

想想 Instagram 的标签很有趣。这是弱监督数据集的最佳来源吗?YouTube 视频包含上传者提供的标签,但这种标签比 Instagram hashtagging 噪音大得多。

精华建筑搜索

脸书最近的论文改变了学生网络体系结构,从 ResNet-18 到 ResNet-50 以及递增的更大版本的 ResNeXt。在一大堆探索各种背景下的神经架构搜索的研究论文中,对升华师生架构关系的研究相对较少。ResNet 变型从较大容量转换到较小容量似乎很直观。这种想法可能更好地体现在一个更结构化的进展,如从 EfficientNet-E7 到 E5。此外,通过搜索最适合从教师的预测标签分布中学习的特定架构,可能会实现性能提升。

生成模型能进一步增加预训练数据集的大小吗?

Generated face images from NVIDIA’s Progressively Growing GAN models. What happens if these models are married with the 1 billion Instagram images used for pre-training? https://arxiv.org/pdf/1710.10196.pdf

使用 GANs 从现有数据集生成新的训练数据的想法似乎很有前途。这已被证明在极其有限的数据集(如医学图像分析)的情况下是成功的,但对于常规任务(如 ImageNet 分类或 COCO 对象检测)尚未奏效。使用“半弱”监督训练框架,GANs 或变分自动编码器能否应用于 10 亿张未标记图像,以产生 20 亿或 100 亿张图像?这会产生新颖的图像来改善计算机视觉模型的预训练吗?

结论

脸书的半弱监督学习框架对半监督学习、弱监督学习、模型提取中的类不平衡以及模型提取的推理加速是一个非常有趣的视角。随着越来越多的人使用 Instagram,数据集自然会变得更大,他们使用 Instagram 图片的方法似乎会自然地扩展到数十亿张图片。top-K 评分法是解决大规模未标记数据集中明显的类别不平衡的一个很好的策略。有趣的是,如果生成模型可以进一步增加这些未标记的数据集。感谢您的阅读,如果您对本文的详细内容感兴趣,请查看下面的视频!

在谷歌云平台虚拟机上释放 Visual Studio 代码(VSCode)的威力

原文:https://towardsdatascience.com/unleash-the-power-of-visual-studio-code-vscode-on-google-cloud-platform-virtual-machine-f75f78f49aee?source=collection_archive---------2-----------------------

在您的远程虚拟机上获得成熟的本地 IDE 体验!

Photo by Joshua Earle on Unsplash

Visual Studio Code(简称 VSCode)是一个强大的、多平台的、免费的代码编辑器,支持多种编程语言[1]。在过去的两年里,它的受欢迎程度有了惊人的增长,这可以从它的谷歌搜索趋势的迅速上升中看出。在这篇文章中,我将分享一种使用安装在本地计算机上的 VSCode 来编辑和运行位于 Google Cloud 虚拟机上的代码的方法。但是首先…

Google Trends comparison between VSCode, Sublime, and Atom from Jan 2016 to Nov 2019.

我有 Jupyter 为什么还要 VSCode?

作为一名数据科学家,当你拥有 Jupyter 笔记本[2]的便利时,为什么还要使用 VSCode?如果你像我一样,那么你的日常数据科学工作包括两个方面。第一个方面是使用著名的 Jupyter 笔记本进行实验。Jupyter 非常适合数据科学项目早期阶段所涉及的那种迭代的、实验性的工作流。一旦您有了想要在生产中运行的产品(每天运行数千次或数百万次),数据科学家工作的第二个方面就开始了。在许多组织中,您没有专门的制作团队。即使您有这种奢侈,在将代码传递给生产团队之前重构代码也是一个好的实践,以确保产品在部署后能按预期工作。这就是 VSCode 在数据科学工作流中的闪光点!使用 VSCode 从 Jupyter 笔记本中重构代码的细节值得一篇独立的帖子来公正地对待。然而,[3]很好地概述了 VSCode 中可用的重构工具。一个简单的例子是“重命名符号”,它只允许你重命名一个变量一次,但是会自动更新你代码中出现的所有变量!超级得心应手!

先决条件

现在让我们进入这篇文章的细节。既然你正在阅读这篇文章,我假设你已经运行了一个 GCP 计算引擎 VM,并且你的个人电脑上也安装了 VSCode。如果你没有这两个,那么参考【4】关于如何设置 GCP 计算引擎 VM 和【1】下载并安装 VSCode 到你的本地计算机上。更新:您还必须安装 gcloud sdk,并按照【9】中的说明在您的系统上运行 gcloud init

详细步骤

Mac 和 Linux 用户可以直接跳到这篇文章的部分,使用内置终端从第 1 步开始。Windows 用户需要注意以下几点:

仅适用于 Windows 用户:

  • 从开始菜单,启动 Windows Powershell
  • 对于这篇文章的为所有用户部分下的所有剩余步骤,请遵循参考网页上 Linux 和 MACOS 部分下的说明。但是,请记住删除出现的下列内容:~/.ssh/
  • 例如,如果参考网页的 Linux 和 MACOS 部分显示:
ssh-keygen -t rsa -f ~/.ssh/[KEY_FILENAME] -C [USERNAME]

改为在 Windows Powershell 中键入:

ssh-keygen -t rsa -f [KEY_FILENAME] -C [USERNAME]

重要!不要按照网页的 Windows 部分的说明操作,因为我还不能让它在我的 Windows10 桌面上运行。

适用于所有用户:
遵循以下网页的 Linux 和 MACOS 部分的说明,即使您是 Windows 用户(请阅读上面的部分,仅适用于 Windows 用户)

  1. 按照【5】中的说明,在您的本地计算机上设置 SSH 密钥。Windows 用户,记得去掉~/.ssh/
  2. 按照【6】中的说明,在本地计算机上找到并复制您的 SSH 密钥。Windows 用户,默认情况下你的密钥保存在C:\Users\your-windows-username
  3. 您必须将此 SSH 密钥(从您的计算机)添加到您的 Google cloud platform 帐户。您可以按照【7】的指示插入整个项目的密钥,也可以按照【8】的指示插入特定虚拟机的密钥。我个人倾向于将它添加到特定的虚拟机中,以便进行组织。记住,您需要复制的公共 SSH 密钥是。pub 文件。Windows 用户,最好在记事本中打开此文件并复制其内容。
  4. 现在,在本地计算机上打开 VSCode。在 Windows 上按 Ctrl+Shift+x 打开 VSCode 中的扩展管理器。在搜索框中,键入 remote-ssh,并安装这个扩展。

Install Remote-SSH extension in VSCode on your local computer

5.安装完成后,在电脑上按 Ctrl+Shift+p (或者在 Mac 上按 Cmd+Shift+p 调出命令面板,键入 remote-ssh 。应该会出现一组选项,如下图所示。单击添加新的 SSH 主机… 选项。

Add New SSH Host… is the second option

6.在弹出的 Enter SSH Connection 命令提示符下,键入:ssh -i ~/.ssh/[KEY_FILENAME] [USERNAME]@[External IP]并按 Enter 键。KEY_FILENAME 和 USERNAME 是您在步骤#1 中键入的内容。外部 IP 可以在您的 GCP 计算引擎虚拟机实例页面中找到,并且对每个虚拟机都是唯一的。又弹出一个提示,要求您选择 SSH 配置文件来更新。只需点击第一个,您应该会看到主机已添加!在 VSCode 窗口的右下角。

对 Windows 用户很重要!,而不是~/。ssh/[KEY_FILENAME],您必须键入带有\ "的完整路径。例如,ssh -i C:\\Users\\your-windows-username\\[KEY_FILENAME] [USERNAME]@[External IP]

Select the first option

7.按下 Ctrl+Shift+p (或者 Mac 上的 Cmd+Shift+p )打开命令面板,再次键入 remote-ssh。这次点击连接到主机。然后从弹出的列表中选择虚拟机的 IP 地址。如果您再次看到关于指纹的弹出窗口,请点按“继续”。

Connect to Host is the fifth option above

8.就是这样!您的本地 Visual Studio 代码现在已经连接到您的 GCP 虚拟机了!您可以单击打开文件夹或打开文件,这将显示虚拟机中的文件,可以直接从本地计算机上运行的 VSCode 编辑这些文件。

常见问题

我已经在 Mac、Linux 和 Windows10 桌面上测试了上述步骤。因此,如果您在此过程中遇到任何错误,很可能您犯了以下常见错误之一:

  • 您的 GCP 虚拟机已停止。启动 GCP 虚拟机,然后重试。
  • 在第 6 步中,您要么提供了错误的 KEY_FILENAME 位置,要么提供了错误的用户名或错误的外部 IP。请记住,如果您没有为 GCP 虚拟机设置静态 IP,那么您可能需要在每次停止和启动虚拟机时执行第 6 步,因为外部 IP 地址可能会发生变化。始终提供正在运行的虚拟机的当前外部 IP。
  • 您按照[5]、[6]、[7]和[8]下的网页中的 Windows 说明进行了操作。DONT!回过头来,按照 Linux 和 MACOS 下的说明重做所有步骤,并做我上面提到的小修改

我希望这篇文章对你有所帮助。如果有,请在下面告诉我。编码快乐!

参考资料:
【1】下载 vs code:https://code.visualstudio.com/
【2】下载 Anaconda 使用 Jupyter 笔记本:https://www.anaconda.com/distribution/
【3】vs code 中的重构选项:https://code.visualstudio.com/docs/editor/refactoring
【4】启动一个 GCP 计算实例 VM:https://cloud.google.com/compute/docs/quickstart-linux
【5】在本地计算机上创建 SSH 密钥:https://cloud . Google . com/Compute/docs/instances/add-removed-SSH-keys

解开行为秘密,克服客户流失的极端情况

原文:https://towardsdatascience.com/unlocking-behavioural-secrets-to-overcome-churn-extremes-9c12a7ccc875?source=collection_archive---------19-----------------------

了解、预测并最大限度减少客户流失

介绍

在新的全球经济中,客户保留已成为当今动荡的商业环境中的一个核心问题,并对许多服务公司提出了重大挑战。尤其令人担忧的是削减成本和激烈的竞争压力。人们越来越担心,没有充分利用现有客户群的公司正处于不利地位。

学术界已经产生了大量的研究来解决这一挑战的一部分——特别侧重于预测客户流失。然而,仍然需要理解企业中存在的对客户流失的各种看法。管理客户关系的核心目的是让企业专注于增加客户群的整体价值,而客户维系是企业成功的关键。

(source: https://www.istockphoto.com)

本博客系列描述了可用于控制客户流失的方法的设计和实现,重点关注主动流失管理,即在预测客户会流失时提前联系客户,并提供旨在防止客户流失的服务或激励。通过采用定性和定量的调查模式,我试图阐明客户流失的预测模型,并提出一个开发主动流失管理计划的框架。

问题

使用简单的保留模型,客户的终身价值是:

客户流失管理的整个原则的核心是保留的概念,。在客户层面,流失率指的是客户在给定时间内离开公司的概率。在公司层面,客户流失是指在给定的时间段内,公司客户群中离开的客户所占的百分比。因此,流失率等于 1 减去留存率:

然而,对于任何一个简单的保持生命周期价值模型适用的行业,都存在与客户流失相关的某些缺点,即,客户可能会离开,并且如果没有重大的重新获得努力,不会自然返回。这体现在许多服务中,如杂志和时事通讯出版、投资服务、保险、电力设施、医疗保健提供商、信用卡提供商。

有两种基本类型的流失:订阅流失和非订阅流失

订阅流失发生在用户或客户签订了一段时间(每月、每年等)合同的企业中。—想想有线电视、网络或电话提供商),客户选择在合同到期后不再回来。正如定义中所指出的,这很容易定义、预测和预防,因为有一个清晰、明确的客户流失风险窗口,可以集中开展营销活动。

非订阅流失指的是用户或客户可以随时终止与业务关系的事件,他们可以随意来来去去。随着时间的推移,客户可能会逐渐减少购买频率,也可能会突然不再购买。这篇博客将关注防止订阅流失的过程。

数据采集

传统上,客户流失预测是通过简单地测量某种形式的客户身份和客户最后一次互动的日期/时间来评估的。这些数据虽然不太详细,但可以让你建立模型,在基本层面上预测客户流失。然而,现实情况是,在这个最小数据集的基础上添加额外的数据是推荐的,也是非常鼓励的。包含的数据越多,对客户流失的预测就越准确,因此,如果可以的话,也要在数据集中包含一些东西,如用户的静态人口统计信息、特定类型用户行为的细节等。来源越多越好。

选定数据

我将使用“电信客户流失”数据(IBM 样本数据集)来预测留住客户的行为。在这个数据集中,每一行代表一个客户,每一列包含列元数据中描述的客户属性。

数据集包括以下信息:

  • 上个月内离开的客户—这一列称为流失
  • 每位客户已注册的服务—电话、多条线路、互联网、在线安全、在线备份、设备保护、技术支持以及流媒体电视和电影
  • 客户账户信息——他们成为客户的时间、合同、支付方式、无纸化账单、每月费用和总费用
  • 客户的人口统计信息—性别、年龄范围,以及他们是否有伴侣和家属

数据预处理

数据预处理是一种数据挖掘技术,用于将原始数据转换成有用和有效的格式。这通常会占到项目总时间的 80%,因为数据是在不同的时间点从多个来源收集的。理解数据中的不同变量是建立直觉的基础。因此,在继续清理不同的拼写或可能丢失的数据之前,建议为这一部分分配足够的时间,以确保一切都是同质的。彻底的探索和清理将在后续步骤中节省时间,尤其是在进行预测的时候。

流失分布表明,我们正在处理一个不平衡的问题,因为有更多的非流失用户。大约四分之一的样本不再是客户(图 1)。当我们构建分类模型时,这将会有所暗示。我将在客户流失建模过程中详细介绍。

数据可视化和特征选择

特征提取旨在通过留下代表最具辨别性信息的变量(属性)来减少变量(属性)的数量。特征提取有助于降低数据维度(维度是数据集中具有属性的列)并排除不相关的信息。

在特征选择过程中,人们可以修改先前提取的特征,并定义其中与客户流失最相关的子组。作为特征选择的结果,我们可以得到只包含相关特征的数据集。

如下图所示,大部分客户流式传输电影和电视流(图 2)。同样,大多数客户使用无纸化账单,没有在线安全保障。

下图显示了大多数客户使用单条电话线提供电话服务。光纤互联网连接比 DSL 互联网服务更受欢迎,每种在线服务都有少数用户。样本中约有一半是按月合同,其余一半是一年期和两年期合同(图 3)。

该图的下半部分显示了付款方式和任期变量的细分,因为大部分客户的任期最短(0-12 个月)。

图 4 总结了相关性分析的结果。一眼就能看出,流失和变量个数是有关系的;具有不同的强度,例如合同类型、总费用、互联网服务等。有时候很明显有因果关系。然而,相关性并不意味着一个变量的变化实际上导致另一个变量的变化。在统计学中,你通常需要进行随机的、受控的实验来确定一种关系是因果的,而不仅仅是相关的。

结论

我们已经讨论了流失问题、其原因,以及从探索性数据分析中发现模式和建立直觉的一些方法。下一次,我们将看看预测模型如何识别流失者并揭示他们流失的原因,以及公司如何管理流失。

👋感谢阅读。如果你喜欢我的作品,别忘了喜欢,在关注我。这将激励我为媒体社区提供更多的内容!😊

参考资料:

Ascarza 等人(2018):追求增强的客户保持管理:回顾、关键问题和未来方向。斯普林格科学+商业媒体有限责任公司 2017

布拉特伯格等人(2008):《数据库营销:分析和管理客户》。起拱石

Ghorbani 和 Taghiyareh (2009): CMF:改善客户流失管理的框架。 IEEE 亚太服务计算大会(IEEE APSCC)

韩等人(2011 年):陈,j .,裴,j .,和 Kamber,M. (2011 年)。数据挖掘:概念和技术。数据管理系统中的摩根考夫曼系列。爱思唯尔科学

“主旨-句法-主题”:https://github.com/lonekorean/gist-syntax-https://business science . github . io/correlation funnel/articles/introducing _ correlation _ funnel . html

https://blogs . r studio . com/tensor flow/posts/2018-01-11-keras-customer-churn/

利用机器学习开启药物研发

原文:https://towardsdatascience.com/unlocking-drug-discovery-through-machine-learning-part-1-8b2a64333e07?source=collection_archive---------6-----------------------

通过利用机器学习来生成和创建分子的逆向合成路径,从而加速药物发现。

我们发现药物的方式效率极低。需要做点什么。

尽管最近制药行业发生了很多创新,尤其是在癌症研究领域,但仍有巨大的差距需要改进!

自 20 世纪 20 年代以来,我们目前的药物发现方法没有太大变化。

这是曾经发现毒品的故事:

1928 年,病理学家亚历山大·弗莱明(Alexander Fleming)经常被描述为“无忧无虑”,他在去度一个月的假之前,不小心把培养皿放在了窗户旁边,没有盖上盖子。

从他美好的假期回来后,发生了更美好的事情。让他吃惊的是,这个被丢弃的培养皿让弗莱明有了惊人的发现,发现了世界上第一种抗生素——青霉素,这一发现颠覆了制药业🤯

这只是一个小错误如何成为治疗突破的众多例子之一。

快进到大约 8 年后,这是目前发现的药物:

最近,纽西兰的研究人员* 出人意料地* 发现,先前在 21 世纪初用于对抗脑膜炎疫情的疫苗,随后也降低了淋病的风险

尽管发生了这么多进展,药物发现的秘方似乎从未逃脱意外收获的魔力。

在过去的 80 年里,技术进步呈指数增长,但药物研发领域的进展相对停滞。

手机甚至都不是东西,更别说 1928 年的苹果了(如果你不是苹果粉丝,我们就不是朋友——开玩笑的😁),现在我们不仅有苹果,而且我们还有脑机接口,人工智能将创新带入每个行业,量子计算(最近,谷歌宣布量子至上)和大量指数级技术的出现。

但是,相比之下,在改进药物发现过程方面进展甚微。

I meant I love eating apples 🍏

目前的药物发现过程是什么样的?

有大量的证据表明,目前的药物发现过程仅仅是 不足 不足 针对那些最需要的人——患有慢性和致命疾病的人。

据估计,将一种药物从研究阶段推向市场平均需要花费 26 亿美元,并且需要 10 年以上的时间😱由于药物研发非常耗费资源,最近的大部分进展都集中在癌症研究等高回报市场。

这部分解释了90%以上的罕见疾病缺乏有效治疗。

但是为什么会这样呢?让我们看看药物发现管道(又名药物开发的多方面过程)。

我们都希望这些救命药物能够更快、更便宜地送到有需要的患者手中。

为什么这个过程如此漫长和昂贵的简单答案是纯粹的复杂性。

药物研发管道看起来像这样:

Drug discovery pipeline! There are a total of 7 phases.

复杂吧?我们来分解一下…

药物研发有七个阶段:

1.目标识别:发现(2 年以上)

第一步甚至不是关于药物,而是关于理解导致疾病的目标。这些靶标通常由 DNA 突变、错误折叠的蛋白质和其他潜在的疾病生物标志物组成。但是,青霉素的发现显然不是这样,纯粹是偶然发现推动的。

问题#1: 虽然理想的途径是确定靶点,然后开发出专门对抗疾病靶点的药物,但这个过程并没有保证。青霉素的发现显然是这个过程的一个例外,而且还有更多例外。有这么多可能的化合物,这么多可能的目标,人类很难理解所有这些可能的组合。

2.线索发现:临床前(1-2 年以上)

这是筛选数千种旨在干扰疾病靶标的化合物的过程。目标是显著缩小各种潜在化合物的范围。

3.药物化学:临床前(1-2 年以上)

这一阶段包括进一步测试化合物的过程,以分析它们与疾病靶标的相互作用。可以进行的一些分析包括,例如,考虑化合物的 3D 构型来研究化合物的相互作用。根据分析得出的结果,朝着预期目标进一步优化化合物。

4.体外研究:临床前(1-2 年以上)

作为概念的证明,进入这一阶段的化合物在细胞系统中进行测试,这是一种疾病的体外模型。这是培养皿研究发生的阶段。体外研究试图详细检查该化合物在干扰靶标方面的有效性。

问题#2: 体外研究结果往往不能反映动物或临床研究结果,导致 失败率高。 根据麻省理工学院的一项研究, 临床试验成功率徘徊在 14%左右,这太疯狂了! 这是因为我们的体外细胞系统模型往往是对我们复杂的人类系统的粗略简化。生物学不是以 2D 模式运行的,但培养皿研究是细胞的 2D 模型,是一种广泛使用的体外研究方法。

5.体内研究:动物研究(1-2 年以上)

体外研究成功后(耶,但最困难的部分还在后面),该化合物通常在动物模型中测试,如大鼠或小鼠模型。与 2D 体外细胞培养模型相比,动物研究的结果通常更具代表性。然而,它明显比体外研究更昂贵。这一阶段的失败率也更高,因为由于细胞模型结构的差异,体外研究的结果不一定与动物研究相关。

注意要牢记: 如果我们能早点失败,而不是晚点失败呢?在如此昂贵的阶段失败是没有意义的,如果我们在体外研究阶段失败了呢?

6.最后,我们进行临床试验(6 年以上)

如果上述所有阶段的结果都表明该化合物有前景,那么它将进入临床试验。临床试验有三个阶段,每个阶段都有不同的目标。临床试验的主要目标是验证化合物或潜在药物在人类环境中的有效性和安全性。

问题#3: 临床试验有许多监管方面,这就是为什么它是最漫长和最昂贵的阶段。证明药物的疗效往往不是一件容易的事;具体来说,化合物的长期副作用通常在一段时间后仍然未知。在人身上试验新药总是存在巨大的内在风险。三期临床试验的平均费用估计为 1900 万美元。

7.还有最后一个阶段:FDA 批准和商业化(1 年以上)

一旦所有测试完成,该化合物可以提交给美国食品和药物管理局审查批准。一旦获得批准,这种药物终于可以在患者手中商业化,以改善生活和治疗疾病!!!!!!—有史以来最激动人心的部分,但这是一次极其漫长和昂贵的旅程!

问题#4: 新上市的药物往往极其昂贵,这是因为研发的成本非常高。公司通常有 20 年的专利来保护他们的药物/产品免受竞争。这意味着他们可以将药物定价在他们认为合理的价格上。有时,这一价格可能高达数十万美元,使普通大众无法承受。

需要牢记的注意事项:我们如何才能加快药物发现的进程?

哇,那是一次旅行🌄!

但是,如果有一种方法可以将早期药物发现(除了临床试验+商业化之外的所有阶段)的过程从 6 年大大加快到 6 天,会怎么样呢?我很乐观,我一点也不觉得这是科幻!其实这是有可能的!我们并不缺乏实现这一点所需的工具,我们只是缺乏乐观和合适的人。

当前的创新:加速药物发现

  • in silico Medicine(AI+pharmaceutical startup)能够在短短 46 天内设计、合成和验证新的候选药物。
  • AlphaFold (谷歌的人工智能算法)能够以前所未有的速度和精度预测蛋白质的三维结构(药物发现中的关键评估),超过了该领域一些世界上最好的生物学家和研究人员。

人是推动增长的唯一最重要的因素,而不是其他因素。不管你是一个 16 岁的高中生(剧透:那是我),还是一个著名的人工智能研究者,我相信我们所有人都可以做一些事情来创造影响。作为一个好奇的 16 岁少年,这也是我决定做点什么的根本原因。

Synbiolic 简介:利用变分自动编码器进行药物发现

我们已经坚持同样的过程,做了大量的湿实验室实验,经历了一堆药物发现的试验和错误太久了!药物研发的人工流程必须改变!

是时候来点新的了,介绍 Synbiolic :推断人工智能的潜力,特别是变型自动编码器(VAE)以 SMILES 的格式生成新的&有效分子(简化的分子输入行输入系统)。

Synbiolic 的魔法是如何发挥作用的?

  1. 使用VAE的魔棒生成分子
  2. 使用更多的魔法将生成的分子列表过滤成几个真正好的分子

Imagine if drug discovery was as easy and fun as lego building!

这里有一个内部的魔术是怎么回事!

除了是一个人工智能+书呆子的时髦词,什么是变化的自动编码器?

变分自动编码器(VAE)是一种类型的机器学习算法。**生成模型是一种人工智能架构,它能够生成与训练数据特征相似的新数据**

它由两个神经网络组成: (1)编码器,和(2)解码器。注:编码器和解码器可以使用不同的神经网络。**

编码器网络负责降低输入到模型中的数据的维度,解码器网络通过将数据的紧凑表示重建回其原始维度/输入来反转该过程。

数据的紧凑表示被称为潜在空间表示(也称为瓶颈)。

Autoencoder 💻

Synbiolic 利用 VAE 生成新的分子,这些分子具有类似药物的特性,类似于用于训练模型的分子。生成的分子与训练分子并不完全相同,而是训练分子的变体。

为了更直观地理解编码器和解码器模型的功能,让我们来玩一个猜字谜游戏!

Finding Demo 😍

让我们进入编程模式,从声明一些变量开始🤖:

  • 右边的女士=编码器
  • 左边的先生=解码器
  • 海底总动员=潜在空间/分子的紧凑表示
  • 动作=生成的分子

猜测短语“海底总动员”(分子的紧凑表示)* 的女士类似于编码器,因为她将“动作”(分子) 浓缩成短语(分子的紧凑表示)。就 AI 语言而言,她本质上是在建构“行动”的潜在表征(分子) 。这类似于编码器如何将用于表示分子的维度减少到更紧凑的形式。*

扮演“海底总动员”的绅士(分子的紧凑表示)* 类似于解码者,因为他试图将短语重新解释为动作(分子) ,这是扩展的表示。就生成分子而言,解码器通过基于其浓缩特征或潜在空间表示来重建分子来实现这一点。*

但是,等等,是什么让变分自动编码器不同于普通自动编码器?

一个变化的自动编码器有一个编码器和解码器网络,就像上图中普通的自动编码器一样(在海底总动员之前的那个)👆。然而,它不仅仅是一个常规的机器学习模型, VAE 为其编码器网络使用了一种概率方法。

之所以用 VAE 代替自动编码器,主要是因为普通的自动编码器不能生成数据。这是因为普通的自动编码器(特别是编码器)似乎无法找出一种好的方法来创建“可用的”潜在空间表示,以馈入解码器网络,从而生成“好的”分子。

当自动编码器试图生成新数据时,最终发生的是一个随机的潜在表示/向量被输入到解码器模型中,这反过来生成真正时髦和无用的数据。这是因为除了强迫编码器从训练数据中创建潜在向量之外,普通的自动编码器不知道如何获得“好的”潜在向量。

普通自动编码器的潜在空间不是连续的,这就是它们不适合生成数据的原因。

这意味着,采用上述图片中的潜在表示,解码器能够生成看起来不错的图片,但如果肤色等潜在参数中的一个从 0.85 到 0.84 稍有改变,那么解码器网络就会完全出错,最终可能会生成类似这样的结果:

这都是因为潜在空间表征不是连续的。

生成随机数据也没那么神奇。自动编码器无法实现的 VAE 的神奇之处在于,它是最好的生成模型之一,可以用来在期望的方向上对你已经拥有的数据进行变化。**

编码器网络被表示为 q(z|x ),解码器网络被表示为 p(x|z ),因为 x 表示网络的输入,z 是潜在表示(它是一个向量)。

Variational Autoencoder breakdown: Green is the encoder network, blue is the decoder network

变化自动编码器的不同之处在于它的编码器网络利用了一个概率模型。这使得潜在空间是连续的。

VAE 通过让它的编码器组合两个向量来做到这一点:一个向量取平均值,另一个向量取输入数据的标准偏差。然后从均值向量和标准差向量中通过采样构建潜在向量 z。

μ represents the mean and σ represents the standard deviation

通过采样,这允许潜在空间是连续的,而不是离散的。这就是为什么 VAEs 可以生成本质上是训练数据的变体的合成数据的原因。(我们可以通过优化潜在空间来有意地应用这些“变化”,以生成具有所需属性的新数据。)

让我们继续关注这一切背后的秘方,也就是 Synbiolic 的 VAE 所用的模型。

对于编码器和解码器模型,使用以下神经网络:

  • 编码器网络=卷积神经网络(CNN)
  • 解码器网络=一种称为门控递归单元(GRU)的递归神经网络(RNN)

理解卷积神经网络:编码器

在我们深入 CNN 之前,让我们先来探索降维实际上是什么。

降维是机器学习中的一种技术,用于通过减少其特征来降低数据。**

编码器模型可以使用两种技术来执行维度缩减:

  1. 按要素选择-仅选择部分要素,排除其余要素
  2. 通过特征提取-将输入数据转换为潜在表示

这两种技术的区别在于,特征选择不会改变特征,而特征提取会改变特征,因为它会对“输入特征/数据”进行变换,以获得潜在空间表示。**

卷积神经网络(CNN)是一种深度学习算法,由于其检测特征的能力而广泛用于图像分类。

他们通过实施特征提取来做到这一点,从而降低输入数据的维度。

和其他深度学习算法一样,CNN 由【1】个输入层、【2】个隐藏层、【3】个输出层组成。

隐藏层由几个不同类型的层组成,如卷积层、池层和全连接层。

Convolutional Neural Networks

使“卷积神经网络”成为“卷积神经网络”的是卷积层。是的,就这么简单,实际上,也许没那么简单…

卷积层本质上执行输入和滤波器之间的点积,以获得数据的低维表示(也就是说,卷积层由数学支持)。

The yellow matrix is the filter, the green matrix is the input image, and the pink matrix is the convolved feature or latent representation.

如你所见,卷积特征在尺寸上比原始输入更加紧凑。

要了解更多关于卷积神经网络及其在皮肤癌检测中的应用,请查看本文!

我没有像从痣的图像中检测皮肤癌那样使用 CNN 进行图像分类,而是在分子数据集上训练 CNN。

VAE 在包含 250 000 个分子的锌数据集上进行训练。编码器(CNN)将分子特征的表示转化为更紧凑的表示。

解码器呢?

对于解码器,使用一种称为门控递归单元(GRU)的特定类型的递归神经网络(RNN)。

与其他类型的神经网络不同,rnn 具有内部记忆能力。rnn 通常应用于序列数据,因为它们的特殊属性是它们的决策受网络内的先前输入和输出 的影响。

普通神经网络也具有“记忆”事物的能力,但它们仅限于记忆来自 先前训练迭代的事物。

“Vanilla” Neural Network

相比之下,rnn 记住每次训练迭代中的事情,并根据输入和前一个隐藏状态生成的输出做出决策。

x nodes are the inputs, y nodes are the outputs, and h nodes are the hidden nodes

这样想:还记得你的数学老师曾经告诉你,如果你不知道数字的加减乘除,你将永远无法掌握微积分!这是因为作为人类,我们理解概念的基础是我们之前学过的概念。

这类似于你在读这句话时,你是基于对前面单词的理解来理解这句话的。如果我只写“以前的话”作为句子,你不会明白我想说什么。本质上,这是 rnn 真正擅长做的事情:像句子结构一样剖析顺序数据的含义。

RNNs 的内部存储容量指的是它能够记住网络中以前的信息,以帮助它做出决策。他们能够通过理解序列中前一个值之间的联系来预测序列数据中的下一个值。

所有机器学习都是由数学驱动的,RNNs 的数学由隐藏状态(h)组成,这些隐藏状态是隐藏节点。

隐藏状态是相互联系的。在每个隐藏状态中,都有门,门是控制信息传递的神经网络。

对于计算信息的隐藏状态,必须对其进行预处理并将其转换为矩阵/向量表示。

“普通”rnn 的隐藏状态如下所示:

  • 前一隐藏状态的输出与当前输入组合形成一个向量,该向量包括关于当前和前一输入的信息。
  • 这个向量通过一个 tanh 激活函数,该函数将范围限制在-1 和 1 之间,以产生新的隐藏状态。

然而,传统的 RNN 遭遇了一个被称为消失梯度下降的问题。

当训练传统 RNN 时发生的是,随着权重被更新,梯度变得如此之小,以至于更新的权重变得不重要。如果原始权重实际上保持不变,这意味着在该模型中有很少或没有学习

小的梯度更新不会导致任何显著的学习,从而阻止模型完成它的工作。

为了解决这个问题,我为解码器实现了门控循环单元(RNN,但有所改变),而不是使用“传统的”RNN。

门控循环单元(GRU)中涉及两个门:更新门和复位门。本质上,门只是隐藏节点内的神经网络

与 RNN 不同, GRU 只记住重要的短语和单词,而不是记住句子中的每个单词。

比如,我们来看看这句话:

“为了研究如何最好地加速罕见病研究的问题,我们将回顾一些罕见病研究中的挑战以及最近的科学进步为治疗发展带来的机遇。”

像“to”、“the”、“of”、“that”和“for”这样的词与句子的意思并不相关,因此 GRU 人会忘记这些词。

为了考察如何最好地 加速罕见病研究 的问题,我们将回顾一下 中的一些挑战*罕见病研究 中的机遇 对于 疗法的发展*

RNN 可能试图记住整个句子,而 GRU 只记住重要的术语(上面用粗体表示)。

Gated Recurrent Unit

更新门

更新门的职责是确定需要保留多少来自先前隐藏状态的信息。消失梯度下降问题通过通过这个门来解决,因为模型能够决定它需要将多少过去的信息传递给未来的隐藏状态。****

复位门

来自先前隐藏状态的输出和当前输入组合形成一个向量,该向量包括关于当前输入和先前输入的信息。每个向量不仅包含当前隐藏状态的信息,还包含先前隐藏状态的信息。

重置门的工作是决定模型应该忘记哪些过去的信息。本质上,这个门的功能与更新门的功能相反。

在生成分子的场景中,GRU 或解码器的输入是表示分子的压缩形式或潜在空间表示的向量。GRU 的最终输出是分子在其原始/扩展表示中的重建。

衡量分子药物相似性的量称为 QED(药物相似性的定量估计)。我获得了生成分子的 QED,以验证它们是类药物分子。

QED 低于 0.5 的所有生成分子都被忽略,这确保了生成分子的质量。可以合成具有最高 QED 值的分子,以通过体外和体内研究进一步验证它们的性质!

耶!我们能够成功地设计和验证分子!这个被归类为早期药物设计的过程至少需要 3 年的传统研究才能完成!

如果你感兴趣,可以在这里查看来自 Github 的源代码。

这要感谢我的优秀团队:雅利安·米斯拉 & 埃利亚斯·昆图里斯

关键要点:

  • 药物研发极其昂贵且漫长
  • VAE 是一种生成神经网络,可用于生成药物发现的分子
  • 人工智能是一个强大的工具,可以用来彻底改变医疗保健

不要忘记:

  • 访问 Synbiolic 的网站,了解更多关于 16 岁青少年的活动!
  • LinkedIn 上和我联系!

来自《走向数据科学》编辑的提示: 虽然我们允许独立作者根据我们的 规则和指导方针 发表文章,但我们并不认可每个作者的贡献。你不应该在没有寻求专业建议的情况下依赖一个作者的作品。详见我们的 读者术语

取消制作图表

原文:https://towardsdatascience.com/unmaking-graphs-f584625c5bfd?source=collection_archive---------17-----------------------

对于图表来说,越少越好吗?是的。

https://pixabay.com/en/equalizer-eq-sound-level-digital-255396/

我很高兴地看了很多图表(* 很多* ),并逐渐了解了哪些图表最有意义。好的图表告诉我关于数据的一件事,它们通过排除干扰和让我简单的头脑容易看到信息来做到这一点。

制作华而不实的图表很容易,但制作简单有效的图表就不那么容易了。

当我第一次创建任何图形时,事情通常是这样的:

想象一下,我刚刚得到一个有趣的新数据集,我正在做一些探索性的数据分析——弓着身子拿着放大镜在键盘上寻找相关性并分析线索。我决定变出一些图表来可视化数据,因为我知道我的视觉皮层会在图案中发现一些我美丽的数学头脑看不见的东西。

我可以使用 Excel、R 或 Python 来处理我的数据,也就是说,这并不重要。唯一重要的是,我的充满活力的条形图充满了旋转的文本、边界线、网格、标题和所有的颜色――它是完美的,它讲述了我的整个故事。(哈哈 j/k 太可怕了。)

你自己看一看,当你看的时候,注意你的眼睛落在哪里,什么东西首先吸引你的注意力。

你注意到的第一件事是什么?第二或第三件事呢?在你对图表有所了解之前,你实际上注意到了多少事情?你可能不知道这个图表是关于什么的,因为我是这样设计它来表达我的观点的,但是有很多事情需要你的注意。这个图表的更少部分会告诉我们更多关于数据的信息。

我们都见过这种充满彩虹的图表。起初,它们看起来确实很酷。但是除了被迷惑,它并不能帮助你理解这一点。桃色/鲑鱼色与大数字有什么关系吗?可能不会,因为图表另一边的短横条看起来完全一样。在这个图表中,所有不同的颜色都是分散注意力的,没有任何意义。让我们去掉它们,用一些对比不那么强烈的东西。黑色对于白色背景来说反差太大了,所以让我们试试简单的灰色。

哇,好多了!仍然不完美,但是现在我们能辨认出一些细节。我认为这是一个关于葡萄酒的图表,但我仍然不确定,因为那些网格线正在杀死我的灵魂。我的眼睛急切地想看着这些条,但这是一种挣扎,因为我被右上角交叉的网格线分散了注意力。我确信这其中有生物学上的原因,但这并不重要,因为我们正在摆脱它们。

*注意:有时你可能需要网格线,这没关系。使用真正的浅灰色让它们消失在背景中。他们不需要成为焦点,也不应该分散注意力。我想我们都同意,如果你使用网格线,他们不应该打你的脸。

哦,哇,如此清晰!没有颜色或网格线,我可以看到这个图表告诉我一些关于葡萄酒的事情。快看。其中一个酒具比其他的都大!要是我能知道酒是什么就好了。我想我可以花一点力气阅读旋转的文本,但是我简单的头脑把旋转的文本当成古代的挂毯。我没有时间解读古代文本,所以不要旋转标签来适应 x 轴,让我们旋转条形图,把它变成水平条形图。

嘣!通过切换到水平条形图,我可以很快地分辨出哪个国家的葡萄酒价格最高,因为阅读标签轻而易举。

感觉还是有点局促,还有一些让人分心的标题和标签。文本的意思有点模糊,黑色字体的颜色非常强烈,吸引了我的注意力。改变标题,使其更有目的性,这将有助于把观众的注意力引向什么是重要的,使用灰色字体将有助于把它更多地放在背景中。如果我们去掉几条样条线(边界),我们也可以把东西打开一点。

让我们修改标题和 x 轴标签,给它们一个目的,改变颜色,使它们不那么突出,并删除一些样条线,使它们不那么拥挤。

现在标题告诉你到底发生了什么,你知道这个图的目的。去掉样条线给我们一些喘息的空间,使用深灰色将你的注意力引向瑞士的酒吧。它摸起来很光滑,看起来很舒服。

即使我们不需要用颜色来表达我们的观点,我仍然喜欢用它。如果你决定使用颜色,只是温柔,因为它不需要太多。让我们假设我们在一家墨西哥酿酒厂工作,我们试图将墨西哥葡萄酒的平均价格与世界其他地区进行比较。让我们试着用我们葡萄酒公司的品牌颜色(石灰绿)来代替深灰色。

好吧,我承认'石灰'的颜色是相当不和谐,我可能会淡化一点。事实上,我可能还会对他的图表做很多修改。这需要一点实验来得到它的权利,所以不要害怕。我反复思考如何修改 x 轴,仍然不知道什么对 x 轴最好。我可以说一整天,但是与我们开始时相比,这个图表是一个很大的进步。

最后,你设计图表的方式取决于你的受众和信息。你可以(也应该!)实验一下弄对。所有这些只是为了说明,我们不需要所有的花里胡哨来制作一个有效的图表。绘图库真的很强大,他们喜欢炫耀他们花哨的默认参数。在这种情况下,我实际上通过移除默认参数来改进图形。一旦你从图表中排除了所有干扰,就更容易表达你的观点。根据你真正想告诉人们的内容来调整图表。

来源(排名不分先后):

数据集:https://www.kaggle.com/zynicide/wine-reviews

创建更有效的图表:创建有效图表的简明且可读性强的指南。

科尔·努斯鲍默。用数据讲故事:商业专家数据可视化指南。

拆包 R

原文:https://towardsdatascience.com/unpacking-r²-a2a2ffcd27db?source=collection_archive---------30-----------------------

R 是评估线性回归模型的常用统计量,但正如我发现的,它很容易被误用。

数据科学是一个迭代的过程,对于新从业者来说尤其如此。我们可能在一个项目上花费数周时间,结果却发现了分析中的一个根本性缺陷。这篇文章探讨了我在一个项目中犯的一个基本错误,并解释了它是如何发生的以及它为什么重要。

我的顶点项目是一个预测分析工具,它利用历史销售数据和天气数据来预测布鲁克林一家获奖餐厅的每夜和每周销售额。历史销售数据直接来自餐馆的销售点系统(实际上是两个独立的系统,必须进行汇总),虽然该项目相当简单,但某些元素确实存在挑战。节假日、闭馆日、只在季节性开放的室外座位以及可能会意外关闭的座位、房间租赁费、不准确的客人数数据以及特殊事件都必须得到适当的理解和处理。

我不得不做出的一个决定是如何处理节假日/休市日,此时销售额为 0 美元。我考虑了两个选项:(1)包含一个编码的布尔“关闭”特性,或者(2)从数据集中完全删除关闭的日子(第三个选项是将这些日子视为异常值——稍后将详细介绍)。当我试验这两个选项时,我注意到无论我使用哪一个回归模型,R 值都会根据我如何处理关闭的日子而显著变化。

我最终使用了布尔“关闭”特性,因为它导致了更高的 R 值,但这个决定从来没有真正让我满意过。这篇文章的目的是重温那个决定,并理解为什么我最初的决定是错误的。

设置

为了提供一些背景信息,下图显示了餐厅的餐厅、酒吧和私人餐厅区域的夜间平均销售额,不包括外部区域。

Nightly Average Sales, Jan-2017 — June-2019

这家餐厅在 2017 年 1 月至 2019 年 6 月期间的平均室内销售额为 14,575 美元,标准差为 1,832 美元(我应该注意,这是一家特别成功的餐厅)。

比较方法

下表显示了处理关闭天数的两个选项之间的三个不同评估指标的差异——除了 R、均方根误差 (RMSE)和平均绝对误差 (MAE):

因此,虽然 RMSE 和梅保持了相当的一致性,但当我删除休市日的观察数据时,R 显著下降。这是为什么呢?是时候打开包装,更好地了解发生了什么。

在我们继续之前,看看这两种情况下的残差是有益的,这将为这里发生的事情提供一些直觉:

具有编码的布尔闭合特征的残差:

剔除休市天数后的残差:

稀有

r 表示因变量(目标变量,在本例中为销售额)的总变化的比例,该比例由自变量(我们的特征变量,如星期几、月份、销售趋势和温度)的变化来解释。

建模环境中 R 的一个最简单的表达式如下:

残差平方和是误差平方和——实际数据点和估计模型预测的数据点之间的差异。总平方和代表每个目标观测值与所有目标观测值平均值的偏差总和。

计算 R 的代码如下所示(y_hat 是预测的目标变量——这个特定的代码块计算测试集的 R):

sum_squares_residual = sum((y_test - y_hat)**2)
sum_squares_total = sum((y_test - np.mean(y_test))**2)r_squared = 1 - (float(sum_squares_residual))/sum_squares_total

我们开始明白为什么包括休市天数是一个错误,但是让我们在计算中采取下一步来真正理解它:

Boolean Closed Feature:sum_squares_residual: 225_779_046
sum_squares_total: 921_523_793sum_squares_residual / sum_squares_total = 0.245
r-squared = 0.755Dropped Closed Days:sum_squares_residual: 223_557_101
sum_squares_total: 484_108_603sum_squares_residual / sum_squares_total = 0.46
r-square = 0.538

看分母的区别!当关闭的天数减少时,RSS 实际上更低,这应该表示更高的 R,但是分母(TSS)明显更低,导致更高的 RSS / TSS 比率(从而更低的 R)。

这是怎么回事?

由于我包括了封闭日的数据点,并且明确地将它们从我的异常值调整中排除,对于数据集中 12 个封闭数据点中的每一个,R 公式从$14,575(整个数据集的平均值—实际上训练 R 使用训练平均值,测试 R 使用测试平均值)中减去$0,,然后对结果求平方($14,575 是$212,430,625!).这是一个完全人为构建的方差,没有必要包含在内,但确实有提高我的 R 值的副作用。休市日不代表自然差异——我们知道为什么这些日子的销售额为 0 美元,并且实际上可以 100%准确地预测这些日子的销售额为 0 美元。它们应该被扔掉。

课程

我的第一个错误是不恰当地处理关闭的日子——将它们从数据集中删除会更有意义。当我深入研究 R 时,我还意识到均方根误差或平均绝对误差可能是这种特定应用的更好的模型评估指标(当您阅读本文时,我的项目将会反映出这一点)。如果你真的想探究为什么 R 是一个有缺陷的度量,原因有很多,请看这些来自卡耐基梅隆大学的科斯马·沙立兹的课堂笔记

这个练习还进一步说明了正确处理异常值的重要性——如果没有正确地考虑这些异常值,机器学习所基于的许多统计假设就根本不起作用。这些封闭的日子实际上是离群值——为他们设计一个功能是错误的方法。

最后,也是最重要和最明显的,这就是为什么理解统计学和底层数学对数据科学如此重要。这是我犯的一个简单的错误,考虑到我在这个领域刚刚起步,理论上是可以原谅的,但也很有教育意义。没有人一夜之间成为专家,当事情看起来不对劲时,你可以从探究原因中学到很多,而不只是假设你的模型知道得最好。

解开机器学习部署的复杂性

原文:https://towardsdatascience.com/unpacking-the-complexity-of-machine-learning-deployments-fbc3affc5e7a?source=collection_archive---------40-----------------------

大规模部署和维护机器学习模型是当今组织面临的最紧迫的挑战之一。包括训练、构建和部署机器学习模型的机器学习工作流可能是一个漫长的过程,沿途有许多路障。许多数据科学项目无法投入生产,因为挑战会减缓或停止整个过程。为了克服模型部署的挑战,我们需要识别问题并了解导致问题的原因。当试图将机器学习模型投入生产时,组织面临的一些最大挑战是:

机器学习需要异质性

端到端的 ML 应用通常由用不同的编程语言编写的组件组成。根据用例的不同,数据科学家可能会选择 Python、R、Scala 或其他语言来构建一个模型,然后选择另一种语言来构建第二个模型。在一种给定的语言中,有许多可用的框架和工具包。TensorFlow、PyTorch 和 Scikit——学习 Python 的所有工作,但是每一个都针对特定类型的操作进行了调整,并且每一个都输出稍微不同类型的模型。对于数据预处理,基于 JVM 的系统,比如 Apache Spark,通常是首选的,因为这种语言中的静态类型可以更好地支持并行执行。这种异构代码库通常很难保持一致。

框架和工具包的多样性使数据科学家能够选择最适合手头问题的语言和工具。然而,他们选择的每个新工具和语言都必须由 IT 团队来启用和处理。容器化技术,比如 Docker,可以解决大量工具带来的不兼容性和可移植性问题。然而,自动依赖检查、错误检查、测试和构建工具将不能跨越语言障碍解决问题。

再现性在这些场景中也是一个挑战。数据科学家可以构建模型的许多版本,每个版本使用不同的编程语言、库或同一库的不同版本。很难手动跟踪这些依赖关系。为了解决这些挑战,需要一个 ML 生命周期工具,它可以在训练阶段自动跟踪和记录这些依赖关系,作为代码配置,然后将它们与训练好的模型捆绑在一个准备部署的工件中。

ML 部署不是独立的

机器学习模型部署不是独立的解决方案。它们通常嵌入或集成到业务应用程序中。通过将模型包装成 REST API 来部署模型是以一种语言无关的方式与业务应用程序集成的最简单的解决方案。

这种方法与微服务架构配合得很好,并且能够单独更新或扩展机器学习模型组件。创建 REST APIs 很容易,因为大多数框架都提供了开箱即用的功能,但有时需要将模型部署为gRPC API以实现高效的网络使用和更好的性能,尤其是当输入(图像、视频、文本)的大小很大时。

随着边缘设备(手机、物联网等)在计算和存储方面变得越来越强大,直接在这些设备上部署和运行模型的趋势越来越明显。然而,这种情况下的模型仍然需要针对 CPU 和内存使用进行优化。在大多数情况下,模型被嵌入到在这些设备上运行的应用程序中,因此出现了运行时兼容性和可移植性的挑战。这里的挑战是采用在任何编程语言/库中训练的模型,并优化和导出它以匹配运行时语言和边缘设备的版本。

除了 REST/gRPC API 之外,一种广泛使用的集成不同组件的方法是使用消息传递系统。打包和部署能够与消息传递系统集成的模型的能力可以避免大量样板代码并简化部署。

在某些情况下,项目约束和合规性要求决定了部署需求,例如,转换使用 python 库训练的模型,并将其部署到支持 C++运行时的 Azure 机密计算环境。

ML 模型定义的复杂性

什么是机器学习模型?是否只有训练后获得的模型参数(例如,逻辑回归模型的权重)?它还需要包括对模型正确工作很重要的特征转换吗?许多库将特性转换和实际的 ML 模型结合在一个抽象中,通常被称为 ML 管道。从系统的角度来看,模型可以被认为是一个定义了输入和输出的“黑盒”,或者可以被认为是具有已知语义的操作的组合。模型可以是模型的组合(例如,集合,其中来自不同语言或库的模型被组合,或者其中一个模型的输出是另一个模型的输入)。

面向服务的架构和微服务已经将应用程序从单一代码转移到更加可组合和可管理的组件上。机器学习甚至更具可组合性,因为它的构建块更加粒度化和分散化。在现实世界的应用程序中,ML 模型是作为单个单元或多个组件来部署和管理的,每个组件都是单独管理和更新的。

例如,一家公关公司希望识别批评其客户的新闻和报道,可以使用以下渠道:

  • 使用光学字符识别(OCR)模型从扫描的文档流中提取文本
  • 使用语言识别模型识别该文本的语言
  • 将非英语文本翻译成英语
  • 为情感准备课文

Figure: An ML pipeline that extracts text from scanned documents and analyzes the sentiment of OCR’ed text.

在每种情况下,模型都可能使用不同的语言和工具集来开发。

测试和验证困难重重

模型随着数据的变化、方法的改进或软件依赖性的改变而不断发展。每次发生这种变化时,都必须重新验证模型性能。这些验证引入了几个挑战和陷阱:

  • 必须使用相同的测试和验证数据集来评估模型,以便能够比较不同 ML 模型的性能。
  • 为了能够保证可比性,必须在不同的时间和不同的模型中使用相同的评估指标的代码。
  • 测试/验证数据集或代码的更新需要重新评估不同的 ML 模型(包括旧的和新的),以便进行比较。这在 CI/CD 管道中引入了独特的挑战,使在生产中自动训练和部署 ML 模型的新版本的过程变得复杂。
  • 新模型的改进可能是有代价的,例如更长的预测时间。为了识别这样的影响,基准测试和负载/压力测试必须是验证和决策过程的一部分。

除了在离线测试中验证模型之外,评估模型在生产中的性能也是至关重要的。这将在部署策略和监控小节中讨论。

复杂的发布策略

像今天部署的任何软件应用程序一样,ML 模型的发布并没有以任何方式降低复杂性。ML 模型需要比常规软件应用更频繁地更新。

ML 的发布策略和部署基础设施必须考虑异构因素,以及一个模型可能包含多个组件的事实,每个组件都使用不同的编程语言或 ML 框架构建。这些组件中的每一个都可能需要单独或作为一个单元进行更新或回滚。此外,为了从 ML 模型中获得最佳 ROI,能够尽可能快地重复部署模型是很重要的。

在“影子模式”中启动新模型(即,在生产中捕获输入和预测,而不实际服务于这些预测)有助于发现运营问题,对模型进行冒烟测试并分析结果,而不会对最终用户产生任何影响。

A/B 或 bandit test 模式需要在生产环境中比较模型性能,并分析对用户体验和 ROI 的影响。然而,在反馈循环长且间接的情况下,这可能是相当具有挑战性的。还应考虑接受人类输入和随机检查的能力。在可用的标记数据较少且错误成本过高的情况下,这是特别需要的。

Figure: Example Runtime Model Graph

CI/CD:一堆不同的管道

软件开发人员使用持续集成(CI)和持续部署(CD)工具已经变得非常普遍。CI/CD 工具正在帮助开发团队将快速准确的更新推向生产。CI/CD 工具的其他好处是可靠性、可再现性、速度、安全性和版本控制。

大多数 CI/CD 工具支持众所周知的软件开发工作流,包括构建、测试和部署步骤。机器学习工作流表现出在传统开发工作流中观察不到的独特特征。

Figure: Machine Learning Workflow

传统应用程序和 ML 模型之间最显著的区别是,主要输入不仅仅是代码。相反,有两个同样重要的输入组件:代码和数据。必须对这两个输入应用版本控制,以实现可再现性和可审计性。还必须监控数据和代码的任何变化,然后自动触发工作流。这可能不是小事,尤其是考虑到数据管理的复杂性。正如在模型验证中所讨论的,测试/验证数据的变化需要重新训练和/或重新验证模型。构建 ML 工作流时,必须考虑这一需求。

传统应用程序开发的硬件和软件依赖通常是同质的。在机器学习的情况下,工作流程的每个阶段可能需要特定的硬件和软件组件。培训阶段通常是漫长而密集的计算阶段。一些工作负载可能需要 GPU 等硬件加速器的可用性。用于 ML 工作流的 CI/CD 工具应该能够按需提供这种依赖性。

没有监控的 ML 是一场噩梦

监控工具不断发展,以支持当今的云原生分布式容器化应用。监视现在被可观察性所取代,包括日志、跟踪和度量。然而,这些工具仍然需要进一步发展以支持机器学习。

范围扩大

监测范围一直在扩大,以支持更多的利益攸关方。当今大多数监控工具不仅帮助开发人员主动监控系统,还帮助开发人员调试和理解问题。

在机器学习的情况下,监测的范围进一步扩大,包括数据科学家和企业主。监控工具需要帮助这些新的涉众了解模型在生产中的表现,并理解其输出。机器学习要监控的指标、要记录的信息、合规性需求和审计要求与常规应用非常不同。在下面的章节中会有更多的介绍。

复杂性增加

正如以上章节所讨论的,ML 是异构的。对于单个编程语言或框架来说,标准化和监控部署管道是很容易的。这样做来支持不同的编程语言和框架是耗时、易错和复杂的。鉴于 ML 模型可以由其他模型和组件组成的事实,能够单独跟踪这些组件并能够将问题缩小到其中一个是非常重要的。采用具有容器、服务网格和不可变基础设施的微服务架构是处理和标准化具有异构性的复杂 ML 模型部署的伟大技术。然而,这些工具不容易配置和维护。将这些付诸实践需要专门的团队。

硬件加速器

像 TensorFlow、PyTorch、Theanos 等 ML 框架支持使用图形处理单元(GPU)来提高计算速度。Google 提供了 Tensorflow 处理单元(TPU ),它提供了超过 GPU 的加速。英特尔最近发布了用于大规模深度学习训练和推理的神经网络处理器(NNP)。

这些硬件加速器价格昂贵,应监控其使用情况,并根据成本效益进行优化。大多数监控工具不提供这种现成的监控功能,并且需要设置额外的工具/插件。

ML 特定指标

ML 性能更加多维,集成了几种不同的度量标准。

  • 准确性:根据反馈和收到的实际数据,模型的预测能力如何
  • 数据漂移:训练的漂移计算&实际反馈差异(输出)、训练/运行时数据差异的漂移计算(输入)和跨特征相关性的漂移计算
  • 偏差:输入与输出的计算(训练与实际)
  • 异常:检测并记录所有异常输入
  • 可解释性:每个预测的主要特征的

结论

机器学习仍处于早期阶段。软件和硬件组件都在不断发展,以满足 ML 的当前需求。它们正以更快的速度发展,但是操作它们所需的工具还没有跟上。

Docker/Kubernetes 和微服务架构可以用来解决异构性和基础设施挑战。Comet 和 MLflow 正试图解决实验版本和再现性问题。SageMaker、Azure ML、Google AI 等云平台服务迎合了可扩展部署的需求。现有的工具可以单独部分解决一些问题。今天最大的挑战是将所有这些工具结合起来操作 ML。大多数情况下,这可能不切实际,尤其是在企业和受监管的行业中。

随着现有工具的发展和新工具的引入来解决这些挑战,人们应该考虑到这样一个事实,即数据科学社区主要由具有学术和研究背景的个人组成。操作 ML 的工具必须足够简单,能够被这些用户使用,同时能够解决 ML 的复杂挑战。

R 中的解开样条回归

原文:https://towardsdatascience.com/unraveling-spline-regression-in-r-937626bc3d96?source=collection_archive---------6-----------------------

(image by author)

当我们谈论回归时,首先想到的是线性或逻辑回归,以及遥远的多项式回归。线性回归和逻辑回归是两种最流行的回归方法。然而,有许多不同类型的回归方法可以证明在不同的情况下是有用的。今天我们将看看使用阶梯函数的样条回归。

样条回归是一种非参数回归技术。这种回归技术将数据集分成间隔或称为结的点的箱,每个箱有其单独的拟合。让我们看看在 r 中使用阶跃函数的样条回归的一个简单实现。

可视化数据集:

Quantity <- c(25,39,45,57,70,85,89,100,110,124,137,150,177)
Sales <- c(1000,1250,2600,3000,3500,4500,5000,4700,4405,4000,3730,3400,3300)
data <- data.frame(Quantity,Sales)
data

Quantity Vs Sales Data

**library**(plotly)plot_ly(data,x=~Quantity,
        y=~Sales,
        type="scatter"
)

Quantity Vs Sales Plot

让我们拟合一个线性回归,看看它是如何工作的:

fit <- lm(Sales ~ Quantity, data=data)
summary(fit)

plot_ly(data,x=~Quantity,
        y=~Sales,
        type="scatter") %>% add_lines(x =  ~Quantity, y = fitted(fit))

这里的等式采用以下形式:

在这种情况下:

我们可以看到,在这种情况下,线性回归产生了一个可怕的拟合,从上面的图和 R 平方值可以看出。

现在让我们将一个多项式项(此处为二次项)引入方程,并分析模型的性能。

fit2 <- lm(Sales ~ poly(Quantity,2) + Quantity, data=data)
summary(fit2)

plot_ly(data,x=~Quantity,
        y=~Sales,
        type="scatter") %>% add_lines(x =  ~Quantity, y = fitted(fit2))

这里的等式采用以下形式:

在这种情况下:

我们可以看到,这不是一个坏的适合,但也不是一个伟大的。预测的顶点与实际的顶点有些距离。多项式回归也有各种缺点,容易过度拟合。随着功能数量的增加,它会导致复杂性的增加。

样条回归可以克服多项式回归的缺点和线性模型的不足。

让我们通过将数据集分成两个箱来可视化数据集。一个在数量= 89 时出现的峰值的左侧,另一个在右侧,分别如下面两幅图像所示。

现在让我们将上述两幅图像合并成一个方程,并使用阶跃函数进行分段回归或样条回归。

该等式将采用以下形式:

在这种情况下:

这里的 Xbar 称为纽结值。

data$Xbar <- ifelse(data$Quantity>89,1,0)
data$diff <- data$Quantity - 89
data$X <- data$diff*data$Xbar

data

执行上述操作后,数据将如下所示:

现在让我们拟合上面看到的等式:

下面等式中的 X 是(x-xbar)*Xk

reg <- lm(Sales ~ Quantity + X, data = data)

plot_ly(data,x=~Quantity,
        y=~Sales,
        type="scatter") %>% add_lines(x =  ~Quantity, y = fitted(reg))

summary(reg)

从上面的图和 R 平方值可以看出,在这种情况下,样条回归产生了更好的结果。

上述结果也可以在 R:

**library**(segmented)

fit_seg <- segmented(fit, seg.Z = ~Quantity, psi = list(Quantity=89))

plot_ly(data,x=~Quantity,
        y=~Sales,
        type="scatter") %>% add_lines(x =  ~Quantity, y = fitted(fit_seg))

注意:如果不提供断点值(此处数量= 89),则使用“psi = NA”

summary(fit_seg)

两种方法产生相同的结果。

这是样条回归的一个简单例子。也可以使用多项式函数来拟合样条,称为多项式样条,因此可以在 X 的单独区域中拟合样条或具有较低次多项式的分段多项式回归,而不是在整个 X 范围内拟合高次多项式。

选择结的位置和数量

样条可以通过添加更多的结来建模,从而增加模型的灵活性。一般来说,放置 K 个结导致 K + 1 个函数的拟合。放置结的选择可能取决于各种因素。由于回归在放置更多结的区域非常灵活,因此直观地将结放置在数据变化更多或函数变化更快的地方。看起来相对稳定的区域不需要太多的结,可以使用较少的结。

结论:

在本文中,我们学习了使用阶跃函数的样条回归。也可以应用其他类型的多项式函数。常见的一种是三次样条,它使用三阶多项式函数。实现样条的另一种方法是平滑样条。与多项式回归相比,样条曲线通常能提供更好的结果。在样条曲线中,可以通过增加结的数量来增加灵活性,而不增加多项式的次数。一般来说,与多项式回归相比,它们还能产生更稳定的结果。

我希望这篇文章有助于理解样条和分段回归的思想,并开始使用它。

参考文献:

[1]Andrew Wheeler 的《回归中的样条》。【http://utdallas.edu/~Andrew.Wheeler/Splines.html

[2]Shokoufeh Mirza ei 如何开发 R 中的分段线性回归模型。https://www.youtube.com/watch?v=onfXC1qe7LI

[3]断点分析,分段回归。https://rpubs.com/MarkusLoew/12164

[4]加雷思·詹姆斯、丹妮拉·威滕、特雷弗·哈斯蒂、罗伯特·蒂布拉尼。《统计学习导论:在 r .纽约的应用》: Springer,2013 年。

用人工智能解开零售中的产品匹配

原文:https://towardsdatascience.com/unravelling-product-matching-with-ai-1a6ef7bd8614?source=collection_archive---------10-----------------------

TL;博士 : 产品匹配,即对多家零售商出售的同一产品进行匹配的能力,是零售业发展不可或缺的一部分。我们探索一种机器学习方法,通过世界上最大的实时零售数据源提供高准确性和可扩展性。

产品匹配是零售技术研究的一个重要领域。从 ASOS 和 Zalando 等零售商的角度来看,确保竞争对手之间一致的定价和折扣是一个优先事项,从单一产品层面到整个产品组合重叠。零售商必须在市场上保持竞争力。然而,对零售商不销售或不专门促销的产品的认识也会对利润产生重大影响。零售商独占性(即当没有匹配时)在零售业中可能有利可图。对于任何正在向不同市场扩张或通过多家零售商销售的知名品牌,如耐克和博柏利,很难跟踪产品的价格和所需的描述。品牌希望他们的产品得到统一的展示,零售商可能在这两方面都卖得不够好。

Matching products can have different images, names and descriptions

编辑的,我们拥有超过 5 亿个零售产品的数据。这些产品由众多零售商以多种语言和市场销售。它们可以在不同的时间,以不同的品牌(汤米·席尔菲格与汤米·席尔菲格内衣)出售,并带有零售商选择的图像和文字。他们的产品信息范围很广,从详尽的叙述到单个单词描述“服装”或数字标识符。看看上面的例子,基于真实数据,每个产品在名称、描述和图像上都有所不同。在 5 亿的数据集中,这些产品不够独特或相似,不足以使产品匹配成为一项简单的任务。如何才能准确匹配这些产品?更重要的是,如何才能对这些比赛有信心?让我们看看如何以可扩展的方式和高精度实现这一点。

每个字节的数据都有帮助

为了了解两种产品是否相同,我们需要尽可能多的产品数据重叠。编辑从零售商网页抓取多个文本字段、图像和元数据(例如抓取时间)。所有这些都被认为是我们模型中的“特征”。例如,一些常见的基于文本的特征包括产品名称、提供的产品描述和产品品牌。

我们需要把这些数据转换成计算机能处理的东西。首先,让我们看看我们基于文本的功能。自然语言处理(NLP)是机器学习的一个子领域,旨在理解计算机如何分析人类语言。一个常见的 NLP 任务是单词嵌入,将单词映射到表示它们的向量,并且存在许多模型来执行该任务。最简单地说,这意味着对文本中的单词进行计数,其中向量的长度相当于词汇表的大小,每个元素代表一个单词。在最复杂的情况下,这可以是对数百万个单词或短语进行训练的模型,以基于训练期间学习的特征产生固定长度的向量,其中单词的表示分布在向量中的几个元素上(例如 BERTXLNet )。在设计模型基础设施时,必须考虑单词嵌入的复杂性和伸缩能力。

接下来,我们需要重新想象这个过程,这样我们的图像就可以用向量来表示了。这是机器学习研究的一个大领域,被称为计算机视觉。在最基本的情况下,我们可以通过散列函数简单地检查两幅图像是否相同。然而,如果有任何差异,即使在单个像素级别,我们也无法匹配图像。相反,我们使用卷积神经网络(CNN),这是一种用于我们图像识别的深度学习算法。CNN 在图像上使用移动过滤器来寻找其特征,同时减少需要处理的数据量。在最底层,这些过滤器提取诸如边缘之类的特征。然后,该网络学习如何将这些特征组合起来形成复杂的结构,从而更深入地了解定义产品的组件。然后,它利用这一点来分类产品,例如,作为一个顶部或服装。这些被称为“特征向量”,其中向量的元素对应于从 CNN 学习的特征。

Our model architecture using word embeddings derived from text and feature vectors learned from images

绘制世界上最大的实时零售数据集

利用从文本和图像中获得的每个产品的这两个向量,我们可以可视化 EDITED 的数据库中的关系。我们通过使用向量作为高维坐标系统来做到这一点,其中每个元素对应于一个单独轴上的一个坐标。例如,想象一个长度为 2 个元素的向量。这意味着一个元素在 x 轴上,另一个元素在 y- 轴上,就像一个简单的图表,如上图的散点图所示。扩展到 3 个元素,该图现在有一个 z- 轴,并且可以通过 3D 绘图可视化。继续这个过程,直到我们在一个向量中有几百或几千个元素,那么多的维度很难概念化。

这是产品的高维映射,其中彼此靠近的产品将由于它们的特征向量和单词嵌入而共享相似的特征。这转化为我们希望查询的产品与其周围数据点或产品之间的距离,其中距离越短越匹配。折叠到 2D(使用降维技术,如 SVD ),我们可以看到下面几个数据点的复杂性。

A 2D representation of mapping for a subset of EDITED data, color-coded by brand

在 EDITED,我们有 5 亿个产品的高维映射!我们称之为“指数”。从存储以及构建和查询索引所花费的时间来看,为一个查询产品检查索引中的每个产品是不现实的。如何才能意识到哪些产品彼此靠近,最关键的是,要快?

进入数据科学的另一个蓬勃发展的领域,近似最近邻居(ANN),涉及一些世界上最大的科技公司的贡献,包括 Spotify 的aroy和脸书的 FAISS 。这些算法通过猜测产品的最近邻居来平衡准确性和速度。在其核心,人工神经网络随机分裂数据,并重复这一过程,直到一个二叉树结构被创建,其中每一个叶子是每次分裂后的数据子集,分支被用来回忆邻居。通过随机化分裂和创建重复的二叉树,我们获得了最近邻的良好估计。

人工神经网络的最新发展使用了一种类似图形的数据结构,称为分层可导航小世界图,它在准确性和速度方面领先于基准。这里,查询开始遍历索引,其中在每个阶段,针对图的每个节点,记录查询数据点与其邻居之间的距离。基于最小化该距离来选择要遍历的下一个节点,并且再次记录最佳邻居。当满足用户定义的特定标准时,该过程结束,例如要执行的计算次数,返回最近邻居的更好估计。

评估评估评估

最后,我们想了解我们的系统性能如何。当我们从高维索引中查询一个产品的邻居时,我们需要检查我们的邻居是否确实匹配,以及我们是否返回了所有可能的匹配。这与 precision(正确的相邻要素的比例)和 recall(返回的匹配要素的比例)相同。除此之外,我们需要匹配和更相关的邻居返回更高的排名,所以对索引有信心。

通过根据与查询产品的距离返回匹配,我们使用了“分级检索”系统。当我们返回大量的邻居(例如 100)时,我们应该能够实现完全召回。

Paul Verhoeven’s Total Recall

然而,我们还想评估无法实现完全召回的查询的准确性。为此,我们将我们的度量修改为“等级为 k 的精度”、“正确的 k 邻居的比例”和“等级为 k 的召回”,在我们的 k 邻居中匹配的比例,其中 k 是返回的邻居的数量(例如 100)。当我们通过距离过滤我们的邻居时, k 将随着每个查询而变化。我们需要确保精度保持在 k. 的变化

Calculating average precision in a ranked retrieval system for a query with four matches

为此,我们可以计算“平均精度”,这不需要固定的k。该方法是可行的——我们迭代通过距离过滤返回的 k 个邻居,并且在每次迭代中,如果乘积是匹配的,我们计算该等级的精度。然后,我们使用这些精度值的平均值,如上图所示。这允许我们更严厉地处罚高等级的不匹配,同时也考虑低等级的不匹配。最后,我们计算多个查询的“平均精度”,这是为每个查询计算的平均精度的平均值。这已被证明是 EDITED 的一个宝贵指标,因为它展示了对精确度和召回率的理解,同时优先考虑以用户为中心的功能,如排名。

Ensuring consistent pricing and discounting amongst competitors. These matched products have different names, brands, descriptions and images

Tracking consistency in a brand’s pricing and descriptions across markets and retailers

关键要点

我们的模型使用基于文本和图像的特征来创建产品如何相关的高维映射,尽管有不同的描述和图像,也能提供产品匹配。通过使用最新的机器学习进展,我们能够精确、自信地在多个零售商、语言和市场中提取相同的产品,并达到零售业前所未有的规模。

产品匹配是零售业中一个难以应对的挑战,根本原因在于数据的差异和庞大规模。通过在 EDITED 上分享我们的方法,我们希望能够为如何完成这项艰巨的任务提供一些见解。

无监督对抗图像重建

原文:https://towardsdatascience.com/unsupervised-adversarial-image-reconstruction-4b07ae38541a?source=collection_archive---------22-----------------------

Reconstructing faces from noisy, corrupted images

我最近偶然看到了论文无监督的对抗性图像重建(帕若等人 2019),并被它迷住了。该文件展示了一种方法来恢复图像从其损坏的副本没有使用任何监督。举个例子,假设你有很多用相机拍摄的图像,但是你在拍摄前只是粗略地清洁了一下镜头,现在你得到的是损坏的图像。您可以使用对抗性图像重建来获得您想要的图像。这不需要任何干净的图像原型供算法使用。很有趣,对吧?这里有一个关于论文中涉及的数学的帖子,可以帮助你更好地理解论文。

该配方

像往常一样,让我们假设观察到的数据有潜在的概率分布。具体来说,让

其中 Y 是代表受损图像的随机变量,而 X 代表我们希望恢复的干净图像。

假设有一个由 θ 参数化的贴图 F : XY ,它根据参数 θ 来破坏图像。这里

可能代表导致损坏的因素,如我们示例中相机镜头上的灰尘。

因此,

在哪里

用于包括附加噪声。

因此,

Equation 1

注意,如果已知 FXθ 中是线性的,等式 1 将与线性回归中看到的等式相同。

我们也可以假设 θ 独立于 X 。我们的外部失真因素与图像无关。

独立性假设给出了下面的等式。

Equation 2

现在,我们的目标是在给定一个损坏图像(y)的情况下,找到最佳的底层未损坏图像 x,。这在数学上可以表示为

Bayes’ rule

注意分母独立于 x,因此我们可以写

我们的目标是优化上面的函数,然而,我们不知道 p(x) 长什么样。此外, log p(y|x) 涉及边缘化 wrt θ ,这不会导致解析形式。

作为实现上述结果的代理,我们将找到从受损图像空间到我们想要恢复的图像空间的总体最佳映射(注意期望 wrt y), G* 。具体来说,

Equation 3

似然项

考虑等式 3 的第一部分。假设要单独优化。

The first term in RHS of Equation 3. Note that the subscript Y|X has been dropped

相反,让我们尝试优化相关的表达式

这将有助于导出第一个量的分析。

为了将数量化为分析形式,我们将使用许多概率技巧。让我们从思考开始,

根据概率链式法则这是正确的。重新排列并再次使用链式法则,

其中最后一个等式是由于 θX. 的独立性。因此,

Yθ,的联合分布取期望 wrt,我们得到

Equation 4

左侧的项与 θ 无关,因此

注意到

这里使用等式 2。此外,等式 4 中的最后一项独立于 x 。因此,当我们优化 wrt x. 时,我们可以忽略它

最后,等式 4 简化为

现在我们可以安全地用 G(y) 替换 x 得到,

Equation 5

根据等式 1,我们有,

代入等式 5,我们得到,

Equation 6

Model for the likelihood term

前一个术语

考虑等式 3 的 RHS 中的另一项,

The second term in RHS of Equation 3

为了理解这个术语的含义,我们必须仔细考虑这篇论文中提到的下面一行

最大化 w.r.t .先验项 p(G(y)) …类似于学习映射 G,使得 G(y) …诱导的分布接近分布 P_x。

为了理解上面的陈述,考虑下面的例子。设分布 P_xP_y 的支撑为集合{1,2,3,4}。让分布由下式给出:

Probability distributions of X and Y

现在我们需要找到一张从 GYX 的地图,使得上面的数量最大化。当您思考上述问题时,您意识到您必须将图中与高楼对应的 y 的映射到与高楼对应的 x 的上,以获得数量的高值。因此, G(y) 的分布开始看起来与 X 的分布相同。上述问题的最优映射 G* 为

The Map G for the above problem

因此 G(y) 的分布与最优情况下的 X 相同。

思考先验项的另一种方式是将其与预期条件损失联系起来:

但是上面的方式更直观。

好的,我们现在的目标是匹配两个分布,如果你以前学过甘斯和瓦瑟斯坦甘斯,你会对解决这个问题有一些见解。如果你还没有,看看这个很棒的博客。其思想是 GAN 的生成器试图匹配两个分布,而鉴别器的工作是区分它们。随着时间的推移,你希望发电机赢得比赛,它能够产生样本,鉴别器无法区分。

Model for the prior term

把它放在一起

上述思想的结合方式如下。你从观察损坏的图像开始, y. 你要求生成器产生未损坏的版本, x. 你从它的分布中取样 θ 。现在你用 y_hat = F(x,θ),构造 y_hat,忽略加性高斯噪声。保持发电机固定,训练鉴别器区分 y_haty. 用于更新鉴别器的损失函数为

Discriminator loss

要求鉴别器将 D(y)推至 1 并将 D(y_hat)推至 0。

使用也包含似然项的损失函数来更新生成器。具体来说,它由下式给出

Generator loss.

其中λ是控制给予 MSE 的重要性的参数。发生器试图将 D(y_hat)的值推至 1。

The Entire Model

封装上述思想的算法由下式给出:

因此,我们已经理解了以无监督的方式获得图像重建的过程。

我希望你喜欢阅读这篇文章。我很想在下面的部分听到你的评论。干杯!

无监督的品牌分类

原文:https://towardsdatascience.com/unsupervised-brand-categorization-15170928ea1b?source=collection_archive---------20-----------------------

使用人工智能根据品牌的历史对其进行分类

存在 100-1000 个品牌和公司,属于不同的行业和公司。如今,这些都是根据各种行业分类方案(如 NAICS、SIC、NIC 等)手动分类和分组的。这些方案是预先确定的,并不反映企业或品牌不断变化的性质。

使用“代码+人工智能”驱动的机器,我们能否在品牌/公司的旅程中创建一个更动态的分类基础?

这里有一个演示的地面零方法。关键是不要期望用户以“无监督”的机器学习方式提供关键词或分类法。我们在大约 500 个品牌名称上运行机器。对于每个品牌,它们的历程、历史和细节都是从维基百科中有计划地挑选出来的。维基百科是互联网上的事实真相。

然后,这些内容被矢量化。矢量化意味着根据上下文(周围的单词和句子)理解文本文档中的每个单词。这将导致一个品牌的旅程被封装成一个数学向量。然后它变得有利于分组。下面是表示为这些品牌的网络的向量空间。(注意:此处看不到品牌名称,但稍后会显示缩小部分)

每个节点是一个品牌名称,边代表“旅程/历史向量”之间的交叉程度。把它想成是两个品牌的旅程中常见的东西。对 500 个品牌中的每一个进行比较。

历史/内容/历程相似的品牌更接近。下图显示了向量空间的缩小部分。人们可以看到机器自动识别汽车品牌。

这些向量然后被数学地分组到许多类似于行业分类的类别中。下图显示了 27 个类别

我们能自动命名这些类别吗?

类别内的旅程向量空间的交集减去跨类别的旅程向量空间的交集将提供独特的类别级洞察。基本上,它将告诉我们哪些因素在一个集群中是共同的,但与其他因素不同。下面是机器自动生成的几个例子。

它按照传统的分类方法对某些品牌进行分类,如尿布品牌,但有趣的是,它提供了新的见解,如可口可乐在第 10 类中是全球主要赞助商的饮料品牌。一种不同的方式来看待品牌的地位。

分类的层次可以更深,尤其是在发现更多品牌组合和需要更多洞察力的情况下。下面是一个特定类别的子分类示例,该类别包含各种设备制造商品牌。

苹果拥有世界上最大的安全移动消费者网络之一。用传统的方法,我们永远不会认为苹果是一个可以与 Hauwei 和 Broadcom 相提并论的品牌。

这种分类的动态性如何?

人们可以选择内容的不同部分来达到不同的类别。例如,只有维基百科的“历史”部分可以比较历史旅程,而“产品”部分可以根据产品进行分类。另一种方法是改变内容源本身。例如,如何从客户的角度对品牌进行分类,将要求内容是客户的反馈。下面是一个使用客户反馈显示为品牌网络的示例手机,可以按照本文所示进一步分类。

这项工作可以经常重复,以保持分类的更新,并反映品牌认知或公司业务的任何变化。

传统的人工分类方法无法提供人工智能机器创造的分类所能提供的动力。在公司分析、收益分析、品牌映射、专利分析、研究等方面,我们是否进入了一个新的分类时代?

无监督分类项目:用聚类分析和 K-Means 构建一个电影推荐器

原文:https://towardsdatascience.com/unsupervised-classification-project-building-a-movie-recommender-with-clustering-analysis-and-4bab0738efe6?source=collection_archive---------2-----------------------

Picture from Unsplash

介绍

这个项目的目标是找出人群中的相似之处,以便为用户建立一个电影推荐系统。我们将分析网飞数据库中的一个数据集,根据人们对电影的评价来探索人们在电影品味上的共同特征。

数据将来自 MovieLens 用户评分数据集

数据集概述

该数据集有两个文件,我们将导入这两个文件并使用它们。

**# Import Libraries**
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
from scipy.sparse import csr_matrix
from mpl_toolkits.axes_grid1 import make_axes_locatable
from sklearn.cluster import KMeans
from sklearn.metrics import mean_squared_error
import itertools
from sklearn.metrics import silhouette_samples, silhouette_score%matplotlib inline**# Import the Movies dataset**
movies = pd.read_csv('ml-latest-small/movies.csv')
movies.head()

**# Import the ratings dataset**
ratings = pd.read_csv('ml-latest-small/ratings.csv')
ratings.head()

我们希望了解数据集的结构是如何工作的,以及在每个表中有多少条记录。

**# Print the number of records and the total number of movies**
print('The dataset contains: ', len(ratings), ' ratings of ', len(movies), ' movies.')

浪漫与科幻

我们将从考虑用户子集开始,发现他们最喜欢的类型。我们将通过定义一个函数来计算每个用户对所有科幻和爱情电影的平均评分。

**# Function to get the genre ratings**
def get_genre_ratings(ratings, movies, genres, column_names):
    genre_ratings = pd.DataFrame()
    for genre in genres:        
        genre_movies = movies[movies['genres'].str.contains(genre) ]
        avg_genre_votes_per_user = ratings[ratings['movieId'].isin(genre_movies['movieId'])].loc[:, ['userId', 'rating']].groupby(['userId'])['rating'].mean().round(2)

        genre_ratings = pd.concat([genre_ratings, avg_genre_votes_per_user], axis=1)

    genre_ratings.columns = column_names
    return genre_ratings**# Calculate the average rating of romance and scifi movies**
genre_ratings = get_genre_ratings(ratings, movies, ['Romance', 'Sci-Fi'], ['avg_romance_rating', 'avg_scifi_rating'])
genre_ratings.head()

为了有一个更明确的人群子集来研究,我们将偏向我们的分组,只从那些喜欢浪漫或科幻电影的用户那里获得评级。

**# Function to get the biased dataset**
def bias_genre_rating_dataset(genre_ratings, score_limit_1, score_limit_2):
    biased_dataset =    genre_ratings[((genre_ratings['avg_romance_rating'] < score_limit_1 - 0.2) & (genre_ratings['avg_scifi_rating'] > score_limit_2)) | ((genre_ratings['avg_scifi_rating'] < score_limit_1) & (genre_ratings['avg_romance_rating'] > score_limit_2))]
    biased_dataset = pd.concat([biased_dataset[:300], genre_ratings[:2]])
    biased_dataset = pd.DataFrame(biased_dataset.to_records()) return biased_dataset**# Bias the dataset**
biased_dataset = bias_genre_rating_dataset(genre_ratings, 3.2, 2.5)**# Printing the resulting number of records & the head of the dataset**
print( "Number of records: ", len(biased_dataset))
biased_dataset.head()

我们可以看到有 183 个记录,每一个都有一个浪漫和科幻电影分级。

现在,我们将进行一些可视化分析,以便更好地了解有偏差数据集及其特征。

**# Defining the scatterplot drawing function**
def draw_scatterplot(x_data, x_label, y_data, y_label):
    fig = plt.figure(figsize=(8,8))
    ax = fig.add_subplot(111) plt.xlim(0, 5)
    plt.ylim(0, 5)
    ax.set_xlabel(x_label)
    ax.set_ylabel(y_label)
    ax.scatter(x_data, y_data, s=30)**# Plot the scatterplot**
draw_scatterplot(biased_dataset['avg_scifi_rating'],'Avg scifi rating', biased_dataset['avg_romance_rating'], 'Avg romance rating')

我们之前制造的偏见现在已经非常清楚了。我们将通过应用 K-Means 把样本分成两个不同的组来进行下一步。

**# Let's turn our dataset into a list**
X = biased_dataset[['avg_scifi_rating','avg_romance_rating']].values**# Import KMeans**
from sklearn.cluster import KMeans**# Create an instance of KMeans to find two clusters**
kmeans_1 = KMeans(n_clusters=2)**# Use fit_predict to cluster the dataset**
predictions = kmeans_1.fit_predict(X)**# Defining the cluster plotting function**
def draw_clusters(biased_dataset, predictions, cmap='viridis'):
    fig = plt.figure(figsize=(8,8))
    ax = fig.add_subplot(111)
    plt.xlim(0, 5)
    plt.ylim(0, 5)
    ax.set_xlabel('Avg scifi rating')
    ax.set_ylabel('Avg romance rating')clustered = pd.concat([biased_dataset.reset_index(), pd.DataFrame({'group':predictions})], axis=1)
    plt.scatter(clustered['avg_scifi_rating'], clustered['avg_romance_rating'], c=clustered['group'], s=20, cmap=cmap)**# Plot**
draw_clusters(biased_dataset, predictions)

很明显,分组逻辑是基于每个人对爱情电影的评价。对爱情电影平均评分为 3 分或更高的人将属于一组,平均评分低于 3 分的人将属于另一组。

现在我们来看看如果我们将数据集分成三组会发生什么。

**# Create an instance of KMeans to find three clusters**
kmeans_2 = KMeans(n_clusters=3)**# Use fit_predict to cluster the dataset**
predictions_2 = kmeans_2.fit_predict(X)**# Plot**
draw_clusters(biased_dataset, predictions_2)

现在很明显,科幻小说的评级已经开始发挥作用:

  • 喜欢科幻和浪漫的人属于黄色群体。
  • 喜欢科幻但不喜欢浪漫的人属于绿色群体。
  • 喜欢浪漫但不喜欢科幻的人属于紫色群体。

让我们看看如果我们添加另一个组会发生什么。

**# Create an instance of KMeans to find three clusters**
kmeans_3 = KMeans(n_clusters=4)**# Use fit_predict to cluster the dataset**
predictions_3 = kmeans_3.fit_predict(X)**# Plot**
draw_clusters(biased_dataset, predictions_3)

从这个分析中,我们可以认识到,我们把数据集分成的组越多,属于每个组的人的偏好就越相似。

选择正确的 K 个集群

正如我们在文章“无监督机器学习:聚类分析”中讨论的:

选择正确的聚类数是 K-Means 算法的关键点之一。有一些方法可以找到这个数字:

领域知识

商业决策

肘法

由于与数据科学的动机和性质一致,肘方法是首选方法,因为它依赖数据支持的分析方法来做出决策。

肘法

肘方法用于确定数据集中聚类的正确数量。它的工作原理是绘制 K 的递增值与使用该 K 时获得的总误差的关系图。

目标是找到对于每个聚类不会显著增加方差的 k

在这种情况下,我们将选择弯头所在的 k=3。

为了更好地理解这种方法,当我们谈到方差时,我们指的是误差。计算该误差的方法之一是:

  • 首先,减去从每个聚类的每个点到其相应组的质心的欧几里德距离。
  • 然后,平方这个值(去掉负项)。
  • 最后,将所有这些值相加,获得总误差。

所以,现在我们想为我们的数据集找出正确的聚类数。为此,我们将对 Kl 的所有可能值执行肘方法,Kl 的范围将在 1 和我们的数据集的所有元素之间。这样,我们将考虑极端情况下的每一种可能性:

  • 如果 K = 1,则所有的点只属于一个群。
  • 如果 K =所有数据点,每个数据点是一个单独的组。
**# Selecting our dataset to study**
df = biased_dataset[['avg_scifi_rating','avg_romance_rating']]**# Choose the range of k values to test.
# We added a stride of 5 to improve performance. We don't need to calculate the error for every k value**
possible_k_values = range(2, len(X)+1, 5)**# Define function to calculate the clustering errors**
def clustering_errors(k, data):
    kmeans = KMeans(n_clusters=k).fit(data)
    predictions = kmeans.predict(data)
    #cluster_centers = kmeans.cluster_centers_
    # errors = [mean_squared_error(row, cluster_centers[cluster]) for row, cluster in zip(data.values, predictions)]
    # return sum(errors)
    silhouette_avg = silhouette_score(data, predictions)
    return silhouette_avg**# Calculate error values for all k values we're interested in**
errors_per_k = [helper.clustering_errors(k, X) for k in possible_k_values]**# Plot the each value of K vs. the silhouette score at that value**
fig, ax = plt.subplots(figsize=(16, 6))
plt.plot(possible_k_values, errors_per_k)**# Ticks and grid**
xticks = np.arange(min(possible_k_values), max(possible_k_values)+1, 5.0)
ax.set_xticks(xticks, minor=False)
ax.set_xticks(xticks, minor=True)
ax.xaxis.grid(True, which='both')
yticks = np.arange(round(min(errors_per_k), 2), max(errors_per_k), .05)
ax.set_yticks(yticks, minor=False)
ax.set_yticks(yticks, minor=True)
ax.yaxis.grid(True, which='both')

从图中可以看出,K 值的最佳选择是:7,22,27,31。根据轮廓分数,增加超出该范围的聚类数会导致最差的聚类。

我们将选择 K = 7,因为它是产生最佳分数的一个,并且将更容易可视化。

**# Create an instance of KMeans to find seven clusters**
kmeans_4 = KMeans(n_clusters=7)**# Use fit_predict to cluster the dataset**
predictions_4 = kmeans_4.fit_predict(X)**# Plot**
draw_clusters(biased_dataset, predictions_4, cmap='Accent')

为我们的分析增加行动

到目前为止,我们只分析了爱情片和科幻片。让我们看看当我们通过添加动作片来添加其他类型时会发生什么。

**# Select our biased dataset and add action genre**
biased_dataset_3_genres = get_genre_ratings(ratings, movies, ['Romance','Sci-Fi', 'Action'],                                          
['avg_romance_rating', 'avg_scifi_rating', 'avg_action_rating'])**# Drop null values**
biased_dataset_3_genres = bias_genre_rating_dataset(biased_dataset_3_genres, 3.2, 2.5).dropna()**# Print the number of records and the head of our dataset**
print( "Number of records: ", len(biased_dataset_3_genres))
biased_dataset_3_genres.head()

**# Turn dataset into a list**
X_with_action = biased_dataset_3_genres[['avg_scifi_rating',                                                   'avg_romance_rating',                                                         'avg_action_rating']].values**# Create an instance of KMeans to find seven clusters**
kmeans_5 = KMeans(n_clusters=7)**# Use fit_predict to cluster the dataset**
predictions_5 = kmeans_5.fit_predict(X_with_action)**# Define 3d plotting function**
def draw_clusters_3d(biased_dataset_3, predictions):
    fig = plt.figure(figsize=(8,8))
    ax = fig.add_subplot(111)plt.xlim(0, 5)
    plt.ylim(0, 5)
    ax.set_xlabel('Avg scifi rating')
    ax.set_ylabel('Avg romance rating')clustered = pd.concat([biased_dataset_3.reset_index(), pd.DataFrame({'group':predictions})], axis=1)colors = itertools.cycle(plt.rcParams["axes.prop_cycle"].by_key()["color"])for g in clustered.group.unique():
        color = next(colors)
        for index, point in clustered[clustered.group == g].iterrows():
            if point['avg_action_rating'].astype(float) > 3: 
                size = 50
            else:
                size = 15
            plt.scatter(point['avg_scifi_rating'], 
                        point['avg_romance_rating'], 
                        s=size, 
                        color=color)**# Plot**
draw_clusters_3d(biased_dataset_3_genres, predictions_5)

这里,我们仍然使用浪漫和科幻评分的 x 轴和 y 轴。此外,我们用圆点的大小来表示动作片的评分(圆点越大,动作片的评分越高)。

我们可以看到,随着动作基因的加入,聚类发生了显著的变化。我们添加到 k-means 模型中的数据越多,每个群体的偏好就越相似。

糟糕的是,用这种方法绘图,我们开始失去在分析三维或更多维时正确可视化的能力。因此,在下一节中,我们将研究其他绘图方法,以正确地可视化高达五维的集群。

更高级别的聚类

一旦我们看到并理解了 K-Means 算法如何根据用户的电影类型偏好对他们进行分组,我们将对数据集进行更大的了解,并探索用户如何对单部电影进行评级。

为此,我们将按“用户标识”与“用户评级”对数据集进行分组,如下所示。

**# Merge the two tables then pivot so we have Users X Movies dataframe**
ratings_title = pd.merge(ratings, movies[['movieId', 'title']], on='movieId' )
user_movie_ratings = pd.pivot_table(ratings_title, index='userId', columns= 'title', values='rating')**# Print he number of dimensions and a subset of the dataset**
print('dataset dimensions: ', user_movie_ratings.shape, '\n\nSubset example:')
user_movie_ratings.iloc[:6, :10]

看看这个数据集的子集,很明显有很多“NaN”值,因为大多数用户没有对大多数电影进行评级。这种具有大量“空”值的数据集被称为“稀疏”或“低密度”数据集。

为了解决这个问题,我们将根据评分最高的电影和对电影评分最多的用户对 datsaset 进行排序。因此,我们将在数据集的顶部获得一个更加“密集”的区域。

**# Define the sorting by rating function**
def sort_by_rating_density(user_movie_ratings, n_movies, n_users):
    most_rated_movies = get_most_rated_movies(user_movie_ratings, n_movies)
    most_rated_movies = get_users_who_rate_the_most(most_rated_movies, n_users)
    return most_rated_movies**# choose the number of movies and users and sort**
n_movies = 30
n_users = 18
most_rated_movies_users_selection = sort_by_rating_density(user_movie_ratings, n_movies, n_users)**# Print the result**
print('dataset dimensions: ', most_rated_movies_users_selection.shape()
most_rated_movies_users_selection.head()

现在,我们想把它形象化。由于我们有大量的维度和数据要绘制,这种情况下的首选方法是“热图”。

**# Define the plotting heatmap function**
def draw_movies_heatmap(most_rated_movies_users_selection, axis_labels=True):

    fig = plt.figure(figsize=(15,4))
    ax = plt.gca()

    # Draw heatmap
    heatmap = ax.imshow(most_rated_movies_users_selection,  interpolation='nearest', vmin=0, vmax=5, aspect='auto')if axis_labels:
        ax.set_yticks(np.arange(most_rated_movies_users_selection.shape[0]) , minor=False)
        ax.set_xticks(np.arange(most_rated_movies_users_selection.shape[1]) , minor=False)
        ax.invert_yaxis()
        ax.xaxis.tick_top()
        labels = most_rated_movies_users_selection.columns.str[:40]
        ax.set_xticklabels(labels, minor=False)
        ax.set_yticklabels(most_rated_movies_users_selection.index, minor=False)
        plt.setp(ax.get_xticklabels(), rotation=90)
    else:
        ax.get_xaxis().set_visible(False)
        ax.get_yaxis().set_visible(False)

    ax.grid(False)
    ax.set_ylabel('User id')# Separate heatmap from color bar
    divider = make_axes_locatable(ax)
    cax = divider.append_axes("right", size="5%", pad=0.05)# Color bar
    cbar = fig.colorbar(heatmap, ticks=[5, 4, 3, 2, 1, 0], cax=cax)
    cbar.ax.set_yticklabels(['5 stars', '4 stars','3 stars','2 stars','1 stars','0 stars'])plt.show()**# Print the heatmap**
draw_movies_heatmap(most_rated_movies_users_selection)

要理解这张热图:

  • 每个专栏都是一部不同的电影。
  • 每一行都是不同的用户。
  • 单元格的颜色是每个用户对每部电影的评价。每种颜色的数值可以在右边的刻度中查看。
  • 白色值对应于尚未给电影评分的用户。

为了提高模型的性能,我们将只对 1000 部电影使用评级。

**# Define Function to get the most rated movies**
def get_most_rated_movies(user_movie_ratings, max_number_of_movies):
    # 1- Count
    user_movie_ratings = user_movie_ratings.append(user_movie_ratings.count(), ignore_index=True)
    # 2- sort
    user_movie_ratings_sorted = user_movie_ratings.sort_values(len(user_movie_ratings)-1, axis=1, ascending=False)
    user_movie_ratings_sorted = user_movie_ratings_sorted.drop(user_movie_ratings_sorted.tail(1).index)
    # 3- slice
    most_rated_movies = user_movie_ratings_sorted.iloc[:, :max_number_of_movies]
    return most_rated_movies**# Pivot the dataset and choose the first 1000 movies**
user_movie_ratings =  pd.pivot_table(ratings_title, index='userId', columns= 'title', values='rating')
most_rated_movies_1k = get_most_rated_movies(user_movie_ratings, 1000)

此外,由于 k-means 算法不能很好地处理稀疏数据集,我们需要将其转换为 SciPi 库中定义的稀疏 csr 矩阵类型。为此,我们首先需要将数据集转换为稀疏数据帧,然后使用 pandas 中的to_coo()方法将其转换为稀疏矩阵。

**# Conversion to sparse csr matrix**
sparse_ratings = csr_matrix(pd.SparseDataFrame(most_rated_movies_1k).to_coo())

大规模聚类

我们将选取任意数量的群组,以便对所获得的结果进行分析,并找出每个群组内的某些趋势和共性。这个数将是 K = 20。之后,我们将把每个集群绘制成热图。

**# 20 clusters**
predictions = KMeans(n_clusters=20, algorithm='full').fit_predict(sparse_ratings)**# Select the mas number of users and movies heatmap cluster**
max_users = 70
max_movies = 50**# Cluster and print some of them**
clustered = pd.concat([most_rated_movies_1k.reset_index(), pd.DataFrame({'group':predictions})], axis=1)
draw_movie_clusters(clustered, max_users, max_movies)

我们可以从这些热图中注意到一些事情:

  • 聚类中相同颜色的垂直线越多,该聚类中的评级就越相似。
  • 一些聚类比其他的更稀疏,这表明该算法倾向于将观看和评价较少电影的人也分组。
  • 集群往往有一个主色:如果他们喜欢他们的分级电影,黄色,如果不喜欢,蓝色。
  • 具有相同颜色的水平线对应于其评级变化低的用户,他们倾向于喜欢或不喜欢大多数电影。

预言;预测;预告

现在,我们将选择一个集群进行分析,并尝试使用它进行预测。

**# Pick a cluster ID from the clusters above**
cluster_number = 11**# Let's filter to only see the region of the dataset with the most number of values** 
n_users = 75
n_movies = 300
cluster = clustered[clustered.group == cluster_number].drop(['index', 'group'], axis=1)**# Sort and print the cluster**
cluster = sort_by_rating_density(cluster, n_movies, n_users)
draw_movies_heatmap(cluster, axis_labels=False)

现在我们将展示评级:

**# Print the ratings**
cluster.fillna('').head()

现在,我们将选取一个空白单元格,这些单元格是尚未被用户评级的电影,我们将尝试预测他/她是否会喜欢这部电影。

用户被分在一个群中,其他用户可能与他们有相似的品味,因此有理由认为他/她会用该群中其他用户的平均值来评价一部空白电影。这就是我们将如何进行。

**# Fill in the name of the column/movie. e.g. 'Forrest Gump (1994)'**
movie_name = "Matrix, The (1999)"cluster[movie_name].mean()

推荐

使用上一步的逻辑,如果我们计算每部电影在聚类中的平均分,我们将了解客户对数据集中每部电影的感受。

**# The average rating of 20 movies as rated by the users in the cluster**
cluster.mean().head(20)

这对我们真的很有用,因为我们可以用它作为推荐引擎,推荐用户去发现他们可能喜欢的电影。

当用户登录我们的应用程序时,我们现在可以向他们展示适合他们口味的推荐。这些推荐的公式是选择该群中用户还没有评级的最高评级的电影。

**# Pick a user ID from the dataset** user_id = 19**# Get all this user's ratings**
user_2_ratings  = cluster.loc[user_id, :]**# Which movies did they not rate?** 
user_2_unrated_movies =  user_2_ratings[user_2_ratings.isnull()]**# What are the ratings of these movies the user did not rate?**
avg_ratings = pd.concat([user_2_unrated_movies, cluster.mean()], axis=1, join='inner').loc[:,0]**# Let's sort by rating so the highest rated movies are presented first**
avg_ratings.sort_values(ascending=False)[:20]

这些将是我们给用户的前 20 条推荐。

最后的话

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

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

无监督抽取摘要:一项比较研究

原文:https://towardsdatascience.com/unsupervised-extractive-summarization-a-comparative-study-ca6ac2181d54?source=collection_archive---------7-----------------------

Laurent El Ghaoui 和 Tanya Roosta。

T 他的文章涉及摘要,目标是提取几个句子,很好地概括一个给定的文档或一组文档。有监督的方法寻求学习基于大量的例子提取哪些句子;它们在实践中的应用和部署可能具有挑战性,因为它们需要大型、高质量的训练集。无监督的方法不需要任何训练集,并且仅与语料库一起工作以进行总结。在这里,我们探索如何非监督的方法可以与最先进的,监督提取摘要方法竞争。

B 背景。抽取方法通过直接从源文本中选择重要的现有单词、短语或句子的子集来生成摘要。关于这个主题有大量的科学文献;最近的调查有(萨基奥等人,2016甘比尔等人, 2017白羊座等人,2019帕帕吉安诺普卢等人, 2019 )。

抽象概括可以与抽象概括形成对比,抽象概括与抽象概括的不同之处在于它试图从零开始生成新的句子,而不是从源文档中提取句子。把提取摘要想象成一支荧光笔,把抽象摘要想象成一个人类作家。抽象方法通常更难开发,因为它们需要高性能的自然语言生成技术,这本身就是一个活跃的研究领域,参见例如( Boutkan 等人,2019等, 2019 ) 及其引用文献。最近还提出了结合抽取和抽象方法的混合策略,例如参见()。,2019 )。

迄今为止,最先进的有监督的纯提取摘要技术依赖于神经网络体系结构;summary runner(Nallapatiet al .,2018 ) 它采用了一种“递归神经网络”,是该类别的最佳模型代表之一。

如(格鲁斯基等人所述。,2018 )在新闻数据集上,非常简单的(无监督的)基线,比如选取一篇新闻文章的前几个句子,仍然能够击败这些高级的监督模型。这可能是通常用于评估的数据集的一个产物:新闻文章倾向于以这样一种方式写作,即前几个句子给出文章的主旨,这在新闻编辑室的说法中被称为“导语”;但这也指出了一个事实,即无人监管的方法仍有可能战胜有人监管的方法。

先前在无监督提取摘要方面的工作集中在统计的、基于图的和基于优化的方法上。统计方法( Saggio et al. ,2016 )以 TF-IDF 评分等简单统计为核心。基于图的方法( Barrios et al .,2016 )将文本表示为链接句子的网络,并使用基于图的排序方法生成摘要;基于优化的方法( Durrett et al .,2016 )使用稀疏优化、整数线性规划和约束优化等技术。

D数据集合。为了比较摘要算法,最好有包含“黄金”或参考摘要的数据集。在我们的比较中,我们使用了标准和不太标准的数据集。

数据集 CNN每日邮报 (DM),在这里可用,都包含新闻文章,通常有 1 或 2 页长,通常只有几个句子长的“黄金”摘要是手工编写的。

对于这些标准数据集,我们开源了这里两个有用的新数据集,因为它们包含更长的文档:

  • 2019 金融展望 (FO)数据集包含来自多家大型金融机构的 10 份公开发布的金融报告。每份报告从 10 页到 144 页不等,平均长度为 33 页。没有黄金总结本身。我们选择将黄金摘要定义为句子的集合,或句子的一部分,在内容中以粗体显示;或者,在内容中突出显示为插页的任何句子。
  • 古典文学书籍(CL) 数据集包含 11 本英文古典书籍,范围从 53 页到 1139 页,中值长度为 198 页。这本书每章的黄金摘要通常有 20 页长,从 WikiSummary 中获取。

E 摘要领域中使用的评估指标通常基于所谓的 ROUGE scores ,其测量提取的句子与其参考对应物之间的词汇重叠,例如,与参考摘要共享的字数。许多作者注意到这种纯词汇测量的缺点,特别是当参考文献摘要使用的语言在意义上相似,但在词的选择上不同。这促使研究人员提出更多基于语义的方法,主要是为了更好地处理同义词。

( Ng et al. ,2015 )的论文通过所谓的句子嵌入来测量提取的句子和参考摘要之间的相似性,从而解决同义性问题;其他方法,如 ROUGE 2.0 基于固定的同义词列表和/或主题的使用。

R结果。我们比较了四种不同的方法:

  • Lede-3:使用前 3 个句子的简单基线。
  • 文本排名 : 一种基于图的无监督方法。
  • sum runner:上面提到的有监督的提取摘要神经网络算法。
  • Nucleus:是指 sumup.ai 开发并商业化的专有文本包中的无监督的、提取的摘要器。

下表显示了与词汇模糊度量相对应的分数,显示了 95%的置信区间。(所示的度量对应于召回和精度测量的调和平均值;它不应与分类中典型的 F1 分数相混淆;对于汇总重叠度量,这些数字通常要低得多。)

Average performance (ROUGE-1 F score) for four extractive summarization methods evaluated on three kinds data sets: News (averaged over CNN and Daily Mail datasets), reports on 2019 Financial Outlooks and classical literature books.

我们观察到,当数据包含较短的文档(CNN 和 DM, news)时,SummaRunner 似乎更受青睐;但是在这种情况下,简单基线(Lede-3)几乎做得一样好。面对更长的文档,如报告和文献,基线和基于图表的方法都被其他两种模型所主导,相差甚远。在不同的数据集上,非监督方法 Nucleus 与复杂的监督模型不相上下。

其他词汇度量,如 ROUGE-*,以及测量,如精度、召回率等。,或使用语义胭脂度量,指向相同的结论。

无监督特征学习

原文:https://towardsdatascience.com/unsupervised-feature-learning-46a2fe399929?source=collection_archive---------5-----------------------

图像任务上的深度卷积网络接受形式为(高度 x 宽度 x 通道)的图像矩阵,并通过一系列参数函数将它们处理成低维特征。监督和非监督学习任务都旨在从原始数据中学习语义上有意义的特征表示。

训练深度监督学习模型需要以标记的 (x,y) 对的形式的海量数据。无监督学习不需要相应的标签 (y) ,最常见的例子就是自动编码器。自动编码器将 x 作为输入,将它通过一系列层来压缩维度,然后在重建 x 的效果方面受到批评。自动编码器最终会学习一组描述数据 x 的特征,但是,这些特征可能对监督学习或辨别任务不是很有用。

使用自动编码器的无监督特征学习的一个扩展是去噪自动编码器。去噪自动编码器将受损图像(原始图像添加了某种形式的随机矩阵)作为输入,并重建原始图像。同样,这些特征对于辨别任务不是很有用,然而,希望这两个例子足以解释如何构建无监督的特征学习任务。

Dosovitskiy 等人提出了一种非常有趣的无监督特征学习方法,使用极端数据增强来创建无监督学习的代理类。他们的方法从图像中裁剪出 32 x 32 的小块,并根据采样的幅度参数使用一组变换对它们进行变换。他们训练一个深度 CNN,根据它们的扩充“代理”类对这些补丁进行分类。

The top left image is a 32 x 32 patch taken from the STL-10 dataset. Dosovitskiy et al. proceed to form all of these other images by sampling a parameter vector that defines a set of transformations. Each of these resulting images belongs to a surrogate class. A Deep Learning model will classify images according to these classes.

链接到论文:

[## 基于卷积神经网络的判别性无监督特征学习

神经信息处理系统电子会议录

papers.nips.cc](https://papers.nips.cc/paper/5548-discriminative-unsupervised-feature-learning-with-convolutional-neural-networks)

在本文中,使用了 6 种变换:平移、缩放、旋转、对比度 1、对比度 2 和颜色添加。这些变换中的每一个都带有一个参数,该参数定义了增加的幅度。例如,translate →(垂直,0.1(面片大小))。幅度参数可以存储在单个向量中。这些向量从参数的总体分布中采样,以变换面片。

这些幅度参数被离散化,使得在参数的边界之间存在有限的值空间,例如范围在[0.2,0.1,0,-0.1,-0.2]之间的平移幅度。离散化的细化导致大量代理类的整体构建。例如,如果有 5 个平移值、5 个缩放值、5 个旋转值、5 个对比度 1 值、5 个对比度 2 值和 5 个颜色添加值。有 5⁶ = 15,625 个结果代理类。

因此,Dosovitskiy 等人试图回答的问题是:

应该使用多少代理类?

构造的代理类的数量

Note the y-axis on the left corresponds to the classification performance using unsupervised features on the supervised STL-10 discriminative task and the y-axis on the right corresponds to the error of the classifier on different surrogate classes, (very low error rate for 50–2000 surrogate classes)

该图显示,大约 2000 个代理类的性能开始趋于稳定。因此,大多数增强之间没有太多的间隔。另一个有趣的问题出现了:

每个代理类应该使用多少个扩充样本?

用于代理类的扩充样本

上面的图显示了 2000 个代理类在前面的图中被证明是最优的;在每类大约 32 到 64 个样本时,性能开始稳定下来。

考虑一下用于这种方法的扩充数据集的大小是很有趣的。

32x32x3 patches → 2,000 surrogate classes → 64 samples per class(32x32x3) x 2000 x 64 = 393,216,000 pixels

只有大约 393 MB,对于大多数现代计算机来说,这真的不是一个大问题。然而,如果他们将方法从 32 x 32 小块改变为完整的图像,这可能变得巨大,需要使用在线数据增强技术。

变换的多样性

他们还研究了使用不同的转换来构造代理类。如上图所示,当仅使用颜色和对比度时,数据集和所使用的增强之间存在一些差异,在 Caltech-101 spike 中尤为明显。但是,使用所有增强在所有三个数据集上都具有一致的高性能。这表明,通过添加更多的转换,结果可能会进一步改善。

感谢您阅读这篇介绍无监督特征学习的论文!我认为看到深度神经网络如何在一项任务中学习特征并将其很好地转移到另一项任务是非常有趣的。使用在任务上训练的深度特征,例如本文中描述的 Exemplar-CNN,对于辨别任务也是有用的。请在评论中告诉我你对此的想法。

无监督学习:聚类

原文:https://towardsdatascience.com/unsupervised-learning-clustering-60f13b4c27f1?source=collection_archive---------19-----------------------

Pokemon is 21 years old. Think about that.

对…的介绍

一个算法如何得知哪些口袋妖怪是传奇,哪些不值得你超球

大约一周前,我写了一篇关于预测《权力的游戏》中一场战斗结果的文章,以便讨论包括流水线和堆栈回归在内的主题。我把这封信发给了我母亲,让她看看我在实习项目中学到的东西,她的回答大致是这样的:“你在温特伯格……把我搞糊涂了,你就不能写一篇关于口袋妖怪或者我能理解的东西的文章吗?”

因此,本周,考虑到我将在项目培训的最后一周研究什么,我开始搜索口袋妖怪数据集。我最初偶然发现了一组图像,意在用来教导算法口袋妖怪是什么样子,以便生成新的口袋妖怪。(剧透:结果吓人。)然后,我找到了超过 800 个口袋妖怪的特征的全集,我决定使用它来练习一些无监督的学习——具体来说,就是聚类。是否有某些特征将口袋妖怪捆绑在一起?算法会按代拆分他们吗?按类型?在游戏过程中,当我们试图决定口袋妖怪是否值得保留和训练时,我们的大脑是否会产生相同的潜意识集群?

让我们来了解一下!

如果你对我的发现比对编码和技术部分更感兴趣,请随意跳到你开始看所有口袋妖怪的地方!

首先,介绍无监督学习:

当谈到“机器学习”这个沉重的话题时,实际上有两种类型:有人监督的和无人监督的。监督是一个过程,在这个过程中,你教算法如何标记事物,或者你给它每个观察值一个 y 值,并训练它预测未标记观察值的 y 值。

Examples of Supervised Learning

这就是我前面提到的《权力的游戏》中发生的事情——我正在训练一个模型,根据之前已经被标记为胜利或失败的战斗,将一场战斗分类为胜利或失败。监督学习对于预测更有用,因为它学习一组和另一组之间的差异,允许它对训练集之外的观察结果进行分类。然而,如果我们的目标不是分类,而是组织呢?这就是无监督学习的用武之地。

那么什么是无监督学习呢?

无监督学习有三种类型:聚类(我们将要关注的)、降维和自动编码。

降维(也称为数据压缩)确实如其名。它会找到压缩和编码数据的方法,以便更容易、更快、更便宜地在模型中运行。它通常用于图像,以便分解它们,但保留大部分信息。数据压缩基于这样的假设,即大多数数据多少有些冗余,可以重新格式化以更有效地包含信息。有两种类型的数据压缩:主成分分析,它寻找传达大部分方差的变量的线性组合,以及奇异值分解,它将数据集分解成三个更小的矩阵。一个自动编码器在缩小数据的意义上非常类似于数据压缩,但它通过深度学习来做到这一点,其中数据被输入到一个神经网络,通过加权,塑造一个输出,这是数据的最佳表示。

集群也名副其实。它获取未标记的数据,并将其组织到相似的组中。有三种方法可以做到这一点。首先,有 k 均值聚类,它创建 k 个互斥组。它通过将 k 个随机质心分配给数据并将观测值分配给它们最接近的质心来实现这一点。质心位于这些观察值的中心,并且重复该过程,直到质心有效地停止移动。困难之处在于选择一个合适的 k 值的过程可能很复杂。较大的 k 意味着较小的组,因此粒度更大,但是您可能希望更广泛地对组进行聚类。下面是一个带有交互式可视化的源代码,它进一步清晰地解释了 k-means 聚类。

[## 可视化 K-均值聚类

不幸的是,尽管 k-means 肯定会收敛,但它所收敛到的最终聚类配置…

www.naftaliharris.com](https://www.naftaliharris.com/blog/visualizing-k-means-clustering/)

from sklearn.cluster import KMeans
k = 10
kmeans = KMeans(n_clusters=k).fit(X)
kmeans.labels_

还有从 n 个聚类开始的层次聚类,每个聚类对应一个观察值。从那里,它将最近的两个聚类组合成一个更大的聚类,并重复这一过程,直到所有的观察结果都在一个聚类中。这被称为凝聚集群和 g,它的逆过程(一群分裂成许多群)被称为分裂集群。您可以划分生成的树状图,以获得所需的聚类数。

Hierarchical Clustering

from sklearn.cluster import AgglomerativeClustering
clusters = AgglomerativeClustering(n_clusters=10).fit(X)
clusters.labels_

最后,还有概率聚类,这是一种较软的聚类形式,它不是给每个观察值分配一个组,而是分配一个组的概率。如果您想知道某个观察与某个组的相似程度,而不仅仅是与该组最相似,这将很有帮助。

无监督学习有两个主要挑战。首先,特别是对于集群,需要探究产生的集群。该算法将拆分数据,但它不会告诉您它是如何做到的,也不会告诉您聚类中的相似性是什么,这可能是执行的目标。第二,很难知道它是否正常工作。与监督学习不同,没有可用于评估它的准确性度量。

回到口袋妖怪!

link

有了 800 个口袋妖怪的数据集,包括 HP(生命值)、攻击和防御、主要类型和次要类型以及世代等特征,我决定看看算法如何将口袋妖怪分成集群。我有几个预测,第一个是分成几代。我是在假设过去 21 年里,他们一定下意识地让新的口袋妖怪客观上变得更好的基础上形成的。(他们没有。)我发现的群体与我感觉到的大多数人在玩耍时无意中形成的群体非常相似。有一些口袋妖怪值得捕捉、训练和战斗,还有一些是你为了你的口袋妖怪而捕捉的,并把它们留在你的电脑里(这个概念我多年前玩的时候还不明白,我的意思是你如何把你实际捕捉的口袋妖怪储存在电脑里?).

我的主要外卖?传说中的口袋妖怪和非传说中的口袋妖怪是有客观区别的。这是有道理的,但事实证明,在 10 个集群中,有两个是完全传奇式的,一个有一个非传奇式的,当该功能不包括在提供给机器的数据中时,它就溜了进来。不仅如此,它还分裂了顶级进攻者、顶级防守者和少数之间的平衡。

就非传奇的口袋妖怪而言,它也做了一些奇怪的事情。它创造了一群强龙口袋妖怪,一群年长但强水/正常型口袋妖怪,一群高 HP 高攻击低防御的毒/战斗型口袋妖怪,一群高攻防但低 HP 的自然岩/虫/水)型口袋妖怪,一群较新的一般口袋妖怪(多为首发和低进化),一群年长的一般口袋妖怪,一群 HP 体面但攻防低的仙鬼型口袋妖怪。

所以…本质上它创造了这些“你想要这些”、“你可以用这些”和“不要在这些上面浪费时间”的集群。这里和那里显然有一些有问题的决定,例如鲤鱼王,一个臭名昭著的无用的口袋妖怪进化前,被放在更老但强大的水/正常类型,而它实际上应该在更老和平均组。然而,它的进化 Gyarados 恰好在同一个组中,并且这种趋势跨越了大多数组,其中进化都在同一个群中,不管一个是否明显优于另一个。

总而言之,这种疯狂似乎有某种方法。

结论

如果你想了解你拥有的数据类型,聚类和无监督学习通常是一个非常有用的工具。然而,你从中获得的洞察力取决于你和你对数据的理解。最终由您来决定您的集群意味着什么以及如何使用它们。

此外,也许我们应该给鲤鱼王一个机会。

Magikarp’s Confusing Evolution

https://github . com/taylorfogarty/launch/blob/master/neural _ net _ pokemon . ipynb

无监督学习:降维

原文:https://towardsdatascience.com/unsupervised-learning-dimensionality-reduction-ddb4d55e0757?source=collection_archive---------3-----------------------

压缩特征,减少过度拟合和噪声,提高效率和性能

Picture from Unsplash

介绍

之前的文章所述,无监督学习是指一种机器学习算法和技术,这些算法和技术通过未标记的数据进行训练和反馈。换句话说,我们事先不知道正确的解或目标变量的值。

这些类型的算法的主要目标是研究数据的内在和隐藏结构,以便获得有意义的见解,将数据集分成相似的组或简化它们。

在整篇文章中,我们将探讨一些最常用于降低数据集维度的算法和技术。

降维基础

维度是数据集中存在的变量、特征或特性的数量。这个维度被表示为列,目标是减少它们的数量。

在大多数情况下,这些列是相关的,因此,存在一些冗余信息,这会增加数据集的噪声。这种冗余信息对机器学习模型的训练和性能有负面影响,这就是为什么使用降维方法变得至关重要。这是降低模型复杂度和避免过拟合的一个非常有用的方法。

降维有两个主要类别:

  • 特征选择→我们选择原始数据集的特征子集。
  • 特征提取→我们从原始集合中提取信息来建立新的特征子空间。

特征选择

特征选择代表一系列用于减少给定数据集的维度特征空间的贪婪算法。目标是获得一个能够自动选择与所面临问题最相关的特征子集的模型。

贪婪算法在组合搜索的每个阶段做出局部最优的选择,并且通常产生次优的解决方案。这就是它们不同于穷举搜索算法的地方,穷举搜索算法评估整个组合集并产生整体最优解。贪婪算法的好处是它们在计算上更有效率,以精度为代价,但是大多数时候它们产生足够好的解。

这样可以提高训练过程的计算效率,减少数据集的噪声,避免过拟合,降低模型的复杂度。

我们将研究两种主要的特征选择技术:

  • 顺序向后选择或 SBS
  • 随机森林具有重要性

顺序反向选择

SBS 算法背后的思想如下:

  • 我们将设置我们想要在数据集中的最终特征数
  • 然后,我们将设置一个标准函数,该函数负责最小化因移除数据集的某个要素而导致的性能损失。
  • 在每次迭代中,该算法将通过简单地计算去除每个当前特征之前和之后的性能来计算性能的降低。
  • 然后,将从数据集中移除导致性能下降最小的要素。
  • 如果数据集中存在的要素数等于 d 数(在开始时设置),则算法停止。否则,它将完成另一次迭代。

随机森林的特征重要性

我们已经在以前的文章中研究了随机森林算法。这是一种集成算法,它将一组弱决策树模型结合起来,以建立一个更健壮、更精确的模型。

使用随机森林,我们可以通过计算森林中所有决策树的平均杂质减少量来评估每个特征的重要性,以及它们对模型信息的贡献。这将在不对数据是否是线性可分的做出任何假设的情况下完成。

这是一种非常简单的获取特性重要性的方法,因为我们将使用 scikit-learn 库的随机森林实现,它已经在拟合了一个 RandomForesClassifier 之后通过使用 feature_importance_ 属性收集了特性重要性。

在之前的文章中,我们已经研究过这个的一个例子,我们想找出那些最有助于预测一个特定的个人收入是否达到或超过 50,000 美元的特征。

***# Import Ada Boost Classifier***
from sklearn.ensemble import AdaBoostClassifier

***# Train the supervised model on the training*** 
model = AdaBoostClassifier().fit(X_train, y_train)

***# Extract the feature importances using .feature_importances****_* 
importances = model.feature_importances_

***# Plot***
vs.feature_plot(importances, X_train, y_train)

特征抽出

特征提取也用于减少某个数据集的特征数量,但与特征选择相反,输出特征不会与原始特征相同。

使用特征提取时,我们将数据投影到一个新的特征空间,因此新的特征将是原始特征的组合,以保留最相关信息的方式进行压缩。

一些最常用的无监督特征提取算法是:

  • 主成分分析
  • 随机投影
  • 独立成分分析

主成分分析

为了理解 PCA 算法是如何工作的,让我们考虑以下数据分布:

PCA 找到一个新的象限系统(y’和 x’轴),该系统是仅通过平移和旋转从旧系统获得的。

  • 它会将坐标系的中心从原点(0,0)移动到数据点分布的中心。
  • 然后,它会将 x 轴移动到变化的主轴,这是相对于数据点变化最大的一个轴(最大扩散的方向)。
  • 然后,它将另一个与主轴正交的轴移动到不太重要的变化方向。

基本上,PCA 在高维数据中找到最大方差的方向,并将该数据投影到一个新的子空间中,该子空间具有与原始子空间相同或更少的维度。

这些包含最大方差的新方向称为主分量,它们具有相互正交的约束。

最大方差和信息损失

数据点将在最大方差的方向上投影,以形成新的轴。离轴越远的点,信息损失越大。

一个数学事实是,当我们将点投影到最大方差的方向上时,它最小化了从旧的和更高维的数据点到其新的变换值的距离。换句话说,它使信息损失最小化。

特征转换的 PCA 核心思想

总的来说,主成分分析所做的是将每个特征结合起来,并自动提取出最相关的特征。这是一种系统化的方法,将输入特征转换成主成分,并将它们用作新特征。

主成分是在投影或压缩数据时使方差最大化(信息损失最小化)的方向。

沿着主成分的数据方差越大,该方向包含的信息就越多,主成分的等级就越高。

主成分的数量将少于或等于输入特征的数量。

Scikit-Learn PCA 实现

让我们看一个在 Scikit-Learn 库中如何实现这个算法的例子。

***# Import PCA Algorithm***
from sklearn.decomposition import PCA

***# Initialize the algorithm and set the number of PC's***
pca = PCA(n_components=2)

***# Fit the model to data*** 
pca.fit(data)***# Get list of PC's***
pca.components_***# Transform the model to data*** 
pca.transform(data)***# Get the eigenvalues***
pca.explained_variance_ratio

何时使用 PCA

  • 当潜在特征驱动数据中的模式时。
  • 为了降维。
  • 来可视化高维数据。
  • 以减少噪音。
  • 作为提高其他算法性能的预处理步骤。

随机投影

随机投影是一种强大的降维方法,在计算上比 PCA 更有效。它通常用于因维数过多而无法直接计算主成分分析的数据集。

像 PCA 一样,它获取具有 d 维度和 n 样本的数据集,并产生具有 k 维度的数据集的变换,其中 k 远小于d(k<<d)。

方法

基本前提是通过乘以一个随机矩阵来降低数据集的维数。这将把数据集投影到新的特征子空间中。

理论方法:约翰逊—林登施特劳斯引理

高维欧几里得空间中具有 N 个样本的数据集可以被向下映射到低得多的维度中的空间,其方式在很大程度上保持了到点的距离。

换句话说,计算数据集中两点之间的距离平方,新数据集中这两点的距离必须是:

  • 小于距离的平方乘以(1-ε)
  • 大于距离的平方乘以(1+ε)

被认为是数据点的 uv

随机投影 Scikit-learn 实现

***# Import Random Projection Algorithm***
from sklearn.random_projection import SparseRandomProjection

***# Initialize the algorithm and set the number of PC's***
randprojection = SparseRandomProjection()

***# Fit and transformthe model to data*** 
randprojection.fit_transform(data)

ε值ε是数据集各点之间允许的误差水平。ε的默认值为 0.1。

我们可以使用随机投影,方法是设置一些组件,或者指定ε的值,并让算法自动计算维数的保守值。

独立成分分析

ICA 是一种类似于 PCA 或随机投影的降维方法,它采用一组特征并产生在某种程度上有用的不同组。

但是当 PCA 试图最大化方差时,ICA 假设特征是独立源的混合物,并且它试图隔离这些混合在数据集中的独立源。

ICA 背后的动机是获取原始特征集,并尝试识别独立贡献于数据集的那些特征,换句话说,那些与其他特征具有 leat 相关性的特征。所以它会分离出那些最重要的成分。这个问题叫做盲源分离。

高级算法

  • x:是我们的原始数据集。
  • 答:混合矩阵
  • 源矩阵
  • w:分解矩阵

这些变量的关系如下:

所以目标是计算 W,以便能够获得 S,独立特征的源矩阵。

为此,该算法将执行以下步骤:

  1. 以 X 为数据集,它会居中并白化它。
  2. 选择一个初始随机权重矩阵 W1,W2,…,Wn。
  3. 估计 W,包含向量。
  4. 去相关。
  5. 从步骤 3 开始重复,直到收敛

ICA 假设这些成分是统计独立的。它们必须具有非高斯分布,因为如果它们是高斯分布,我们将无法恢复原始信号。

从这一点出发,中心极限定理说,独立变量之和的分布趋于高斯分布。

Sci-kit 学习中的 ICA 实现

***# Import Independent Component Analysis Algorithm***
from sklearn.decomposition import FastICA

***# Initialize the algorithm and set the number of PC's***
ica = FastICA(n_components=2)

***# Fit and transform the model to data. It returns a list of independent components*** 
ica.fit_transform(data)

ICA 的一个有趣的应用是脑电图数据的分析。以下是来自持续 4.5 秒的 EEG 扫描的 14 个通道的读数以及从数据集中提取的独立分量的示例。

Original Paper: https://www.semanticscholar.org/paper/Applying-Independent-Component-Analysis-to-Factor-Cha-Chan/a34be08a20eba7523600203a32abb026a8dd85a3

最后的话

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

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

股票期权定价中异常检测的无监督学习

原文:https://towardsdatascience.com/unsupervised-learning-for-anomaly-detection-in-stock-options-pricing-e599728958c7?source=collection_archive---------5-----------------------

链接到 Github(笔记本+数据)。

注意:这篇文章是预测股票价格的更广泛工作的一部分。结果(识别出的异常)是模型(在 GAN 架构内)链接到 post 的一个特征(输入)。

1.动机

期权估价是一项非常困难的任务。首先,它需要使用大量数据点(下面列出了一些),其中一些非常主观(如隐含波动率——见下文),难以精确计算。例如,让我们检查呼叫的θθ的计算:

其中 N(d1)N(d2) 分别是标准正态分布的累积分布函数:

期权定价困难的另一个例子是用于计算期权价格的布莱克-斯科尔斯公式。计算到期日为 t 且当前价格为 S0 的欧式看涨期权价格的公式为:

The Black-Scholes formula for pricing a European call option.

第二,布莱克-斯科尔斯模型,又称二叉树,为了模型准确,需要满足很多假设。然而,这些规则在现实生活中往往无法实现。其中一些包括:

  • 该模型假设基础波动率( σ )在期权有效期内保持不变,不受基础股价水平变化的影响。很多时候,波动性随着执行价格的变化而变化——执行价格和基础价格之间的差异越大,波动性就越大。这种现象被称为波动微笑** ( 参见下图),**
  • 假设恒定的无风险回报率(随着全球经济每天都在变化,这是很难预测的事情),
  • 该模型没有考虑流动性风险和额外的费用/收费。
  • 它假设股票回报遵循对数正态分布(这意味着该模型忽略了价格大幅偏离、飙升或下跌的可能性,这在实际交易中很容易观察到),
  • 它假设没有股息支付。股息支付改变了股票的当前价值,进而改变了期权价格,
  • 该模型仅适用于欧式期权。

Not a perfect smile at this example, but we only used data for one day.

上述假设在现实生活中很少能得到满足,这一事实正是可以观察到异常现象的原因。这反过来又创造了很多机会,我们可以用机器/深度学习来探索和利用,比如套利交易

****注意:为了让我们完全理解异常检测是否有效(以及如何有效),了解希腊期权是很重要的。因此,我们将简要介绍它们:

  • 隐含波动率-σ :隐含波动率是对价格变化幅度的估计。更高的数字意味着交易者认为期权可以带来巨大的变化。基本上,只是一个波动指数。
  • Delta : δ 衡量期权价格相对于标的股票价格的变化幅度。0.5 的 delta 意味着股票每移动 1 美元,期权将改变 50 美分( δ 是价格的一阶导数)。
  • ****γ:γ衡量股价变化时 δ 的变化速度。高数值意味着这是一个非常活跃的选项,可能会迅速增加或减少价值(这是价格的二阶导数)。
  • ****θ:θ衡量期权每天因时间衰减而损失价值的速度。当到期日到来时,θ增加。
  • Vega**:VegaVega衡量期权价格对隐含波动率变化的敏感程度。没有钱的期权,或者离到期还有很长时间的期权对隐含波动率的变化更敏感,
  • Rho: rho 是衍生产品价格相对于无风险利率变化的变化率。(我们没有 Rho,tho 的数据)。

所以,回到异常检测。

2.数据

期权数据可以在 historicaloptiondata.com 找到。这将花费你 1-2K 美元,但数据丰富有序。

# Filtered options data for Goldman Sachs
options_df = pd.read_csv('option_GS_df.csv', parse_dates=["Expiration", ' DataDate'])# Let's create **Maturity** and **Spread** features
options_df['date_diff'] = (options_df['Expiration'] - options_df[' DataDate']).dt.days
options_df['Spread'] = options_df['Ask'] - options_df['Bid']

我们将在本帖中使用的数据是 2016 年 1 月 5 日高盛期权的每日报价。它包含不同到期日的定价(加上波动率和希腊),以及在该日期创建的行权价格。当天的当前(GS)价格为 174.09 美元。共有 22 个特性和 858 行(每行是截至 2016 年 1 月 5 日不同行使和到期日的定价和希腊人)。查看 Github repo 了解更多信息——顶部的链接。

options_df.shape**output** >>> (858, 22)

我们有什么特点?

print(', '.join(x for x in options_df.columns))**output** >> UnderlyingPrice, OptionSymbol, Type, Expiration,  DataDate, Strike, Last, Bid, Ask, Volume, OpenInterest, T1OpenInterest, IVMean, IVBid, IVAsk, Delta, Gamma, Theta, Vega, AKA, date_diff, Spread

基本上我们需要的所有功能都有了。让我们将数据可视化成一对图,其中:

  • 我们互相暗算的特征是 Strike,Bid,Delta,Gamma,Vega,和 Spread(我们不会暗算每一个特征),
  • 色调是期权的类型(看涨或看跌),
  • 对角线当然是各个特征的分布。

Goldman Sachs options data for 2016/01/05. The purple-ish color represents the calls, and the blue — the puts.

3.用于发现异常值(异常)的无监督学习

****什么是异常现象?在我们的案例中(以及一般情况下),异常是期权逻辑中的任何不匹配。例如,两个看涨期权的买入(或卖出)价格具有相同的执行价格,但是,比方说,在执行日有 1-2 天的差异,这两个价格应该几乎相同(除非有什么不寻常的事情,这可能在希腊人身上有所体现)。因此,这两种期权的投标价格的巨大差异不会是正常的。或者,举例来说,高θ或小织女星( OTM )期权的到期时间较长。诸如此类。

****注意:我们将再次跳过期权定价背后的技术和数学方面(如随机过程、布朗运动和扩散方程)。相反,我们试图看看我们是否可以使用机器学习来近似所有这些使用数据的数学公式(数据驱动的方法与模型驱动的方法相反)。结果可能不会像原始公式那样精确,但计算量会更小。或者,另一方面,机器学习可以“学习”如何进行金融建模(如期权定价),甚至比金融数学更好,因为我们可以在模型中纳入许多新方法和数据,允许模型揭示对人类隐藏的模式和相关性。

出于异常检测的目的,我们将使用隔离林

让我们可视化一个交易日(2016/01/05)的期权数据,并尝试看看我们是否可以直观地识别异常。有几件事看起来很可疑——这些可能是(也可能不是)异常现象:

  • 图 2** 中,奇怪的是,一份看跌期权合约的 delta 比它旁边的合约小得多,考虑到该合约具有相同的特征——买入价/卖出价的平均值、当前价格和执行价格之间的差异、非常非常接近的到期日——它是底部的选项,蓝色被灰色看跌期权包围(有点隐藏)。另一边,有一个同样异常的叫声——被灰色圆圈包围的紫色圆圈。**
  • 图 3** —(在右侧)中,有几个看涨期权(我们知道它们是看涨期权,因为看涨期权具有正的 delta —在 0 和 1 之间),具有明显更低的θ范围——圆圈具有小于(-4.5)的θ,考虑到具有相同特征的其他期权(附近)具有大于(-1.5)的θ。**

我们感兴趣的主要特征将是买价/卖价(或我们创建的特征——这些特征的平均值)和价差(=卖价)。理论上,相同类型的期权、成交价格和到期日不应该有明显不同的价格和价差。

以下四个图表是用 Tableau 制作的。

GS options data (x-axis is the difference between the Current price and the Strike price, and the y-axis is the average of the Bid and Ask — basically the option’s price), where the circles represent calls and the stars are puts. The clustering color is based on Vega.

GS options data (following the logic in Chart 1) but the clustering color is based on the Delta.

GS options data (x-axis is the Delta, y-axis is the difference between Current price and Strike price). The clustering color is based on the Delta and the clustering shape (circle, square, plus, and x) is based on the Theta.

GS options data (x-axis is Delta, y-axis is the Spread) where clustering color range comes from the mean price of Bid and Ask.

好了,让我们进入异常检测。我们的赌注是,通过数据分布,该算法将学习这些 optoins 规则,并设法发现不符合“平均分布的数据点。

it_X_train = options_df[['Strike', 'Delta', 'Gamma', 'date_diff']]
it_X_train['s_k'] = options_df['UnderlyingPrice'] - options_df['Strike']
it_X_train['b_a_mean'] = (options_df['Bid'] + options_df['Ask']) / 2
it_X_train['b_a_mean'] = it_X_train['b_a_mean'].apply(lambda x: int(round(x, 0)))
it_X_train['s_k'] = it_X_train['s_k'].apply(lambda x: int(round(x, 0)))

我们不会将每个特征都用于异常检测。我们使用的功能有:

print(', '.join(col_names[x] for x in it_X_train.columns))**output** >>> Strike, Delta, Gamma, Difference between Date of valuation and Exercise date, Difference between Current and Strike prices, Average of Bid and Ask.

我们为什么要使用这些功能?我们希望使用(一起)应该遵循上述选项逻辑的功能。这六个被选择的特征中的破碎逻辑应该构成一个'奇怪的契约。

****隔离林的逻辑极其简单:

clf = IsolationForest(max_samples='auto', contamination=.025,\
                      n_estimators=10, \
                      random_state=19117,  max_features=it_X_train.shape[1])clf.fit(it_X_train)
y_pred_train = clf.predict(it_X_train)

4.结果

让我们想象一下模型的结果。x 轴是当前价格和执行价格之间的差异,y 轴是买价和卖价的平均值(如上面的图表 1 和 2)。蓝色的 x 和紫色的圆圈分别是看跌期权和看涨期权,特征分布没有异常。其他的都是异常现象。

这些是隔离林发现的异常。有趣的是,我们发现(尽管从上一张图中看不到,因为我似乎无法修复 python 和 Tableau 之间的 y 轴刻度)识别的异常(红色和橙色)就是我们在上面的 4 张图中观察到的异常(我交叉引用了每个合同的索引)。

Pair-plot between the features we used for anomaly detection. (Date difference is the number of days until expiration)

从这个配对图中可以观察到异常期权定价样本:

  • 他们的平均价格(出价要价的平均值)高于其他选项,
  • 它们平均分布在不同的期限上(尽管原始数据主要分布在更接近的期限附近),
  • 它们当前的负执行价格不像原始数据那样正态分布。

如上所述,我们创建了股票期权定价异常检测,以便将其用作预测高盛股票价格变动的一个特征。期权定价的异常对于预测股票价格的变动到底有多重要?在这里查看。(还在做,不过)

感谢阅读。

最好的,鲍里斯

无监督学习:K-均值与层次聚类

原文:https://towardsdatascience.com/unsupervised-learning-k-means-vs-hierarchical-clustering-5fe2da7c9554?source=collection_archive---------8-----------------------

在进行无人监督的学习任务时,提供给你的数据不会被标记。这意味着您的算法将致力于推断数据中存在的内部结构,尝试根据它们之间的相似性将它们分组或聚类成类。

我想详细介绍两种主要的集群化算法:

  • k 均值
  • 分层聚类

让我们更多地了解他们。

k 均值

该算法的第一步是在我们未标记的观察值中,创建随机定位的新观察值,称为“质心”。质心的数量将代表输出类的数量(记住,我们不知道)。现在,将开始一个迭代过程,由两个步骤组成:

  • 首先,对于每个质心,该算法找到离该质心最近的点(根据通常计算为欧几里德距离的距离),并将它们分配到其类别中;
  • 其次,对于每个类别(由一个质心表示),该算法计算属于该类别的所有点的平均值。该计算的输出将是该类的新质心。

每次重复该过程时,最初与一个质心分类在一起的一些观察结果可能被重定向到另一个质心。此外,在几次重复之后,质心位置的变化应该越来越不重要,因为初始随机质心收敛到真实质心。当质心位置不再变化时,该过程结束。

现在,我们如何决定质心的数量?

有许多方法可以用来完成这项任务。然而,在这篇文章中,我将解释和使用所谓的“肘法”。这个想法是,我们希望在我们的集群内观察到的是低水平的变化,这是用集群内平方和(WCSS)来衡量的:

直观地理解,质心的数量越多,WCSS 越低。特别地,如果我们有和我们观察的数量一样多的质心,每个 WCSS 将等于零。然而,如果我们记得简约定律,我们知道设置尽可能多的质心是不一致的。

这个想法是挑选质心的数量,在此之后,WCSS 的减少是不相关的。我刚才描述的关系可以用下图来表示:

这个想法是,如果图是一个手臂,手臂的肘部是质心的最佳数量。

分层聚类

该算法可以使用两种不同的技术:

  • 结块的
  • 分裂的

后者基于相同的基本思想,但以相反的方式工作:当 K 是聚类的数量(可以像 K-means 中那样精确设置)并且 n 是数据点的数量,而 n > K 时,聚集 HC 从 n 个聚类开始,然后聚集数据直到获得 K 个聚类;另一方面,分裂 HC 仅从一个集群开始,然后根据相似性将其分裂,直到获得 K 个集群。注意,当我说相似性时,我指的是数据点之间的距离,它可以用不同的方法计算(我将在后面详述)。

让我们想象一下凝聚和分裂的技术:

Agglomerative HC

Divisive HC

正如预期的那样,这里的关键区别是数据点之间的相似性。在数学术语中,相似性主要是指距离,它可以用不同的方法计算。在此,我将提出其中的三条:

  • Min:它指出,给定两个集群 C1 和 C2,它们之间的相似性等于点 a 和 b 之间的最小相似性(翻译:距离),使得 a 属于 C1,b 属于 C2。

  • 它陈述了给定两个集群 C1 和 C2,它们之间的相似性等于点 a 和 b 之间的最大相似性,使得 a 属于 C1,b 属于 C2。

  • 平均:取所有的点对,计算它们的相似度,然后计算相似度的平均值。后者是集群 C1 和 C2 之间的相似性。

因此,概括地说,两种算法都寻找数据之间的相似性,并且都使用相同的方法来确定聚类的数量。选择哪一个真的取决于你面临的任务类型。

无监督学习项目:创建客户群

原文:https://towardsdatascience.com/unsupervised-learning-project-creating-customer-segments-17c4b4bbf925?source=collection_archive---------0-----------------------

了解如何开发端到端聚类和降维项目!

Picture from Unsplash

介绍

在整个项目中,我们将分析一些产品类别中几个客户的消费行为。该项目的主要目标是:

  • 将具有相似消费特征的客户分组。
  • 描述不同组内的差异,以便为每个组找到最佳的交付结构。

为了执行这个项目,我们将使用可以在下面的 UCI 机器学习知识库中找到的数据集。

你可以在我的 GitHub 页面上找到完整的项目、文档和数据集:

https://github . com/rromans 23/Machine _ learning _ Engineer _ uda city _ nano degree/tree/master/projects/customer _ segments

我们将重点分析为客户记录的六个产品类别,不包括“渠道”和“地区”字段。

***# Import libraries necessary for this project***
import numpy as np
import pandas as pd
from IPython.display import display *# Allows the use of display() for DataFrames*

***# Import supplementary visualizations code visuals.py***
import visuals as vs

***# Pretty display for notebooks***
%matplotlib inline

***# Load the wholesale customers dataset***
try:
    data = pd.read_csv("customers.csv")
    data.drop(['Region', 'Channel'], axis = 1, inplace = True)
    print("Wholesale customers dataset has {} samples with {} features each.".format(*data.shape))
except:
    print("Dataset could not be loaded. Is the dataset missing?")

数据探索

现在,我们将通过可视化和代码来探索数据集,以了解要素之间的关系。此外,我们将计算数据集的统计描述,并考虑每个特征的整体相关性。

***# Display a description of the dataset***
display(data.describe())

***# Display the head of the dataset***
data.head()

选择样本

为了更好地了解我们的数据集以及数据将如何通过分析进行转换,我们将选择几个样本点并详细研究它们。

***# Select three indices to sample from the dataset***
indices = [85,181,338]

***# Create a DataFrame of the chosen samples***
samples = pd.DataFrame(data.loc[indices], columns = data.keys()).reset_index(drop = True)
print("Chosen samples of wholesale customers dataset:")
display(samples)

考虑

现在,让我们考虑每个产品类别的总购买成本,以及上述样本客户数据集的统计描述。如果我们必须预测三个样本中的每一个代表哪种机构(客户):

考虑平均值:

  • 新鲜度:12000.2977
  • 牛奶:5796.2
  • 杂货:3071.9
  • 洗涤剂 _ 纸张:2881.4
  • 熟食店:1524.8

我们可以做出如下预测:

1)指数 85:零售商:

-在洗涤剂、纸张和杂货上的支出最大,通常是家庭用品。

-高于牛奶的平均支出。

-低于冷冻产品的平均支出。

2)指数 181:大市场

-几乎每个产品类别的高支出。

-在整个数据集的新鲜产品上花费最高。很可能是一个大市场。

-洗涤剂支出低。

3)索引 338:餐馆

-每种产品的数量都显著低于前两个客户考虑的数量。

-生鲜产品支出是整个数据集中最低的。

-在牛奶、清洁剂和纸张上的支出处于最低的四分之一。

  • 它可能是一个小而便宜的餐馆,需要食品杂货和冷冻食品来提供食物。

特征相关性

我们现在将分析这些特性的相关性,以了解顾客的购买行为。换句话说,确定购买某一类产品的某一数量的顾客是否一定会购买另一类产品的某一比例的数量。

我们将通过在删除一个特征的数据子集上训练一个监督回归学习器来研究这一点,然后对该模型预测删除特征的效果进行评分。

***# Display the head of the dataset***
data.head(1)

***# Make a copy of the DataFrame, using the 'drop' function to drop the given feature***
new_data = data.drop('Grocery', axis=1)

***# Split the data into training and testing sets(0.25) using the given feature as the target*
*# Set a random state.***
from sklearn.model_selection import train_test_split

X_train, X_test, y_train, y_test = train_test_split(new_data, data.Grocery, test_size=0.25, random_state=42)

***# Create a decision tree regressor and fit it to the training set***
from sklearn.tree import DecisionTreeRegressor
regressor = DecisionTreeRegressor()
regressor = regressor.fit(X_train, y_train)
prediction = regressor.predict(X_test)

***# Report the score of the prediction using the testing set***
from sklearn.metrics import r2_score
score = r2_score(y_test, prediction)
print("Prediction score is: {}".format(score))

  • 我们试图预测食品杂货的特点。
  • 报道的预测得分为 67.25%。
  • 由于我们获得了高分,这表明我们非常适合。因此,考虑到其他的消费习惯,这个特征是很容易预测的,因此,对于识别顾客的消费习惯来说不是很必要。

可视化特征分布

为了更好地理解我们的数据集,我们将展示每个产品特性的散点图。

散点图中显示相关性的产品特性将与预测其他特性相关。

***# Produce a scatter matrix for each pair of features in the data***
pd.scatter_matrix(data, alpha = 0.3, figsize = (14,8), diagonal = 'kde');

@

**# Display a correlation matrix
import seaborn as sns**
sns.heatmap(data.corr())

使用散布矩阵和相关矩阵作为参考,我们可以推断如下:

  • 数据不是正态分布的,它是正偏态的,并且符合对数正态分布。
  • 在大多数图中,大多数数据点位于原点附近,这表明它们之间几乎没有相关性。
  • 从散点图和相关热图中,我们可以看到“杂货店”和“洗涤剂 _ 纸”特征之间有很强的相关性。特征“食品杂货”和“牛奶”也显示了很好的相关性。
  • 这种相关性证实了我对“杂货”特征相关性的猜测,这可以通过“洗涤剂 _ 纸”特征来准确预测。因此,不是数据集中绝对必要的特征。

数据预处理

这一步是至关重要的,以确保获得的结果是重要的,有意义的,他们是优化的。我们将通过缩放数据和检测潜在的异常值来预处理数据。

特征缩放

通常,当数据不是正态分布时,特别是如果平均值和中值变化很大(表明偏差很大),最通常最适合应用非线性标度,尤其是对于金融数据。

实现这种缩放的一种方法是使用 Box-Cox 测试,该测试计算减少偏斜的数据的最佳幂变换。一种在大多数情况下都可行的更简单的方法是应用自然对数。

***# Scale the data using the natural logarithm*** 
log_data = np.log(data) ***# Scale the sample data using the natural logarithm*** 
log_samples = np.log(samples) ***# Produce a scatter matrix for each pair of newly-transformed features*** 
pd.scatter_matrix(log_data, alpha = 0.3, figsize = (14,8), diagonal = 'kde');

观察

在对数据应用自然对数标度后,每个特征的分布看起来更加正常。对于我们之前识别为相关的任何特征对,我们在这里观察到相关性仍然存在(以及它现在比以前更强还是更弱)。

显示实际数据:

***# Display the log-transformed sample data***
display(log_samples)

离群点检测

在任何分析的数据预处理步骤中,检测数据中的异常值都是极其重要的。异常值的存在通常会扭曲考虑这些数据点的结果。

这里,我们将使用图基的方法来识别异常值:一个异常值步长被计算为四分位间距(IQR)的 1.5 倍。具有超出该特征的 IQR 之外的异常值步长的特征的数据点被视为异常。

outliers = []

***# For each feature find the data points with extreme high or low values***
for feature in log_data.keys():

   ***# Calculate Q1 (25th percentile of the data) for the given feature***
    Q1 = np.percentile(log_data[feature],25)

 ***# Calculate Q3 (75th percentile of the data) for the given feature***
    Q3 = np.percentile(log_data[feature],75)

 **   *# Use the interquartile range to calculate an outlier step (1.5 times the interquartile range)***
    step = 1.5 * (Q3-Q1)

    ***# Display the outliers***
    print("Data points considered outliers for the feature '{}':".format(feature))
    display(log_data[~((log_data[feature] >= Q1 - step) & (log_data[feature] <= Q3 + step))])
    lista = log_data[~((log_data[feature] >= Q1 - step) & (log_data[feature] <= Q3 + step))].index.tolist()
    outliers.append(lista)

outliers 

**# Detecting outliers that appear in more than one product**
seen = {}
dupes = []

for lista in outliers:
    for index in lista:
        if index not in seen:
            seen[index] = 1
        else:
            if seen[index] == 1:
                dupes.append(index)
            seen[index] += 1
dupes = sorted(dupes)
dupes

***# Removing outliers* ** 
good_data = log_data.drop(dupes, axis=0).reset_index(drop=True)

观察

  • 存在于多个特征中的被视为异常值的数据点有:65、66、75、128、154。
  • K-Means 受异常值的影响很大,因为它们会显著增加算法试图最小化的损失函数。该损失函数是每个数据点到质心的距离的平方和,因此,如果异常值足够远,质心将被错误地定位。因此,离群值应该被去除。

特征转换

现在我们将使用主成分分析(PCA)来提取关于数据集的隐藏结构的结论。PCA 用于计算那些方差最大化的维度,因此我们将找到最能描述每个客户的特征组合。

主成分分析

一旦数据被调整为正态分布,必要的异常值被移除,我们可以将 PCA 应用于good_data以发现数据的哪些维度最大化了相关特征的方差。

除了找到这些维度,PCA 还将报告每个维度的解释方差比率—数据中有多少方差是由该维度单独解释的。

**# Get the shape of the log_samples**
log_samples.shape

***# Apply PCA by fitting the good data with the same number of dimensions as features***
from sklearn.decomposition import PCA
pca = PCA(n_components=good_data.shape[1])
pca = pca.fit(good_data)

***# Transform log_samples using the PCA fit above***
pca_samples = pca.transform(log_samples)

***# Generate PCA results plot***
pca_results = vs.pca_results(good_data, pca)

观察

  • 前两个主成分解释的方差占总方差的 70.68%。
  • 前三个主成分解释的方差占总方差的 93.11%。

尺寸讨论

  • 维度 1:根据负方差,该维度很好地代表了以下特征:洗涤剂 _ 纸、牛奶和杂货。主要是日常消费的公用事业。
  • 维度 2:这个维度很好地代表了负方差方面的以下特征:新鲜、冷冻和熟食。主要是消耗食物。
  • 维度 3:这个维度很好地代表了,就正方差而言,熟食特征,就负方差而言,新鲜特征。当天要吃的食物。
  • 维度 4:这个维度很好地代表了正方差方面的冷冻特征,以及负方差方面的熟食特征。可以储存的食物。
***# Display sample log-data after having a PCA transformation applied***
display(pd.DataFrame(np.round(pca_samples, 4), columns = pca_results.index.values))

降维

当使用主成分分析时,主要目标之一是降低数据的维数。

维数减少是有代价的:使用的维数越少,意味着数据中被解释的总方差越少。正因为如此,累计解释方差比对于了解问题需要多少个维度极其重要。此外,如果大量的差异只能用二维或三维来解释,那么减少的数据可以在以后可视化。

***# Apply PCA by fitting the good data with only two dimensions***
pca = PCA(n_components=2).fit(good_data)

***# Transform the good data using the PCA fit above***
reduced_data = pca.transform(good_data)

***# Transform log_samples using the PCA fit above***
pca_samples = pca.transform(log_samples)

***# Create a DataFrame for the reduced data***
reduced_data = pd.DataFrame(reduced_data, columns = ['Dimension 1', 'Dimension 2'])

下面的单元格显示了对数变换后的样本数据在仅使用二维数据进行 PCA 变换后的变化。观察与六维中的 PCA 变换相比,前二维的值如何保持不变。

***# Display sample log-data after applying PCA transformation in two dimensions***
display(pd.DataFrame(np.round(pca_samples, 4), columns = ['Dimension 1', 'Dimension 2']))

可视化双标图

双标图是一种散点图,其中每个数据点都由其沿主成分的分数表示。轴是主要部件(在这种情况下是Dimension 1Dimension 2)。

双绘图显示原始特征沿组件的投影。双标图可以帮助我们解释数据的降维,并发现主要成分和原始特征之间的关系。

***# Create a biplot***
vs.biplot(good_data, reduced_data, pca)

一旦我们有了原始特征投影(红色),就更容易解释散点图中每个数据点的相对位置。

例如,图右下角的点可能对应于在'Milk''Grocery''Detergents_Paper'上花费很多,但在其他产品类别上花费不多的客户。

使聚集

在本节中,我们将选择使用 K 均值聚类算法或高斯混合模型(GMM)聚类算法来识别隐藏在数据中的各种客户群。

然后,我们将从集群中恢复特定的数据点,通过将它们转换回原始维度和规模来理解它们的重要性。

K 均值 vs GMM

1)使用 K-Means 作为聚类算法的主要优点是:

——容易实现。

-对于大量变量,如果(K 很小),它在计算上可能比分层聚类更快。

-一致且比例不变。

-保证会收敛。

2)使用高斯混合模型作为聚类算法的主要优点是:

-它在聚类协方差方面更加灵活。这意味着每个聚类可以具有无约束的协方差结构。换句话说,K-means 假设每个簇都有球形结构,而 GMM 允许椭圆结构。

-积分可以属于不同的集群,具有不同的成员级别。这个隶属级别是每个点属于每个聚类的概率。

3)选择的算法:

  • 选择的算法是高斯混合模型。因为数据没有被分割成清晰和不同的簇,所以我们不知道有多少簇。

创建集群

当事先不知道簇的数量时,不能保证给定数量的簇最好地分割数据,因为不清楚数据中存在什么结构。

然而,我们可以通过计算每个数据点的轮廓系数来量化一个聚类的“良好性”。一个数据点的轮廓系数从-1(不相似)到 1(相似)测量它与其分配的聚类有多相似。计算平均值轮廓系数提供了给定聚类的简单评分方法。

****# Import the necessary libraries***
from sklearn.mixture import GaussianMixture
from sklearn.metrics import silhouette_score

scores = {}
for i in range(2,7):

    print('Number of clusters: ' + str(i))

    ***# Apply your clustering algorithm of choice to the reduced data*** 
    clusterer = GaussianMixture(random_state=42, n_components=i)
    clusterer.fit(reduced_data)

  **  *# Predict the cluster for each data point***
    preds = clusterer.predict(reduced_data)

    ***# Find the cluster centers***
    centers = clusterer.means_
    print('Cluster Center: ' + str(centers))

   ** *# Predict the cluster for each transformed sample data point***
    sample_preds = clusterer.predict(pca_samples)
    print('Sample predictions: ' + str(sample_preds))

  **  *# Calculate the mean silhouette coefficient for the number of clusters chosen***
    score = silhouette_score(reduced_data, preds)
    scores[i] = score
    print('Silhouette score is: ' + str(score), '\n')

print('Scores: ' + str(scores))*

**

轮廓得分最好的聚类数为 2,得分为 0.42。

集群可视化

一旦我们使用上面的评分标准为聚类算法选择了最佳的聚类数,我们现在可以在下面的代码块中可视化结果。

****# Apply your clustering algorithm of choice to the reduced data*** 
clusterer = GaussianMixture(random_state=42, n_components=2)
clusterer.fit(reduced_data)

***# Predict the cluster for each data point***
preds = clusterer.predict(reduced_data)

***# Find the cluster centers***
centers = clusterer.means_
print('Cluster Center: ' + str(centers))

***# Predict the cluster for each transformed sample data point***
sample_preds = clusterer.predict(pca_samples)
print('Sample predictions: ' + str(sample_preds))

***# Calculate the mean silhouette coefficient for the number of clusters chosen***
score = silhouette_score(reduced_data, preds)
scores[i] = score
print('Silhouette score is: ' + str(score), '\n')*

****# Display the results of the clustering from implementation***
vs.cluster_results(reduced_data, preds, centers, pca_samples)*

数据恢复

上图中的每个星团都有一个中心点。这些中心(或平均值)不是来自数据的特定数据点,而是在相应聚类中预测的所有数据点的平均值

对于创建客户细分的问题,一个聚类的中心点对应于该细分的平均客户。由于数据目前已降维并按对数进行了缩放,我们可以通过应用逆变换从这些数据点中恢复代表性的客户支出。

****# Inverse transform the centers***
log_centers = pca.inverse_transform(centers)

***# Exponentiate the centers***
true_centers = np.exp(log_centers)

***# Display the true centers***
segments = ['Segment **{}**'.format(i) **for** i **in** range(0,len(centers))]
true_centers = pd.DataFrame(np.round(true_centers), columns = data.keys())
true_centers.index = segments
display(true_centers)*

  • 细分 0 可能代表新鲜食品市场,因为除了冷冻和新鲜,其他所有特征都低于中值。
  • 分段 1 可以代表超市,因为除了新鲜和冷冻之外的每个特征都高于中间值。

下面的代码显示了每个样本点预计属于哪个库。

****# Display the predictions***
**for** i, pred **in** enumerate(sample_preds):
    print("Sample point", i, "predicted to be in Cluster", pred)*

观察结果

  • 样本点 0 →超市而最初的猜测是零售商。这种差异可能是因为集群的大小(相当大)
  • 样本点 1 →超市与原猜测相同。
  • 样本点 2 →生鲜食品市场,最初的猜测是一家餐馆,考虑到该特征的消费金额,这是合理的。

结论

批发分销商如何仅使用估计的产品支出和 客户群 数据来标记新客户?

可以使用监督学习算法,将估计的产品支出作为属性,将客户群作为目标变量,使其成为一个分类问题(我们将有 2 个可能的标签)。由于客户细分和产品支出之间没有明确的数学关系,KNN 可能是一个很好的算法。

可视化底层分布

在本项目开始时,我们讨论过将'Channel''Region'特征从数据集中排除,以便在分析中强调客户产品类别。通过向数据集重新引入'Channel'特征,当考虑先前应用于原始数据集的相同 PCA 降维时,一个有趣的结构出现了。

下面的代码块显示了每个数据点是如何被标记为'HoReCa'(酒店/餐厅/咖啡馆)或'Retail'缩减空间的。

****# Display the clustering results based on 'Channel' data*** vs.channel_results(reduced_data, preds, pca_samples)*

我们可以观察到,聚类算法在将数据聚类到底层分布方面做得非常好,因为聚类 0 可以很好地与零售商相关联,聚类 1 可以很好地与 Ho/Re/Ca 相关联。

最后的话

一如既往,我希望你喜欢这篇文章,你现在是神经网络的专家了!

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

市场行为预测的无监督学习

原文:https://towardsdatascience.com/unsupervised-learning-to-market-behavior-forecasting-ee8f78650415?source=collection_archive---------5-----------------------

这篇文章描述了预测市场行为的技术。第二部分展示了该方法在交易策略中的应用。

介绍

市场数据是一个称为时间序列的序列。通常,研究人员仅使用价格数据(或资产回报)来创建预测下一个价格值、运动方向或其他产出的模型。我认为更好的方法是使用更多的数据。这个想法是试图结合多种多样的市场条件(波动性、交易量、价格变化等)。)

第一类潜在特征是价格数据的各种衍生物。第二类是体积导数的集合。

这些特征将描述比原始市场数据或简单回报更复杂的当前市场状况。

您将在本文的下一部分看到这些特性。至于建模,我们将使用隐马尔可夫模型。

隐马尔可夫模型(HMM)是一种统计马尔可夫模型,其中被建模的系统被假设为具有未观察到的(即隐藏的)状态的马尔可夫过程。观察数据是我们的市场特征,隐藏状态是我们的市场行为。

我们的目标是解释建模后的隐藏状态,并基于这些知识创建交易策略。

隐马尔可夫模型的基本图形是这样的

Hidden Markov Model

本文以实践为导向。要了解更多信息,你可以阅读由托默·阿米特撰写的这篇文章中的对隐马尔可夫模型的介绍。还有,我推荐从这个视频开始

特征工程和建模

我认为代码和解释的结合是深入研究的好方法。开始编码吧。

我们的图书馆

这段代码从 Quandl 下载 BTC/美元的数据

然后我们可以绘制价格和交易量数据

之后我们得到了这个数字

Price for BTC/USD from 01/01/2014

Volume for BTC/USD from 01/01/2014

现在我们已经准备好对特征工程和建模功能进行编码了。

让我们将火车时段拆分为 2018 年 1 月 1 日之前的时段。下一段代码运行特性工程并将其可视化。

之后,我们得到了五个新的时间序列和训练好的模型。

Feature sequences

在上面的代码中,我们还创建了 future_return 列,它为 last_return 移动了一个滞后。这是了解隐藏状态的第一把钥匙。让我们将这个值绘制成每个状态的累积和。

Future return cumulative sum for each state

正如我们看到的,状态#0 有下降的趋势。状态#1 没有明确的趋势。最后一个状态#2 有很强的上升趋势。这个简单的累积和 future_return 的技巧让我们理解每个状态如何对应下一个价格运动。

第二个关键是通过特征研究每个状态。之后,我们可以将这两个事件(未来运动和当前条件)联系起来。让我们为每个状态的特性编写模拟和可视化代码。

Feature distributions for each state

现在你可以看到每个状态是如何描述当前状态的。例如,状态#0 和#2 具有高音量偏差,这意味着这些状态经常出现在高音量上,而状态#1 出现在低音量上。此外,状态#0 和#2 通常呈现高波动性。

有趣的事实是状态#0 具有 last_returnma_ratio 的低值。大概是,状态#0 对应下行电流状态(目前)。落后的情况是状态#2。

对这两个结论的解释是

如果市场处于当前状态#0,那么在当前情况下,我们处于最不利的市场条件(第二个关键点),并且这种趋势将继续下去(第一个关键点)。

如果市场有当前状态#1,我们有趋势的不确定性。

如果市场处于当前状态#2,那么在当前情况下,我们有大部分上行市场条件(第二个关键点),并且这种趋势将继续下去(第一个关键点)。

下一行代码将训练好的模型保存到文件中。

应用

让我们试着根据这些知识来制定交易策略。我们应该从 2018 年 1 月 1 日开始测试这一策略,因为这一时期超出了样本范围。

逻辑很简单:状态#0 时短,状态#1 时无位置,状态#2 时长。

我们的战略将使用 Catalyst 框架来实现。在这篇帖子中,我演示了 Catalyst 的快速介绍。该策略将包含在单独的 py 文件中。让我们编写基本函数并包含库

主参数、模型加载都包含在初始化功能中

handle_data 函数包含的基本逻辑。该功能每分钟运行一次。主要活动是获取数据、创建特征、市场行为评估和头寸管理。

最后一个功能是附加的。我们绘制数字并打印结果。

让我们运行策略

正如我们看到的,建议的算法直接击败了基准。这种策略似乎试图抓住趋势并跟随它。策略的不利条件是没有趋势期。

Backtesting result

总回报:1.486611137708

索尔提诺系数:1 . 54866 . 38868688661

最大水位下降:-0.30000000001

阿尔法值:0.56725414679740467

贝塔系数:-0.1541654082608784

Alpha 为正,beta 非常接近 0(关于这些标准的定义,参见本)。下降幅度太高,但比基准下降幅度低得多。

结论

  1. 提出了基于多变性价格和交易量特征作为序列的方法。
  2. 对模型的隐藏状态进行了解释。
  3. 利用隐马尔可夫模型对 4 年的数据进行建模。
  4. 创建了简单的交易策略,用样本数据(1.5 年)进行测试,没有再培训,佣金和滑点。
  5. 该策略击败了买入并持有基准,它有正的 alpha,beta 接近于 0。
  6. 研究成果被上传到 GitHub

[## lamres/hmm _ 市场 _ 行为

此时您不能执行该操作。您已使用另一个标签页或窗口登录。您已在另一个选项卡中注销,或者…

github.com](https://github.com/lamres/hmm_market_behavior/tree/master)

如何提高已取得成果的方法:

  1. 向模型中添加新特征。
  2. 尝试窗口长度。
  3. 用不同数量的隐藏状态建立模型。
  4. 尝试为隐藏状态和策略中使用的规则制定新的解释。
  5. 基于一些资产创建投资组合。
  6. 添加简单的交易规则,如止盈、止损等。

这些改进有助于获得更复杂的策略结果:将压降降低到 15–20%,增加 alpha 和 sortino,增加产能。

如果你喜欢这类应用程序,你可以阅读我的文章,基于类似的方法。

最诚挚的问候,

谢尔盖

来自《走向数据科学》编辑的注释: 虽然我们允许独立作者根据我们的 规则和指南 发表文章,但我们并不认可每个作者的贡献。你不应该在没有寻求专业建议的情况下依赖一个作者的作品。详见我们的 读者术语

相似性传播算法解释

原文:https://towardsdatascience.com/unsupervised-machine-learning-affinity-propagation-algorithm-explained-d1fef85f22c8?source=collection_archive---------3-----------------------

https://www.pexels.com/photo/a-boy-in-beige-hoodie-smiling-beside-the-blackboard-6256070/

2007 年,布伦丹·弗雷和德尔伯特·杜克在《科学》杂志上首次发表了《亲缘关系传播》。与其他传统的聚类方法相比,相似性传播不需要您指定聚类的数量。通俗地说,在亲和力传播中,每个数据点向所有其他点发送消息,通知其目标每个目标对发送者的相对吸引力。然后,每个目标用回复来响应所有发送者,通知每个发送者它可以与该发送者相关联,因为它已经从所有其他发送者接收到消息的吸引力。发送者用消息回复目标,通知每个目标该目标对发送者的修正的相对吸引力,给定它从所有目标接收的可用性消息。消息传递过程继续进行,直到达成共识。一旦发送者与其目标之一相关联,该目标就成为该点的样本。具有相同样本的所有点被放置在相同的簇中。

算法

假设我们有以下数据集。每个参与者被表示为 5 维空间中的一个数据点。

http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.490.7628&rep=rep1&type=pdf

相似矩阵(c)

除了对角线上的那些,相似性矩阵中的每个单元都是通过对参与者之间的差异的平方和求反来计算的。

如果这对你来说没有任何意义,不要烦恼,一旦浏览一个例子,它就会变得清晰。对于 Alice 和 Bob 之间的相似性,差异的平方和为(3–4)+(4–3)+(3–5)+(2–1)+(1–1)= 7。因此,相似性值是-7。

还不清楚?让我们看另一个例子。

我强烈推荐你自己计算一些。您应该会得到与下表相近的结果。

如果为对角线选择较小的值,则该算法将在少量的聚类周围收敛,反之亦然。因此,我们用-22 填充相似性矩阵的对角线元素,这是不同单元格中的最小数字。

http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.490.7628&rep=rep1&type=pdf

责任矩阵

我们首先构建一个可用性矩阵,所有元素都设置为零。然后,我们使用以下公式计算责任矩阵中的每个单元:

其中 I 表示相关矩阵的行,k 表示相关矩阵的列。

比如 Bob(列)对 Alice(行)的责任是-1,就是 Bob 对 Alice 的相似度(-7)减去 Alice 的行的剩余相似度的最大值(-6)。

再次,我强烈建议你试着自己计算一些。

在计算完其余几对参与者的责任后,我们得出了下面的矩阵。

http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.490.7628&rep=rep1&type=pdf

可用性矩阵(a)

我们使用单独的等式来更新可用性矩阵对角线上的元素,而不是可用性矩阵对角线外的元素。

下面的公式用于填充对角线上的元素:

其中 I 表示相关矩阵的行,k 表示相关矩阵的列。

本质上,该等式告诉您对该列中所有大于 0 的值求和,除了其值等于所讨论的列的那一行。例如,爱丽丝的自我可用性是爱丽丝专栏的积极责任的总和不包括爱丽丝的自我责任(10 + 11 + 0 + 0 = 21)。

还不明白?让我们再看几个例子。

以下等式用于更新非对角线元素:

换句话说,假设你试图填写 a(凯里,埃德娜)。考虑到埃德娜一栏的内容,你排除了埃德娜/埃德娜关系和卡里/埃德娜关系,并将所有剩余的积极责任加在一起。例如,Bob(列)对 Alice(行)的可用性是 Bob 的自我责任加上 Bob 的列中除 Bob 对 Alice 的责任之外的剩余积极责任之和(-15 + 0 + 0 + 0 = -15)。

我强烈建议您尝试自己计算一些单元格。

在计算完其余部分后,我们得到了下面的可用性矩阵。

http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.490.7628&rep=rep1&type=pdf

标准矩阵(c)

标准矩阵中的每个单元只是该位置的可用性矩阵和责任矩阵的总和。

Bob(列)对 Alice(行)的标准值是 Bob 对 Alice 的责任和可用性之和(-1 + -15 = -16)。

http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.490.7628&rep=rep1&type=pdf

每行的最高标准值被指定为样本。共享同一个样本的行在同一个簇中。因此在我们的例子中。Alice、Bob 和 Cary 形成一个集群,而 Doug 和 Edna 构成第二个集群。

值得注意的是,在这个例子中,变量的范围相同。然而,一般来说,变量在不同的尺度上,必须在训练前标准化。

密码

让我们跳到一些代码中。首先,导入以下库。

import numpy as np
from matplotlib import pyplot as plt
import seaborn as sns
sns.set()
from sklearn.datasets.samples_generator import make_blobs
from sklearn.cluster import AffinityPropagation

我们使用scikit-learn来生成具有良好定义的集群的数据。

X, clusters = make_blobs(n_samples=300, centers=4, cluster_std=0.60, random_state=0)
plt.scatter(X[:,0], X[:,1], alpha=0.7, edgecolors='b')

接下来,我们初始化并训练我们的模型。

af = AffinityPropagation(preference=-50)clustering = af.fit(X)

最后,我们用不同的颜色绘制每个聚类的数据点。

plt.scatter(X[:,0], X[:,1], c=clustering.labels_, cmap='rainbow', alpha=0.7, edgecolors='b')

最后的想法

相似性传播是一种无监督的机器学习算法,特别适合于我们不知道最佳聚类数的问题。

使用 Python 实现时间序列异常检测的无监督机器学习方法

原文:https://towardsdatascience.com/unsupervised-machine-learning-approaches-for-outlier-detection-in-time-series-using-python-5759c6394e19?source=collection_archive---------12-----------------------

在这篇文章中,我将介绍一些我最喜欢的检测时间序列数据中异常值的方法。有许多不同的方法来检测异常数据点;为了简洁起见,我在这篇文章中只关注无监督的机器学习方法。

本文涉及的异常/异常值检测算法包括:

  1. 低通滤波器:取时间序列的居中滚动平均值,并基于 Z 分数移除异常
  2. 隔离森林
  3. 季节性极端学生化离差(S-ESD)算法
  4. 一类支持向量机(SVM)

那么什么是时间序列中的“异常”,为什么我们关心检测时间序列序列中的异常?

我经常处理时间序列数据,数据集经历意想不到的下降或峰值、平线或相移并不罕见。这些情况中的每一种都可以称之为“异常”——与整个序列的行为相比,有些不寻常。

出于各种原因,检测时间序列中的异常是重要的。有时,异常是某些模式的指示,如特定日期或时间内趋势的峰值或下降。其他时候,异常是“错误的”读数,这是由于仪器或仪表的错误造成的。通常,我们希望从时间序列数据中分离出异常,因为它们扭曲了“平均”行为——平均变化率、平均值、平均分布等。

本文中介绍的所有算法都有二进制输出:时间序列中的数据点要么异常,要么正常。

时间序列示例

在本文中,我们比较了几种不同的异常检测方法在单个时间序列上的结果。我们将使用的时间序列是美国墨西哥湾海岸汽油价格的每日时间序列,它是使用能源信息管理局(EIA) API 检索的。

关于使用 EIA 的免费 API 在 Python 中检索能源相关数据的更多背景知识,请查看本教程***。*****

我们使用以下 Python 代码提取并可视化时间序列:

为了增加趣味,我们在时间序列中加入了一些异常值。希望这些点能被异常检测算法发现。

Gasoline Price Time Series, with artificially generated anomalies in yellow

既然我们已经选择了我们的时间序列并添加了一些异常值,让我们在其上测试我们的异常检测算法。

简单的低通滤波器:取一个滚动平均值,并根据 Z 分数去除异常

我用来检测异常的一个最简单(但仍然非常有效)的方法如下:

  1. 实现时间序列数据的居中滚动平均
  2. 计算时间序列中每个数据点的单独 Z 值,并与滚动平均值进行比较
  3. 移除偏离滚动平均值超过特定标准偏差数的数据点(通常偏离 2 到 3 个标准偏差,但取决于数据行为)

让我们用一个例子来试试这个方法。

代码示例

如上所述,我们使用美国墨西哥湾沿岸汽油价格的时间序列作为我们的示例时间序列集。

值得注意的是,我们为低通滤波器实现的滚动平均值以为中心。这意味着长度为 x 的滚动平均值是之前 x/2 个数据点和之后 x/2 个数据点的平均值。例如,如果我们在值 t 处实施 60 点滚动平均,那么我们会发现范围在(t-30)和(t+30)之间的数据点的平均值。使用居中的滚动平均值有助于解释时间序列中两端的较大偏移。

我们使用以下代码生成低通滤波器并可视化异常:

Gasoline time series, color-coded by detected low-pass filter anomalies. Anomalous data points are in yellow, and normal data points are in purple.

在检查上述结果时,低通滤波器表现相当好。在添加到时间序列中的 9 个异常值中,低通滤波器成功检测到 6 个,加上其他几个看起来异常的数据点。

隔离森林

隔离森林是流行的随机森林算法的无监督扩展。隔离林的构造块是具有二元结果(是/不是离群值)的隔离树。

构建隔离林时,算法会将每个单独的数据点从所有其他数据点中分离出来。空间中的单个点越容易与所有其他点隔离,它就越有可能是异常值(因为它远离所有其他数据点)。如果一个数据点是一个插入点,它将被其他数据点紧密包围,并需要更多的分裂来隔离( 1 )。请参见下图中的插图。

Each line represents a split performed by the algorithm to isolate individual data points. In the first figure, X0 is an outlier, and is isolated in ~3 splits. In the second figure, Xi is an in-lier, and requires many more splits to isolate from all other data points. Image courtesy of https://www.semanticscholar.org/paper/Anomaly-Detection-through-on-line-Isolation-Forest%3A-Susto-Beghi/c321685dd03fa1a54e99b4c046950b96c3b0f040/figure/1.

关于隔离森林的更多信息,请查看福特斯的本教程

代码示例

我们再次使用汽油时间序列,但这次我们应用隔离森林算法来检测异常。我们使用 scikit-learn 包中提供的 IsolationForest()模型来构建一个模型,并在我们的数据集上测试它:

Gasoline time series, color-coded by detected Isolation Forest anomalies. Anomalous data points are in yellow, and normal data points are in purple.

像低通滤波器一样,隔离林检测到大多数人为产生的异常;但是,它会对更多的误报进行分类(数据点被标记为异常,而实际上并非如此)。该算法特别难以识别大的时间序列偏移(参见 2014 年末时间段作为示例)。

季节性极端学生化离差(S-ESD)算法

Twitter 的一组数据科学家最初开发了 S-ESD 算法。该算法最初的(也是最流行的)实现之一是在的“异常检测”包中。幸运的是,R 包已经被多次修改以用于 Python。

这种算法很容易理解,而且根据所用的时间序列,相当稳健。它的工作原理如下:

  1. 使用 STL(季节-趋势-黄土)分解对时间序列进行分解。
  2. ESD 算法在生成的黄土时间序列上运行,以检测异常。黄土时间序列代表系统中的噪声,在趋势和季节行为被过滤掉之后。

我们来试一个例子来论证。

代码示例

在实现 S-ESD 算法之前,让我们分解汽油价格时间序列,以了解时间序列的趋势、季节性和噪声:

STL Decomposition of Gulf Coast Gasoline Price Time Series, 2014-Present

在上面的代码片段中,我们以每年的频率分解时间序列。在检测异常时,我们真正关心的分解时间序列是残差时间序列(或黄土时间序列)。这个时间序列代表序列中的噪声,在考虑了季节性和趋势之后。

在分解之后,我们对剩余时间序列应用极端学生化偏离(ESD)检验来检测异常值。ESD 测试的主要优点之一是,它只需要检测异常值总数的上限;这与 Grubbs 测试形成对比,Grubbs 测试中异常值的数量必须准确声明( 2 )。

有关极端学生化偏离(ESD)算法的更多信息,请查看 此链接

在下面的代码片段中,我们对时间序列执行 S-ESD 异常检测,包括使用 ESD 的 STL 分解和异常值检测:

Gasoline Time Series, color coded on S-ESD anomalies, with outliers in yellow and all other data points in purple

基于上述结果,S-ESD 算法的结果并不太乐观。该算法仅成功地识别了九个产生的异常中的一个。我以前使用其他时间序列集成功地使用了这种算法,但在这个特殊的例子中似乎有些困难。

单类支持向量机(SVM)

一类 SVM 是支持向量机的无监督版本,因为它们只在一个类(“正常”类)上训练。由于数据是无标签的,单类支持向量机“推断出正常情况的性质,并从这些性质中预测哪些例子与正常例子不同”( 3 )。一类 SVM 使用一个二元函数来映射平面上的数据概率密度,高概率区域设置为+1,低概率区域设置为-1 ( 4 )。

查看 这篇由 Hsu 等人撰写的文章 提供了关于单类支持向量机的更深入的信息。

代码示例

我们再次求助于 sci kit——学习构建我们的模型;这一次,对于一等 SVM 的。我们生成几个变量插入算法中以提高性能——主要是汽油价格时间序列的中心 6 点滚动平均值。然后,我们通过 one _ class _ SVM _ anomaly _ detection()函数运行原始时间序列及其滚动平均值。在函数中,我们缩放每个变量,并训练无监督模型。最后,我们对每个数据点进行分类,并使用散点图进行可视化:

Gasoline time series, color-coded by detected one-class SVM anomalies. Anomalous data points are in yellow, and normal data points are in purple.

单类 SVM 表现相对较好,可以检测出 9 个人工生成的异常值中的 6 个。然而,像隔离林一样,它在序列中检测到几个假阳性。

结论

在本文中,我们比较了各种异常检测技术的结果——隔离森林、低通滤波器、一类 SVM 和 S-ESD 算法。令人惊讶的是,当并排比较结果时,性能最好的算法(至少对于本例来说)是一个简单的低通滤波器。性能最差的算法是 S-ESD 算法。

重要的是要注意,这些算法对每个单独的时间序列执行不同。仅仅因为低通滤波器在这个例子中工作得最好,并不意味着它在所有时间序列中都工作得最好。为了获得最佳结果,在最终决定使用哪种算法之前,请尝试上述所有选项。

我关于时间序列异常检测的无监督机器学习方法的教程到此结束。感谢阅读!

****关于本教程中使用的完整 Python 代码,请查看以下 Github repo:https://Github . com/kperry 2215/unsupervised _ anomaly _ detection _ time _ series

来源

  1. T.福特斯。2018 年 4 月 4 日。隔离森林:与世隔绝的艺术。https://quantdare.com/isolation-forest-algorithm/
  2. 工程统计手册。异常值的通用 ESD 测试。https://www . ITL . NIST . gov/div 898/handbook/EDA/section 3/EDA 35h 3 . htm
  3. Azure 机器学习工作室。2019 年 5 月 5 日。单类支持向量机https://docs . Microsoft . com/en-us/azure/machine-learning/studio-module-reference/one-class-support-vector-machine
  4. 罗默·弗拉斯维尔德。2013 年 7 月 12 日。单类支持向量机简介。http://rvlasveld . github . io/blog/2013/07/12/introduction-to-one-class-support-vector-machines/

看看我的其他时间系列教程和文章:

** [## 使用 Python - Tech Rando 进行变化点检测简介

我的很多工作都大量涉及时间序列分析。我使用的一个很棒但不太为人所知的算法是…

techrando.com](https://techrando.com/2019/08/14/a-brief-introduction-to-change-point-detection-using-python/) [## 使用 Python 分析电价时间序列数据:时间序列分解和价格…

欢迎来到科技兰多博客!在今天的帖子中,我将使用能源信息管理局的 API…

techrando.com](https://techrando.com/2019/07/19/analyzing-electricity-price-time-series-data-using-python-time-series-decomposition-and-price-forecasting-using-a-vector-autoregression-var-model/)

原载于 2019 年 8 月 23 日https://techrando.com**

无监督机器学习:聚类分析

原文:https://towardsdatascience.com/unsupervised-machine-learning-clustering-analysis-d40f2b34ae7e?source=collection_archive---------0-----------------------

无监督学习简介

到目前为止,我们只探索了监督机器学习算法和技术来开发模型,其中数据具有先前已知的标签。换句话说,我们的数据有一些带有特定值的目标变量,我们用它们来训练我们的模型。

然而,在处理现实世界的问题时,大多数时候,数据不会带有预定义的标签,因此我们希望开发能够正确分类这些数据的机器学习模型,通过自己找到特征中的一些共性,用于预测新数据的类别。

无监督学习分析过程

在开发无监督学习模型时,我们将遵循的整个过程可以总结在下表中:

无监督学习的主要应用有:

  • 利用共享属性分割数据集。
  • 检测不适合任何组的异常。
  • 通过聚合具有相似属性的变量来简化数据集。

总之,主要目标是研究数据的内在(通常是隐藏的)结构。

这种技术可以浓缩为无监督学习试图解决的两种主要类型的问题。这些问题是:

  • 使聚集
  • 降维

在整篇文章中,我们将关注聚类问题,并将在以后的文章中讨论降维。

聚类分析

基本上,聚类的目标是在数据的元素中找到不同的组。为此,聚类分析算法查找数据中的结构,以便同一个聚类(或组)的元素彼此之间比来自不同聚类的元素更相似。

以一种可视化的方式:想象我们有一个电影的数据集,想要对它们进行分类。我们有以下电影评论:

机器学习模型将能够推断出有两个不同的类别,而无需从数据中了解任何其他信息。

这些无监督学习算法具有令人难以置信的广泛应用,并且对于解决现实世界的问题非常有用,例如异常检测、推荐系统、文档分组或者基于购买发现具有共同兴趣的客户。

一些最常见的聚类算法,以及将在本文之外探讨的算法有:

  • k 均值
  • 层次聚类
  • 基于密度的扫描聚类(DBSCAN)
  • 高斯聚类模型

k 均值聚类

K-Means 算法非常容易实现,而且计算效率非常高。这些是解释它们为什么如此受欢迎的主要原因。但是当处理不具有球形分布形状的组时,它们不太适合于识别类。

K-Means 算法的目标是找到彼此之间具有高度相似性的数据点并将其分组。就算法而言,这种相似性被理解为数据点之间距离的反义词。数据点越接近,它们就越相似,并且更有可能属于同一个聚类。

关键概念

  • 平方欧几里德距离

K-Means 中最常用的距离是平方欧几里德距离。在 m 维空间中的两点 x 和 y 之间的距离的一个例子是:

这里, j 是样本点 x 和 y的第j维(或特征列)

  • 集群惯性

聚类惯性是聚类上下文中误差平方和的名称,表示如下:

其中 μ(j) 是聚类 j,的质心,如果样本 x(i) 在聚类 j 中,则 w(i,j) 为 1,否则为 0。

K-Means 可以理解为一种算法,它将尝试最小化聚类惯性因子。

算法步骤

  1. 首先,我们需要选择 k,我们希望被发现的集群的数量。
  2. 然后,该算法将随机选择每个聚类的质心。
  3. 将每个数据点分配到最近的质心(使用欧几里德距离)。
  4. 将计算群集惯性。
  5. 新的质心将被计算为属于上一步质心的点的平均值。换句话说,通过计算每个聚类中心的数据点的最小二次误差,将中心移向该点
  6. 回到步骤 3。

K-均值超参数

  • 簇的数量:要生成的簇和质心的数量。
  • 最大迭代次数:单次运行的算法。
  • Number initial:使用不同质心种子运行算法的次数。就惯性而言,最终结果将是所定义的连续运行次数的最佳输出。

K 均值的挑战

  • 任何固定训练集的输出不会总是相同的,因为初始质心是随机设置的,这将影响整个算法过程。
  • 如前所述,由于欧几里德距离的性质,当处理采用非球形形状的聚类时,它不是合适的算法。

应用 K 均值时需要考虑的要点

  • 必须在相同的尺度上测量要素,因此可能有必要执行 z 分数标准化或最大-最小缩放。
  • 在处理分类数据时,我们将使用 get dummies 函数。
  • 探索性数据分析(EDA)非常有助于对数据进行概述,并确定 K-Means 是否是最合适的算法。
  • 当有大量的列时,minibatch 方法非常有用,但是它不太准确。

如何选择合适的 K 数

选择正确的聚类数是 K-Means 算法的关键点之一。有一些方法可以找到这个数字:

  • 领域知识
  • 商业决策
  • 肘法

由于与数据科学的动机和性质一致,肘方法是首选方法,因为它依赖数据支持的分析方法来做出决策。

肘法

肘方法用于确定数据集中聚类的正确数量。它的工作原理是绘制 K 的递增值与使用该 K 时获得的总误差的关系图。

目标是找到对于每个聚类不会显著增加方差的 k

在这种情况下,我们将选择弯头所在的 k=3。

K-Means 局限性

虽然 K-Means 是一个很好的聚类算法,但当我们预先知道准确的聚类数,并且处理球形分布时,它是最有用的。

下图显示了如果我们在每个数据集中使用 K-means 聚类,即使我们事先知道准确的聚类数,我们会得到什么:

将 K-Means 算法作为基准来评估其他聚类方法的性能是很常见的。

层次聚类

层次聚类是基于原型的聚类算法的替代方法。层次聚类的主要优点是我们不需要指定聚类的数量,它会自己找到。此外,它还能够绘制树状结构。树形图是二进制层次聚类的可视化。

融合在底部的观察结果是相似的,而融合在顶部的观察结果则完全不同。对于树形图,结论是根据纵轴的位置而不是横轴得出的。

等级聚类的种类

这种类型的聚类有两种方法:聚合和分裂。

  • Divisive:这种方法首先将所有数据点聚集在一个单独的集群中。然后,它会迭代地将聚类分成更小的聚类,直到每个聚类只包含一个样本。
  • 凝聚:这种方法从每个样本是一个不同的聚类开始,然后通过彼此更接近的样本来合并它们,直到只有一个聚类。

单联动&全联动

这些是用于凝聚层次聚类的最常用算法。

  • 单键

作为一种凝聚算法,单链从假设每个样本点是一个簇开始。然后,它计算每对聚类的最相似成员之间的距离,并合并最相似成员之间的距离最小的两个聚类。

  • 完全连锁

虽然与它的兄弟(单链)相似,但它的原理完全相反,它比较一对集群中最不相似的数据点来执行合并。

层次聚类的优势

  • 由此产生的层次结构表示可以提供很多信息。
  • 树形图提供了一种有趣且信息丰富的可视化方式。
  • 当数据集包含真正的层次关系时,它们特别有用。

层次聚类的缺点

  • 它们对异常值非常敏感,当异常值出现时,模型性能会显著下降。
  • 从计算角度来说,它们非常昂贵。

基于密度的噪声应用空间聚类(DBSCAN)

带噪声应用程序的基于密度的空间聚类,或 DBSCAN,是另一种对正确识别数据中的噪声特别有用的聚类算法。

DBSCAN 分配标准

它基于多个具有指定半径ε的点,每个数据点都有一个特殊的标签。分配该标签的过程如下:

  • 它是指定数量(最小点数)的相邻点。如果有这个最小点数的点落在ε半径内,将指定一个核心点。
  • 边界点将落在核心点的ε半径内,但其邻域数将少于 MinPts 数。
  • 每隔一个点将是噪声点。

DBSCAN 算法

该算法遵循以下逻辑:

  1. 确定一个核心点,并为每个核心点或每个连接的核心点组(如果它们符合核心点的标准)分组。
  2. 确定边界点并将其分配给各自的核心点。

下图很好地总结了这个过程和注释符号。

DBSCAN 与 K 均值聚类

DBDSCAN 的优势

  • 我们不需要指定集群的数量。
  • 簇可以采用的形状和大小具有高度的灵活性。
  • 识别和处理噪声数据和异常值是非常有用的。

DBSCAN 缺点

  • 它在处理两个集群可达的边界点时面临困难。
  • 它找不到不同密度的井丛。

高斯混合模型(GMM)

高斯混合模型是一种概率模型,它假设所有样本都是由有限个高斯分布和未知参数混合而成的。

它属于软聚类算法组,其中每个数据点将属于数据集中存在的每个聚类,但是每个聚类具有不同的成员级别。这种隶属关系被指定为属于某一类的概率,范围从 0 到 1。

例如,高亮显示的点将同时属于聚类 A 和聚类 B,但由于其与聚类 A 的接近性,因此属于聚类 A 的成员更高。

GMM 是我们将在本系列中学习的最高级的聚类方法之一,它假设每个聚类遵循一个概率分布,该分布可以是高斯分布或正态分布。它是 K-均值聚类的推广,包括关于数据的协方差结构以及潜在高斯中心的信息。

一维 GMM 分布

GMM 将在数据集中搜索高斯分布并混合它们。

二维中的 GMM

当多元分布如下所示时,对于 de 数据集分布的每个轴,平均中心应为+ σ。

GMM 算法

这是一种期望最大化算法,其过程可以概括如下:

  1. 初始化 K 高斯分布。它通过(平均值)和σ(标准差)值来实现这一点。它们可以取自数据集(朴素方法)或通过应用 K-Means。
  2. 对数据进行软聚类:这是“期望”阶段,在此阶段,所有的数据点将被分配给每个具有各自隶属级别的聚类。
  3. 重新估计高斯分布:这是“最大化”阶段,在此阶段检查期望值,并使用期望值计算高斯分布的新参数:new 和σ。
  4. 评估数据的对数似然性以检查收敛性。对数似然性越高,我们创建的模型的混合物就越有可能符合我们的数据集。这是最大化的函数。
  5. 从步骤 2 开始重复,直到收敛。

GMM 的优势

  • 这是一种软聚类方法,它将样本成员分配给多个聚类。这一特性使其成为学习混合模型的最快算法
  • 集群的数量和形状具有高度的灵活性。

GMM 的缺点

  • 它对初始值非常敏感,这将极大地影响它的性能。
  • GMM 可能收敛到局部最小值,这将是次优解。
  • 当每个混合物没有足够的点时,该算法发散并找到具有无限可能性的解,除非我们人工地调整数据点之间的协方差。

聚类验证

聚类验证是对聚类结果进行客观定量评估的过程。我们将通过应用聚类验证指数来进行验证。有三个主要类别:

外部指数

这些是我们在原始数据被标记时使用的评分方法,这在这类问题中并不常见。我们将把一个聚类结构与预先知道的信息进行匹配。

使用最多的指数是调整后的兰德指数。

  • 调整后的€兰德指数[-1,1]

为了理解它,我们应该首先定义它的组成部分:

  • a:是在 C 和 K 中的同一个簇中的点数
  • b:是在 C 和 k 中不同簇中的点数。
  • n =样本总数

ARI 可以得到范围从-1 到 1 的值。该值越高,与原始数据的匹配程度越高。

内部验证指标

在无监督学习中,我们将处理未标记的数据,这是内部索引更有用的时候。

最常见的指标之一是轮廓系数。

  • 轮廓系数:

每个数据点都有一个轮廓系数。

  • a =到同一组中其他样品 I 的平均距离
  • b =到最近的相邻聚类中的其他样本 I 的平均距离

轮廓系数(SC)的值可以从-1 到 1。值越高,选择的 K 越好。如果我们超过了理想的 K 值,就会比我们低于理想的 K 值受到更多的惩罚。

它只适用于某些算法,如 K-Means 和层次聚类。它不适合与 DBSCAN 一起工作,我们将使用 DBCV。

结论

我们首先介绍了无监督学习和主要的聚类算法。

在下一篇文章中,我们将完成一个实现,作为构建 K-means 模型的示例,并回顾和实践所解释的概念。

敬请期待!

从头开始实现谱聚类算法

原文:https://towardsdatascience.com/unsupervised-machine-learning-spectral-clustering-algorithm-implemented-from-scratch-in-python-205c87271045?source=collection_archive---------1-----------------------

https://www.pexels.com/photo/back-view-of-a-student-answering-a-problem-on-the-chalkboard-8197497/

谱聚类是一种流行的无监督机器学习算法,其性能往往优于其他方法。此外,谱聚类实现起来非常简单,并且可以通过标准的线性代数方法有效地解决。在谱聚类中,确定哪些点属于哪个聚类的是相似性,而不是绝对位置(即 k 均值)。后者在处理数据形成复杂形状的问题时特别有用。

算法

该算法可以分为 4 个基本步骤。

  1. 构建相似度图
  2. 确定邻接矩阵 W、度矩阵 D 和拉普拉斯矩阵 L
  3. 计算矩阵 L 的特征向量
  4. 使用第二小特征向量作为输入,训练 k-means 模型并使用它来对数据进行分类

密码

在下一节中,我们将从头开始实现谱聚类。我们将需要以下库。

import numpy as np
float_formatter = lambda x: "%.3f" % x
np.set_printoptions(formatter={'float_kind':float_formatter})
from sklearn.datasets.samples_generator import make_circles
from sklearn.cluster import SpectralClustering, KMeans
from sklearn.metrics import pairwise_distances
from matplotlib import pyplot as plt
import networkx as nx
import seaborn as sns
sns.set()

通常,数据集由样本(行)及其要素(列)组成。但是,谱聚类算法只能应用于连接节点的图。

因此,我们必须对数据进行转换,以便从由行和列组成的表格转换成图形。假设我们有以下数据集。我们可以清楚地看到,这些数据可以分成三组。

X = np.array([
    [1, 3], [2, 1], [1, 1],
    [3, 2], [7, 8], [9, 8],
    [9, 9], [8, 7], [13, 14],
    [14, 14], [15, 16], [14, 15]
])plt.scatter(X[:,0], X[:,1], alpha=0.7, edgecolors='b')
plt.xlabel('Weight')
plt.ylabel('Height')

首先,我们构造相似性矩阵,一个 NxN 矩阵,其中 N 是样本的数量。我们用每一对点之间的欧几里德距离填充单元格。

然后,我们通过复制相似性矩阵的内容来创建邻接矩阵,并且仅在这一次,我们设置阈值,使得如果距离大于预定义的限制,则我们将值设置为 0,否则设置为 1。

邻接矩阵可以用来构建一个图。如果邻接矩阵的单元格中有 1,那么我们在列和行的节点之间画一条边。

W = pairwise_distances(X, metric="euclidean")
vectorizer = np.vectorize(lambda x: 1 if x < 5 else 0)
W = np.vectorize(vectorizer)(W)
print(W)

在本教程的剩余部分,我们将使用networkx库来可视化图形。

def draw_graph(G):
    pos = nx.spring_layout(G)
    nx.draw_networkx_nodes(G, pos)
    nx.draw_networkx_labels(G, pos)
    nx.draw_networkx_edges(G, pos, width=1.0, alpha=0.5)

首先,我们随机生成一个图并打印它的邻接矩阵。

G = nx.random_graphs.erdos_renyi_graph(10, 0.5)draw_graph(G)W = nx.adjacency_matrix(G)
print(W.todense())

请注意这些节点是如何形成单个组件的(即,所有其他节点都可以从一个给定的节点到达)。

一旦我们建立了邻接矩阵,我们就建立了度矩阵。对于度矩阵的每一行,我们通过对邻接矩阵中相应行的所有元素求和来沿着对角线填充单元。

然后,我们通过从度矩阵中减去邻接矩阵来计算拉普拉斯矩阵。

# degree matrix
D = np.diag(np.sum(np.array(W.todense()), axis=1))
print('degree matrix:')
print(D)# laplacian matrix
L = D - W
print('laplacian matrix:')
print(L)

一旦我们有了拉普拉斯矩阵,我们就可以利用它的一个特殊属性来分类我们的数据。

  • 若图(W)有 K 个连通分量,则 L 有 K 个特征值为 0 的特征向量。

因此,由于在我们当前的例子中,我们只有一个组件,一个特征值将等于 0。

e, v = np.linalg.eig(L)# eigenvalues
print('eigenvalues:')
print(e)# eigenvectors
print('eigenvectors:')
print(v)

fig = plt.figure()ax1 = plt.subplot(121)
plt.plot(e)
ax1.title.set_text('eigenvalues')i = np.where(e < 10e-6)[0]
ax2 = plt.subplot(122)
plt.plot(v[:, i[0]])fig.tight_layout()
plt.show()

正如我们所见,在 10 个特征值中,有一个等于 0。

让我们看另一个例子。上图由两部分组成。因此,2 个特征值等于 0。

G = nx.Graph()
G.add_edges_from([
    [1, 2],
    [1, 3],
    [1, 4],
    [2, 3],
    [2, 7],
    [3, 4],
    [4, 7],
    [1, 7],
    [6, 5],
    [5, 8],
    [6, 8],
    [9, 8],
    [9, 6]
])draw_graph(G)W = nx.adjacency_matrix(G)
print(W.todense())

# degree matrix
D = np.diag(np.sum(np.array(W.todense()), axis=1))
print('degree matrix:')
print(D)# laplacian matrix
L = D - W
print('laplacian matrix:')
print(L)

e, v = np.linalg.eig(L)# eigenvalues
print('eigenvalues:')
print(e)# eigenvectors
print('eigenvectors:')
print(v)

fig = plt.figure(figsize=[18, 6])ax1 = plt.subplot(131)
plt.plot(e)
ax1.title.set_text('eigenvalues')i = np.where(e < 10e-6)[0]
ax2 = plt.subplot(132)
plt.plot(v[:, i[0]])
ax2.title.set_text('first eigenvector with eigenvalue of 0')ax3 = plt.subplot(133)
plt.plot(v[:, i[1]])
ax3.title.set_text('second eigenvector with eigenvalue of 0')

如果我们仔细看看每个特征向量的图,我们可以清楚地看到,前 5 个节点映射到相同的值,其他 5 个节点映射到另一个值。我们可以利用这一事实将节点分为两类。

让我们看一个稍微复杂一点的例子。前面的图是由一个单独的部分组成的。然而,看起来我们有两节课。

G = nx.Graph()
G.add_edges_from([
    [1, 2],
    [1, 3],
    [1, 4],
    [2, 3],
    [3, 4],
    [4, 5],
    [1, 5],
    [6, 7],
    [7, 8],
    [6, 8],
    [6, 9],
    [9, 6],
    [7, 10],
    [7, 2]
])draw_graph(G)W = nx.adjacency_matrix(G)
print(W.todense())

# degree matrix
D = np.diag(np.sum(np.array(W.todense()), axis=1))
print('degree matrix:')
print(D)# laplacian matrix
L = D - W
print('laplacian matrix:')
print(L)

e, v = np.linalg.eig(L)# eigenvalues
print('eigenvalues:')
print(e)# eigenvectors
print('eigenvectors:')
print(v)

fig = plt.figure(figsize=[18, 6])ax1 = plt.subplot(131)
plt.plot(e)
ax1.title.set_text('eigenvalues')i = np.where(e < 0.5)[0]
ax2 = plt.subplot(132)
plt.plot(v[:, i[0]])ax3 = plt.subplot(133)
plt.plot(v[:, i[1]])
ax3.title.set_text('second eigenvector with eigenvalue close to 0')

因为我们只有一个分量,所以只有一个特征值等于 0。然而,如果我们看看第二小的特征值,我们仍然可以观察到两类之间的区别。如果我们画一条横线,我们就能正确地对节点进行分类。

让我们看另一个例子。同样,图将由单个组件组成,但这一次,看起来节点应该放在三个容器中的一个。

G = nx.Graph()
G.add_edges_from([
    [1, 2],
    [1, 3],
    [1, 4],
    [2, 3],
    [3, 4],
    [4, 5],
    [1, 5],
    [6, 7],
    [7, 8],
    [6, 8],
    [6, 9],
    [9, 6],
    [7, 10],
    [7, 2],
    [11, 12],
    [12, 13],
    [7, 12],
    [11, 13]
])draw_graph(G)W = nx.adjacency_matrix(G)
print(W.todense())

# degree matrix
D = np.diag(np.sum(np.array(W.todense()), axis=1))
print('degree matrix:')
print(D)# laplacian matrix
L = D - W
print('laplacian matrix:')
print(L)

e, v = np.linalg.eig(L)# eigenvalues
print('eigenvalues:')
print(e)# eigenvectors
print('eigenvectors:')
print(v)

fig = plt.figure(figsize=[18, 6])ax1 = plt.subplot(221)
plt.plot(e)
ax1.title.set_text('eigenvalues')i = np.where(e < 0.5)[0]
ax2 = plt.subplot(222)
plt.plot(v[:, i[0]])ax3 = plt.subplot(223)
plt.plot(v[:, i[1]])
ax3.title.set_text('second eigenvector with eigenvalue close to 0')ax4 = plt.subplot(224)
plt.plot(v[:, i[2]])
ax4.title.set_text('third eigenvector with eigenvalue close to 0')fig.tight_layout()

因为我们只有 1 个分量,所以 1 个特征值等于 0。但是,我们可以再次使用第二小的特征值来计算出哪个节点应该放在哪个类别中。

在实践中,我们使用 k-means 根据节点在特征向量中的对应值对节点进行分类。

U = np.array(v[:, i[1]])km = KMeans(init='k-means++', n_clusters=3)km.fit(U)km.labels_

接下来,让我们使用 scitkit-learn 的实现来比较 k-means 和谱聚类。假设我们的数据在绘制时采用了以下形状。

X, clusters = make_circles(n_samples=1000, noise=.05, factor=.5, random_state=0)
plt.scatter(X[:,0], X[:,1])

当使用 k-means 时,我们得到以下结果。

km = KMeans(init='k-means++', n_clusters=2)km_clustering = km.fit(X)plt.scatter(X[:,0], X[:,1], c=km_clustering.labels_, cmap='rainbow', alpha=0.7, edgecolors='b')

相反,当使用谱聚类时,我们将每个圆放在自己的聚类中。

sc = SpectralClustering(n_clusters=2, affinity='nearest_neighbors', random_state=0)sc_clustering = sc.fit(X)plt.scatter(X[:,0], X[:,1], c=sc_clustering.labels_, cmap='rainbow', alpha=0.7, edgecolors='b')

最后的想法

与 k-means 相反,谱聚类考虑了数据点的相对位置。

使用 LDA 主题模型作为分类模型输入

原文:https://towardsdatascience.com/unsupervised-nlp-topic-models-as-a-supervised-learning-input-cf8ee9e5cf28?source=collection_archive---------2-----------------------

预测未来 Yelp 评论情绪

主题建模概述

自然语言处理中的主题建模旨在发现文档中隐藏的语义结构。它们是概率模型,可以帮助你梳理大量的原始文本,并以一种无人监管的方式将相似的文档分组在一起。

这篇文章特别关注潜在狄利克雷分配(LDA ),这是一种在 2000 年提出的用于群体遗传学的技术,并由 ML-hero 吴恩达等人在 2003 年独立重新发现。LDA 指出,语料库中的每个文档都是固定数量的主题的组合。一个主题具有生成各种单词的概率,其中单词是语料库中所有观察到的单词。这些“隐藏的”主题随后根据单词共现的可能性浮出水面。形式上,这是贝叶斯推理问题[1]。

LDA 输出

一旦 LDA 主题建模应用于一组文档,您就能够看到组成每个隐藏主题的单词。在我的例子中,我使用 Yelp 数据集[2]在 2016 年从 Yelp 餐馆中提取了 10 万条评论。以下是通过 LDA 发现的两个主题示例:

你可以看到,第一个主题组似乎已经识别出负面汉堡评论的单词共现,第二个主题组似乎已经识别出正面的意大利餐馆体验。第三个话题不是很明确,但似乎总的来说是关于可怕的、干咸的食物。

将无监督输出转换为有监督问题

我更感兴趣的是看看这种隐藏的语义结构(非监督生成的)是否可以转换成用于监督分类问题。假设我只训练了一个 LDA 模型来找到上述的 3 个主题。训练后,我可以收集所有 10 万条评论,并查看每条评论的主题分布。换句话说,一些文档可能是 100%的主题 1,其他文档可能是主题 1/2/3 的 33%/33%/33%,等等。该输出只是显示分布的每个评论的向量。这里的想法是测试隐藏语义信息的每次评论的分布是否可以预测积极和消极的情绪。

项目目标

介绍完毕后,我的目标是:

具体来说:

  1. 在 2016 年的 100,000 条餐厅评论上训练 LDA 模型
  2. 使用 LDA 模型获取每个评论的主题分布
  3. 将主题分布直接用作监督分类模型(逻辑回归、SVC 等)中的特征向量,并获得 F1 分数。
  4. 使用相同的 2016 年 LDA 模型获得 2017 年的主题分布(LDA 模型没有看到这个数据!)
  5. 对 2017 年向量再次运行监督分类模型,看看这是否一般化。

如果在看不见的数据上的监督 F1 分数一般化,那么我们可以假设 2016 主题模型已经识别了在这个餐馆评论领域中随着时间持续存在的潜在语义结构。

数据准备

更新(9/23/19):我给的 Repo 添加了一个自述文件,展示了如何使用源数据创建一个 MongoDB。我还包含了一个预处理脚本,它将允许你创建我在下面使用的精确的训练和测试数据帧。然而,我意识到这可能需要大量的工作,所以我还在这里的目录中包含了我的训练和测试数据帧的 pickle 文件。这将允许您直接跟踪回购中的笔记本,即这里的和这里的。如果你只想知道重点/要点,我会在这篇博文的剩余部分用代码片段指出所有的关键点。

LDA 预处理

我使用了非常棒的 gensim 库来创建评论的二元表示并运行 LDA。Gensim 的 LDA 实现需要作为稀疏向量进行审查。方便的是,gensim 还提供了将 NumPy 密集矩阵或 scipy 稀疏矩阵转换成所需形式的便利实用程序。

我将展示如何使用 gensim 函数获得必要的表示。我从 pandas DataFrame 开始,它在一个名为'text’的列中包含每个评论的文本,这个列可以被提取到一个字符串列表的列表中,其中每个列表代表一个评论。这是我下面例子中名为words的对象:

from nltk.corpus import stopwords
stop_words = stopwords.words('english')
stop_words.extend(['come','order','try','go','get','make','drink','plate','dish','restaurant','place','would','really','like','great','service','came','got']) def remove_stopwords(texts):
    out = [[word for word in simple_preprocess(str(doc))
            if word not in stop_words]
            for doc in texts]
    return outdef bigrams(words, bi_min=15, tri_min=10):
    bigram = gensim.models.Phrases(words, min_count = bi_min)
    bigram_mod = gensim.models.phrases.Phraser(bigram)
    return bigram_moddef get_corpus(df):
    df['text'] = strip_newline(df.text)
    words = list(sent_to_words(df.text))
    words = remove_stopwords(words)
    bigram_mod = bigrams(words)
    bigram = [bigram_mod[review] for review in words]
    id2word = gensim.corpora.Dictionary(bigram)
    id2word.filter_extremes(no_below=10, no_above=0.35)
    id2word.compactify()
    corpus = [id2word.doc2bow(text) for text in bigram]

    return corpus, id2word, bigramtrain_corpus, train_id2word, bigram_train = get_corpus(rev_train)

为了简洁起见,我在这篇文章中省略了几个额外的预处理步骤(标点、换行等)。

这个代码块中实际上有两个关键项目:

  1. Gensim 的短语类允许您将相关短语分组到 LDA 的一个令牌中。例如,请注意,在这篇文章开头找到的主题列表中, ice_cream 被列为单个标记。因此,bigram = [bigram_mod[review] for review in words]这一行的输出是一个列表列表,其中每个列表代表一篇评论,每个列表中的字符串都是单字和双字的混合。这是因为我们所做的是将bigram_mod短语建模模型应用于每个评审。
  2. 一旦你有了一元和二元的列表,你就可以把它传递给 gensim 的 Dictionary 类。这将为每个评论输出每个单词的词频计数。我发现,当我额外做了一些处理来删除语料库中最常见和最罕见的单词时,我用 LDA 得到了最好的结果,如上面代码块的第 21 行所示。最后,下面是doc2bow() 正在做的事情,来自他们的官方例子【3】:

函数*doc2bow()*简单地计算每个不同单词的出现次数,将单词转换为整数单词 id,并将结果作为稀疏向量返回。稀疏向量*[(0, 1), (1, 1)]*因此读作:在“人机交互”文档中,计算机(id 0)和人类(id 1)这两个词出现一次;其他十个词典单词(隐式地)零次出现。”

上面的第 23 行给出了 LDA 所需的表示中的语料库。

为了举例说明我们正在处理的文本类型,这里有一个 Yelp 评论的快照:

选择 LDA 的主题数量

为了训练一个 LDA 模型,你需要在你的语料库中提供一个固定的假设数量的主题。有很多方法可以解决这个问题:

  1. 用不同数量的主题在你的语料库上运行 LDA,看看每个主题的单词分布是否合理。
  2. 检查你的 LDA 模型的一致性分数,并有效地网格搜索以选择最高的一致性[4]。
  3. 创建一些具有不同主题值的 LDA 模型,然后查看这些模型在监督分类模型训练中的表现。这是我的目标,因为我的最终目标是看看主题分布是否有预测价值。

其中:我根本不相信#1 是一种方法。在这种情况下,我有什么资格说什么是明智的,什么是不明智的?我依靠 LDA 来识别 100,000 个文档的潜在主题表示,它可能不一定是直观的。对于#2:我和一些前 NLP 专业人士交谈过,他们劝我不要依赖基于他们行业经验的一致性分数。方法#3 对我的目的来说是合理的,但是现实情况是,即使我使用的是 16GB 的 8 核 AWS 实例,LDA 也需要花费大量的时间来训练。

因此,我想到了一个我认为相当新颖的想法——至少,我还没有在网上或报纸上看到任何人这样做:

Gensim 还提供了一个分层的狄利克雷过程(HDP)类[5]。HDP 类似于 LDA,只是它试图从数据中学习正确的主题数量;也就是说,你不需要提供固定数量的主题。我想我应该在我的 100,000 条评论上运行几次 HDP,看看它正在学习的主题数量。在我的情况下,这总是 20 个主题,所以我去了。

为了对 HDP 有一个直观的感受:我在网上找到了一些资料,说它最类似于中国餐馆的流程。埃德温·陈在这里【6】对此做了精辟的解释,在【7】在这里做了漂亮的形象化处理。这是来自[7]的视觉化图像:

在这个例子中,我们需要给一个主题分配 8 分。有 3/8 的概率 8 将到达话题 C1,有 4/8 的概率 8 将到达话题 C2,有 1/8 的概率一个新话题 C3 将被创建。通过这种方式,发现了许多主题。所以一个集群越大,就越有可能有人加入这个集群。我觉得这和其他为 LDA 选择固定主题号的方法一样合理。如果任何有较重贝叶斯推理背景的人对此有想法,请权衡!

更新[2020 年 4 月 13 日] — 爱德华多·科罗纳多通过评论提供了一些关于 HDP 的更精确的信息:

“的确,HDPs 的非参数特性允许我们从数据中学习主题,但是 Dirichlet 过程混合物已经做到了这一点。HDPs 的主要优势是它们允许不同的语料库(组)在建模时共享统计优势——在这种情况下,共享潜在无限主题的公共集合。所以它是狄利克雷过程混合物的一个扩展。”

创建 LDA 模型

下面是用 Gensim 运行 LDA 的代码:

import gensim

with warnings.catch_warnings():
    warnings.simplefilter('ignore')
    lda_train = gensim.models.ldamulticore.LdaMulticore(
                           corpus=train_corpus,
                           num_topics=20,
                           id2word=train_id2word,
                           chunksize=100,
                           workers=7, # Num. Processing Cores - 1
                           passes=50,
                           eval_every = 1,
                           per_word_topics=True)
    lda_train.save('lda_train.model')

通过打开eval_every标志,我们能够以块的形式处理语料库:在我的例子中,100 个文档的块在收敛方面表现得相当好。遍数是对整个语料库的单独遍数。

完成后,您可以查看组成每个主题的单词,如下所示:

lda_train.print_topics(20, num_words=15)[:10]

有了这段代码,你会看到 20 个主题中的 10 个,以及每个主题的 15 个热门词汇。

将主题转换为特征向量

现在有趣的部分来了。我们将使用 LDA 模型来获取每篇评论的这 20 个主题的分布。这 20 个向量将是我们监督分类的特征向量,监督学习的目标是确定积极或消极的情绪。

注意,我认为这种使用主题模型向量的监督分类方法并不常见。当我这么做的时候,我不知道网上有人尝试过这个例子,尽管后来当我完成时,我发现了这篇在 2008 年完成的论文。请让我知道是否有其他的例子!

最终目标不仅是看看这在当前数据的训练/测试 CV 分割中表现如何,而且是这些主题是否触及了一些基本的东西,这些基本的东西转化为未来看不见的测试数据(在我的情况下,是一年后的数据)。

以下是我为每篇评论获取特征向量的方法:

train_vecs = []
for i in range(len(rev_train)):
    top_topics = (
        lda_train.get_document_topics(train_corpus[i],
                                      minimum_probability=0.0)
    ) topic_vec = [top_topics[i][1] for i in range(20)]
    topic_vec.extend([rev_train.iloc[i].real_counts])
    topic_vec.extend([len(rev_train.iloc[i].text)])
    train_vecs.append(topic_vec)

key bit 在第 3 行使用minimum_probability=0.0。这确保了我们能够捕捉到某些主题中某篇评论的呈现率为 0%的情况,而每篇评论的呈现率加起来将达到 100%。

第 5 行和第 6 行是我添加的两个手工设计的特性。

因此,用于监督分类审查的单个观察现在看起来像这样:

前 20 个项目代表每个评论的 20 个主题的分布。

训练监督分类器

我们现在准备好训练了!在这里,我使用了 100,000 条 2016 年餐厅评论及其主题-模型分布特征向量+两个手工设计的特征:

X = np.array(train_vecs)
y = np.array(rev_train.target)

kf = KFold(5, shuffle=True, random_state=42)
cv_lr_f1, cv_lrsgd_f1, cv_svcsgd_f1,  = [], [], []

for train_ind, val_ind in kf.split(X, y):
    # Assign CV IDX
    X_train, y_train = X[train_ind], y[train_ind]
    X_val, y_val = X[val_ind], y[val_ind]

    # Scale Data
    scaler = StandardScaler()
    X_train_scale = scaler.fit_transform(X_train)
    X_val_scale = scaler.transform(X_val)

    # Logisitic Regression
    lr = LogisticRegression(
        class_weight= 'balanced',
        solver='newton-cg',
        fit_intercept=True
    ).fit(X_train_scale, y_train)

    y_pred = lr.predict(X_val_scale)
    cv_lr_f1.append(f1_score(y_val, y_pred, average='binary'))

    # Logistic Regression SGD
    sgd = linear_model.SGDClassifier(
        max_iter=1000,
        tol=1e-3,
        loss='log',
        class_weight='balanced'
    ).fit(X_train_scale, y_train)

    y_pred = sgd.predict(X_val_scale)
    cv_lrsgd_f1.append(f1_score(y_val, y_pred, average='binary'))

    # SGD Modified Huber
    sgd_huber = linear_model.SGDClassifier(
        max_iter=1000,
        tol=1e-3,
        alpha=20,
        loss='modified_huber',
        class_weight='balanced'
    ).fit(X_train_scale, y_train)

    y_pred = sgd_huber.predict(X_val_scale)
    cv_svcsgd_f1.append(f1_score(y_val, y_pred, average='binary'))

print(f'Logistic Regression Val f1: {np.mean(cv_lr_f1):.3f} +- {np.std(cv_lr_f1):.3f}')
print(f'Logisitic Regression SGD Val f1: {np.mean(cv_lrsgd_f1):.3f} +- {np.std(cv_lrsgd_f1):.3f}')
print(f'SVM Huber Val f1: {np.mean(cv_svcsgd_f1):.3f} +- {np.std(cv_svcsgd_f1):.3f}')

关于这一点有几点需要注意:

  1. 我找到了标准逻辑回归、对数损失随机梯度下降和修正 Huber 损失随机梯度下降之间的比较。
  2. 我正在运行一个 5 重 CV,因此在每次运行中,1/5 的评论作为验证数据,另外 4/5 是训练数据。每次折叠都重复这一过程,最后对 f1 得分结果进行平均。
  3. 我的班级不平衡。特别是,在 Yelp 评论数据集中,4 星和 5 星评论的数量不成比例。模型中的class_weight='balanced'线近似于欠采样,以对此进行校正。这一选择的理由见[9]。
  4. 我还将分析限制在数据集中总评论数超过 25%的餐馆。这更多是为了加快速度,因为最初的数据集大约有 400 多万条评论。

2016 年培训结果

以下是 f1 得分结果:

我将首先使用逻辑回归分析较低的. 53 和. 62 f1 分数。当我开始训练时,我试图预测个人评价:1、2、3、4 或 5 星。如你所见,这并不成功。我对最初的. 53 分有点气馁,所以回去检查我最初的 EDA 图表,看看我是否能注意到数据中的任何东西。我之前运行过这个图表:

这显示了单词计数 IQR 评级范围。由于主要的 IQR 范围相当紧凑,我决定尝试重新运行 LDA 预处理和模型仅限于(大致)IQR 范围。进行这一更改后,我的 1、2、3、4、5 星分类的 f1 逻辑回归得分增加到了 0.62。还是不太好。

在这一点上,我决定看看如果我去掉 3 颗星会发生什么,并将 1、2 颗星归类为“差”,4、5 颗星归类为“好”。正如你在上面的图表中看到的,这是一个奇迹!现在逻辑回归得出了 0.869 的 f1 分数。

修正的休伯损失

当我运行这些时,我注意到 SKLearn 的随机梯度下降实现中有一个“修正的 huber”损失选项[10]。在这种情况下,出错的代价比铰链(SVC)或日志丢失要严重得多:

我仍然在努力解决为什么这个方法如此有效,但是我最初的想法是这些惩罚性的惩罚使得 SGD(记住,1 比 1 的重量更新)学得很快。正规化在这方面也有很大帮助。上面代码中第 42 行的 alpha 是一个正则化参数(就像在 Ridge 或 Lasso 正则化中一样),这有助于我的 f1 分数达到 0.936。

对看不见的数据应用模型

在这一点上,我对这些结果感到非常兴奋,但想进一步看看在完全看不见的数据上会发生什么。

具体来说:

  1. 从 2016 年的评论中提取 LDA 模型,并获取测试数据的特征向量。需要注意的是,同样的 2016 款可以做到这一点!
  2. 在测试向量上重新运行模型。

所有需要做的就是为测试语料库制作二元模型,然后像以前一样将它投入到测试向量提取方法中:

def get_bigram(df):

    df['text'] = strip_newline(df.text)
    words = list(sent_to_words(df.text))
    words = remove_stopwords(words)
    bigram = bigrams(words)
    bigram = [bigram[review] for review in words]
    return bigram

bigram_test = get_bigram(rev_test)

test_corpus = [train_id2word.doc2bow(text) for text in bigram_test]

test_vecs = []
for i in range(len(rev_test)):
    top_topics = (
            lda_train.get_document_topics(test_corpus[i],
                                          minimum_probability=0.0)
    topic_vec = [top_topics[i][1] for i in range(20)]
    topic_vec.extend([rev_test.iloc[i].real_counts])
    topic_vec.extend([len(rev_test.iloc[i].text)])
    test_vecs.append(topic_vec)

最后,结果是:

令我有些震惊的是,这种概括!

我对这个结果感到兴奋,因为我相信这种方法对任何试图以这种方式训练分类器的公司都是可行的。最后我还使用 mlxtend [11]做了一个假设检验,最终结果确实具有统计学意义。

未来的工作

我打算在未来扩展这一点,我留给你:

我还在我的 GitHub 这里托管了所有的代码和经过训练的 LDA 模型。

感谢阅读!

来源

[1]https://en.wikipedia.org/wiki/Latent_Dirichlet_allocation
【2】https://www.yelp.com/dataset
【3】https://radimrehurek.com/gensim/tut1.html
【4】https://radimrehurek.com/gensim/models/coherencemodel.html
【5】https://radimrehurek.com/gensim/models/hdpmodel.html
【6】http://blog . echen . me/2012/03/20/infinite-mix-models-with-nonparameter-Bayes-and-the-Dirichlet-process/
SGDClassifier.html
【11】http://rasbt.github.io/mlxtend/user_guide/evaluate/mcnemar/

无监督组学整合

原文:https://towardsdatascience.com/unsupervised-omics-integration-688bf8fa49bf?source=collection_archive---------17-----------------------

生命科学的数理统计和机器学习

将数据投射到跨组学的公共变化轴上

The idea behind OMICs integration from Wang et al., Quantitative Biology 4, p.58, 2016, image source

这是专栏 生命科学的数理统计和机器学习 的第十篇文章,我试图在这里涵盖生物信息学、生物医学、遗传学、进化论等常用的分析技术。之前,我对组学集成做了一个介绍,并介绍了监督的 PLS-DA 模型。今天,我们将考虑无监督组学整合,这在没有类别标签(没有明确的表型)可用时尤其方便,但我们仍然希望通过组合不同来源的生物信息来了解数据中样本之间的异质性。

监督与非监督数据集成

比较有监督和无监督的数据分析就像比较披头士和天鹅绒地下音乐。两者都很优秀,但方式不同。虽然监督建模在现代研究中占主导地位,因为它提供了缓慢但有保证的进展,但无监督模型一直被认为是“高风险-高收益”的方法

列夫·朗道 (诺贝尔物理学奖获得者)他问正在努力解决数学问题的学生的问题:“你怎么能在不知道答案的情况下解决一个科学问题?”反映了有监督的假设驱动的主流研究的心态。例如,如果一个人胆敢对编辑的评论“我不太理解你的生物学假设”回复“我没有”,这将很可能导致同行评审科学期刊拒绝该论文。这是因为在研究中,我们倾向于用事物如何工作的最初想法来约束自己,而要做的研究只是为了证明我们的假设是正确的。相比之下,无监督方法是一种 解放你的思想 的方法,当你不知道你的数据中有什么,因此可以发现意想不到的现象

多组学因素分析(MOFA)

是典型的无假设数据探索框架。它允许通过从多组学层中提取公共变化轴进行数据整合。给定来自相同或重叠样本的多个组学的数据矩阵,MOFA 根据潜在/隐藏因素推断出数据的低维表示,然后可以对其进行可视化和解释。

Idea of unsupervised OMICs integration with Multi-OMICs Factor Analysis (MOFA)

类似于其他整合组学方法,如 DISCO、JIVE 和 O2PLS ,MOFA 推断异质性的潜在轴是否为个体 OMIC 或所独有,表现在多个组学中。此外,MOFA 提供了几个有用的功能,包括:

  • 低维潜在空间中样本的可视化
  • 使用(基因集)富集分析的因子注释
  • 缺失和稀疏数据的插补和支持
  • 非高斯分布的组学支持

后两个优点源于 MOFA 是在贝叶斯T2 框架内实现的,不依赖于大量数据或高斯分布等频繁统计假设。重要的是,MOFA 是一个线性** 集成组学算法,一个更一般的非线性组学集成可以通过例如自动编码器来执行,我在我以前的帖子中描述过。关于 MOFA 要提到的最后一点是,它是一种 因子分析(FA) 算法,尽管 FA 在视觉上可能看起来与 PCA 相同,但这两种线性降维技术不应混淆。PCA 是一种纯粹的矩阵分解技术(除非它是一种概率 PCA ),它将总方差分解成正交的主分量,FA 寻求构造隐藏的潜在变量,这些变量生成观察到的数据,因此因子分析是一种生成模型,类似于隐马尔可夫模型(HMM)、高斯混合模型(GMM)、变分自动编码器(ve)、生成对抗网络(GANs)等。**

多组学数据集的整合

在本节中,我们将 MOFA 应用于单细胞多组学 scNMT 数据集,该数据集描绘了来自相同生物细胞染色质可及性(scATACseq)、DNA 甲基化(scBSseq)和基因表达(scRNAseq)** ,这些细胞属于两种类型:分化小鼠胚胎干细胞(ESCs)和胚胎体(EBs) 。我们将从读取、过滤和对数转换 scNMT 的 scRNAseq 子集开始:**

接下来,我们将读取 scNMT 的 scBSseq 和 scATACseq 子集,并显示它们的分布。因为 CpG 位点可以是甲基化或未甲基化,并且类似地,使用 GpC 甲基转移酶 标记的位点可以来自开放或封闭染色质区域,所以 scBSseq 和 scATACseq 的分布看起来生物模态指示数据的二元性质就不足为奇了。

Histograms of scBSseq and scATACseq subsets of scNMT

因此,我们将 scBSseq 和 scATACseq 数据建模为来自 Benoulli 分布 。我们将通过将低于 50 的值编码为 0,高于 50 的值编码为 1** 以及移除低方差特征以避免冗余,进一步使 scBSseq 和 scATACseq 数据集成为纯二进制数据集:**

此外,我们将创建 MOFA 对象并设置模型参数,例如 scBSseq 和 scATACseq 的伯努利分布,以及 scRNAseq 组学的高斯分布(由于对数变换):

MOFA provides a useful visualization of the dimensions of the data

最后,我们将准备 MOFA 对象并运行 MOFA。事实证明,MOFA 只选择了 3 个隐藏的潜在因素(LFs ),解释了 scNMT 数据集超过 3%的变化。MOFa 的主要成果是下面的个体组学之间协方差的巨大可视化:****

我们可以看到,scRNAseq 对总的整合组学 scNMT 数据集贡献了最大的变异( 13% ),scBSseq 和 scATACseq 贡献了约 5% 的变异。在 MOFA 选择的 3 个 LF 中,scRNAseq 对所有 LF 都有贡献,而第二个 LF 主要由 scBSseq 驱动,scATACseq 仅对第一个 LF 有贡献。有趣的是, scRNAseq 在第一个 LF 中与 scATACseq 共变,而 scRNAseq 在第二个 LF 中与 scBSseq 共变。现在让我们通过显示它们的加载来解释 LF,即负责每个 LF 的特征,这里我们考虑 scRNAseq 和 LF1:

Visualization of MOFA loadings and heatmap demonstrating separation of ESC and EB cells

在右边的热图上,看起来加载基因在 ESC 和 EB 细胞之间提供了一个很好的分离。最后,我们将显示低维潜在空间中的细胞,这种嵌入是来自 scNMT 多组学数据集的 3 组学整合的结果。****

Low-dimensional MOFA representation of scNMT cells

我们的结论是,MOFA 将来自 scNMT 数据集的 3 个组学投影到一个共同的潜在空间,其中技术差异被忽略,仅共同变异被考虑。整合方法能够成功地区分 3 种细胞类型:ESCs、EBs 和对照。

摘要

在这篇文章中,我们了解到多组学因子分析(MOFA)是一种优雅的基于贝叶斯的组学整合算法,通过提取跨模态的共同变化轴。这对于数据探索和理解组学之间的相互作用特别有用。MOFA对缺失数据不敏感,并允许组合来自不同非高斯统计分布的组学。

在下面的评论中让我知道生命科学中的哪些分析对你来说似乎特别神秘,我会在这个专栏中尝试回答它们。在我的 github 上查看帖子中的代码。在 Medium 关注我,在 Twitter @NikolayOskolkov 关注我,在 Linkedin 关注我。下一次我们将讨论如何批量更正单细胞数据,敬请关注。

无监督情感分析

原文:https://towardsdatascience.com/unsupervised-sentiment-analysis-a38bf1906483?source=collection_archive---------0-----------------------

如何从没有任何标签的数据中提取情感

Photo by Amanda Jones on Unsplash

注意:github repo 中提供了完整的代码:

[## rafaljanwojcik/无监督情感分析

如何从观点中提取情感而不被贴上文章回购的标签....在无监督的情绪上…

github.com](https://github.com/rafaljanwojcik/Unsupervised-Sentiment-Analysis)

NLP 方法的一个常见应用是情感分析,你试图从数据中提取关于作者情感的信息。主要是,至少在开始时,你会试图区分积极和消极的情绪,最终也是中立的,或者甚至仅基于文本检索与给定观点相关的分数。

你可以采取两种主要方法,教一种算法来区分写作中的积极和消极情绪——有监督的和无监督的。

第一个将向你询问以收集标记数据,并以监督的方式教导算法(例如, LSTM 网络)序列中的每个单词(实际上是所有单词一个接一个出现,如果我们谈论 RNNs )如何对应于整个句子是否定还是肯定的结果。这种方法需要手动标记数据,这通常很耗时,而且并不总是可行的。其次,对于在 NLP 方面没有得到很好利用的语言,例如波兰语,没有太多的预训练模型可以使用,所以不可能使用已经预训练了模型的来估计句子中每个单词的情感得分。

后一种方法是一种无人监管的方法,这也是本文关注的对象。无监督学习背后的主要思想是,对于你输入的变量的结果,你不给模型任何预先的假设和定义——你只是插入数据(当然之前进行了预处理),并希望模型学习数据本身的结构。如果您没有带标签的数据,或者您不确定数据的结构,并且您想要了解更多关于您正在分析的过程的性质,而不事先对其结果做出任何假设,那么这是非常有用的。

在我们进入本文的主要部分之前,还有一件事可能很重要。在自然语言处理和计算机视觉的最新突破中,最重要的思想之一是迁移学习的有效利用。在 NLP 领域,大多数迁移学习以某种方式发生,即一些模型(在 Word2Vec 的情况下,让它成为 MLP,或者像 BERT 这样的转换器)首先以无监督的方式(实际上是假监督的)对数据进行训练,然后针对特定任务进行微调,或者只是在另一个模型中使用,以产生更好的质量特征。通常会给它一个假的监督任务,比如根据周围的单词预测单词,或者根据给定的单词预测周围的单词(参见: word2vec ,或者根据前面的单词/句子预测下一个单词/句子( transformer models )。这种训练不应该被认为是直接监督的,因为没有人的因素告诉算法什么答案是正确的(除了人自己写句子)。我提这个是因为 Word2Vec 算法可以作为迁移学习的例子来教。

也就是说,我们到达了这篇文章的主题,即无监督的情感分析。让事情变得更难的是,因为我来自波兰,我选择了分析波兰情感数据集,尽管这种方法也应该适用于任何语言,因为我没有对波兰语做出任何特定的假设,也没有使用预先训练的模型。在本文中,Szymon Pł otka 在监督下收集并分析了该数据集:

[## 使用 Keras 和 Word2vec - Ermlab 软件进行波兰情感分析

博客上的帖子将致力于分析多愁善感的波兰语,这是一个属于…

ermlab.com](https://ermlab.com/en/blog/nlp/polish-sentiment-analysis-using-keras-and-word2vec/)

解决这个问题有不同的方法,我将在本文的底部提到,这些方法可能会更好,但我发现我的方法实际上很令人兴奋,因为它是这些想法中的一个,只是在你的脑海中出现,并在没有投入太多努力的情况下实际工作(这也可能令人担忧)。

1.主要思想

Photo by Nicole Honeywill / Sincerely Media on Unsplash

这种方法背后的主要思想是消极和积极的词通常被相似的词包围。这意味着,如果我们有电影评论数据集,单词“boring”将被与单词“derive”相同的单词包围,通常这些单词将与单词“not”(like)接近,这也将使 word 与它们不相似。另一方面,这不太可能发生,单词“乏味”与单词“令人兴奋”的环境更相似,而不是与单词“无聊”的环境更相似。在这样的假设下,单词可以形成具有相似环境的负面单词、具有相似环境的正面单词以及一些结束于它们之间的中性单词的集群(基于它们环境的相似性)。一开始这看起来不太令人信服,我可能不是完美的解释者,但事实证明这是真的。

解决此类问题(拥有与其周围相似的单词)的完美工具是唯一的 word2vec!如果你以前没听说过,这里有一篇关于 word2vec 算法的文章,作者是 Chris McCornick:

[## Word2Vec 教程—跳格模型

本教程涵盖了 Word2Vec 的 skip gram 神经网络架构。本教程的目的是…

medium.com](https://medium.com/nearist-ai/word2vec-tutorial-the-skip-gram-model-c7926e1fdc09)

和 Pierre Megret 的 perfect tutorial,我在本文中使用它来训练我自己的单词嵌入:

[## Gensim Word2Vec 教程

下载数千个项目的开放数据集+在一个平台上共享项目。探索热门话题,如政府…

www.kaggle.com](https://www.kaggle.com/pierremegret/gensim-word2vec-tutorial)

2.数据

Photo by Robert Bye on Unsplash

T 他每个数据科学/机器学习项目第一步、唯一一步、也是最重要的一步就是数据准备。如果没有良好的数据质量,最终总是可能得到一个有偏差的模型,要么根据我们选择的一些指标(例如测试集的 F 分数)表现不佳,要么一开始就很难诊断,被告知有偏差的关系,这实际上并不能反映出它区分积极和消极情绪的可用性,而是允许它在给定的数据集上表现良好。

下面的单元格显示了我选择使用的基本文本准备步骤之一,但我没有包括所有步骤,因为所有内容都包含在我的中,我不想降低文章的可读性。坦率地说,我没有在这上面花太多时间,仍然有足够的空间让您自己做准备,特别是如果您想为像英语这样的语言实现它,这些语言有文本规范化的库。对于波兰语来说,使用像 Morfologik 这样的工具来使单词符合其基本结构可能非常重要,因为我们有许多不同的单词后缀来改变模型的单词,但实际上意思完全相同(例如,“beznadziejny”和“beznadziejna”都表示无望,但第一个指的是男人,另一个指的是女人)。

https://gist.github.com/rafaljanwojcik/f00dfae9843dadc0220eba3d36694e27

我选择包括的所有步骤:

  • 删除缺少(NaN)值的行,
  • 删除重复的行,
  • 删除 rate 等于 0 的行,因为它包含一些错误,可能来自数据收集阶段,
  • 使用 unidecode 包替换波兰字母,
  • 用一个空格替换所有非字母数字符号、标点符号和重复的空格
  • 保留所有包含长度至少为 2 个单词的句子的行。

另一个想法可以是实现拼写检查,以防止训练太多的单词嵌入,这实际上意味着完全相同的事情。这里有一篇关于拼写检查器的很棒的文章,它使用 Word2Vec 和 Levenstein 距离来检测语义上最相似的单词:

[## 用 word2vec 数据建立一个拼写检查器(用 python)

在 SubitoLabs,我们正在做一个非常酷的聊天信息分析项目。基本上,我们需要检测一些关键字…

link.medium.com](https://link.medium.com/L6iSZUIov1)

清理完单词后,还有其他几个步骤为 word2vec 模型准备数据,这些都包含在我的 github repo 中。主要步骤包括使用 gensim 的短语模块检测和替换最常见的词的二元模型。所有这些步骤和我使用的 Word2Vec 模型中的大部分超参数都是基于我之前链接的 kaggle 的 Word2Vec 教程

3.Word2Vec 模型

Photo by Max Kleinen on Unsplash

在这个练习中,我使用了 gensim 的 word2vec 算法的实现与 CBOW 架构。我训练了 300 个维嵌入,查找窗口等于 4,负采样设置为 20 个词,子采样设置为 1e-5,学习率从 0.03 衰减到 0.0007。

w2v_model = Word2Vec(min_count=3,
                     window=4,
                     size=300,
                     sample=1e-5, 
                     alpha=0.03, 
                     min_alpha=0.0007, 
                     negative=20,
                     workers=multiprocessing.cpu_count()-1)

4.k 均值聚类

Photo by Arnaud Mariat on Unsplash

K -means clustering 是数据聚类的基本技术,它似乎最适合于给定的问题,因为它将所需聚类的数量作为输入,并输出计算出的聚类质心(发现的聚类的中心点)的坐标。这是一种迭代算法,在第一步中,选择 n 个随机数据点作为聚类质心的坐标(其中 n 是搜索的聚类的数量),然后在每一步中,基于欧几里德距离,将所有点分配给它们最近的质心。接下来,计算每个质心的新坐标,作为分配给每个质心的所有数据点的坐标的平均值,并且重复迭代,直到达到分配给质心的点和它们的质心坐标之间的距离的平方和的最小值(这仅仅意味着聚类的坐标停止变化),或者迭代次数达到给定的限制。

在给定的问题中,我使用 sklearn 的具有 50 个重复起始点的 K-means 算法的实现,大概是为了防止算法选择错误的起始质心坐标,这将导致算法收敛到非最佳聚类,以及 1000 次将点重新分配到聚类的迭代。

https://gist.github.com/rafaljanwojcik/275f18d3a02f6946d11f3bf50a563c2b

在估计的单词向量上运行之后,我得到了两个质心,它们的坐标可以用下面的方法检索:

model.cluster_centers_

接下来,为了检查哪个聚类是相对正的,哪个是相对负的,使用 gensim 的 most_similar 方法,我检查了哪些词向量在余弦相似性方面与第一个聚类的坐标最相似:

word_vectors.similar_by_vector(model.cluster_centers_[0], topn=10, restrict_vocab=None)

哪些输出:

[('pelen_profesjonalim', 0.9740794897079468),
 ('superszybko_supersprawnie', 0.97325599193573),
 ('bardzon', 0.9731361865997314),
 ('duzu_wybor', 0.971358060836792),
 ('ladne_garnki', 0.9698898196220398),
 ('najlpszym_porzadku', 0.9690271615982056),
 ('wieloma_promocjami', 0.9684171676635742),
 ('cudowna_wspolpraca', 0.9679782390594482),
 ('pelen_profesjonaliz', 0.9675517678260803),
 ('przyzwoicie_cenowo', 0.9674378633499146)]

正如你所看到的(如果你懂波兰语,我鼓励你学习波兰语,如果你想拥有一些超能力来炫耀的话)10 个余弦距离最接近 0 号聚类的单词是那些有积极情绪的单词。一些被分类到聚类 0 的词甚至是上下文积极的,例如,由字面意思为“蜂蜜”和“覆盆子”的词组成的搭配“miod_malina”,意味着某事是惊人的和完美的,并且它获得了+1.363374 的情感分数(与它被分配到的聚类的距离成反比,详细信息请参见库中的代码)。

负面聚类更难描述,因为不是所有最接近其质心的最相似的单词都是直接负面的,但当你检查像“无望”、“差”或“坏”这样的单词是否被分配给它时,你会得到相当好的结果,因为它们都在它们应该在的地方。

temp[temp.words.isin(['beznadziejna', 'slaba', 'zepsuty'])]

给出:

{'zepsuty': -1.2202580315412217,
 'slaba': -1.0219668995616882,
 'beznadziejna': -1.0847829796850548}

这可能看起来很棘手,我使用余弦距离来确定每个聚类的情感,然后使用欧几里德距离将每个单词分配到一个聚类,但这背后并没有动机,我只是使用了两个库中可用的方法,并且它工作了。

5.分配聚类

Photo by Guillermo Ferla on Unsplash

上一章中提到的下一步,是根据单词所属的聚类,给每个单词分配一个情感分数,负值或正值(-1 或 1)。为了衡量这个分数,我把它乘以他们离他们的集群有多近(来衡量他们潜在的积极/消极程度)。由于 K-means 算法输出的分数是与两个聚类的距离,为了适当地对它们进行加权,我将它们乘以接近度分数的倒数(情感分数除以接近度分数)。

https://gist.github.com/rafaljanwojcik/865a9847e1fbf3299b9bf111a164bdf9

随着这些步骤的完成,完整的字典被创建(以熊猫数据框架的形式),其中每个单词都有自己的加权情感得分。为了评估这些加权情感系数有多准确,我用获得的系数随机抽样了数据帧。正如你所看到的,对于大多数人来说,可能在谷歌翻译的帮助下,下表中的单词大多出现在正确的簇中,尽管我必须承认许多单词看起来并不那么有前途。也许,纠正它的最佳选择是适当地标准化数据,或者为不应该分配任何情感的词创建第三个中性簇,但是为了不使这个项目变得太大,我没有改进它们,并且它仍然工作得很好,正如你稍后将看到的。

sample of words with calculated weighted sentiment coefficients

6.Tfidf 加权和情感预测

Photo by Brett Jordan on Unsplash

N 下一步是用 sklearn 的 tfidf 矢量器计算每个句子中每个单词的 tfidf 得分。进行该步骤是为了考虑每个单词对于每个句子有多独特,以及与整个语料库相比,增加与对于给定句子高度特定的单词相关联的肯定/否定信号。

https://gist.github.com/rafaljanwojcik/9d9a942493881128629664583e66fb3a

最后,每个句子中的所有单词一方面被替换为它们的 tfidf 分数,另一方面被替换为它们相应的加权情感分数。

https://gist.github.com/rafaljanwojcik/ec7cd1f4493db1be44d83d32e8a6c6c5

上面和下面的列表给出了用它们相关的 tfi df/情感分数替换句子中的单词的函数,以获得每个句子的 2 个向量

https://gist.github.com/rafaljanwojcik/fa4c85f22cc1fedda25f156d3715ccae

这两个句子向量的点积指示总体情绪是积极的还是消极的(如果点积是积极的,则情绪是积极的,反之则是消极的)。

https://gist.github.com/rafaljanwojcik/9add154cb42b2450d68134a7150de65c

7.模型分数

Photo by Markus Spiske on Unsplash

用于评估模型性能的 hosen 指标是 precision、recall 和 F-score,主要是因为数据集中的类高度不平衡,但事实上,数据集是如此的不平衡,以至于我可能应该想出一个指标来更好地惩罚这种不平衡。事实证明,该模型达到了 0.99 的精度,这表明它真的很擅长区分负面情绪观察(它几乎不会将负面观察误认为正面观察)。有人可能会说,很明显,它应该有,因为它只有很少的负面观察,它们可能是与其他模型最不同的,这是部分正确的,但如果你考虑到该模型也实现了近 80%的召回率(这意味着数据集中 80%的正面观察被正确分类为正面),它可能会显示,它也学到了很多东西,而不只是将数据分成两半,负面观察最终出现在正确的聚类中。如果你将这些结果与 Szymon Pł otka 在他的文章中取得的结果进行比较,无监督模型的精度实际上比他的监督模型高,准确率和召回率低大约 17.5 个百分点,尽管很难进行比较,因为我们使用了不同的测试集(我的测试集由完整的数据集组成,而他的测试集来自 20%的原始数据)。

╔════════════════ Confusion Matrix ══════════════╗
╔═══════════╦════════════════════╦═══════════════╗
║           ║         0          ║       1       ║
╠═══════════╬════════════════════╬═══════════════╣
║     0     ║        9523        ║       306     ║
╠═══════════╬════════════════════╬═══════════════╣
║     1     ║       127125       ║     508277    ║
╚═══════════╩════════════════════╩═══════════════╝╔═══════════╦════════════════════╗
║   Scores  ║                    ║
╠═══════════╬════════════════════╣
║ accuracy  ║ 0.802503           ║
║ precision ║ 0.999398           ║
║ recall    ║ 0.799930           ║
║ F1        ║ 0.888608           ║
╚═══════════╩════════════════════╝

总之,无监督方法取得了相当好的结果(在我看来),因为没有使用任何预先训练的模型,并且实际上没有给定文本中正面或负面的先前信息,它取得了相当高的度量,明显高于随机预测。坦率地说,我很想听听你是如何为你的数据集工作的!

8.进一步讨论

Photo by Zdeněk Macháček on Unsplash

T 他写这篇文章主要是为了提出一个关于无监督语言处理的想法,而不是为了在此基础上创造出可能的最佳解决方案,因此有足够的空间来改进它。除了我之前提到的改进之外,我想到的改进包括:

  • K-Means 聚类基于余弦,而不是欧几里德距离
  • 包括第三,中性聚类,或者分配一些结束于正和负聚类之间某处的词,情感得分等于零
  • Word2Vec 算法的超参数调整,基于例如在数据集上获得的 F1 分数(尽管它需要将数据集分成训练和测试数据集,因为训练将受到监督)
  • 不考虑单词的双字母组合

这篇短文到此结束——我真的希望你喜欢它,并期待听到你提出的任何改进。我也希望它对你有所帮助,感谢你阅读它!

祝一切顺利,愿 F1 高分与你同在!

拉斐尔

用数据科学理清英国政治

原文:https://towardsdatascience.com/untangling-uk-politics-with-data-science-a5afe9a86923?source=collection_archive---------22-----------------------

我们能通过分析问题找到答案吗?

TL;在这篇文章中,我们使用 spaCy、BERT 和新颖的聚类算法提取了英国议会中讨论的关键主题

The House of Commons in the early 19th Century, it was around this time (1833) that the practice of giving a Minister notice of a question by printing it in the House’s Notice Paper of future business began

"判断一个人要看他的问题,而不是他的回答。"

伏尔泰

在过去的三年里,英国政治变得令人困惑。除了高度动荡的政治环境之外,误导性信息在网上和社交媒体上的传播显著增加。

在本文中,我们将试图通过分析英国政治引擎源头的数据来“穿透”这种噪音;议会问题。

什么是议会问题?

议会问题是议员用来寻找信息或敦促采取行动的工具。他们要求部长们解释和维护他们部门的工作、政策决定和行动。[1]

这些问题可以使用 http://www.data.parliament.uk/提供的 API 下载。

从 API 下载所有问题、预处理和清理数据后,从 2013 年至今,我们剩下 255,000 个问题:

A sample of the data set for analysis

数据显示:

  • 提出问题的议员
  • 它所针对的部门
  • 问题和答案的日期
  • 问题本身的文本。

由于我们需要的大多数信息都包含在问题本身的文本中,我们需要找到一种方法来提取这些问题中传达的关键主题,然后才能更详细地分析这些主题。

输入伯特

模型在 NLP 中的发展速度之快令人惊讶。不仅新的和更强大的模型正在定期开发,开源社区也在不断进步,使得这些模型的使用越来越直接。

在本文中,我们将使用先进的 BERT 模型来帮助我们从问题数据中提取信息。在过去的几个月里,这个模型的部署变得越来越简单,最近它被集成到了 spaCy 库中,使得在 NLP 管道中使用它变得很容易。

我们将使用 BERT 将单词转换为上下文相关的单词向量,然后我们可以对每个问题进行加权,以产生代表每个问题语义的向量。

2019, the year that NLP became more popular than the Muppets [2]

1。用 BERT 创建单词向量

spaCy NLP 库为我们做了大量的工作。它最近发布了对许多 transformer 模型的支持,这些模型允许最先进的功能,同时仍然使用简单的 spaCy API,这使得它非常受欢迎。只需几行代码就可以启动并运行 BERT:

!pip install spacy-transformers --quiet!python -m spacy download en_trf_bertbaseuncased_lg #requires the runtime to be restarted if using Colab...import spacy
import torchis_using_gpu = spacy.prefer_gpu()if is_using_gpu: torch.set_default_tensor_type("torch.cuda.FloatTensor")nlp = spacy.load("en_trf_bertbaseuncased_lg")

一旦我们加载了模型,使用张量属性从模型中获取单词向量就非常简单了:

doc = nlp("This is an example question")doc.tensor[0] #returns the vector for the first word (This)

2。使用 TF-IDF 为每个问题创建一个加权向量

我们现在有能力从 BERT 中获取问题中每个单词的向量,但我们现在需要一种方法来将这些向量组合成每个问题的单个向量。有不同的技术来做到这一点,平均和求和向量已被证明工作良好。

然而,我们在这里需要小心。伯特是一个非常强大的模型,但它不能读取我们的思想!从数据来看,回答问题的方式有不同的模式,例如:

  • “他的部门过去采用什么标准…”
  • “她的部门正在采取什么措施来……”
  • “他的部门正在采取什么措施来……”

如果我们不小心,我们的分析会被问题的结构而不是内容所迷惑。我们需要一种方法来过滤掉这些噪音,这样我们就可以把重点放在代表问题本身的单词上。

TF-IDF 前来救援

关于 TF-IDF 与词向量的结合,我之前已经写过了,所以这里就不赘述了。这是一种简单却非常强大的聚合单词向量的方法,同时还能过滤掉噪音。

为了证明这个概念,我们来举个例子:

import IPythontkn = tfidf.build_tokenizer()sent = df.questionText.values[236178].lower()
sent = tkn(sent)html=''for wrd in sent:  
   try:    
      weight = (tfidf.idf_[tfidf.vocabulary_[wrd]])*10
      print(weight/10)  
   except:    
      weight = 1    
      print('{} not found'.format(wrd))  
   html+='<span style="font-size:{}px">{}</span>'.format(weight,wrd) 
IPython.display.HTML(html)

这从我们的数据框架中随机抽取一个问题,并对每个单词进行加权。然后将它添加到 HTML 中,这样我们就可以看到 TF-IDF 对每个单词的影响:

The results from TF-IDF. Notice how it is able to reduce the importance of ‘noisy’ words whilst amplifying words which have greater meaning to the question.

由此我们可以看出,这种方法在过滤噪声的同时放大更有见地的单词是非常有效的。

把这个和来自 spaCy 的 BERT 向量放在一起,我们得到下面的,它为每个问题创建一个向量,然后把这个向量保存到一个 numpy 数组中。

import spacy
import torch
from sklearn.feature_extraction.text import TfidfVectorizer
import IPython
from tqdm import tqdmis_using_gpu = spacy.prefer_gpu()
if is_using_gpu:
   torch.set_default_tensor_type("torch.cuda.FloatTensor")nlp = spacy.load("en_trf_bertbaseuncased_lg")vectorizer = TfidfVectorizer(min_df=0.0,lowercase=True)
tfidf = vectorizer.fit(df.questionText.values)
tkn = tfidf.build_tokenizer()print('creating a lookup dictionary') #this speeds up the script significantly...tfidf_lookup = {}
for key,value in tfidf.vocabulary_.items():
   tfidf_lookup[key]=tfidf.idf_[value]vect = []for doc in tqdm(nlp.pipe(df.questionText.values,batch_size=5000)):
   weighted_doc_tensor = []
   try:
      for cnt, wrd_vec in enumerate(doc.tensor):
         word = doc[cnt].text
         try:
            weight = tfidf_lookup[word.lower()]
         except:
            weight = 0.5
         pass
         doc.tensor[cnt] = doc.tensor[cnt]*weight
      vect.append(np.mean(doc.tensor,axis=0))
   except:
      vect.append(np.zeros(768,))#if it is blank...
   passvect = np.vstack(vect)
np.save('question_vects_tfidf.npy', vect)

3。分组问题以确定关键主题

我们现在有了 255,000 个问题的向量,我们可以通过使用降维和聚类的组合从这些向量中识别关键主题:

3.1 降维:UMAP

我以前使用过 TSNE 来降低文档嵌入的维度,但是在本文中我想尝试 UMAP 算法。这类似于 TSNE,但有一个额外的好处,即保持数据的“宏观”结构不变,并识别本地集群。它也适用于大型数据集。一个 Python 库以优秀的UMAP-学习的形式提供。

!pip install umap-learn --quietimport umapreducer = umap.UMAP(n_neighbors=25)y = reducer.fit_transform(vect)

该库以符合数据的方式紧密遵循 Scikit Learn。在该算法中选择的邻居的数量可以用于平衡对局部聚类和数据集的整体结构的强调。为了创建对数据进行聚类的特性,我使用该参数的值 5 和 25 运行了该算法两次。

3.2 聚类:HDBSCAN

HDBSCAN 与 DBSCAN 相关。这两种算法都被设计成基于密度来寻找聚类,并且可以自动识别聚类的数量。此外,它们可以突出不属于任何聚类的离群点。

注意: 在使用基于密度的聚类算法如 HDBSCAN 或 DBSCAN 时,使用 UMAP 或 TSNE 来降维可能是危险的。其原因是原始数据集的密度没有被保留[3]。因此,仔细审查这种方法的结果以确保所创建的集群符合分析的目标是很重要的。

HDBScan 的额外优势是能够处理不同密度的集群。与大多数聚类算法一样,调整参数(min_cluster_size 和 min_samples)更像是一门艺术,而不是科学,您需要检查结果并迭代以找到这些参数的最佳值:

!pip install hdbscan --quietdb = hdbscan.HDBSCAN(min_cluster_size=40, min_samples=1).fit(df[['x_tfidf_umap_5','y_tfidf_umap_5','y_tfidf_umap_25','x_tfidf_umap_25']])labels = db.labels_n_clusters_ = len(set(labels)) - (1 if -1 in labels else 0)
n_noise_ = list(labels).count(-1)print('Estimated number of clusters: %d' % n_clusters_)
print('Estimated number of noise points: %d' % n_noise_)df['cluster'] = db.labels_

3.3 获取集群标签

我们可以用 TF-IDF(再次!)来更好地理解集群是如何工作的。

通过查找每个聚类的关键词,我们不仅可以了解这些聚类代表什么,还可以为每个聚类生成一些用户友好的标签:

from sklearn.feature_extraction.text import TfidfVectorizervectorizer = TfidfVectorizer(stop_words='english')
tfidf = vectorizer.fit_transform(df.questionText.values)totals = 0for cluster in df.cluster.value_counts()[0:10].index:
   stg = " ".join(df.loc[df.cluster==cluster].questionText.values)
   response = vectorizer.transform([stg])
   count = df.cluster.value_counts().loc[cluster]
   totals += count
   feature_array = np.array(vectorizer.get_feature_names())
   tfidf_sorting = np.argsort(response.toarray()).flatten()[::-1]
   n = 10
   print("Cluster Label: {}, Items in Cluster: {}".format(cluster,count))
   print(feature_array[tfidf_sorting][:n])

这返回(去除噪声后的前 5 个聚类):

Success! We can clearly see that each cluster represents a specific political theme.

太棒了,我们已经成功地建立了一种将每一个项目聚集成核心主题的方法。

将这一切结合在一起

Viewing the key themes over time we see that these these are very reactive to key events. Brexit (green) dominates from mid 2016 onward.

那么,这个练习告诉了我们关于英国政治的什么?随着时间的推移,对 10 大主题进行可视化显示,大多数问题都是针对当天的时事提出的。对 2016 年年中退出欧盟的大量关注并不令人惊讶,但图表显示了这在多大程度上扭曲了议会辩论,使卫生、能源和交通等话题黯然失色。

未来的工作

当然,这只是触及了这个数据集所能做的事情的表面。此数据的其他可能用途包括:

  • 根据议员在议会中提出的问题对他们进行剖析。
  • 理解政府的机构是否反映了下议院辩论的焦点。
  • 在议会提问之前预测问题。

参考资料:

[1]来自 parliment . uk:https://www . parliament . uk/documents/commons-information-office/P01 . pdf

[2]谷歌趋势 2019 年 11 月 24 日

[3]https://umap-learn.readthedocs.io/en/latest/clustering.html

挖掘企业可穿戴物联网的潜力

原文:https://towardsdatascience.com/untapping-the-potential-of-enterprise-wearable-iot-f99cc482821f?source=collection_archive---------47-----------------------

企业可穿戴物联网将在商业 4.0 中全面实现

Source: Pixabay

可穿戴技术已经席卷了消费主义——从智能手表、虚拟现实耳机、增强现实眼镜、可穿戴健康等等的发展。自 2015 年以来,美国使用各种可穿戴设备的成年人数量增加了一倍多(3950 万),仅在 2018 年就超过了 8170 万。2019 年,预计可穿戴设备的销售额预计将达到 420 亿美元。

虽然可穿戴设备继续主导消费技术市场的很大一部分,但在企业端使用可穿戴设备的讨论或行动却很少。特别是在公司继续进行数字化转型并变得更加数据驱动的时期,企业需要开始大力投资可穿戴物联网,以帮助提供更多可操作的决策数据,提高员工的工作效率,并提供无与伦比的客户体验。

潜在的使用案例是无限的

Gartner 最近发布了一项研究,展示了企业物联网的增长——预计到 2020 年将达到56 亿个终端。这比 2019 年同比增长了 21%。从现场服务物联网设备到店内零售亭、服务行业平板电脑、制造车间物联网管理等等,各行业的物联网采用正在成为行业规范。

可穿戴物联网可以为这些投资增加一层便利性和互操作性,这是通过传统物联网技术无法实现的。以现场服务管理为例。如今,现场服务技术人员很可能会配备一台平板电脑,用于维护查询简报和日程安排、现场维护以及维护后客户满意度分析。通过为现场服务技术人员提供可穿戴设备,这些技术人员将能够在现场更快地工作并更好地处理多项任务,最终提高客户满意度,并提高工作效率和日常维护完成率。即使节省的时间只有几秒钟——考虑到任何一家互联网或有线电视提供商每天都在与数百万家庭打交道,这几秒钟加起来很快。

可穿戴物联网还可以为车间带来优化的生产力,因为组织正在不断寻找新的方法,为制造车间经理提供所需的工具,以最大限度地减少设备停机时间和优化正常运行时间。通过将可穿戴设备与预测性维护传感器相连接,推送通知可以最大限度地缩短检测到故障零件或设备与对所述零件进行定期维护和修理之间的时间。

在零售领域,商场经理可以利用可穿戴设备为客户服务代表提供产品信息、库存状态等,以提供卓越的店内体验。最近的研究显示大多数零售和消费品公司正在大力投资于产品和服务的个性化——可穿戴技术为这些零售商提供了以前无法想象的个性化店内功能。

医疗保健专业人员可以利用可穿戴设备即时访问病历,简化签到和分诊流程,并普遍改善住院护理。研究显示医疗保健专业人员已经开始在他们的各种流程和治疗中采用数字能力,但仍有增长空间。可穿戴技术的采用可能会成为医疗保健领域广泛采用数字技术的转折点。用例确实是无限的,但设备对用户的直接影响并不是广泛可穿戴实施的唯一好处。

跨工作流优化可穿戴数据

就像任何其他物联网设备一样,可穿戴设备将为企业提供有价值的数据,这些数据可以被聚合并在其他工作流中投入使用。例如,从可穿戴物联网设备收集的现场服务数据可以为库存管理和终端设备耐用性的优先级和最佳实践提供信息。如果某个设备缺陷是现场服务维护的主要原因,那么企业可以对终端产品设计进行更改,以解决这些问题。

同样,如果零售商为其客户服务专家采用可穿戴设备功能,他们将能够实时了解客户的购买趋势。这将有助于优化库存管理和减少不必要的过剩。它还为零售商提供了关于客户如何与其物理空间互动的见解。通过可穿戴和移动支付选项,零售商可能会发现不需要实体销售点。通过非接触式支付或移动钱包集成等方法,可穿戴物联网设备最终也将能够作为一种支付方式(无需大型笨重的 POS 机)。

可穿戴物联网设备为所有不同行业的企业提供了更高的移动性和敏捷性。迄今为止,企业一直明智地在其供应链战略和客户体验能力的各个接触点采用物联网技术。也就是说,技术在不断变化,单靠物联网投资不足以带来竞争优势。虽然可穿戴投资可能不是主流,但早期采用者肯定会受益——能够简化物联网流程,并激活通过这些设备收集的各种工作流的宝贵数据。可穿戴物联网设备不仅仅是支持个人用户,它们还能提供大规模的指数级价值。

用深度显微镜揭示生物学

原文:https://towardsdatascience.com/unveiling-biology-with-deep-microscopy-bcfbc39a02d6?source=collection_archive---------29-----------------------

人工智能引发的生命科学革命

Source: Shutterstock

随着历史上最重要的两项发明——望远镜和显微镜的发展,科学革命在 17 世纪初开始了。借助望远镜,伽利略将注意力转向天空,光学的进步促使罗伯特·胡克和安东尼·范·列文虎克在大约 1665 年首次将复合显微镜用作科学仪器。今天,我们正在见证显微镜领域的信息技术时代革命,深度学习算法推动了人工智能改变了一个又一个行业。

深度学习的一个重大突破出现在 2012 年,当时 Hinton 和他的同事[1]在 ImageNet 大规模视觉识别挑战赛( ILSVRC )中揭示了深度卷积神经网络结合 GPU 进行图像分类的性能优势。在人工智能当前的创新和实施阶段,深度学习算法正在推动几乎所有计算机视觉密集型应用,包括自动驾驶汽车(交通、军事)、面部识别(零售、IT、通信、金融)、生物医学成像(医疗保健)、自动武器和瞄准系统(军事)以及自动化和机器人(军事、制造、重工业、零售)。

毫不奇怪,通过人工智能辅助的图像处理、分析和解释,显微镜领域的变革已经成熟。在生物学研究中,显微镜产生大量的图像数据;使用透射电子显微镜进行的一次实验可以生成一个包含超过 100 万亿字节图像的数据集[2]。如今可用的无数仪器和图像处理技术可以解析从单个分子到整个生物体的近 10 个数量级大小的结构,并在飞秒到秒的时间尺度上捕捉空间(3D)和时间(4D)动态。

深度学习算法正在解决广泛的适用于生物图像的计算机视觉问题。这些包括图像分类和图像分割;目标检测和跟踪;图像风格转换、彩色化和重建;图像超分辨率和图像合成。这些任务中有许多非常适合深度学习方法。超分辨率定位显微镜已经取得了惊人的成果,与标准协议相比,新开发的深度学习技术 ANNA-PALM 可以在更少的图像上执行超分辨率图像重建[3]。

生物成像中深度学习的另一个强有力的例子来自冷冻电子显微镜(cryo-EM)的应用,用于为结构生物学家产生 1 到 5 埃分辨率的分子模型。要了解 cryo-EM 技术的价值,只需描绘出病毒、酶和大分子复合物以及超分子组装体的精致 3D 模型。要生成一个原子尺度的模型,需要数万甚至数十万张图像,图像处理工作流程复杂,难以完全自动化。在一个称为粒子拾取的步骤中,需要选择数十万个粒子(用于表示所有方向)来识别分子图像,然后这些图像被共同用于构建结构。人工神经网络(CNN)现在显示出解决工作流程中这一令人生畏的部分的前景[4]。

涉及深度显微镜的研究可以利用商业应用中的架构进行图像分类和分割,这是生物应用中的两个主要用例。目前缺少的是带注释的训练数据集。因此,迁移学习在启动生物数据图像分类器方面发挥了重要作用[5,6]。例如,通过将在另一个(非生物)数据集上训练的图像分类器的最后一层替换为适合于新分类任务的图像分类器的最后一层,随后可以在更小的注释数据集上重新训练该模型。细胞认知浏览器(https://software.cellcognition-project.org/是一个基于 Python 的工具,用于通过深度学习对细胞表型进行分类。

图像分割的新模式正在出现,以预测和识别图像中的不同对象,如细胞、细胞核、细丝和所有类型的细胞边缘和边界。几个例子是:http://www.deepcell.org 的 DeepCell 、http://github.com/vanvalenlab/deepcell-tf 的一个支持深度学习的单细胞分析的软件库【7】和 http://github.com/lmb-freiburg/Unet-Segmentation 的 U-Net 一个用于单细胞图像分割的 ImageJ 插件【8,9】。这两个软件库都将分割作为像素级分类任务,并为一组特征产生像素级预测。基于深度学习的分割正在对癌症研究产生影响,正如一种量化乳腺癌复杂肿瘤微环境中免疫细胞行为的优雅方法所显示的那样[10]。

深度学习的影响在神经科学领域表现得最为显著。许多与神经元电路、突触可塑性模型、网络的实时成像等相关的突出问题,正面临着拥有基于人工智能的方法的研究人员的挑战。

上周发表在《科学》杂志上的一篇具有里程碑意义的论文让人们得以一窥深度显微镜所带来的生物洞察力和发现的可能性。该研究小组的目标是使用 3D 电子显微镜重建位于小鼠皮层第 4 层内的一个小脑组织体积的整个连接模式——轴突、树突、突触前和突触后过程,尤其是突触。从一组总共 194 千兆字节数据的 3,400 幅图像中,分析管道生成了大量的信息,并导致了 89 个神经元的重建,其中连接矩阵由 34,221 个突触前过程和 11,400 个突触后过程组成。这个神经解剖学的杰作需要大约 100 名学生的众包努力,并使用几个人工智能算法来处理和生成结果。管道涉及 SegEM(使用 CNN 和分水岭)从 1500 万个体积片段生成特征;这些被输入连通性分类器 ConnectEM 和对象分类器 TypeEM(轴突、树突、棘头、神经胶质)。SynEM 用于对突触前和突触后片段进行分类。对输出进行的定量分析对神经元回路的形成产生了重要的见解,并描述了学习(即长期增强和长期抑郁)可能如何印在神经网络中。

深度显微镜正在为一个曾经主要由描述性研究驱动的领域提供新的实验范式。除了上面的例子,基于成像的人工智能驱动的协议也开始影响药物发现操作。递归制药(Recursion Pharmaceuticals)等公司正在形态分析中使用深度学习(称为基于图像的分析),以识别与药物反应和疾病相关状况相关的生物特征和变量。

以类似的方式,通过 3D 电子显微镜研究实现的密集大脑区域重建开辟了一种可能性,即现在可以使用基于图像的分析来表征和预测连接组表型。例如,在环境或药物暴露后,在疾病状态下以及作为基因变化的结果,可以跟踪突触水平上神经回路的变化,并产生新的治疗方法。同样显而易见的是,对由此产生的连通性图的进一步探索可以阐明连通性规则,并作为一种测试大脑信息处理操作的数学模型的方法。我们可能会接近一个良性循环,深度显微镜的发现会导致新的人工神经网络架构,从而可以更深入地探索生物学。

参考

[1] A. Krizhevsky、I. Sutskever 和 G. Hinton,使用深度卷积神经网络的 ImageNet 分类(2012),载于 Proc。神经信息处理系统的进展 251090–1098

[2] E. Moen,D. Bannon,T. Kudo 等,细胞图像分析的深度学习(2019),Nature Methods16:1233–1246【https://doi.org/10.1038/s41592-019-0403-1】T4

[3] W .欧阳,a .阿里斯托夫,m .勒莱克等,深度学习大规模加速超分辨率定位显微术(2018)Nat bio technol36,460–468https://www.nature.com/articles/nbt.4106

[4] T. Bepler,A. Morin,M. Rapp 等人,用于 cry 电子显微图中粒子拾取的正-无标记卷积神经网络。(2019),自然方法16:1153–1160https://doi.org/10.1038/s41592-019-0575-8

[5] W. Zhang,R. Li,T. Zeng 等,面向生物图像分析的基于深度模型的迁移和多任务学习(2016), IEEE Trans .大数据

[6] N .鲍洛夫斯基、J. C .凯塞多、s .辛格等人,《利用通用深度卷积网络实现形态分析自动化》(2016 年),预印本可在https://www.biorxiv.org/content/early/2016/11/02/085118 获得

[7]达·范·汪妮等,深度学习实现活细胞成像实验中单个细胞的定量分析自动化,(2016), PLoS Comput。Biol 。12,e1005177。doi:10.1371/journal.pcbi

[8] O. Ronneberger,P. Fischer 和 T. Brox,U-net:生物医学图像分割的卷积网络(2015),载于医学图像计算和计算机辅助干预-MICCAI 2015计算机科学讲义,第 9351 卷。瑞士查姆:施普林格。

[9] T. Falk,D. Mai,R. Bensch 等人,U-Net:细胞计数、检测和形态测量的深度学习(2019),Nature Methods16:67–70https://doi.org/10.1038/s41592-018-0261-2

[10] L. Keren,M. Bosse,D. Marquez 等,多重离子束成像揭示的三阴性乳腺癌中的结构化肿瘤免疫微环境(2018)Cell174(6):1373–1387 . e19 . doi:10.1016/j . Cell . 2018 . 08 . 039

[11] A. Motta,M. Berning,K. M. Boergens 等人体感皮层第 4 层的致密连接体重建(2019), Science 366,eaay3134

面向情感分析的文本预处理技术

原文:https://towardsdatascience.com/updated-text-preprocessing-techniques-for-sentiment-analysis-549af7fe412a?source=collection_archive---------17-----------------------

让我们讨论一些技术的缺点以及如何改进它们

Photo by Charles 🇵🇭 on Unsplash

人们使用了许多文本预处理技术,但是有多少是真正有用的呢?我从事文本数据工作已经快 6 个月了,我觉得当你开发一个会被很多人使用的产品时会遇到很多挑战。

这里有一些你随处可见的技巧-

  1. 移除数字、标点符号、表情符号等。
  2. 删除停用词
  3. 词汇化或词干化

移除数字后会发生什么?

数字在情感分析中起着重要的作用。怎么会?考虑你提供情绪分析服务的食品交付应用程序,通过文本反馈。现在,如果在文本预处理过程中你删除了所有的数字,那么你将如何区分两个反馈,即“我会给食物打 5 分,满分 5 分”和“我会给食物打 1 分,满分 5 分”。这只是一个例子。数字在很多情况下都发挥了作用。

移除表情符号会发生什么?

表情符号可以帮助你正确评估写评论的人的情绪。怎么会?如果有人写反馈“食物是😋另一个人写道,“食物是😖".在表情符号的帮助下,这个人想说的话清晰可见。还有更多的案例。

当你移除停用字词时会发生什么?

我在以前的文章中讨论过这个问题。如果你想深入了解,那么你一定要阅读这篇文章。

[## 为什么应该避免删除停用词

删除停用词真的能提高模型性能吗?

medium.com](https://medium.com/zykrrtech/why-you-should-avoid-removing-stopwords-aa7a353d2a52)

既然我们在这里,让我们快速讨论当停用字词被移除时会发生什么问题。删除停用词最常见的方法是借助 NLTK 库。NLTK 的停用词表也包含像 not、not、don 等这样的词,出于显而易见的原因,这些词不应该被删除,但这并不意味着你不应该删除任何停用词。

如果你正在使用像 TF-IDF,Count Vectorizer,BOW 这样的方法,那么就有必要删除停用词(不是全部),否则它们会产生很多噪音。使用预训练嵌入的深度学习方法是目前处理所有这些的最佳方法。深度学习方法的好处是它们不需要任何类型的预处理。如果你对深度学习方法更感兴趣,那么你可以看看我的文章

[## 超越传统的情感分析技术

传统方法失败在哪里?

medium.com](https://medium.com/analytics-vidhya/going-beyond-traditional-sentiment-analysis-technique-b9c91b313c07)

当你变元或变干时会发生什么?

Lemmatize 和 stem 都生成单词的词根形式,除了 stem 可能生成字典中不存在的单词。变元化比词干化使用得更广泛,对于本文,我们也考虑变元化。

当您使用 TF-IDF、CountVectorizer 或 BOW 模型时,引理化起着重要的作用。为什么?因为每个单词都会被还原成它的基本形式。例如——“狗”将被简化为“狗”。由于这些方法创建了一个稀疏矩阵,我们需要将所有单词转换成它们的基本形式,以减少唯一单词的数量。问题是,很多时候你会因为把一个单词转换成它的基本形式而失去它的上下文。

具有单词嵌入的深度学习情感分析遵循不同的方法。它将创建一个 n 维向量,而不是稀疏矩阵。所以,在 n 维向量中,像“狗”和“狗”这样的词会彼此更接近。因此,变元化的需要变得不必要。除此之外,矢量嵌入还有很多优点。

到目前为止,我们已经讨论了许多问题。其中一些仍在研究范围内,但我们可以尝试解决一些。

  1. 让我们从停用词问题开始。解决这个问题的最好办法是不要删除每一个在某种程度上有用的单词。然而,最好的方法是使用深度学习方法,像 Glove 一样预先训练嵌入,不需要删除停用词。
  2. 让我们谈谈第二个问题,即表情符号。我认为可行的解决方案是创建一个 python 字典,用一些单词替换所有出现的表情符号。这方面的一个例子是替换“😊“用‘快乐’或者也许别的什么。虽然这种方法看起来很幼稚,实际上也是如此,但它仍然比删除表情符号要好。
  3. 数字呢?深度学习是解决方案。

结论

深度学习方法真的好吗?

是的,他们更强大。DL 方法在预测时考虑词序。如果你把一个句子中的单词混在一起,然后应用 TF-IDF、CountVectorizer 或 BOW,那么得到相同结果的可能性就太高了。

最近,像 BERT,Robert 等预先训练的模型证明了 NLP 任务可以通过深度学习方法更好地完成。这些方法的优点是,它们的工作方式就像迁移学习一样,与从头开始训练它们相比,你实际上需要的例子要少得多。

如果你有兴趣了解更多关于情绪分析的工作原理,你可以在这里阅读—https://monkeylearn.com/sentiment-analysis/

更新非本地客户端缓存中的特定查询并重新呈现数据

原文:https://towardsdatascience.com/updating-apolloclient-cache-and-re-rendering-data-4537c11c6daf?source=collection_archive---------13-----------------------

使用 ApolloClient 的最大好处之一是开箱即用的自动内存缓存。当对数据进行分页时,这允许您返回到以前的页面,并且转换非常快。但是有时您不希望这些数据永远被缓存。有时候你希望能够清空缓存,从你的服务器上获取 新的 数据。您还希望这个触发一个 重新呈现 正在呈现该数据的任何组件。

我的问题

这是我最近在为公司开发数据可视化工具时发现自己处于的一种情况。我们有一个网络爬虫,它 24/7 爬行出版商的网页,并更新几个不同的数据库和表格。我们可以使用各种 regex、xpath 和元数据配置来操纵这个爬虫的行为,我们为每个发布者提供了这些配置。

我们面临的问题是,当对这些配置进行更改时,您希望能够看到您的更改在所有这些不同的数据库和表中的效果,这些数据库和表是由 crawler 更新的。以前,我们只是用大量的JOIN语句手动编写大量的 SQL 查询,以便在任何给定的时间点只查看我们需要的数据。这相当麻烦,有时真的会降低我们的速度。

因此,我构建了一个服务器,将所有这些数据库和各种表聚合成一个图(使用 Node.js、GraphQL、ApolloServer 和 MySQL)。然后我构建了一个 web 应用程序,它提供了大量的过滤器,我们可以使用这些过滤器只查看我们想要的数据(使用 Next.js 和 ApolloClient)。

因为我们从出版商那里抓取网站,这款应用被称为酒吧抓取

它处理大量的数据。以下是一个示例查询:

前端面临的主要挑战(由于 ApolloClient 出色的内存缓存)是让用户能够随意更新数据,这样他们就可以检查一些东西,对配置进行更改,然后看看效果如何。

挑战

搜索“清除阿波罗缓存”的方法并不是解决这个问题的好方法。不幸的是,我就是这么做的。

我了解到这样做是因为 Apollo 允许您访问缓存对象上的一个名为resetStore()的方法。该方法将清空整个缓存,并从服务器重新获取所有查询。我真的希望这能解决我的问题,因为它看起来很简单。

但事实并非如此,这让我很难过。

这不是为用例resetStore()构建的。这里的问题是它不会触发重新渲染,所以即使缓存中充满了新数据,用户也看不到它。我希望用户点击一个按钮,看到一个加载屏幕,然后看到新的数据。我也不想重置整个缓存,因为应用程序中的一些数据不会改变。

以狗为例的解决方案

让我们假设有一个页面向我们展示了一只狗。我们的数据库里有一只狗,但是这只狗变了。也许他洗了个澡,也许他在泥土里打滚。但是他很活跃,他的属性经常变化。

通过最初的查询,Apollo 让事情变得如此简单。您可以访问一些具有类似于loadingerrordata属性的状态。超级好看。它允许您编写这样的代码:

那太好了。可爱的开发者体验。

但是现在我们想用一个按钮刷新我们的狗。让我们给我们的 jsx 添加一个按钮:

那个按钮是做什么的?

事实证明,我们的useQuery()钩子也给了我们一个叫做refetch()的函数。这个功能太赞了。它允许您只刷新这一个查询的结果,或者甚至向它传递新的参数并获得结果。这解决了我之前提出的清除整个缓存的问题,但并没有为我们重新打开那个loading布尔值。因此,只有当数据提取完成时,它才会重新呈现。这对我来说是个问题,因为我需要我的用户知道他们的数据正在被重新加载,而不仅仅是信任这个按钮。有可能数据没有改变,在这种情况下,用户不会看到任何事情发生!

经过大量的黑客攻击,我发现阿波罗给了我们一个工具,当重取开始时触发我们的重渲染。这是由useQuery()钩子返回的networkStatus。要使用它,我们需要向钩子传递一个选项,告诉它在networkStatus改变时提醒我们(在重取时它会改变)。这个选项是notifyOnNetworkStatusChange

现在我们可以说“如果网络状态是重新获取,显示加载组件”。其状态代码为4。因此,我们可以将其添加到我们的loading检查中:

现在让我们为调用refetch()函数的按钮创建一个点击处理程序:

*import { useQuery } from '[@apollo/react-hooks](http://twitter.com/apollo/react-hooks)';
import Loading from './Loading';
import Error from './Error';
import Dog from './Dog';
import { DOG_QUERY } from '../lib/queries';export default () => {
  const { data, error, loading, refetch, networkStatus } = useQuery(
    DOG_QUERY,
    { notifyOnNetworkStatusChange: true }
  ); 

  if (loading || networkStatus === 4) return <Loading />;
  if (error) return <Error error={error} />;

  return (
    <>
      <button 
        type="button" 
        role="button"
        onClick={() => refetch()}
      >
        See what's new with the dog
      </button>
      <Dog dog={data.dog} />
    </>
  );
}*

仅此而已。现在,当我们单击按钮时,我们将看到<Loading />组件,缓存将刷新,然后我们将在<Dog />组件中看到新的狗数据。

就这样

我希望这对你有帮助。我知道我被困在这几个小时仅仅是因为我谷歌了错误的词。希望你不会遇到同样的问题!

欢迎在推特上关注我 @sour_utley

如果你(出于某种奇怪的原因)想看看我为我的公司制作的工具的回购,它住在这里。此外,如果您对 Carbon 的 iframes 有任何问题,页面上的代码如下:

*import { useQuery } from '[@apollo/react-hooks](http://twitter.com/apollo/react-hooks)';
import Loading from './Loading';
import Error from './Error';
import Dog from './Dog';
import { DOG_QUERY } from '../lib/queries';export default () => {
  const { data, error, loading, refetch, networkStatus } = useQuery(
    DOG_QUERY,
    { notifyOnNetworkStatusChange: true }
  ); 

  if (loading || networkStatus === 4) return <Loading />;
  if (error) return <Error error={error} />;

  return (
    <>
      <button 
        type="button" 
        role="button"
        onClick={() => refetch()}
      >
        See what's new with the dog
      </button>
      <Dog dog={data.dog} />
    </>
  );
}*

再见!

免费在 Google Colab 上升级您的内存

原文:https://towardsdatascience.com/upgrade-your-memory-on-google-colab-for-free-1b8b18e8791d?source=collection_archive---------3-----------------------

将 12GB 限制增加到 25GB

oogle Colab 真的是天赐之物,为每个人的深度学习项目提供免费的 GPU 资源。然而,有时我确实发现缺乏记忆。但是不要担心,因为实际上有可能免费增加 Google Colab 上的内存,并为您的机器学习项目增加涡轮增压器!每个用户当前分配有 12 GB 的 RAM,但这不是一个固定的限制,您可以将其升级到 25GB。看来“天下没有免费的午餐”这句话在这种情况下并不成立…

因此,不再拖延,我将介绍如何免费从目前的 12GB 升级到 25GB。这个过程其实很简单,只需要 3 行代码!连接到运行时后,只需键入以下代码片段:

a = []
while(1):
    a.append(‘1’)

Github 上为这段代码片段鸣谢 klazaj!

就是这样——多简单啊!简单地执行代码块,然后坐下来等待。大约一分钟后,您将收到来自 Colab 的通知,说“您的会话崩溃了”(相信我,你真的会很高兴看到这条消息)。

You will receive a message on the bottom left side of your screen saying your session has crashed

接下来会出现一个屏幕,询问您是否想切换到高 RAM 运行时。

Yes, definitely more RAM please!

点击是,你将获得 25GB 的内存。太棒了!

Notice the new 25.51 GB limit. (And yes, Corgi Mode!)

当然,让我们都负起责任,用好谷歌好心为我们提供的这些额外的内存。我非常感谢谷歌为我们提供了这个免费的平台来运行我们的机器学习和深度学习项目。我从这项免费服务中受益匪浅,并将永远感激不尽!

这个帖子到此为止。祝每个人在机器学习的努力中取得巨大成功!

这篇文章也发表在我的博客里。

隆起建模

原文:https://towardsdatascience.com/uplift-modeling-e38f96b1ef60?source=collection_archive---------2-----------------------

使用 Python 实现数据驱动的增长

最大化营销活动的增量回报

这一系列文章旨在解释如何以一种简单的方式使用 Python,通过将预测方法应用于您的所有行动来推动您公司的发展。它将是编程、数据分析和机器学习的结合。

我将在以下九篇文章中讨论所有主题:

1- 了解你的衡量标准

2- 客户细分

3- 客户终身价值预测

4- 流失预测

5-预测下一个购买日

6-预测销售额

7-市场反应模型

8-隆起建模

9- A/B 测试设计和执行

文章将有自己的代码片段,使您可以轻松地应用它们。如果你是编程的超级新手,你可以在这里很好地介绍一下 PythonPandas (一个我们将在任何事情上使用的著名库)。但是仍然没有编码介绍,您可以学习概念,如何使用您的数据并开始从中产生价值:

有时候你必须先跑,然后才能走——托尼·斯塔克

作为先决条件,确保你的电脑上安装了 J upyter Notebook 和 P ython 。代码片段只能在 Jupyter 笔记本上运行。

好吧,我们开始吧。

第 8 部分:隆起建模

成长黑客最关键的工作之一是尽可能高效。首先你需要省时。这意味着你必须快速构思、实验、学习和重复。第二,你需要是性价比。它意味着给定的预算/时间/努力带来最大的回报。

细分帮助成长型黑客提高转化率,从而更具成本效益。但是想象一下这样一种情况,你将要发起一个促销活动,并且你知道你想要针对哪个细分市场。你需要把报价发给每个人吗?

答案是否定的。在你目前的目标群体中,无论如何都会有顾客购买。给你升职会让你失去自我。我们可以根据这种方法对细分市场进行如下总结:

  • 治疗响应者:只有收到报价才会购买的顾客
  • 处理无响应者:无论如何都不会购买的客户
  • 控制响应者:无报价购买的客户
  • 控制不响应者:如果客户没有收到报价,他们将不会购买

画面很明显。你需要瞄准治疗反应者( TR )和控制无反应者( CN )。因为除非你出价,否则他们不会购买,所以这些团体正在促销活动中提升你的地位。另一方面,你需要避免针对治疗无反应者( TN )和对照反应者( CR )。你不会从针对 TN 和 CN 中获益,CN 会让你自相残杀。

还有最后一件简单的事情要做。我们需要确定哪些客户属于哪个类别。答案是隆起建模。它有两个简单的步骤:

1-预测所有客户在每个组中的概率:我们将为此建立一个多分类模型。

2-我们将计算提升分数。提升分数的公式为:

我们将被 TRCN 的概率相加,减去落入其他桶的概率。更高的分数意味着更高的提升。

好的,让我们看看如何用一个例子来实现它。我们将在上一篇文章中使用相同的数据集,您可以在这里 找到

我们从导入我们需要的库和函数开始:

然后我们将导入我们的数据:

df_data = pd.read_csv('response_data.csv')
df_data.head(10)

正如您在上一篇文章中回忆的那样,我们有收到折扣和买一送一优惠的客户的数据,以及他们的反应。我们还有一个对照组,没有收到任何东西。

列描述如下:

  • 最近:自上次购买以来的月数
  • 历史:历史采购的价值
  • used_discount/used_bogo:指示客户是否使用了折扣或先买一送一
  • zip_code:邮政编码的分类,如郊区/城市/农村
  • is_referral:指示客户是否是从推荐渠道获得的
  • 渠道:客户使用的渠道,电话/网络/多渠道
  • 报价:发送给客户的报价,折扣/买一送一/无报价

在构建模型之前,让我们应用我们的calc _ upgrade函数来查看作为基准的该活动的当前提升:

calc_uplift(df_data)

折扣的转换提升为 7.66%,买一送一(BOGO)的转换提升为 4.52%。

接下来,我们将开始构建我们的模型。

预测抬升得分的多分类模型

目前,我们的标签是客户是否转换(1 或 0)。我们需要为 TRTNCR、CN 创建四个类。我们知道收到折扣和 bogo 优惠的客户是治疗,其余的是控制。让我们创建一个 campaign_group 列来显示这些信息:

df_data['campaign_group'] = 'treatment'
df_data.loc[df_data.offer == 'No Offer', 'campaign_group'] = 'control'

太好了,现在我们需要创建我们的新标签:

df_data['target_class'] = 0 #CN
df_data.loc[(df_data.campaign_group == 'control') & (df_data.conversion > 0),'target_class'] = 1 #CR
df_data.loc[(df_data.campaign_group == 'treatment') & (df_data.conversion == 0),'target_class'] = 2 #TN
df_data.loc[(df_data.campaign_group == 'treatment') & (df_data.conversion > 0),'target_class'] = 3 #TR

在本例中,类的映射如下:

  • 0 ->控制无响应者
  • 1 ->控制响应者
  • 2 ->治疗无反应者
  • 3 ->治疗响应者

在训练我们的模型之前,有一个小的特征工程步骤。我们将从历史列创建聚类,并应用 get_dummies 将分类列转换为数字列:

#creating the clusters
kmeans = KMeans(n_clusters=5)
kmeans.fit(df_data[['history']])
df_data['history_cluster'] = kmeans.predict(df_data[['history']])#order the clusters
df_data = order_cluster('history_cluster', 'history',df_data,True)#creating a new dataframe as model and dropping columns that defines the label
df_model = df_data.drop(['offer','campaign_group','conversion'],axis=1)#convert categorical columns
df_model = pd.get_dummies(df_model)

让我们拟合我们的模型,并获得每一类的概率:

#create feature set and labels
X = df_model.drop(['target_class'],axis=1)
y = df_model.target_class#splitting train and test groups
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=56)#fitting the model and predicting the probabilities
xgb_model = xgb.XGBClassifier().fit(X_train, y_train)
class_probs = xgb_model.predict_proba(X_test)

变量 class_probs 拥有每个客户的概率。让我们来看一个例子:

对于该特定客户,我们可以将概率映射如下:

  • 中国:32%
  • CR: 2%
  • 总人口:58.9%
  • TR: 6.9%

因此,该客户的提升分数为:

0.32+0.069-0.02-0.589 =-0.22

让我们将此应用于所有用户,并计算提升分数:

#probabilities for all customers
overall_proba = xgb_model.predict_proba(df_model.drop(['target_class'],axis=1))#assign probabilities to 4 different columns
df_model['proba_CN'] = overall_proba[:,0] 
df_model['proba_CR'] = overall_proba[:,1] 
df_model['proba_TN'] = overall_proba[:,2] 
df_model['proba_TR'] = overall_proba[:,3]#calculate uplift score for all customers
df_model['uplift_score'] = df_model.eval('proba_CN + proba_TR - proba_TN - proba_CR')#assign it back to main dataframe
df_data['uplift_score'] = df_model['uplift_score']

通过运行上面的代码,我们在主数据帧中添加了一个upgrade _ score列,如下所示:

是时候检查拥有这个模型最关键的部分了。模型真的有效吗?评价隆起建模的真实性能有点困难。我们将检查上升分数分位数之间的上升是如何变化的,以查看我们是否可以在现实生活中使用该模型。

模型评估

为了评估我们的模型,我们将创建两个不同的组,并将它们与我们的基准进行比较。组包括:

1-高提升分数:客户的提升分数大于第三个分位数

2-提升得分低:客户的提升得分< 2nd quantile

We are going to compare:

  • Conversion uplift
  • Revenue uplift per target customer to see if our model can make our actions more efficient.

Here is our benchmark for the discount campaign.

Total Targeted Customer Count: 21307
Discount Conversion Uplift: 7.66%
Discount Order Uplift: 1631.89
Discount Revenue Uplift: $40797.35
Revenue Uplift Per Targeted Customer: $1.91

Let’s create the first group and see the numbers:

df_data_lift = df_data.copy()
uplift_q_75 = df_data_lift.uplift_score.quantile(0.75)
df_data_lift = df_data_lift[(df_data_lift.offer != 'Buy One Get One') & (df_data_lift.uplift_score > uplift_q_75)].reset_index(drop=True)#calculate the uplift
calc_uplift(df_data_lift)**results:** User Count: 5282
Discount Conversion Uplift: 12.18%
Discount Order Uplift: 643.57
Discount Revenue Uplift: $16089.36
Revenue Uplift Per Targeted Customer: $3.04

The results are great. Revenue uplift per target customer is 57% 更高,我们很容易看到目标群体的 25% 贡献了 40% 的收入提升。

我们将检查提升分数较低的组的相同数字:

df_data_lift = df_data.copy()
uplift_q_5 = df_data_lift.uplift_score.quantile(0.5)
df_data_lift = df_data_lift[(df_data_lift.offer != 'Buy One Get One') & (df_data_lift.uplift_score < uplift_q_5)].reset_index(drop=True)#calculate the uplift
calc_uplift(df_data_lift)**results:** User Count: 10745
Discount Conversion Uplift: 5.63%
Discount Order Uplift: 604.62
Discount Revenue Uplift: $15115.52
Revenue Uplift Per Targeted Customer: $1.4

正如预期的那样,每个目标客户的收入增长降至 $1.4 。此外,该集团有 50% 的目标客户贡献了 37% 的收入提升。

通过使用这种模式,我们可以通过以下方式轻松提高营销活动的效率:

  • 根据提升分数锁定特定细分市场
  • 根据客户的提升分数尝试不同的优惠

在下一篇文章中,我将解释增长黑客的核心要素之一: A/B 测试 。这将是我们这个系列的最后一篇文章。

你可以在这里找到这篇文章的 Jupyter 笔记本。

需要帮助来发展你的公司吗?在此与我预约免费课程。

上传大文件到 GitHub

原文:https://towardsdatascience.com/uploading-large-files-to-github-dbef518fa1a?source=collection_archive---------1-----------------------

3 种避免在上传过程中收到错误信息的方法

Photo by Jay Wennington on Unsplash

GitHub 有严格的 100MB 文件限制。如果你只是上传几行代码,这不是你需要担心的事情。然而,如果你想上传一点数据,或者二进制的东西,这是一个你可能想要跨越的限制。这里有三种不同的方法来克服 100MB 的限制

原载于我的博客edenau . github . io

1.。gitignore

创建一个文件 。gitignore 在存储库的父目录中,存储所有希望 Git 忽略的文件目录。使用*作为通配符,这样您就不需要在每次创建新的大文件时手动添加文件目录。这里有一个例子:

*.nc
*.DS_store

这些被忽略的文件会被 Git 自动忽略,不会上传到 GitHub。不再有错误消息。

2.仓库清理器

如果你不小心在本地提交了超过 100MB 的文件,你将很难把它推送到 GitHub。它不能通过删除大文件并再次提交来解决。这是因为 GitHub 跟踪每一次提交,而不仅仅是最近一次。从技术上讲,您是在整个提交记录中推送文件。

Photo by Samuel Zeller on Unsplash

虽然您可以通过分支在技术上解决它,但这绝不是简单的。幸运的是,您可以运行一个 库清理器 ,它会自动清理所有的大文件提交。

下载 BFG 回购清理器 bfg.jar 并运行以下命令:

java -jar [bfg.jar](https://rtyley.github.io/bfg-repo-cleaner/#download) --strip-blobs-bigger-than 100M <your_repo>

它会自动清理您的提交,并生成一个新的提交,注释为“删除大文件”。按下它,你就可以走了。

3.吉特 LFS

你可能已经注意到,上述两种方法都避免上传大文件。如果您真的想上传它们,以便在另一台设备上访问它们,该怎么办?

Git 大文件存储让你把它们存储在一个远程服务器上,比如 GitHub。将 git-lfs 放入您的 $PATH 中下载并安装 。然后,您需要对每个本地存储库运行一次下面的命令:

git lfs install

大文件由以下人员选择:

git lfs track '*.nc'
git lfs track '*.csv'

这会创建一个名为 的文件。gitattributes ,瞧!您可以正常执行添加和提交操作。然后,你首先需要 a)将文件推送到 LFS,然后 b)将指针推送到 GitHub。以下是命令:

git lfs push --all origin master
git push -u origin master

Photo by Lucas Gallone on Unsplash

Git LFS 上的文件可以在 GitHub 上找到,标签如下。

为了将存储库拉到另一个设备上,只需在那个设备上安装 git-lfs (每个本地存储库)。

相关文章

感谢您的阅读!如果您对数据科学感兴趣,请查看以下文章:

[## 我希望我能早点知道的 5 个 Python 特性

超越 lambda、map 和 filter 的 Python 技巧

towardsdatascience.com](/5-python-features-i-wish-i-had-known-earlier-bc16e4a13bf4) [## 为什么样本方差除以 n-1

解释你的老师没有教过的高中统计学

towardsdatascience.com](/why-sample-variance-is-divided-by-n-1-89821b83ef6d)

原载于我的博客edenau . github . io

使用 SMOTE 对分类项目进行上采样

原文:https://towardsdatascience.com/upsampling-with-smote-for-classification-projects-e91d7c44e4bf?source=collection_archive---------15-----------------------

或者我是如何学会开始担心阶级不平衡的

https://www.researchgate.net/figure/Graphical-representation-of-the-SMOTE-algorithm-a-SMOTE-starts-from-a-set-of-positive_fig2_317489171

你是否曾经对自己说:“世界上没有足够的坏酒。”?

真的吗?只有我吗?好吧,我应该解释一下。我最近在处理一个葡萄酒数据集的分类问题。基本上,我有葡萄酒的化学成分值和平均用户评级,表面上是 1-10 的评级尺度,10 是最高的。

现在看来,人们并不真的很擅长分辨高档酒和廉价酒。这让我的前提变得非常简单:确定对大多数人来说尝起来像醋的葡萄酒,其他任何葡萄酒对大多数餐馆来说都很好。所以我把“坏”酒(在这个实验中,那些评分为 3 和 4 的)和“好”酒(其他的)区分开来。

但是有一个问题:我没有喝足够的烈酒。

Oh bother.

我的红酒数据库中只有 61 种“坏”酒,而有 1286 种“好”酒。“好”和“坏”的比例是 21:1。事实上,我的模型很可能每次都简单地预测多数类。我需要找到一种方法来平衡这些课程。要是以前有人碰到过这个问题就好了…

对,当然。每个数据科学家都遇到过这个问题。我知道。答案显然是重新采样。

重采样与合成采样

首先简单介绍一下重采样。谈到重采样,基本上有两大阵营:过采样和欠采样。欠采样是从多数类(在这种情况下是“好”葡萄酒)中随机选择观察值的过程,以便它具有与少数类相等数量的观察值(例如,我最终得到 61 个“好”葡萄酒和 61 个“坏”葡萄酒)。这在我的情况下不起作用,因为欠采样意味着我会丢失大部分观察结果,从而丢失我的信息。

那么过采样。过采样是指我们为少数类创建新的观察值,这些观察值在我们现有的数据中并不存在。通常,这是通过从少数类中复制观测值并将其添加到数据集中来实现的,因此您可以增加少数类的大小。

好消息是,您的模型将了解更多关于少数民族的信息,而不仅仅是针对给定的观察预测多数民族。坏消息是,它也可能会过度适应那些你已经重复多次的观察的特征。这就是 SMOTE 的用武之地。

击杀

SMOTE 代表合成少数过采样技术。SMOTE 执行与基本重采样相同的基本任务(为少数类创建新的数据点),但它不是简单地复制观测值,而是沿着随机选择的点及其最近邻创建新的观测值。基本上,您是在模拟数据中的一些额外变化(在您的少数类的既定范围内),减少了过度拟合的危险(尽管没有消除)。

下一个问题(对我来说也是一个大问题)是我们应该把少数民族班级扩大到多大?要回答这个问题,我需要思考我在尝试优化我的模型是为了什么。在我的例子中,我试图正确地识别“坏”酒。我不介意错误地将一些实际上还不错的葡萄酒归类为“劣质”,因为世界上有很多葡萄酒可供选择,但我想确保我们找到了劣质酒。这意味着我需要优化召回,以避免假阴性。

现在我知道我在优化什么了,我应该追求什么样的多数:少数比例?我看过很多在少数和多数类之间建立 1:1 关系的教程,但这意味着 1000+新的综合观察。在大量阅读和一些实验之后,我最终得到了一个占最终完整数据集 15%的少数民族班级。

下面是一些代码!

这大概就是你要找的。下面是实际执行上采样的几个函数。请注意,这应该在您完成培训/测试分割后进行。首先,我们将这些类分开:

def resamplingDataPrep(X_train, y_train, target_var): 
    # concatenate our training data back together
    resampling = X_train.copy()
    resampling[target_var] = y_train.values
    # separate minority and majority classes
    majority_class = resampling[resampling[target_var]==0]
    minority_class = resampling[resampling[target_var]==1]
    # Get a class count to understand the class imbalance.
    print('majority_class: '+ str(len(majority_class)))
    print('minority_class: '+ str(len(minority_class)))
    return majority_class, minority_class

然后执行上采样本身:

def upsample_SMOTE(X_train, y_train, ratio=1.0):
    """Upsamples minority class using SMOTE.
    Ratio argument is the percentage of the upsampled minority class in relation
    to the majority class. Default is 1.0
    """
    sm = SMOTE(random_state=23, sampling_strategy=ratio)
    X_train_sm, y_train_sm = sm.fit_resample(X_train, y_train)
    print(len(X_train_sm), len(y_train_sm))
    return X_train_sm, y_train_sm

就是这样!

击打纸张

互动地图上的美国制药公司:通过排名和人工智能(AI)的使用进行分类

原文:https://towardsdatascience.com/us-pharmaceutical-companies-on-an-interactive-map-categorized-by-ranking-and-the-use-of-b22a3bc98945?source=collection_archive---------14-----------------------

简介:

上周,我有机会参加了由美国孟加拉药物科学家协会在马里兰州贝塞斯达举办的会议。在会议上,我与来自制药行业和 FDA 的人交谈。在那些谈话中,我发现大多数在位于该国东海岸的制药公司工作的人,令人惊讶的是,该国有许多我从未听说过的公司。我合理地问自己,“大多数制药公司都位于东海岸吗?或者它们是如何分布在各州的?为什么我没有听说过这些公司的名字”?。在谷歌上快速搜索“美国制药公司”给了我几个链接。其中,这两个(drugs.com 和 rxlist.com)网站很有帮助,到目前为止,drugs.com 包含了更多的信息。所以,我开始用 python 保存所有公司的信息,包括它们在 drugs.com 的地址。

数据:

这里是我写的代码的快照,但是为了保持文章简短,我不会在这里分享所有的代码。

这个代码让我想到网站上有 404 家公司。所以,我开始从链接中收集这些公司的地址。大约有 80 个链接是灰色的,我发现它们要么被大公司收购,要么是大公司的一部分。所以,我剩下了大约 320 个链接。在第一次尝试中,我保存了 262 家公司的信息,包括名称、完整地址、网站和职业页面链接。在另一次尝试中,它只给了我一些公司的信息(名称和地址)。然后,我手动添加了一些数据,总共创建了 308 家公司的信息,包括它们在该国的实际地址。

第一张地图:

现在,我使用名为“googlegeocoder”的 python 库找到了这 308 个物理地址的纬度和经度。然后,我用 python 的“叶子”库创建了我的第一张地图。现在我想知道,如何在地图上找到顶尖的制药公司?

更多数据:

接下来,我在谷歌上搜索顶级制药公司,结果发现 pharmexec.com 是排名前 50 的制药公司的好来源。由于它们被列为图片或带有各自公司的标志,我无法使用我的编码技能。但我还是想回答之前被问到的问题。因此,当我在实验室用脱脂牛奶封闭蛋白质印迹膜时,我不得不手动收集数据。在我对制药公司的信息进行研究期间,我发现相当多的公司将人工智能(AI)用于药物发现,这篇文章题为“33 家制药公司在药物发现中使用人工智能”。这就是为什么我很好奇,想看看地图,看看哪些公司一直在使用人工智能。

这些数据如下所示:

最终地图:

有了这些数据,我就能制作出我的最终地图了。点击下面的链接查看。

制药 _ 地图

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

https://bit.ly/2NWBT7u

你可以放大和缩小左上角的按钮。你也可以用光标拖动和移动页面。

地图上的颜色是如何工作的?

如果你点击彩色图标,它会显示公司的名称和一些其他信息,如下图所示。

  • 如果一家公司被列为 50 强并使用人工智能,它将被标记为-红色
  • 顶部但不使用人工智能-蓝色
  • 不顶但是用 AI-紫色
  • 不顶也不用 AI——绿色。

现在,我可以想象你在想什么。你想要资源(代码、数据)还玩它!!所有代码和数据都可以在我的 github_page 上找到

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

最初发表于 linkedin

参考资料:

  1. Drugs.com 制药公司。从 https://www.drugs.com/pharmaceutical-companies.html取回
  2. 克里斯特尔,M. (2019)。pharm Exec 2019 年 50 强企业。从 http://www.pharmexec.com/pharm-execs-top-50-companies-2019取回
  3. 史密斯,S. (2017)。33 家制药公司在药物研发中使用人工智能。检索自https://blog . bench sci . com/pharma-companies-using-artificial-intelligence-in-drug-discovery

我的 linkedin

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

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

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

用 AI 用 Cloudsight + Python 为图片写标题

原文:https://towardsdatascience.com/use-ai-to-write-captions-for-images-with-cloudsight-python-a82115f16ab8?source=collection_archive---------27-----------------------

Pythonic API 允许您自动为图像编写人类可读的标题

How would you caption this? Credit: Gado Images.

如今市场上有很多使用人工智能和机器学习来标记图像的解决方案。IBM Watson、Imagga、Cloudsight、Google Vision 和微软 Azure 的解决方案都表现良好,通过 Algorithmia 等服务,你可以轻松地启动和训练自己的图像标记网络。

然而,为图像编写人类可读的句子长度的标题是一项更困难的任务。您生成的句子不仅需要准确描述场景中的对象,还需要捕捉它们彼此之间的关系、上下文等。它需要知道什么才是真正重要的——没有人想要一个对桌子上的每一个物体或背景中的每一株植物都进行详细描述的图像。当人工智能知道得太多时,它可能比知道得太少更糟糕。

总部位于洛杉矶的初创公司 Cloudsight 正致力于解决使用人工智能和机器学习来自动为图像编写句子长度、人类可读的字幕的挑战。

他们为特定应用提供完全定制的人在回路系统,但他们也有一个通用模型,你可以很快开始测试,并返回一些令人印象深刻的结果。这是他们唯一的人工智能系统,但同样,你也可以将其插入人类团队,并获得更好的输出(以更高的价格和更多的训练时间)。

入门指南

要开始使用 Cloudsight API 进行测试,您不能像在 IBM 或 Google Vision 中那样注册一个帐户。Cloudsight 是一家新兴公司,他们喜欢与潜在的新客户进行合作,尤其是在早期测试阶段。

好消息是他们反应很快。通过他们网站上的联系方式联系他们,他们通常会在几个小时后回来。你甚至可能会听到他们的首席执行官或团队的高级成员的消息。Cloudsight 通常可以提供 API 访问和一定数量的免费 API 调用来进行测试。我得到了 1000 个免费的 API 调用来开始。

一旦你联系并设置好了,他们会给你一个 API 密匙。

准备 Python

方便的是,Cloudsight 有一个随时可用的 Python 库。

用 pip 安装。

pip install cloudsight

如果你还没有,我也喜欢通过 Pillow 安装 PIL,这是一个图像处理库。

pip install pillow

预处理

首先,选择要处理的图像。我将使用本文顶部的那张照片,它是由我公司的一位新西兰摄影师拍摄的。

设置基本导入。

from PIL import Imageimport cloudsight

我喜欢先通过 PIL 的缩略图功能将图像缩小到标准尺寸。这使得它更小,更容易上传。如果你不这样做,Cloudsight 会帮你做,但是发送更少的字节更容易,所以你也可以在你这边精简一下。

这是标准的东西——你接收图像,使用缩略图功能使其大小一致,然后再次保存。

im = Image.open('YOURIMAGE.jpg')im.thumbnail((600,600))im.save('cloudsight.jpg')

打电话

现在您已经有了一个经过适当处理的图像,您可以进行实际的 API 调用了。首先,使用 API 密钥进行身份验证。

auth = cloudsight.SimpleAuth('YOUR KEY')

接下来,打开您的图像文件,并发出请求:

with open('cloudsight.jpg', 'rb') as f:
    response = api.image_request(f, 'cloudsight.jpg',  {'image_request[locale]': 'en-US',})

接下来的一点有点出乎意料。因为 Cloudsight 有时会有人参与,所以您需要给他们几秒钟或更长的时间来完成他们的请求。这与 API 对 Watson 等标签服务的请求略有不同,后者往往会立即完成。

使用 Cloudsight,您可以调用 wait 函数,并定义最大等待时间。30 秒通常足够了。

status = api.wait(response['token'], timeout=30)

最后,打印出响应!

print status

回应

Cloudsight 将返回一个包含响应数据的对象。这是我得到的上面的图像。

{u'status': u'completed', u'name': u'man in gray crew neck t-shirt sitting on brown wooden chair', u'url': u'https://assets.cloudsight.ai/uploads/image_request/image/734/734487/734487841/cloudsight.jpg', u'similar_objects': [u'chair', u't-shirt', u'crew neck'], u'token': u'fgo4F5ufJsQUCLrtwGJkxQ', u'nsfw': False, u'ttl': 54.0, u'structured_output': {u'color': [u'gray', u'brown'], u'gender': [u'man'], u'material': [u'wooden']}, u'categories': [u'fashion-and-jewelry', u'furniture']}

这是非常酷的东西!正如你所看到的,系统给图片加了标题“一个穿着灰色圆领 t 恤的男人坐在棕色的木椅上。”说得好极了!

除了非结构化的句子,API 还给我关于图像的结构化数据,比如图像中的颜色(灰色、棕色)、人的性别(男人)、类别和呈现的材料。

在一次调用中结合结构化和非结构化数据非常有帮助——您可以进行标记或语义映射,同时还可以获得人类可读的句子来描述图像。

这是完整的节目单。

from PIL import Imageimport cloudsight im = Image.open('YOUR IMAGE')im.thumbnail((600,600))im.save('cloudsight.jpg')auth = cloudsight.SimpleAuth('YOUR API KEY')api = cloudsight.API(auth)with open('cloudsight.jpg', 'rb') as f:response = api.image_request(f, 'cloudsight.jpg', {'image_request[locale]': 'en-US',})status = api.wait(response['token'], timeout=30)print status

这是一个句子长度的图像字幕,通过人工智能,大约 10 行代码!

从这里去哪里

如果您想在测试后扩大您对 Cloudsight 的使用,该团队可以帮助您为生产做好准备。他们不报一般价格,这完全取决于您的预计数量、使用情形和所需的任何额外培训。

如果通用模型的输出还不错,但并不完美,您还可以与团队合作,根据您的特定用例对其进行定制。例如,我正与他们合作,将人类部分引入到处理历史图像的循环中。定价可能会高于纯人工智能解决方案,但它也将更具体地针对我的用例。这是与新兴公司合作的最大好处,因为他们能更好地满足你的特殊需求。

如果你对自动图像字幕感兴趣,可以看看 Cloudsight!同样,使用 Python,您可以在几分钟内开始为您的图像添加字幕——或者只是使用这一新功能——而且只需很少的代码!

通过 Spring Boot 或 Java 使用 Apache Drill,使用 SQL 查询来查询数据

原文:https://towardsdatascience.com/use-apache-drill-with-spring-boot-or-java-to-query-data-using-sql-queries-f6e186a5f31?source=collection_archive---------32-----------------------

原文发布于此:https://blog . contact sunny . com/tech/use-Apache-drill-with-spring-boot-or-Java-to-query-data-using-SQL-queries

在过去的几篇文章中,我们看到了如何将 Apache Drill 与 MongoDB 连接起来,以及如何将与 Kafka 连接起来,使用简单的 SQL 查询来查询数据。但是,当您想将它应用到实际的项目中时,您不能整天坐在那里从终端查询数据。你想写一段代码来替你做脏活。但是如何在代码中使用 Apache Drill 呢?今天,我们将看看如何用 Spring Boot 或几乎任何其他 Java 程序来实现这一点。

依赖关系

对于这个概念验证,我将编写一个简单的 Spring Boot CommandLineRunner 程序。但是您可以使用几乎任何其他 Java 框架或普通的 Java 代码来实现这一点。如果你有一个依赖管理工具,比如 Maven 或者 Gradle,你可以在项目中添加依赖,然后继续编码。否则,可以添加所需的。jar 文件到类路径,这样应该就可以了。所有需要的。jar 文件随 Apache Drill 的发行版一起提供。

这个项目我们会和 Maven 一起去。在项目的 pom.xml 文件的依赖项部分中添加以下 Drill 依赖项。

<dependency>
	<groupId>org.apache.drill.exec</groupId>
	<artifactId>drill-jdbc-all</artifactId>
	<version>1.16.0</version>
</dependency>

这种依赖性在 Maven 中央存储库中是可用的,因此您不需要添加任何额外的存储库。

代码

现在让我们开始有趣的部分。首先,我们需要在 Java 代码中加载 Drill JDBC 驱动程序。为此,我们将使用 Class.forName() 方法:

Class.forName("org.apache.drill.jdbc.Driver");

接下来,我们需要使用 DriverManager 和 Drill JDBC 连接字符串创建一个连接。如果您使用 Apache Drill 的独立本地实例,则需要使用以下连接字符串:

jdbc:drill:drillbit=localhost

如果您将 Drill 与 Zookeeper 一起使用,则必须使用以下连接字符串:

*jdbc:drill:zk=local*

因为我使用的是本地实例,所以我将创建一个连接来进行如下钻取:

Connection connection = DriverManager.getConnection("jdbc:drill:drillbit=localhost");

接下来,我们需要创建一个语句对象,使用它我们将运行实际的查询。一旦我们有了对象,我们将使用。executeQuery() 方法在对象上得到我们的 ResultSet :

Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery("select * from kafka.`drill` limit 10");

我使用了与前面的 MongoDB 和 Kafka 示例相同的数据集和示例。

从上面的例子可以看出,我们从 Kafka 主题 drill 中获取数据。让我们看看如何访问数据:

while(resultSet.next()){
    logger.info("ID: " + resultSet.getString(1));
    logger.info("First Name: " + resultSet.getString(2));
    logger.info("Last Name: " + resultSet.getString(3));
    logger.info("Email: " + resultSet.getString(4));
    logger.info("Gender: " + resultSet.getString(5));
    logger.info("IP Address: " + resultSet.getString(6));
    logger.info("----------------------------------");
}

接下来,让我们查询一个 MongoDB 数据库并从中获取一些数据:

resultSet = statement.executeQuery("select * from mongo.drill.sampleData limit 10");

我们可以使用上面相同的 while() 循环来打印数据。

差不多就是这样。我们现在能够在 Java 程序中使用 Apache Drill 作为简单的 JDBC 源,从 Drill 支持的任何源获取数据。您可以对复杂的 SQL 查询进行同样的尝试,看看 Drill 是如何工作的。

如果你对这个例子中完整的 Spring Boot 项目感兴趣,你可以在我的 GitHub 简介上查看。

Google 的通用句子编码器在生产中的用例

原文:https://towardsdatascience.com/use-cases-of-googles-universal-sentence-encoder-in-production-dd5aaab4fc15?source=collection_archive---------3-----------------------

在自然语言处理(NLP)中建立任何深度学习模型之前,文本嵌入起着主要作用。文本嵌入将文本(单词或句子)转换成数字向量。

为什么我们要把文本转换成向量?

向量是特定维度的数字数组。一个 5×1 大小的向量包含 5 个数,我们可以把它看作 5D 空间中的一个点。如果有两个 5 维的向量,它们可以被认为是 5D 空间中的两点。因此,我们可以根据这两个向量之间的距离来计算它们的远近。

因此,在机器学习的研究中,大量的努力被投入到将数据转换成向量中,因为一旦数据被转换成向量,我们就可以通过计算它们的距离来判断两个数据点是否相似。像 Word2vec 和 Glove 这样的技术是通过将单词转换成矢量来实现的。因此“猫”的对应向量将比“鹰”更接近“狗”。但是在嵌入一个句子时,需要在这个向量中捕获整个句子的上下文以及单词。这就是“通用句子编码器”的用武之地。

通用语句编码器将文本编码成高维向量,这些向量可用于文本分类、语义相似性、聚类和其他自然语言任务。预训练的通用句子编码器在 Tensorflow-hub 公开提供。它有两种变化,即一种用变压器编码器训练,另一种用深度平均网络(DAN) 训练。这两者在准确性和计算资源需求之间有一个折衷。虽然具有变换器编码器的那个具有更高的精度,但是它在计算上更加密集。使用 DNA 编码的方法在计算上花费较少,并且准确性也稍低。

这里,我们将使用变压器编码器版本。在 5 GB ram 实例中,它与其他 5 个深度学习模型一起运行时,对我们来说效果很好。此外,我们可以使用这个版本的通用语句编码器在嵌入级别训练一个具有 150 万数据的分类器。我遇到的通用句子编码器的几个用例是:

  1. 作为深度学习模型开始时的嵌入层。
  2. 通过寻找语义相似的句子来执行分类。
  3. 在分析之前去掉重复的句子或短语。

让我们看看如何使用 Tensorflow-hub 上提供的预训练通用句子编码器,用于 python 中的上述用例。

首先,让我们导入所需的库:

import tensorflow as tf
import tensorflow_hub as hub

在生产中使用时,我们需要将预先训练好的通用语句编码器下载到本地,这样我们每次调用它时都不会被下载。

#download the model to local so it can be used again and again
!mkdir ../sentence_wise_email/module/module_useT
# Download the module, and uncompress it to the destination folder. 
!curl -L "[https://tfhub.dev/google/universal-sentence-encoder-large/3?tf-hub-format=compressed](https://tfhub.dev/google/universal-sentence-encoder-large/3?tf-hub-format=compressed)" | tar -zxvC ../sentence_wise_email/module/module_useT

在这里,”../sentence _ wise _ email/module/module _ useT”是下载句子编码器文件的文件夹。该编码器优化了大于单词长度的文本,因此可以应用于句子,短语或短段落。

例如(官方网站示例):

embed = hub.Module("../sentence_wise_email/module/module_useT")# Compute a representation for each message, showing various lengths supported.
word = "Elephant"
sentence = "I am a sentence for which I would like to get its embedding."
paragraph = (
    "Universal Sentence Encoder embeddings also support short paragraphs. "
    "There is no hard limit on how long the paragraph is. Roughly, the longer "
    "the more 'diluted' the embedding will be.")
messages = [word, sentence, paragraph]# Reduce logging output.
tf.logging.set_verbosity(tf.logging.ERROR)with tf.Session() as session:
    session.run([tf.global_variables_initializer(), tf.tables_initializer()])
    message_embeddings = session.run(embed(messages))for i, message_embedding in enumerate(np.array(message_embeddings).tolist()):
        print("Message: {}".format(messages[i]))
        print("Embedding size: {}".format(len(message_embedding)))
        message_embedding_snippet = ", ".join((str(x) for x in        message_embedding[:3]))
        print("Embedding[{},...]\n".
                   format(message_embedding_snippet))

它给出的输出:

Message: Elephant
Embedding size: 512
Embedding: [0.04498474299907684, -0.05743394419550896, 0.002211471786722541, ...]

Message: I am a sentence for which I would like to get its embedding.
Embedding size: 512
Embedding: [0.05568016692996025, -0.009607920423150063, 0.006246279925107956, ...]

Message: Universal Sentence Encoder embeddings also support short paragraphs. There is no hard limit on how long the paragraph is. Roughly, the longer the more 'diluted' the embedding will be.
Embedding size: 512
Embedding: [0.03874940797686577, 0.0765201598405838, -0.0007945669931359589, ...]

可以看出,无论是单词、句子还是短语,句子编码器都能够给出大小为 512 的嵌入向量。

如何在 Rest API 中使用

在 Rest API 中使用它时,您必须多次调用它。一次又一次地调用模块和会话将会非常耗时。(在我们的测试中,每次通话大约需要 16 秒)。可以做的一件事是调用模块并在开始时创建会话,然后继续重用它。(第一次呼叫需要大约 16s,然后连续呼叫需要大约. 3s)。

#Function so that one session can be called multiple times. 
#Useful while multiple calls need to be done for embedding. 
import tensorflow as tf
import tensorflow_hub as hub
def embed_useT(module):
    with tf.Graph().as_default():
        sentences = tf.placeholder(tf.string)
        embed = hub.Module(module)
        embeddings = embed(sentences)
        session = tf.train.MonitoredSession()
    return lambda x: session.run(embeddings, {sentences: x})embed_fn = embed_useT('../sentence_wise_email/module/module_useT')
messages = [
    "we are sorry for the inconvenience",
    "we are sorry for the delay",
    "we regret for your inconvenience",
    "we don't deliver to baner region in pune",
    "we will get you the best possible rate"
]
embed_fn(messages)

输出是一个 5*512 维的矩阵。(每个句子是一个大小为 512 的向量)。因为这些值是归一化的,所以编码的内积可以被视为相似性矩阵。

encoding_matrix = embed_fn(messages)
import numpy as np
np.inner(encoding_matrix, encoding_matrix)

输出是:

array([[1\.        , 0.87426376, 0.8004891 , 0.23807861, 0.46469775],
       [0.87426376, 1.0000001 , 0.60501504, 0.2508136 , 0.4493388 ],
       [0.8004891 , 0.60501504, 0.9999998 , 0.1784874 , 0.4195464 ],
       [0.23807861, 0.2508136 , 0.1784874 , 1.0000001 , 0.24955797],
       [0.46469775, 0.4493388 , 0.4195464 , 0.24955797, 1.0000002 ]],
      dtype=float32)

从这里可以看出,“我们对给您带来的不便感到抱歉”和“我们对延迟感到抱歉”之间的相似度是 0.87(第 1 行,第 2 列),而“我们对给您带来的不便感到抱歉”和“我们将为您提供尽可能好的价格”之间的相似度是 0.46(第 1 行,第 5 列),这很惊人。还有其他方法可以从编码中找到相似性得分,如余弦相似性、曼哈顿距离等。(文末提到的我的 Github repo 里有代码)。

删除重复文本

在开发问答验证系统时,一个主要问题是回答语句的重复。遍历我们的可用数据,我们发现语义相似性得分> 0.8(通过上述编码的内积计算)的句子实际上是重复语句,因此我们删除了它们。

#It takes similarity matrix (generated from sentence encoder) as input and gives index of redundant statements
def redundant_sent_idx(sim_matrix):
    dup_idx = [] 
    for i in range(sim_matrix.shape[0]):
        if i not in dup_idx:
            tmp = [t+i+1 for t in list(np.where( sim_matrix[i][i+1:] > 0.8 )[0])]
            dup_idx.extend(tmp)
    return dup_idx
#indexes of duplicate statements.
dup_indexes  = redundant_sent_idx(np.inner(encoding_matrix,
                                           encoding_matrix))unique_messages = np.delete(np.array(messages), dup_indexes)

独特的信息是:

array(['we are sorry for the inconvenience',
       "we don't deliver to baner region in pune",
       'we will get you the best possible rate'], dtype='<U40')

基本上,它放弃了陈述“我们为延迟感到抱歉”和“我们为你的不便感到抱歉”,因为它们是第一句的重复。

通过查找语义相似的句子进行分类

在构建答案评估系统时,我们遇到了检测后续语句的问题。但是没有足够的数据来训练一个统计模型。多亏了通用句子编码器,我们可以解决这个问题。我们采用的方法是,创建一个所有可用数据的编码矩阵。然后获取用户输入的编码,看是否与任何可用数据的相似度超过 60%,以此作为后续。简单的问候标识可以是:

greets = ["What's up?",
 'It is a pleasure to meet you.',
 'How do you do?',
 'Top of the morning to you!',
 'Hi',
 'How are you doing?',
 'Hello',
 'Greetings!',
 'Hi, How is it going?',
 'Hi, nice to meet you.',
 'Nice to meet you.']
greet_matrix = embed_fn(greets)
test_text = "Hey, how are you?"
test_embed = embed_fn([test_text])
np.inner(test_embed, greet_matrix)
sim_matrix  = np.inner(test_embed, greet_matrix)
if sim_matrix.max() > 0.8:
    print("it is a greetings")
else:
    print("it is not a greetings")

[## sambit 9238/深度学习

深度学习技术在自然语言处理、计算机视觉等领域的实现。-sambit 9238/深度学习

github.com](https://github.com/sambit9238/Deep-Learning/blob/master/tensorflow_hub_useT.ipynb)

https://tfhub.dev/google/universal-sentence-encoder-large/3

[## 通用句子编码器

我们提出了将句子编码成嵌入向量的模型,这些向量专门针对其他自然语言处理的迁移学习

arxiv.org](https://arxiv.org/abs/1803.11175)

使用 Cython 可以将 Python 代码的速度提高 30 倍以上

原文:https://towardsdatascience.com/use-cython-to-get-more-than-30x-speedup-on-your-python-code-f6cb337919b6?source=collection_archive---------0-----------------------

Cython will give your Python code super-car speed

想获得灵感?快来加入我的 超级行情快讯 。😎

Python 是社区最喜欢的编程语言!这是迄今为止最容易使用的方法之一,因为代码是以直观、人类可读的方式编写的。

然而,你经常会一遍又一遍地听到对 Python 的相同抱怨,尤其是来自 C 代码大师的抱怨: Python 很慢。

他们没有错。

相对于很多其他编程语言,Python 比较慢基准测试游戏有一些比较各种编程语言在不同任务上速度的坚实基准。

我以前写过几个不同的方法可以加快速度:

(1)使用多处理库来使用所有的 CPU 内核

(2)如果您使用 Numpy、Pandas 或 Scikit-Learn,请使用 Rapids 来加速 GPU 上的处理。

如果您正在做的事情实际上可以并行化,例如数据预处理或矩阵运算,那就太棒了。

但是如果你的代码是纯 Python 呢?如果你有一个大的 for 循环,而你只有可以使用,并且不能放入一个矩阵中,因为数据必须在序列中处理,那该怎么办?有没有办法加速 Python 本身

这就是 Cython 加速我们的原始 Python 代码的原因。

Cython 是什么?

就其核心而言,Cython 是 Python 和 C/C++之间的中间步骤。它允许您编写纯 Python 代码,只需稍加修改,然后直接翻译成 C 代码。

您对 Python 代码所做的唯一调整是向每个变量添加类型信息。通常,我们可以像这样在 Python 中声明一个变量:

x = 0.5

使用 Cython,我们将为该变量添加一个类型:

cdef float x = 0.5

这告诉 Cython,我们的变量是浮点型的,就像我们在 c 中做的一样。使用纯 Python,变量的类型是动态确定的。Cython 中类型的显式声明使得到 C 的转换成为可能,因为显式类型声明是必需的+。

安装 Cython 只需要一行 pip:

pip install cython

Cython 中的类型

使用 Cython 时,变量和函数有两组不同的类型。

对于变量,我们有:

  • cdef int a、b、c
  • cdef char *s
  • cdef 浮点型 x = 0.5(单精度)
  • cdef double x = 63.4(双精度)
  • cdef 列表名称
  • cdef 词典进球 _for_each_play
  • cdef 对象卡片 _ 卡片组

请注意,所有这些类型都来自 C/C++!对于我们拥有的功能:

  • def —常规 python 函数,仅从 Python 调用。
  • cdef — Cython only 不能从纯 python 代码访问的函数,即必须在 Cython 内调用
  • cpdef — C 和 Python。可以从 C 和 Python 中访问

有了对 Cython 类型的了解,我们就可以开始实施我们的加速了!

如何用 Cython 加速你的代码

我们要做的第一件事是建立一个 Python 代码基准:一个用于计算数字阶乘的 for 循环。原始 Python 代码如下所示:

我们的 Cython 相同的功能看起来非常相似。首先,我们将确保我们的 Cython 代码文件有一个.pyx扩展名。代码本身唯一的变化是我们声明了每个变量和函数的类型。

注意这个函数有一个cpdef来确保我们可以从 Python 中调用它。也看看我们的循环变量i是如何拥有类型的。你需要为函数中的所有变量设置类型,以便 C 编译器知道使用什么类型!

接下来,创建一个setup.py文件,该文件将 Cython 代码编译成 C 代码:

并执行编译:

python setup.py build_ext --inplace

嘣!我们的 C 代码已经编译好了,可以使用了!

你会看到在你的 Cython 代码所在的文件夹中,有运行 C 代码所需的所有文件,包括run_cython.c文件。如果你很好奇,可以看看 Cython 生成的 C 代码!

现在我们已经准备好测试我们新的超快的 C 代码了!查看下面的代码,它实现了一个速度测试来比较原始 Python 代码和 Cython 代码。

代码非常简单。我们以与普通 Python 相同的方式导入文件,并以与普通 Python 相同的方式运行函数!

Cython 几乎可以在任何原始 Python 代码上获得很好的加速,根本不需要太多额外的努力。需要注意的关键是,你经历的循环越多,你处理的数据越多,Cython 就能提供越多的帮助。

查看下表,它显示了 Cython 为我们提供的不同阶乘值的速度。我们通过 Cython 获得了超过 36 倍的速度提升!

喜欢学习?

在 twitter 上关注我,我会在这里发布所有最新最棒的人工智能、技术和科学!也在 LinkedIn 上和我联系吧!

利用数据科学找到你的下一个 Airbnb 度假地

原文:https://towardsdatascience.com/use-data-science-to-find-your-next-airbnb-getaway-3cb9c8333ad1?source=collection_archive---------15-----------------------

在数据中查找模式并对相似的列表进行分组

截至 2019 年 8 月,纽约市五个区约有 5 万个 Airbnb 房源。假设您根据自己的旅行兴趣将搜索范围缩小到一两个街区。每个街区的 Airbnb 房源密度如此之高,以至于你最终仍会有数百个房源可供选择。我们是否可以让机器学习算法在数据中找到模式,并将相似的房源分组,而不是通读每一个房源的描述、提供的便利设施和各种其他功能?

Figure 1: Each point represents an Airbnb Listing. The points closer to each other have similar characteristics: eg: amenities offered, their description, price and hundreds of other features. The price is encoded as the size of the bubble, so larger bubbles are higher price. An interactive plot is embedded in the results section below.

方法:在数据科学中寻找许多解决方案的一个常见流程是跨行业数据挖掘标准流程(CRISP-DM)。它有六个主要阶段:

  • 业务理解-发展业务理解。
  • 数据理解-形成数据理解。
  • 数据准备-准备您要分析的数据。
  • 建模-对数据建模。
  • 评价-评价结果回答你感兴趣的问题。
  • 部署-根据您的分析结果部署您的模型。

我利用这个过程从 airbnb 收集数据,并在 Heroku 上部署了一个交互式数据仪表板,让用户可以找到类似的 Airbnb 房源。

Figure 2: A subset of the phases of a CRISP-DM process starting from data preparation to deployment.

业务理解:这个阶段的目标是弄清楚我们到底要解决什么。基于问题陈述,我们的主要目的是帮助用户快速、可靠地找到 airbnb 房源。因此,我们的商业目标是:更好的用户体验和增加对搜索结果的信任度。这些目标转化为一系列问题/任务:

  • 创建一个可视化界面,显示各个社区的价格分布:这样做可以让用户根据价格缩小搜索范围。
  • 创建一个数据仪表板,让用户选择一个街区,并找到类似的 airbnb 房源:这将允许用户轻松找到类似的位置。
  • 建立一个交互式地图来显示 airbnb 房源的聚类:这将允许用户不仅根据相似性,还根据地理位置来挑选房源。

数据理解:在这个阶段,我们需要理解回答问题所需的数据,以及构建我们在业务理解阶段确定的应用程序所需的数据。在我们的例子中,我们可以从 Airbnb 网站内的获取数据,该网站发布了几个城市的 Airbnb 房源数据。数据集由几个 csv 文件组成,每个文件捕获关于列表的信息。在我的分析中,我使用了详细列表,它包含了 48,884 airbnb 列表的 106 个特征。

Figure 3: Overview of the datasets released by Inside Airbnb website. (Source: http://insideairbnb.com/get-the-data.html)

遵循 CRISP-DM 流程,我创建了一系列博客文章,详细介绍了数据收集、预处理、建模和部署步骤(以及代码),解释了为获得结果所做的选择。这些博文可以在本文末尾找到。

结果:

在这里,我想分享我的分析结果,并解释我们可以从这些结果中收集的见解。

不同社区的价格分布:

缩小搜索范围的一个很好的起点是了解哪些社区价格昂贵。此处显示的价格是每个街区的中间价格。乍看之下,我们知道有些地区相对于其他地区来说相当昂贵,尤其是曼哈顿下城的那些地区。可以为其他行政区收集类似的见解,帮助您缩小价格范围内的社区范围,并满足您的出行需求。

Figure 4: The median price per neighborhood is displayed here. We can gather from this plot that price tends to differ greatly based on location.

假设你希望住在曼哈顿中央公园附近,并决定在切尔西区搜索 Airbnb 房源。仅在这一个社区就有 980 个房源。图 5 中的*显示的是该社区 Airbnb 房源的密度。正如你所看到的,这是一个相当大的列表,这是我们可以使用机器学习 在数据中找到模式,并将相似的列表分组为集群的地方。*

Figure 5: Density of Airbnb listings in the Chelsea neighborhood

现在,我们的任务是根据我们从描述、便利设施和其他几个因素为每个列表构建的特征找到相似的列表。对于每个列表,从最初的 106 个特性中总共设计了 2151 个特性。完整的特性列表可以在这里找到:【2151 特性】

处理包含许多要素的数据集时,很难可视化/探索要素之间的关系。这就是降维的用武之地。在机器学习中,降维是通过获得一组主变量来减少所考虑的随机变量的数量的过程。主成分分析(PCA) 是一种线性降维技术,适用于具有许多相关特征的数据集。简而言之,主成分分析试图减少数据集中的要素数量,同时保留“主成分”,主成分被定义为现有要素的加权线性组合,旨在实现线性独立,并解释数据中最大可能的可变性。您可以将这种方法视为采用许多功能(2151)并将相似或冗余的功能组合在一起,以形成一个新的、更小的功能集。下面显示的是前 50 个主成分以及每个主成分解释的差异量。

Figure 6: Variance explained by each of the first 50 principal components

由于每个主成分都是原始特征的线性组合,因此可以查看这些成分的构成。通过查看图 7,由前两个主要部分组成的部分,我们可以看到最显著的特征是每个 airbnb 房源提供的便利设施。解释部件组成的一种方法是说:

有助于区分切尔西区 Airbnb 房源的主要特征是所提供的便利设施。

Figure 7: Component make up of the first two principal components.

为了构建我们的数据仪表板,我们可以采用前 3 个主要组件,但是,如果我们丢弃剩余的 47 个组件,我们将丢弃许多有用的信息。

另一种方法是应用t-分布式随机邻居嵌入(t-SNE)——这是一种非线性降维技术,特别适合高维数据集的可视化。t-SNE 将多维数据映射到低维空间,并试图通过基于具有多个特征的数据点的相似性识别观察到的聚类来发现数据中的模式。在我们的例子中,我们将采用前 50 个主成分,并应用 t-SNE 将数据集减少到 3 维。

在切尔西附近找到类似的 Airbnb 房源:

通过减少到 3 维,我们现在能够在 3-D 散点图中可视化。每个数据点对应一个 airbnb 房源。距离较近的点具有相似的特征,即提供的便利设施、主机身份验证等。您可以与下面的 Plotly 可视化交互,如果您喜欢,甚至可以修改它!

Figure 8: A 3D-scatter plot constructed from t-SNE features. Each point represents an Airbnb Listing. The points closer to each other have similar features: eg: amenities offered, their description, price and hundreds of other features. The price is encoded as the size of the bubble, so larger bubbles are higher price. Hover over each of the data points to see more details.

这个情节有什么用处?

  • 省钱:由于彼此距离较近的点具有相似的特征,因此我们可以找到在我们价格范围内的房源。

在一个较大的泡泡旁边找一个较小的泡泡,你就可以省点钱了!

  • 找到独一无二的东西:一个远离其余的数据点,表明它有非常独特的东西,要么是坏的,要么是好的。你可以自己调查一下。
  • 比较:假设您喜欢某个列表,并且希望找到相似的列表,您可以找到该数据点并查看其最近的邻居。

对数据仪表板的需求

一次可视化所有列表不是一个好主意,因为阅读情节变得非常困难。这就是数据仪表板的用武之地。使用数据仪表板,我们可以基于某些属性过滤可视化,并更轻松地调查数据点之间的关系。

例如,下面的演示显示了我们如何在 Chelsea 社区找到两个类似的 3 居室 airbnb 房源,并与 West Village 等其他社区的价格进行比较。

您可以在这里与部署到 Heroku 的应用程序进行交互:【Airbnb 数据仪表板】 。这里记录了构建和部署它的步骤: [ 将 data dashboard 应用程序部署到 Heroku]

Demo: Select the neighborhood from the drop-down menu, move the slider to filter based on number of bedrooms. Using the tools at the top right, you can zoom, pan and rotate the plot to find similar listings. Hover over each data point to see more details.

使用 K-means 聚类相似的 airbnb 列表:

上面的 t-SNE 可视化让我们可以根据它们在组件空间的接近程度找到类似的 airbnb 列表。但是它没有将单个列表分组到聚类中,并且将每个列表标记为聚类的一部分。这就是 K 均值聚类派上用场的地方!

考虑这个场景:假设您在第 10 大道和西 20 街找到了一个非常好的列表,并且您希望在第 34 街宾州车站附近找到一个类似的列表。通过选择同一个集群中更靠近宾州车站的另一个成员,你可以相信这两个位置之间有一些相似之处。

Figure 9: Results of K-means clustering — shown here are three clusters represented by three colors.

相似的 T21 这个词在这里有着比仅仅说相似的价格、相似的生活设施等更深刻的含义。它是我们使用 NLP 和特征工程创建的 2151 个特征的组合,然后要求像 K-Means 这样的无监督机器学习算法根据它们在向量/分量空间中的距离的接近程度对它们进行分组。

结论:

每个数据科学问题都始于一个问题。我们感兴趣的问题是:我们能根据 Airbnb 提供的信息找到类似的房源吗?通过使用 CRISP-DM 流程,我们从了解问题开始了我们的旅程,从 Airbnb 获取数据,预处理数据,建立数据模型,最后部署了一个数据仪表板,让用户可以轻松找到类似的房源。虽然仅仅为了找到一个 Airbnb 房源,这看起来有点过分,但是发现独特事物的快乐让这一切都是值得的!

CRISP-DM 步骤:

博客系列,涵盖了实现上述结果的每个步骤:

本帖中用于构建可视化效果的工具:

所有的可视化都是用 python 创建的🐍

  • geo pandas:让使用 python 处理地理空间数据变得更加容易。如果您有纬度和经度信息,那么您可以构建一个 geopandas 数据框架,并开始使用 pandas 的所有功能,如过滤、分组、合并空间组件。我被它的简单和强大迷住了。在这里阅读如何安装它:【安装 geo pandas】
  • leave:folium使用 Python 处理的数据在交互式活页地图上可视化变得容易。它既可以将数据绑定到地图上进行choropleth可视化,也可以将丰富的矢量/栅格/HTML 可视化作为地图上的标记进行传递。
  • plot ly Express:plot ly 这些年来有了很大的改进,最新的版本用 plotly.express 做出来易如反掌。现在你几乎可以在任何地方嵌入 plotly 可视化。阅读这篇博客,看看它能做些什么:【Plotly 4.0】
  • Dash:它写在 Flask、Plotly.js 和 React.js 之上,Dash 非常适合用纯 Python 构建具有高度自定义用户界面的数据可视化 app。它特别适合任何使用 Python 处理数据的人。
  • Giphy:我用这个创建了 gif。就像上传一个视频并从中挑选你想要的一样简单。Medium 只允许 Embed.ly 支持嵌入,giphy 是其中之一。
  • Heroku: 在我看来,在云上拥有 python app 最快的方法就是使用 Heroku PaaS。他们让它变得非常简单,下面是从头开始的步骤。【将数据仪表板部署到 Heroku】
  • Github 链接到代码

使用我的不安预测模型来挑选 NCAA 锦标赛中的失败者

原文:https://towardsdatascience.com/use-my-upset-prediction-model-to-pick-underdogs-in-your-ncaa-tournament-bracket-87c4aa3935f5?source=collection_archive---------12-----------------------

机器学习模型给出了 3 个需要寻找的关键干扰信号

NCAA 锦标赛场地已经设置好,现在是开始填写你的括号的时候了。每年都有一些顶级球队被提前淘汰,所以挑几个冷门是有意义的,尤其是在前几轮。正确挑选冷门是在支架竞赛的前几轮中获得优势并使你的支架与竞争对手区分开来的好方法。

问题是,很难准确预测不愉快。当不被看好的人赢了,他们只有 1/5 的机会被选中。每个人都预计会发生一些令人沮丧的事情,而且有很多关于应该挑选多少的建议。但大多数括号玩家仍然很难选择正确的。

根据 2003 年以来所有锦标赛球队的数据,我使用机器学习创建了一个预测模型,具有很好的准确性来检测冷门,我将冷门定义为一个不被看好的球队获胜,他们的种子比对手低至少 4 个位置(a 5 击败 a 1,a 6 击败 a 2,等等。).去年的锦标赛有 12 场冷门。我的模型预测了其中的 10 个,还有 5 个假阳性。不完美,但比随机猜测好得多。

今天,我利用我的模型中的见解,给你提供由硬数据支持的颠覆性指导。我在这里关注的是处于劣势的球队的品质,不管对手是谁,这些品质都预示着更大的翻盘机会。我的目标不是告诉你应该挑选哪些令人沮丧的事情,因为这有什么意思呢?相反,我想给你三个明确的不安信号,当你在自己的分类中寻找不安时可以考虑。

冷门信号 1:由上届锦标赛冠军教练带领的弱队

篮球专家经常讨论好教练在锦标赛中的重要性,但通常是指像肯塔基、北卡罗来纳和密歇根州立大学这样的精英项目的教练。但事实证明,教练在锦标赛中的成功记录也能对弱队产生很大影响。

当我查看弱队教练成功的几个指标时,有一个因素很突出:弱队教练之前参加第四轮比赛的次数,也就是“精英 8 强”。

Underdog coaches with Elite 8 experience are more likely to lead their team to a win

在左边我展示了“冷门率”,定义为导致冷门的游戏的百分比。由简历上没有“精英 8”访问记录的教练领导的失败者只有大约 16%的胜率,但由“精英 8”教练领导的失败者表现得好得多,失误率接近 40%。

根据定义,每个有精英 8 经验的教练以前都在锦标赛中至少赢过 3 场。这些跑步可能有助于给教练宝贵的经验,或者可能只是代表教练在管理激烈的比赛压力,为下一个对手制定比赛计划,或者两者兼而有之的技能的证据。

下面我展示了今年所有拥有精英教练的潜在弱势球队(种子 5-16)。对于每支队伍,我会展示他们第一次被认为处于劣势的比赛回合和对手。在第一轮中只有两支队伍符合这个标准,但是在第二轮和以后的比赛中,有几个潜在的冷门在等着我们。

Underdogs led by coaches with previous Elite 8 experience

请注意,无论谁在第一轮赢得贝勒-锡拉丘兹,冈萨加都将在第二轮面对一位精英 8 教练,要么是斯科特德鲁,要么是吉姆·伯海姆。对于头号种子冈萨加来说,这两场比赛都是艰难的第二轮比赛,这意味着选择他们逃离这个地区可能是有风险的。锡拉丘兹去年处于类似的 10 号种子的位置,当时我的模型正确预测了他们将在第二轮击败 2 号种子密歇根州立大学。

冷门信号 2:中期主要弱队在艰难的赛程中保持强劲的胜利记录

对于遴选委员会而言,日程安排的强度是决定邀请哪些网络普通用户团队的一个重要因素。事实证明,赛程的强度也是预测弱队在锦标赛中获胜的一个有用因素。

对于“中大型”团队来说尤其如此,这些团队不属于“Power 5”会议(ACC、SEC、Big 12、Big 10、PAC-12)。当我特别观察中等职业球队时,赛程的强度和高胜率都是预测冷门的潜在因素。

Among mid-majors, underdogs with both strong schedules and winning records are most likely to pull an upset

对于所有涉及不被看好的中等球队的锦标赛,我会在纵轴上显示不被看好的球队在锦标赛前的总胜场数。横轴显示了球队在赛程中的赛前实力,数值越高表示球队遇到的对手越难对付。进度表的平均中主要强度以蓝色显示。请注意,扰乱(绿色)清楚地聚集在右上角。这意味着当弱队的赛程强度高于平均水平并且至少赢了 20 场比赛时,冷门往往会发生。

为了使用这两个因素创建更具体的指导,我按照赛程强度(平均或更低,平均以上)对中-大比分落选者进行了分组,并针对总胜率的 3 个类别分别绘制了每组的沮丧率:少于 18,18-23 和超过 23 胜。

这里的数据讲述了一个有趣的故事。拥有强大胜利记录的中职棒球队确实更有可能取得冷门,正如两个中职棒球队从左(少于 18 场胜利)到右(超过 23 场胜利)的整体冷门率增加所示。然而,对于时间表更紧的中等专业(绿色/蓝色线),增长幅度更大。这种模式符合常识:那些通过战胜更难对付的对手来证明自己价值的中等职业者,也是那些更有可能在大舞台上翻盘的人。

上面的图表显示,冷门对于拥有超过 18 场胜利和艰难赛程的中期主要弱队来说是最常见的。下面我展示了今年符合这两个标准的 11 支中型球队。对于每支球队,我还展示了他们第一轮的对手(11-16 号种子队)或他们预计的未来比赛(5-10 号种子队)。

Mid-major underdogs with at least 18 wins and a difficult season schedule

坦普尔和圣玛丽看起来像是第一轮中强劲的冷门竞争者,尽管坦普尔必须在前四轮中首先通过另一个中期专业(贝尔蒙特)。在第二轮比赛中,UCF 对杜克大学和辛辛那提对田纳西大学都以获胜记录和赛程证明脱颖而出。

将这些数据与上面的教练表联系起来,我还注意到密歇根肯定会在第二轮面对一个艰难的中期联盟(内华达州)或一个经验丰富的教练(佛罗里达州),还有另一个艰难的中期联盟(水牛城)或全国最有效率的三号种子选手(德州理工)在第三轮等待着。密歇根是一支伟大的球队,但像这样一连串艰难的比赛是可以打破支架的地雷,伟大的球队每年都会提前出局,包括第二轮三分之一的 2 号种子。狼獾队可能是你可以考虑尽早淘汰的队伍之一。

不安信号 3:在家门口的比赛中处于劣势的精英

因为每场锦标赛都是在一个中立的场地进行,所以没有哪支球队有真正的主场优势。然而,不被看好的球队通常会在离家更远的地方比赛,这可能会使他们处于劣势,可能是因为长途旅行和减少的球迷到场人数。

但有时,失败者很幸运,最终比最受欢迎者走了相似(甚至更短)的距离。当这些球队碰巧是非常熟练的失败者时,不安分的手表就处于警戒状态。

我用术语“精英”失败者来描述具有关键不安信号的团队,我在之前的帖子中讨论过:肯波调整后的效率余量超过 10。只有 40%的不被看好的球队达到了这个基准,但是这些球队在大约 30%的时间里击败了热门球队,相比之下,其他不被看好的球队只有 10%。作为挑选冷门的唯一规则,你可以做得更糟…但我认为我们也可以做得更好。

Elite underdogs (those with Kenpom efficiency margin over 10) who play close to home upset the favorite 40% of the time

在“精英”阶层的失败者中,在离家近的地方比赛是一个明显的沮丧信号。正如我在左边展示的,在距离校园不到 400 英里的地方打球的“精英”失败者的失望率在 40%左右,而其他精英的失望率在 30%以下。精英失败者只有 20%的时间在校园附近玩这种游戏,但当他们这样做时,就会大大增加冷门的几率。

下面我展示了今年锦标赛的相关游戏。辛辛那提(我们已经知道他们有获胜记录和赛程强度的冷门信号)再次出现在俄亥俄州哥伦布市与田纳西的第二轮比赛中。我还注意到,对于杜克大学在南卡罗莱纳州的第二轮比赛,他们的两个潜在对手(VCU 和 UCF)都符合旅行标准。足够疯狂的是,两支球队都有上面讨论过的胜利记录和赛程实力。

Elite underdogs who will travel less than 400 miles to their game

杜克是头号种子选手,拥有我们所见过的最有天赋的首发阵容之一。我会选择杜克大学在一场比赛中输给 UCF 或 VCU 吗?不,我不会。但在括号池中,最小化风险是成功的重要组成部分,这包括识别哪些顶级团队进入四强的道路更加艰难。因此,在自动将头衔授予杜克大学之前,你可能会三思而行。

闭幕词

即使是遇到这些令人沮丧的信号的失败者也有超过 50%的机会输掉比赛,还有许多其他因素影响着 NCAA 锦标赛中每场比赛的结果。那么,你应该如何利用这些信息来挑选烦恼呢?

我的建议是把信号作为工具,而不是硬性规定。如果你对处于劣势的团队有预感,对照这些信号检查他们,看看他们是否通过测试。试着想出你自己的信号,看看他们今年表现如何。

在未来,我还计划发布带有信心指标和其他数据的完整预测,所以如果你想了解更多,请在 Medium 或 Twitter @bracket_vision 上关注我。

使用物体识别来确保你的车没有被偷

原文:https://towardsdatascience.com/use-object-recognition-to-make-sure-your-car-hasnt-been-stolen-70c866710fe1?source=collection_archive---------24-----------------------

什么?一篇博文的标题真奇怪。这就像说“不要为了避免不打电话而不使用你的电话”。但我认为它准确地描述了我将向你展示如何使用机器学习来确保你的车仍然在你的车道上。

几年前,有人决定在半夜大摇大摆地走进我的车道,偷走我的车。这不是一次愉快的经历,这当然让我想到了防止这种事情再次发生的聪明方法。

一种方法是在每个地方安装安全摄像头,然后设置它们在有任何动静时提醒我。但是,我相信你能猜到,如此多的小事情触发了运动检测,以至于通知很快变成了噪音,然后我忽略了它,这违背了最初获得通知的目的。

Source: https://cdn.macrumors.com/article-new/2018/07/groupednotifications-800x646.jpg

但是如果我可以告诉你,你可以建立一个系统,只有在你的车丢了的时候提醒你,而不会提醒你任何其他的事情,那会怎么样呢?

嗯…我不能告诉你…所以…我现在告诉你。

怎么会?

魔法。

所谓魔法,我指的是相对简单的技术,基于非常坚实的数学基础,比如 2+2=4,6/2=3,三角形=有趣。

显然,你首先需要的是一台照相机。接下来你需要做的是安装一些 DIY 家庭自动化设备。我推荐看看这些家伙。他们有很多开源家庭自动化的东西,你可以很容易地设置,以实现如下的工作流程。

我想说这是为技术爱好者准备的。你可能应该成为一名开发人员,或者至少在电视上扮演一名开发人员。

现在,给你自己找一些训练数据。也就是说,你的车停在平时停放的地方的一些视频文件。

我的情况是这样的。

注意到背景中的回收箱了吗?我的建议是从一周中获取视频示例,使用不同的照明,街道上不同的“场景”,如汽车、垃圾箱、动物、鬼魂,以及任何其他常见的场景。就我而言,我需要有和没有这些箱子的视频。

现在有趣的部分来了。

继续从称为对象盒机器盒下载这个漂亮的工具。

给…作注解

按照说明使用 Objectbox 中的注释工具进行设置,并将您的视频放入boxdata/files目录。

然后通过访问http://localhost:8080点击注释工具打开注释应用,并选择您的一个示例视频。播放视频,然后暂停,并在您的汽车周围画一个方框。给它一个有意义的标签,再次播放视频,几秒钟后再次点击暂停,然后在你的车周围再画一个方框。冲洗,每个视频重复 2 到 3 次。

我的建议是在尽可能多的不同场景中抓取大约 20 个例子。例如,你看到我的好车旁边的那只笨猫了吗?这次我确保它包含在盒子里,但不是为了后续的注释。我希望模型每次都能学习什么是相同的,什么是不同的。Objectbox 将整个框架放入上下文中,所以你真的需要在一天的不同时间和一周的不同日子的真实生活的例子来获得最佳结果。

我们表现如何?

我最喜欢 Objectbox 的一点(因为我是它的产品经理,也是我要求的)是能够立即获得对你的培训的反馈。你提供了足够多的例子吗?你做得对吗?很棒的问题。Objectbox 通过让你点击“训练”,然后在一帧上播放和暂停视频来给你答案。它会根据这个框架进行训练,然后马上给你一个答案。

例如,这里有一个 Objectbox 从未见过的新框架。

Objectbox draws a box around the car and labels it ‘Mazda’

搞定了。现在,让我们看看当一些视频中没有美味的马自达出现时会发生什么:

完美—没有检测到。

下面是我设置 pleasedontstealmycar 工作流程的方法:

  1. 从 Objectbox 下载状态文件(training)(在检查了几个视频之后)。
  2. 建立我的相机定期检查下载一帧,张贴到 Objectbox 运行与我的状态文件,这将检查看看是否马自达=真。
  3. 如果马自达=被盗,发送警报到我的手机和国民警卫队。
  4. 当你预计马自达在别的地方的时候,可能安排这个不提醒你。

这将大大减少你从爱洛,环,巢等收到的通知数量。等等。等等。只在应该在那里的东西不在的时候提醒你。

你还能用 Objectbox 做什么?当你驶入车道时打开车库,当你的邮件到达时提醒你,如果你的回收箱不在街上时通知你,因为你一直在忙着做很酷的事情…我相信你可以想到许多伟大的使用案例。

更上一层楼

如果你是一个大机构或小办公室,你想开始考虑使用机器学习来发出更多相关的警报,看看这个。使用 aiWARE ,一个由 Veritone (谁收购了机器盒子)开发的平台,你就可以开始考虑规模化做这种事情了。

只需将您的状态文件上传到 aiWARE 的库应用程序,然后使用 Objectbox 来运行您的所有相机馈送。你不必担心编排 Docker 容器或管理视频的处理。您甚至不需要做太多事情来让通知工作,aiWARE 有一个定制的 Node-RED 实现,让您可以轻松地处理这样的工作流,而无需做太多的编码。

在 AWS EMR 群集中使用 Pyspark 和 Jupyter 笔记本电脑

原文:https://towardsdatascience.com/use-pyspark-with-a-jupyter-notebook-in-an-aws-emr-cluster-e5abc4cc9bdd?source=collection_archive---------4-----------------------

Jupyter Notebook 是学习和解决代码问题的一个不可思议的工具。这里有一个博客来展示如何在学习 Spark 时利用这个强大的工具!

如果您正在做任何可以并行化的计算密集型工作,Spark 会很有帮助。查看这个 Quora 问题获取更多信息。

这篇博客将通过 AWS Elastic Map Reduce (AWS EMR)和 Jupyter Notebook 来设置使用 Spark 的基础设施。

导航至 AWS EMR

您将在屏幕顶部看到以下内容:

Click ‘Create cluster’

选择高级选项

在屏幕的顶部

复制以下截图

我用黄色突出显示了需要更改的默认项目,除了第 2 步中的节点类型。这将取决于你的任务的计算强度。如果你只是在测试,资源可能会很少。以' g-'开头的实例是 GPU 实例,最适合运行 Spark。

For more information about how to choose which types of instances to use, check out the AWS docs: https://docs.aws.amazon.com/emr/latest/ManagementGuide/emr-plan-instances-guidelines.html

如果您计划从 S3 存储桶调入数据或文件,请确保您与 S3 存储桶位于同一个 VPC。

See the “Add bootstrap action” ?

好的,这里是你安装引导动作的地方。默认情况下,引导操作以 Hadoop 用户的身份执行。您可以使用 sudo 以 root 权限执行引导操作。

引导操作是将额外的 Python 包安装到其他内核的最有效方式。根据我们在软件配置中选择安装的软件,Anaconda 已经安装在它们上面了。对于我希望运行的脚本,我需要的附加包是 xmltodict。

为了安装 python 库 xmltodict,我需要保存一个包含以下脚本的引导操作,并将其存储在 S3 桶中。这就是在您将要引用的 S3 所在的 VPC 上安装 EMR 集群的重要性所在。这是一个 shell 脚本,将在 S3 保存为. sh 文件:

sudo pip install xmltodict

一定要包括须藤!

如果你需要比xmltodict更多的包,你可以把它们放在同一行代码中,用空格隔开。示例:sudo pip install xmltodict s3fs

Make sure you choose an EC2 key pair you have access to

`为什么选择这些安全组?:

在 EC2 仪表板中,应该有以下入站规则。

在本例中,源是 0.0.0.0/0,这是所有的 IP 地址。为了更加安全,请输入您自己的 IP 地址。

如何检查:转到 EC2 仪表板,单击安全组,找到您的组并添加自定义规则:

The 22 one allows you to SSH in from a local computer, the 888x one allows you to see Jupyter Notebook. As a note, this is an old screenshot; I made mine 8880 for this example.

关于入境交通规则的更多信息,查看 AWS 文档

现在转到您的本地命令行;我们将通过 SSH 进入 EMR 集群。

In general, don’t share your public DNS on the internet. This is one of my old ones.

结果:现在你在 EMR 命令行中。

找到你的蟒蛇版本

https://repo.continuum.io/archive/并在下一步复制/粘贴文件路径。选择 Python 3.6 或更低版本,因为在这个时候,我认为不可能将 worker 节点一直更新到 3.7。如果是的话,请在评论中给我留言吧!

安装 Anaconda

将上一步中的文件路径放在这里:

wget [https://repo.continuum.io/archive/Anaconda2-2018.12-Linux-x86_64.sh](https://repo.continuum.io/archive/Anaconda2-2018.12-Linux-x86_64.sh)

按回车键

bash Anaconda2–2018.12-Linux-x86_64.sh

按 enter 键,并继续按 enter 键浏览条款和条件

键入 yes,

按回车键确认位置

等待软件包安装。

键入 yes 添加到环境变量中,以便 Python 能够工作

which python /usr/bin/python

按回车键

source .bashrc

配置带 Jupyter 的火花

在 EMR 命令提示符下键入以下每一行,并在每一行之间按 enter 键:

export PYSPARK_DRIVER_PYTHON=jupyterexport PYSPARK_DRIVER_PYTHON_OPTS='notebook --no-browser --port=8888'source .bashrc

在 EMR 命令提示符下键入 pyspark

结果:

See that highlighted token? copy it.

在网络浏览器中打开 Jupyter 笔记本

在地址栏中键入以下内容:localhost:8880
结果:粘贴上一步中的令牌并登录的页面。

耶!你做到了!

现在,您可以在 Jupyter 笔记本中查看您的 spark 上下文:

资源:

https://medium . com/@ alexjsanchez/python-3-notebooks-on-AWS-ec2-in-15-mosely-easy-steps-2e C5 e 662 C6

https://medium . com/@ vats al 410/running-py spark-on-an-AWS-cluster-through-jupyter-notebook-Fe 28 f 6 ef 47 a 4

Python 错误的版本错误:

https://AWS . Amazon . com/premium support/knowledge-center/EMR-pyspark-python-3x/

使用 Python 包装上市公司报告中的业务数据(tabula-py)

原文:https://towardsdatascience.com/use-python-to-wrap-business-figures-from-listed-company-reports-6a48b01bf624?source=collection_archive---------20-----------------------

(声明:这是一个只教 Python 的教育帖。内容仅供参考。它无意成为投资建议。)

对于一家上市公司来说,它不断在网上发布不同的报告和数据,让投资者和潜在投资者更好地了解企业。然而,大多数报告都是 PDF 格式的,我们都知道很难复制和处理数字。对于大型投资公司和机构来说,他们肯定有专门的和复杂的工具来阅读 pdf 报告。但是像你我这样的个人投资者呢?有什么方法可以自动读取 pdf 报告并存储或分析?幸运的是,在 Python 的帮助下,答案是肯定的。

This is the result. Impressed? You can do it also.

我将使用的主要模块叫做“tabula”。还有一些其他的模块可以读取 pdf 文件,但是到目前为止,经过多次测试,“tabula”是从 pdf 文件包装表格并存储为 dataframe 的最佳模块。因此,包装后,您可以将结果存储为 csv 文件或与历史数据相结合。

我将使用的公司是国泰航空公司。国泰航空是香港的上市航空公司。每个月,它都会通过不同的目的地释放大量的乘客和货物。因此,通过了解每月的数据,您可以更好地了解其收入流,并帮助您做出更好的投资判断。

第一步是获取 pdf 报告。我将使用更直接的方法在线访问文件并阅读 pdf 文件,而不是手动下载。因此,有必要知道存储这些报告的路径。

https://www.cathaypacific.com/cx/en_HK/about-us/investor-relations/announcements.html

上图是下载各种公告的页面。“交通数字”报告是我们感兴趣的一个。

输入关键词后,可以看到所有的流量数字报告。

下一步是研究如何在线获取这些报告。幸运的是,文件路径是标准化的。

如上图所示,唯一的变化就是最后显示年和月的数字。第一部分不变。

但是,在某些月份,文件路径的子前缀不是“pdf”,而是“PDF”(全部大写)。因此,在编写 Python 脚本时,有必要处理这种情况。

Please keep the format unchanged!!

所以文件路径是“' https://www . cathay Pacific . com/dam/CX/about-us/investor-relations/announcements/en/{ year _ month } _ cxtraffic _ en . pdf(或 PDF)”。

我们感兴趣的页面显示了每个月的流量和容量。它们存储在两个独立的表中。这是我们下一阶段需要努力的地方。

遗憾的是,显示这些表的页面并不是恒定的。相反,它们显示在每个报告的倒数第二页。所以在包装之前,有必要知道每份报告的页数。

下面显示了 Python 脚本应该执行的列表:

  1. 通过文件路径访问文件
  2. 检查总页数
  3. 转到倒数第二页,将两张表格换行

通过文件路径访问文件

所需模块:请求

由于文件路径中的{year_month}变量每个月都会发生变化,因此变量“link”与格式一起使用,以便包含变量“month”。

link = 'https://www.cathaypacific.com/dam/cx/about-us/investor-relations/announcements/en/{}_cxtraffic_en.pdf'.format(month)

下一步是使用请求模块来访问文件

import requests
response = requests.get(link)

如前所述,在某些月份子 fix 是 pdf,所以上面的链接不会给你 PDF 文件,而只是一个错误页面。所以有必要检查一下反应。如果响应是 404(错误),则更改链接并以 PDF 结尾。通过键入 response.status_code 可以获得响应代码。

if response.status_code == 404:
    link = 'https://www.cathaypacific.com/dam/cx/about-us/investor-relations/announcements/en/{}_cxtraffic_en.PDF'.format(month)
    response = requests.get(link)

检查总页数

所需模块:io,PyPDF2

成功访问文件路径后,下一步是读取文件并获得页数。

这里,内置模块“io”与“BytesIO”一起使用,从请求中读取响应的内容。

import io
io.BytesIO(response.content)

现在是时候引入另一个模块来读取 pdf 文件了,PyPDF2。不像 tabula,PyPDF2 可以让你获得关于 PDF 文件的信息,甚至合并 pdf 文件。您可以通过在线阅读 PyPDF2 文档来了解更多信息。

[## PyPDF2 文档- PyPDF2 1.26.0 文档

编辑描述

pythonhosted.org](https://pythonhosted.org/PyPDF2/index.html)

我们需要使用的类是“PdfFileReader ”,并使用“getNumPages”返回页数。

import PyPDF2
with io.BytesIO(response.content) as open_pdf_file:
    pdf_file  = PyPDF2.PdfFileReader(open_pdf_file)
    num_pages = pdf_file.getNumPages()

翻到倒数第二页,把两张表包起来

所需模块:白板

在这个阶段,您需要做的就是转到那个特定的页面,复制这两个表。很简单,对吧?不完全是。

之前说过,pdf 是给人类看的,不是给机器看的。因此,当您使用 tabula 来包装表格时,tabula 很有可能无法成功读取表格或读取不正确。

Tabula 允许您定义 pdf 文件中指定的区域。但是,在这种情况下,由于两个表在同一页上,所以先包装整个页面,然后再拆分成两个表会更容易。使用 tabula.read_pdf 来完成此操作。

table  = read_pdf(link, pages = num_pages-1)

PS:如果你想指定一个特定的区域,你可以在函数中包含“区域”选项。首先,您可以在 Acrobat Reader 中使用 Measure 来获得上、左、下和右(以英寸为单位)的距离,然后乘以 72。

Click “Tool” tab and select “Measure” in Acrobat Reader

table  = read_pdf(link, pages = 4 , area = [1.1*72, 0.9*72, 4.8*72, 7.26*72])

最好包含一个稍微大一点的区域,这样 tabula 可以正确地包裹表格。

如果成功,返回的表将是您想要的结果。通常在结果数据帧中有一些不必要的行或列,所以你需要在换行后清理表格。

现在,您不需要手动复制和保存任何公司报告中的数据。您还可以使用这种方法包装任何 pdf 文件中的数字,例如您部门的月销售额。这可以为你节省很多做无聊工作的时间,这样你就可以做更重要的工作了。

这是这篇文章的结尾。希望你看完能有所收获。给我一个评论或者鼓掌表示支持。下次见。

完整的代码可以在https://github.com/wyfok/Cathay_Pacific_Monthly_figures找到

使用 Scikit-Learn 管道更快地清理数据和训练模型

原文:https://towardsdatascience.com/use-scikit-learn-pipelines-to-clean-data-and-train-models-faster-82a5171f50dc?source=collection_archive---------9-----------------------

将管道纳入机器学习工作流程的快速指南

Photo by Gerd Altmann from Pixabay

如果您正在寻找一种方法来组织您的数据处理工作流并减少代码冗余,Scikit-Learn 管道将是您的数据科学工具包的一个很好的补充。在解释了它们是什么以及为什么使用它们之后,我将向你展示如何使用它们来自动化数据处理,通过使用它们来预测全球票房收入

什么是 Scikit-Learn 管道?

管道可能是一个非常模糊的术语,但一旦你意识到它在建立机器学习模型的背景下做什么,它就非常合适了。Scikit-Learn 管道将多个数据处理步骤链接成一个可调用的方法。

例如,假设您想要从电影数据中转换连续的特征。

Continuous features from movie data

要处理回归模型的连续数据,标准处理工作流包括输入缺失值、转换倾斜变量以及标准化数据。您可以在单独的步骤中处理数据,就像这样。

cont_vars = ['budget', 'popularity', 'runtime']imputer = SimpleImputer(strategy = 'median')
transformer = PowerTransformer(method = 'yeo-johnson', standardize = False)
scaler = StandardScaler()X_train[cont_vars] = imputer.fit_transform(X_train[cont_vars])
X_train[cont_vars] = transformer.fit_transform(X_train[cont_vars])
X_train[cont_vars] = scaler.fit_transform(X_train[cont_vars]) 

但是如果你只是使用一个管道来一次应用所有的数据转换,那将会更干净、更高效、更简洁。

cont_pipeline = make_pipeline(
    SimpleImputer(strategy = 'median'),
    PowerTransformer(method = 'yeo-johnson', standardize = False),
    StandardScaler()
)X_train[cont_vars] = cont_pipeline.fit_transform(train[cont_vars], columns = cont_vars)

通过使用管道,您可以清楚地看到您的处理步骤,并快速添加或删除步骤。你也只需要调用fit_transform()一次,而不是三次。

使用管道同步处理不同的数据类型

我使用管道来处理连续数据,但是在电影数据中也有离散的数字列、分类列和 JSON 类型的列。每种数据类型都需要不同的处理方法,因此您可以为每种数据类型构建唯一的管道。

disc_vars = list(X_train.select_dtypes(include = int).columns)disc_pipeline = make_pipeline(
    SimpleImputer(strategy = 'constant', fill_value = -1)
)cat_vars = ['original_language', 'release_season']cat_pipeline = make_pipeline(
    SimpleImputer(strategy = 'constant', fill_value = 'unknown'),
    OneHotEncoder()
)json_vars = ['Keywords', 'crew_department', 'production_countries', 'cast_name', 'crew_job', 'production_companies', 'crew_name', 'genres', 'spoken_languages']json_pipeline = make_pipeline(
    TopCatEncoder()
)

TopCatEncoder()是我专门为电影数据编写的自定义转换器。一些数据列包含以 JSON 格式编码的信息,所以我定义了TopCatEncoder()和一些帮助函数来根据键将 JSON 解析成分类变量,然后保留每个新分类变量的顶级类别。这就是你需要知道的关于 transformer 的全部内容,但是如果你想了解更多,你也可以查看我的 GitHub 中的代码

现在我已经有了处理数据所需的所有管道——cont_pipelinedisc_pipelinecat_pipelinejson_pipeline——我可以将它们组装成一个管道,使用ColumnTransformer()来指定哪个管道转换哪个变量。变形金刚被指定为一个元组列表,看起来像这样:(name, transformer, columns)

preprocessor = ColumnTransformer(
    transformers = [
        ('continuous', cont_pipeline, cont_vars),
        ('discrete', disc_pipeline, disc_vars),
        ('categorical', cat_pipeline, cat_vars),
        ('json', json_pipeline, json_vars)
    ]
)

要使用这条管道转换我的所有数据,我只需调用preprocessor.fit_transform(X_train)

使用管道测试机器学习算法

这里,我使用一个名为quick_eval()的效用函数来训练我的模型并进行测试预测。

通过将processor管道与回归模型相结合,pipe可以同时处理数据处理、模型训练和模型评估,因此我们可以快速比较 8 个不同模型的基线模型性能。输出如下所示。

接下来的步骤:模型选择、特征选择和最终模型

随着数据处理和模型原型化步骤的完成,我们可以选择一个模型子集来关注。我使用了随机森林回归器,因为它的表现相对较好,而且很容易解释。

在此基础上,我们可以继续进行特征工程、特征选择和超参数调整,以获得最终模型。我使用了基于随机森林的交叉验证的变量选择程序,将我的数据从 194 个特征减少到 57 个特征,并改进了测试 RMSE。

5-fold CV model performance, p_hat is number of features fed into Random Forest regressor

这个变量选择实现不是这篇文章的重点,但是你可以在我的代码的函数rf_variable_selection()中找到它的实现。

上面的TopFeatureSelector()是另一个定制的转换器,它选择前 k 个特性来保持使用预先计算的特性重要性。

这就是你的最终模型!它的性能比具有较少特性的基线要好一点。

要采取的其他步骤

由于我专注于 Scikit-Learn 管道,所以我跳过了一些步骤,如合并外部数据、特性工程和超参数调整。如果我重新审视这个项目,让我的模型变得更强大,我会专注于这三件事。我也没有在quick_eval()函数中使用交叉验证,但是实现交叉验证会使这个工作流更加健壮。

感谢阅读!我是 Scikit-Learn Pipelines 的新手,这篇博文帮助我巩固了迄今为止所做的工作。我将用我遇到的新用例来更新这个文档。

你可以在这里 查看这个项目的 Jupyter 笔记本 。有关管道的更多信息,请查看丽贝卡·维克里的 帖子 和 Scikit-Learn 的 管道官方指南

Python 异常检测手册— (4)隔离森林

原文:https://towardsdatascience.com/use-the-isolated-forest-with-pyod-3818eea68f08?source=collection_archive---------9-----------------------

Figure (A)

(2022 年 10 月 13 日修订)

如果让你把上面的树一棵一棵分开,哪棵树会是第一棵开始的?你可以选择左边的那个,因为它是独立的。去掉那棵树后,下一棵容易分离的树是什么?可能是大星团左下方的那颗。移走那棵树后,下一棵树是哪棵?可能是左上角的那个,以此类推。这里我提出一个很重要的直觉:离群值应该是最容易被孤立的。就像剥洋葱一样,离群值在外层。这就是 Isolate Forest 寻找离群值的直觉。

隔离林速度很快,并且不会消耗太多内存,因为它不使用任何距离度量来检测异常。这一优势使其适用于大数据量和高维问题。

什么是孤立森林?

许多异常值检测方法首先分析正常数据点,然后识别那些不符合正常数据模式的观察值。由刘,廷,周(2008) 提出的隔离林森林与这些方法不同。I forest直接识别异常,而不是分析正常数据点以发现异常值。它应用树结构来隔离每个观察。异常将是首先被挑选出来的数据点;而正常点往往隐藏在树的深处。他们称每棵树为隔离树隔离树。他们的算法建立了一个 iTrees 集合。异常是那些在 iTrees 上具有短平均路径长度的观测值。**

图(A)使用一个分区图和一棵树来解释 iTree 是如何隔离数据点的。红点是离其他点最远的点,然后是绿点,然后是蓝点。在分区图中,只需要一个“切口”就可以将红点与其他点分开。第二次切割是为了绿点,第三次切割是为了蓝点,以此类推。分割一个点需要的切割越多,它在树中的位置就越深。切割次数的倒数是异常分数。图(A)右边的树形结构讲述了同样的故事。它需要一次分裂来挑出红点,然后第二次分裂来达到绿点,然后第三次分裂来达到蓝点,以此类推。深度的数量成为异常分数的良好代表。为了符合异常与高分相关联的惯例,异常分数被定义为深度数的倒数。

Figure (A): iTree (Image by author)

一棵 iTree 是一棵二叉树,其中树中的每个节点恰好有零个或两个子节点。一棵 iTree 开始增长,直到满足其中一个条件:(I)结束节点只有一个数据点,(ii)节点中的所有数据都具有相同的值,或者(iii)树达到了(由研究人员设置的)高度限制。直到所有的端节点都有一个数据点,iTree 才需要完全开发。通常当高度达到设定的极限时,它就会停止生长。这是因为我们的兴趣在于更接近根部的异常。因此,没有必要构建大的 iTree,因为 iTree 中的大多数数据都是正常的数据点。小样本量产生更好的 iTrees,因为淹没和掩蔽效应减少了。注意,这个 iTree 算法不同于决策树算法,因为 iTree 不使用目标变量来训练树。它是一种无监督的学习方法。

(B)为什么是“森林”?

你可能更经常听到随机森林而不是孤立森林。“森林”指的是为树木构建森林的集合学习。为什么需要这样做?我们都知道单个决策树的缺点是过度拟合,这意味着模型对训练数据的预测很好,但对新数据的预测很差。集成策略通过构建许多树,然后平均这些树的预测来克服这个问题。

Figure (B): Isolation Forest

图(B)显示了一个数据矩阵,其中每一行都是具有多维值的观察值。IForest 的目标是给每个观察值分配一个异常值。首先,它随机选择任意数量的行任意数量的列来创建表,如(1)、(2)和(3)。观察将出现在至少一个表中。为每个表构建一个 iTree 来呈现异常值。表格(1)有 6 行 3 列。表(1)的第一个切割可能是第 6 个观察值,因为它的值与其他值非常不同。之后,表(1)的第二次切割可能是第四次观察。类似地,在表(3)中,第一次切割可能是第 6 次观察(这是第三次记录)。第二次切割是第 4 次观察(这是表中的第一条记录)。简而言之,如果有 N 个表,就会有 N 个树。一次观察最多可以有 N 个分数。IForest 计算分数的算术平均值,得到最终分数。

[## 通过我的推荐链接加入 Medium-Chris Kuo/data man 博士

阅读 Chris Kuo/data man 博士的每一个故事。你的会员费直接支持郭怡广/戴塔曼博士和其他…

dataman-ai.medium.com](https://dataman-ai.medium.com/membership)

(C)建模程序

像其他章节一样,我使用以下建模过程进行模型开发、评估和结果解释。

  1. 模型开发
  2. 阈值确定
  3. 描述正常和异常组

对两个组的剖析对于交流模型的可靠性是很重要的。你的商业知识会告诉你一个特征的平均值在异常组中应该更高还是更低。如果与直觉相反,建议您调查、修改或放弃该特性。您应该迭代建模过程,直到所有的特性都有意义。

(C.1)第一步:建立模型

我生成了一个包含六个变量和 500 个观察值的模拟数据集。尽管这个模拟数据集有目标变量 Y,但无监督模型只使用 X 变量。Y 变量只是用于验证。“污染=0.05”时,异常值的百分比设置为 5%我们可以绘制前两个变量的散点图。黄色点是异常值,紫色点是正常数据点。

Figure (C.1)

下面我们声明并拟合模型。树“max_samples”的大小被设置为 40 个观察值。在 IForest 中,没有必要指定大的树大小,小的样本大小可以产生更好的 I tree。

让我解释一下污染率。在大多数实际应用中,我们不知道离群值的百分比。我将在第(C.2)节中说明,当事先不知道异常值的百分比时,如何确定一个合理的阈值。PyOD 默认污染率为 10%。在这里,我将污染设置为 5%,因为它在训练样本中是 5%。此参数不影响异常值分数的计算。内置函数threshold_计算污染率下训练数据的阈值。在这种情况下,当污染率为 0.05 时,阈值为-5.082e-15。函数decision_functions()生成异常值分数,函数predict()基于阈值分配标签(1 或 0)。

(C.1.1)超参数

我将用.get_params()解释一些重要参数:

  • “max_samples”:从 X 中抽取的样本数,用于训练每个基本估计量。这是一棵树的大小,是一个重要的参数。
  • “n_estimators”:集合中树的数量。默认值是 100 棵树。
  • “max_features”:从 X 中抽取的特征数,用于训练每个基本估计量。默认值为 1.0。
  • “n_jobs”:为“fit”和“predict”并行运行的作业数。默认值为 1.0。如果设置为-1,则作业数量将设置为核心数量。

(C.1.2)可变重要性

因为 IForest 应用了一个树形框架,我们将能够理解特性在确定离群值时的相对重要性。特征的重要性通过基尼系数来衡量。这些值的总和为 1.0。

我们可以像基于树的模型一样绘制特征重要性。图(C.1.2)显示了特征在确定异常值时的相对强度。

Figure (C.1.2): Variable importance of IForest for Outliers

(C.2)步骤 2——为模型确定一个合理的阈值

阈值将由异常值分数的直方图来确定。图(C.2)建议阈值为 0.0 左右。这意味着大多数正常数据的异常值小于 0.0。异常数据的异常值在高范围内。

Figure (C.2)

(C.3)步骤 3 —呈现正常组和异常组的描述性统计数据

描述正常组和异常组是证明模型可靠性的关键步骤。我创建了一个简短的函数descriptive_stat_threshold()来显示正常组和异常组的特征的大小和描述性统计。下面我简单地采用设定污染率的阈值。您可以测试阈值范围,以确定离群值组的合理大小。

Table (C.3)

上表包括模型评估和模型结果的基本要素。提醒您使用功能名称来标记功能,以便有效地进行演示。

  • 离群组的大小:记住离群组的大小是由阈值决定的。如果为阈值选择较高的值,大小将会缩小。
  • 各组的特征统计:特征统计要与任何之前的业务知识一致。如果任何特征显示出与直觉相反的结果,则该特征应该被重新检查或移除。应该重新迭代模型,直到所有特性都有意义。
  • 平均异常分:异常组的平均异常分远高于正常组(0.18 > -0.10)。你不需要对分数解读太多。

因为我们在数据生成中有基础事实,所以我们可以生成混淆矩阵来理解模型性能。该模型提供了一个体面的工作,并确定了所有 25 个异常值。

(D)通过聚合多个模型实现模型稳定性

由于 IForest 是一种基于邻近度的算法,因此它对异常值很敏感,并且可能会过度拟合。为了产生稳定的预测结果,我们可以汇总多个模型产生的分数。在所有的超参数中,树的数量n_estimators可能是最重要的一个。我将为一系列的树木制作 5 个模型。这些模型的平均预测将是最终的模型预测。PyOD 模块提供了四种汇总结果的方法。记住使用pip install combo功能。你只需要使用一种方法来产生你的综合结果。

对 5 个模型的预测进行平均,以获得平均异常值分数(“y_by_average”)。我在图(D)中创建了它的直方图。

Figure (D): The histogram of the average score

图(D)表明阈值等于 1.0。这样,我在表(D)中描绘了正常组和异常组的特征。它将 25 个数据点识别为异常值。读者应对表(C.3)进行类似的解释。

Table (D)

(E)摘要

  • 大多数现有的基于模型的异常检测方法构建正常实例的简档,然后将不符合正常简档的实例识别为异常值。但是 IForest 直接且明确地隔离了异常。
  • IForest 采用树形结构来隔离每一个数据点。异常是首先被挑选出来的奇异数据点;而正常点倾向于在树中聚集在一起。
  • 因为隔离林不使用任何距离度量来检测异常,所以它速度很快,适合于大数据量和高维问题。

(F) Python 笔记本:点击此处为笔记本。

参考文献

  • 刘福亭,丁克明,周志宏(2008)。隔离森林。 2008 年第八届 IEEE 数据挖掘国际会议(第 413-422 页)。

为了便于导航到章节,我在最后列出了章节。

[## 通过我的推荐链接加入 Medium-Chris Kuo/data man 博士

阅读 Chris Kuo/data man 博士的每一个故事。你的会员费直接支持郭怡广/戴塔曼博士和其他…

dataman-ai.medium.com](https://dataman-ai.medium.com/membership)

建议读者购买郭怡广的书籍:

对数据科学家有用的命令行工具

原文:https://towardsdatascience.com/useful-command-line-tools-for-data-scientists-f9c929901e08?source=collection_archive---------13-----------------------

适用于您的 linux 终端的各种便利工具

从命令行工作可能令人畏惧,但对于任何数据科学家来说,这都是一项重要的技能。当在远程 linux 实例上工作时,您不再能够访问您最喜欢的 GUI,而是必须使用命令行来导航您的远程实例。这个工具列表并不是命令行入门指南,而是我觉得有用的工具大杂烩,我希望你也一样!

我们的好朋友 grep

grep 是一个命令行工具,用于在文件中搜索模式。grep 将打印文件中与标准输出(终端屏幕)模式匹配的每一行。当我们可能希望使用给定模式对我们的数据子集进行建模或执行 EDA 时,这可能特别有用:

 grep "2017" orders.csv > orders_2017.csv

在上面的命令中,我们从“orders.csv”数据集中捕获所有包含模式“2017”的行,然后将包含此字符串的行写入名为“orders_2017.csv”的新文件。当然,如果我们对 order_date 列感兴趣,而另一个不同的列,如 address 包含模式“2017”(即 2017 Wallaby Lane) ,那么我们可能会得到错误年份的数据;然而,这在熊猫身上可以很快得到解决。在马上使用 pandas 之前使用 grep 的一个原因是命令行工具通常是用 C 编写的,所以它们非常快。另一个原因是,使用 os.system()可以很容易地将它们放在 python 脚本中:

Grep is great and can also be used with all kinds of regular expressions using the -E option.

htop

有没有在熊猫工作,收到内存错误的?您是否并行运行了一些操作(即使用 n_jobs=-1 来拟合 sklearn 模型)并且不确定是否所有的 CPU 都在使用中?那么 htop 是给你的! htop 很棒,因为它允许您查看机器上当前的 CPU 和 RAM 使用情况:

在我的例子中,我的机器有四个 CPU,所以前四行显示了每个 CPU 的使用统计。第五行显示了我的电脑 8GB 内存的使用情况。下表显示了正在运行的进程以及相关的进程 id (PID)、内存和 CPU 使用情况以及一些其他有用的统计信息。

假设我们在 Jupyter 笔记本中遇到了熊猫操作的内存问题,使用 htop 可以帮助我们监控每个操作对 RAM 使用的影响。如果我们有这样的代码:

在上面的代码段中,我们正在为我们的熊猫数据帧制作大量副本,htop 可以帮助我们更好地认识到我们何时接近 RAM 阈值。此外,如果我们的机器上正在运行其他我们目前不需要的内存密集型进程,我们可以使用 kill 命令行工具终止或暂停它们( kill 的-9 选项将终止该进程,确保您终止的进程是非必要的/不是系统进程)。看 htop 或者 ps 输出得到 PID。

kill -9 {insert PID here}

df

df 是一个有用的工具,用来验证我们的机器上有多少可用的磁盘空间。当在没有指定任何文件名的情况下使用时, df 返回所有当前挂载的文件系统上的可用空间;但是,如果我想查看整个机器上有多少可用空间,我可以运行:

df -h /

h 选项返回人类可读的格式,而“/”表示根文件系统中有多少可用空间:

当需要在远程 AWS EC2 实例上为大量下载创建空间时, df 有助于确定还需要清理多少空间。如果您正在从一个包含大量大文件的旧项目中释放磁盘空间,您可以运行“ls -hlS”来查看可读的长格式(-l,意味着您可以查看权限/文件大小/最后修改日期)的文件,这些文件在给定的目录中按文件大小降序(-S)排序。这样可以快速确定删除哪些文件可以释放最多的空间:

watch 是一个易于使用的命令,当你需要一个命令的输出每 n 秒刷新一次时,这个命令可以派上用场。我过去从 pushshift reddit 评论数据库下载大型 JSON 文件时使用过这个命令。每个解压后的月评论是一个 100GB 的文件,所以我写了一个脚本一次下载一个文件,从 subreddits 中过滤掉我不感兴趣的评论,写到 MongoDB,删除大的 JSON 文件。在这种情况下,我使用手表反复检查是否正确的文件被下载,解压缩,然后在下载后删除。

正如我们在上面看到的,watch 的默认设置是每两秒钟重复一次命令,尽管我们可以用“ -n {number_seconds} ”选项来修改它。

单细胞蛋白质

scp 代表 secure copy,是一个有用的命令,我们可以用它在远程实例之间发送文件。

发送到远程:

scp -i ~/.ssh/path/to_pem_file /path/to/local/file ubuntu@IPv4:./desired/file/location

在上面的命令中,“ubuntu”是 ubuntu 实例的默认 AMI ssh 用户名,因此这可以根据您使用的 linux 发行版而改变。您的 IPv4 通常被格式化为由句点分隔的四个 8 位字段(即 32.14.152.68)。I 选项只是指定我们将使用一个身份文件,该文件包含公钥认证所必需的私钥。

从遥控器下载:

scp -i ~/.ssh/path/to_pem_file ubuntu@IPv4:./path/to/desired/file/   ~/my_projects/

注意,这个下载命令仍然是从我们的本地终端执行的。我们刚刚交换了本地文件系统和远程文件系统的写入顺序。此外,值得一提的是,如果我们对该命令使用-r 选项,我们可以递归地复制目录,而不仅仅是文件:

scp -i ~/.ssh/path/to_pem_file -r ubuntu@IPv4:./path/to/desired/folder/ ~/my_projects/

结论

linux 命令行提供了一系列功能强大的工具,可以真正帮助提高生产率,并了解机器的当前状态(即磁盘空间、正在运行的进程、RAM、CPU 使用情况)。在远程 linux 实例上工作通常是熟悉命令行的一个很好的方式,因为您被迫使用它,并且不能依靠 Mac 的 Finder 来导航文件系统。上面讨论的工具是我最喜欢/最常用的(除了 ls 和 cd 之外),我希望如果你以前不知道它们,你能把它们结合到你的工作流程中。感谢您的阅读!

进一步阅读

有用的命令列表:T3【http://www.slackstu.net/171/171-class-19f.xhtml】T5

命令行的数据科学:https://www . datascienceathecommandline . com/chapter-5-scrubping-data . html

诊断神经网络的有用图表

原文:https://towardsdatascience.com/useful-plots-to-diagnose-your-neural-network-521907fa2f45?source=collection_archive---------2-----------------------

训练神经网络不是一项容易的任务,有时会产生比预期好得多的结果,或者表现得差得多,产生的只是噪音。

Photo by Nina Ž. on Unsplash

让我们面对它…训练一个神经网络很难,如果你认为它很容易,那么很有可能你还没有完全理解深度学习。典型的深度学习模型由数百万个可学习的参数组成。分析他们中的每一个人在训练中如何变化,以及一个人如何影响其他人,是一项不可能完成的任务。

幸运的是,我们有一定的数量可以观察训练的进展。这些措施让我们得以一窥黑箱,了解它们是如何变化的。

随着每一次网络培训的开始,让我们从数据开始。

数据

对于每一个机器学习模型,数据的重要性高于所有其他因素。我不能强调这一点…看看你的数据!!!。数据可能会解释为什么你在训练时会有问题。您的数据可能会让您了解为什么您的模型没有像预期的那样运行。让我解释一下。

在训练分类模型之后,可能存在模型的输出完全或大部分属于一个类别的情况,即模型有偏差的情况。这主要是由于不平衡的数据集。

人们可能面临的另一个问题是没有足够的数据来支持问题陈述。为了说明这一点,我来分享一个经历。几个月前(在我发表这篇文章的时候),我的一个朋友请我帮个忙。他让我用很少的数据点重新生成一个图形,即训练一个神经网络作为函数逼近器。

光是看原图照片,就知道是指数曲线。但这还不够,因为他需要对情节进行推理。他需要精确的曲线。他设法给了我一些从图表中手动提取的数据点。当我训练网络并预测一个小域的值时,我得到的只是一条略微弯曲的线。我没想到会是这样的曲线。无论我做什么,图表都保持不变。

当我将数据可视化时,我发现数据是不够的。网络仅仅理解它是一条指数曲线是不够的。

这种情况在数据收集期间是一个严重的问题。我们可能认为我们得到了一切,但我们可能只收集了所需数据的一个子集。这可能不足以解决问题。想想吧…

损失曲线

调试神经网络最常用的图之一是训练期间的损失曲线。它为我们提供了训练过程和网络学习方向的快照。斯坦福大学的安德烈·卡帕西在这个链接上给出了一个令人惊叹的解释。这一节深受它的启发。

Effect of Learning rate on Loss (Source: CS231n Convolutional Neural Networks for Visual Recognition)

这个图像很容易理解。您可以在两个时间段内记录您的损失:

  • 在每个时代之后
  • 每次迭代后

据说绘制跨时期的损失比迭代更理想。

在一个历元期间,跨每个数据项计算损失函数,并且保证在给定的历元给出定量的损失度量。但是跨迭代绘制曲线仅给出整个数据集的子集的损失。

通过绘制验证损失和训练损失图,可以获得更多的信息。

精确度曲线

另一个最常用于理解神经网络进展的曲线是精度曲线。对于任何在深度学习方面有一些经验的人来说,使用准确度和损失曲线是显而易见的。

更重要的曲线是同时具有训练和验证准确性的曲线。

Accuracy Plot (Source: CS231n Convolutional Neural Networks for Visual Recognition)

训练和验证准确性之间的差距是过度拟合的明显标志。间隙越大,过度拟合程度越高。

不确定

另一个可能被削弱的量是不确定性。不确定性是一个有点高深的话题,但我建议每个人都应该理解这个概念。它更像是一个定量的衡量,而不是一个情节。不确定性有两种类型:

  • 随机不确定性/数据不确定性
  • 认知不确定性/模型不确定性

在本节中,我们将重点关注模型的不确定性。

模型不确定性是关于模型参数和模型结构的不确定性。两种神经网络架构可以具有不同的不确定性值。因此,我们得到了一个量化的方法来比较这些体系结构,并找到更好的一个。

在我个人看来,完全偏向准确性不是一个好的方法。

在下面的例子中,我绘制了一个建筑的不确定性,这个建筑是在波士顿房价数据集上训练出来的。模型的不确定性被记录在整个训练时期。

模型的不确定性随着训练而降低……这是有道理的。我已经训练了 250 个时期的模型,只是为了向你们展示不确定性是如何变化的。

结论

当一个模型没有给出想要的结果时,试着去理解发生了什么。这些措施可以让我们一窥神经网络的训练。此外,可视化隐藏层输出(尤其是在卷积网络中)在很大程度上有所帮助。

谢谢大家!!😁

Python 中有用的字符串方法

原文:https://towardsdatascience.com/useful-string-methods-in-python-5047ea4d3f90?source=collection_archive---------7-----------------------

了解一些 Python 内置的可用于字符串的方法

original Image: Terri Bleeker on Unsplash

字符串是一系列字符。Python 中内置的 string 类表示基于 Unicode 国际字符集的字符串。字符串实现了 Python 中常见的操作序列,以及一些它们独有的附加方法。下图显示了所有这些可用的方法:

Built-in String Functions in Python

在这篇文章中,我们将了解一些更常用的。这里需要注意的重要一点是,所有的字符串方法总是返回新值,并且不改变或操作原始字符串。

这篇文章的代码可以从相关的 Github 库获得,或者你可以点击下面的图片在我的活页夹上查看。

1.居中( )

[center()](https://docs.python.org/3.7/library/stdtypes.html#str.center)方法居中对齐字符串。对齐是使用指定的字符完成的(缺省情况下是空白)

句法

str.**center**(length, fillchar),其中:

  • 长度是字符串的长度要求
  • fillchar 是指定对齐的字符[ 可选

例子

2.计数( )

[count()](https://docs.python.org/3.7/library/stdtypes.html#str.count)方法返回特定值在字符串中出现的次数。

句法

str.**count**(value, start, end),其中:

  • 是要在字符串[ 必选 ]中搜索的子字符串
  • start 是字符串中开始搜索指定值的起始索引[ 可选
  • end 是字符串中结束搜索指定值的结束索引[ 可选

例子

3.查找( )

[find()](https://docs.python.org/3.7/library/stdtypes.html#str.find)方法返回字符串中特定子串的最低索引。如果找不到子字符串,则返回-1。

句法

str.**find**(value, start, end),其中:

  • 在字符串[ 必选 ]中要搜索的值或子字符串
  • start 是字符串中开始搜索指定值的起始索引[ 可选 ]
  • end 是字符串中结束搜索指定值的结束索引[ 可选

类型

rfind():rfind()方法类似于 find(),只是它返回子串的最高索引值

例子

4.交换情况( )

方法返回一个字符串的副本,所有的大写字母都转换成小写,反之亦然。

句法

string.swapcase()

例子

5.startswith()和 endswith()

如果字符串以指定的值开始,则[startswith()](https://docs.python.org/3.7/library/stdtypes.html#str.startswith)方法返回 True 否则,它返回 False。

另一方面,如果字符串以指定的值结束,函数endswith()返回 True,否则返回 False。

句法

string.startswith(value, start, end)

string.endsswith(value, start, end)

  • 是在字符串[ 必选 ]中查找的字符串
  • start 是字符串中开始搜索指定值的起始索引[ 可选
  • end 是字符串中结束搜索指定值的结束索引[ 可选

例子

6.拆分( )

split() 方法返回一个字符串中的单词列表,其中默认分隔符是任何空格。

句法

string.split(sep, maxsplit)

  • sep :用于分割字符串的分隔符。如果没有指定,空白是默认分隔符[ 可选 ]
  • 最大分割:表示分割的次数。默认值为-1,表示“所有事件”可选 T43

版本

例子

7.字符串大写

1.大写( )

方法只将字符串的第一个字符大写。

语法

string.capitalize()

2.上部( )

upper() 方法将字符串中的所有字母大写。

语法

string.upper()

3.string.title()

title() 方法将给定字符串的所有首字母大写。

语法

string.title()

例子

8.ljust()和 rjust()

方法使用一个指定的字符返回给定字符串的左对齐版本,默认为空白。rjust()方法将字符串右对齐。

句法

string.rjust/ljust(length, character)

  • length: 要返回的字符串的长度[ 必选
  • 字符:用于填充缺省空格的字符[ 可选 ]

例子

9.条状( )

方法返回一个去掉了前导和尾随字符的字符串的副本。要删除的默认字符是空白。

句法

string.strip(character)

字符:要删除的字符集[ 可选

版本

  • rstrip() :从字符串右侧剥离字符。
  • lstrip() :从字符串左侧剥离字符。

10.零填充( )

zfill()方法在字符串的开头添加零(0)。返回字符串的长度取决于提供的宽度。

句法

string.zfill(width)

  • width :指定返回字符串的长度。但是,如果宽度参数小于原始字符串的长度,则不会添加零。

例子

结论

这些是 Python 中一些有用的内置字符串方法。还有一些文章中没有提到,但同样重要。如果您想更深入地了解细节,Python 文档是一个很好的资源。

使用 Spark 进行用户流失预测

原文:https://towardsdatascience.com/user-churn-prediction-using-spark-22ff8dafb5c?source=collection_archive---------28-----------------------

Udacity 数据科学家纳米学位计划顶点项目

该项目是 Udacity 数据科学家纳米学位项目:数据科学家顶点计划的最终项目。目标是预测用户是否会从虚拟的数字音乐服务中流失 Sparkify

流失预测是商业中最受欢迎的大数据用例之一。正如这篇帖子中更好地解释的那样,它的目标是确定客户是否会取消他的服务订阅

让我们从使用 CRISP-DM 流程(数据挖掘的跨行业流程)开始:

  1. 业务理解
  2. 数据理解
  3. 准备资料
  4. 数据建模
  5. 评估结果
  6. 展开

业务理解

Sparkify 是一项数字音乐服务,可以免费使用,方法是在歌曲之间收听一些广告,或者支付每月订阅费以获得无广告体验。在任何时候,用户都可以决定从高级降级到免费,从免费升级到高级或者取消服务。

https://www.udacity.com/course/data-scientist-nanodegree--nd025

数据理解

所提供的数据集基本上由平台上每个用户操作的日志组成。每个动作都标有时间戳 ts

Dataset attributes

First 5 records as example

在这个小数据集中,我们有来自 225 个用户的 286500 条记录:

46%的女性和 54%的男性

Gender distribution in the small dataset

54%的互动来自免费用户,46%来自高级用户

Level distribution in the small dataset

Page distribution in the small dataset

% page distribution in the small dataset

这些记录的时间跨度从 2018 年 10 月到 2018 年 12 月

准备数据

第一步是删除所有用户 Id 为空的记录。空字符串 userId 很可能指的是尚未注册的用户,或者已经注销并即将登录的用户,因此我们可以删除这些记录。

然后我定义了一个新的Churn列,它将被用作模型的标签。基本上,如果用户曾经访问过Cancellation Confirmation页面,我们会将其标记为搅动。当然,这个事件对于付费和免费用户都可能发生。

我们获得了 23%的流失用户和 77 %的未流失用户,因此数据集非常不平衡。正如这篇精彩的帖子中所解释的,当我们在评估结果部分讨论指标时,我们必须记住这一点

Churn distribution in the small dataset

然后,我对一些特性进行了比较,同时也考虑了Churn值:

Churn Gender distribution in the small dataset

Churn Level distribution in the small dataset

Churn Page distribution in the small dataset

% churn page distribution in the small dataset

数据建模

所有对我们的任务有用的分类特征都已经通过用户 Id :
-性别
-级别
-页面进行了一次性编码和聚合

Engineered dataset attributes

然后,我们通过提出以下问题添加了一些有趣的工程特性:
-用户订阅该服务多久了?流失与此有关吗?
-上个月的活动(对于不满意的用户,取消是取消前的最后一个月)以周为单位划分
-一个用户听了多少艺术家的音乐?

Churn Registration days distribution in the small dataset

Churn Last week average activity distribution in the small dataset

Churn Artist distribution in the small dataset

为 ML 准备的最终数据集如下所示:

Engineered dataset attributes in input to the model

重要的是不要考虑像page_Cancellation_Confirmationpage_Cancel这样的属性,因为它们精确地映射了标签列,所以准确率总是 100%,因为我们基本上是在学习我们想要预测的值

评估结果

混淆矩阵是一个表格,通常用于描述一个分类模型对一组真实值已知的测试数据的性能。

准确性衡量分类器做出正确预测的频率。它是正确预测数与总预测数的比率:

Accuracy = (True Positives + True Negative) / (True Positives + False Positives + True Negatives + False Negatives)

精度告诉我们正确的预测中有多少是正确的。它是真阳性与所有阳性的比率:

Precision = True Positives / (True Positives + False Positives)

回忆(敏感度)告诉我们实际上正确预测中有多少被我们归类为正确的。它是真阳性与所有实际阳性预测的比率:

Recall = True Positives / (True Positives + False Negative)

F-beta 评分是一个同时考虑精确度和召回率的指标:

生成朴素预测器的目的只是为了显示没有任何智能的基础模型是什么样子。如前所述,通过观察数据的分布,很明显大多数用户不会流失。因此,总是预测'0'(即用户不访问页面Cancellation Confirmation)的模型通常是正确的。

将所有用户标记为流失= 0 的朴素模型在测试集上做得很好,准确率为 81.2%,F1 分数为 0.7284

数据集不平衡的事实也意味着精确度没有太大帮助,因为即使我们获得高精确度,实际预测也不一定那么好。在这种情况下,通常建议使用精度召回

让我们比较 3 个模型的结果:

  • 逻辑回归
  • 梯度提升树
  • 支持向量机

第一步是删除培训中不必要的列

colonne = df.columns[1:-1]
colonne

Features used for ML training

然后所有的特征都被矢量化(不需要转换,因为所有的特征都是数字)

assembler = VectorAssembler(inputCols = colonne, outputCol = ‘features’)data = assembler.transform(df)

StandarScaler()用于缩放数据

scaler = StandardScaler(inputCol = 'features', outputCol = 'scaled_features', withStd = True)scaler_model = scaler.fit(data)data = scaler_model.transform(data)

然后,我将数据分为训练、测试和验证数据集

train, rest = data.randomSplit([0.6, 0.4], seed = 42)validation, test = rest.randomSplit([0.5, 0.5], seed = 42)

对于所有车型,我都使用了 F1 分数作为衡量标准

f1_evaluator = MulticlassClassificationEvaluator(metricName = ‘f1’)

以及ParamGridBuilder()和 3 倍CrossValidator()来确定考虑所有参数的模型的最佳超参数

param_grid = ParamGridBuilder().build()

逻辑回归

logistic_regression = LogisticRegression(maxIter = 10)crossvalidator_logistic_regression = CrossValidator(  
estimator = logistic_regression,                                 evaluator = f1_evaluator,                                                    estimatorParamMaps = param_grid,                                                    numFolds = 3)cv_logistic_regression_model = crossvalidator_logistic_regression.fit(train)

Best parameters

梯度提升树

gradient_boosted_trees = GBTClassifier(maxIter = 10, seed = 42)crossvalidator_gradient_boosted_trees = CrossValidator(
estimator = gradient_boosted_trees,                                                       evaluator = f1_evaluator,                                                       estimatorParamMaps = param_grid,                                                       numFolds = 3)cv_gradient_boosted_trees_model = crossvalidator_gradient_boosted_trees.fit(train)

Best parameters

GBT 也允许看到特性的重要性:

Feature importances from GBT

我们可以看到registration_dayscount_page_last_week具有最高的重要性

支持向量机

linear_svc = LinearSVC(maxIter = 10)crossvalidator_linear_svc = CrossValidator(
estimator = linear_svc,                                           evaluator = f1_evaluator,                                           estimatorParamMaps = param_grid,                                           numFolds = 3)cv_linear_svc_model = crossvalidator_linear_svc.fit(train)

Best parameters

总的来说,逻辑回归具有最好的结果,在测试数据集上 F-1 得分为 0.8218,在验证数据集上为 0.7546

Results on test and validation datasets

细化

我第一次尝试手动调整模型的一些参数,但是通过让ParamGridBuilder()CrossValidator()搜索所有参数获得了最佳结果

部署

根据 DSND 顶点项目的云部署说明的建议,我已经用 AWS 创建了一个集群

My cluster configuration

正如这里更好地解释的m3 . xlarge是第二代通用 EC2 实例,配备了高频英特尔至强 E5–2670和 2 个基于 40 GB 固态硬盘的实例存储

My cluster summary

然后我创建了一个笔记本并复制粘贴了必要的代码

sparkify notebook summary

在真实数据集上,我们有来自 22278 个用户的 26259199 条记录:

47%的女性和 53%的男性

Gender distribution in the full dataset

21%的互动来自免费用户,79%来自高级用户

Level distribution in the full dataset

Page distribution in the full dataset

22%的用户感到不适,78 %没有

这个小数据集很好地代表了真实数据集,这意味着它似乎没有偏见

结论

我们的目标是预测用户是否会取消服务,以使公司能够为他提供优惠或折扣,从而留住这些用户。在清理数据并将它们建模为准备用于 ML 训练的数据集之后,我们测试了三个不同模型的性能。所有产生的模型都成功地预测了用户是否会离开服务,比给出总是答案的'0'(用户不会流失)的天真预测器好不了多少。考虑到 F-1 得分最好的模型是逻辑回归。尽管结果很好,但该模型可以通过精心设计更多的工程特征来捕捉一些可能与用户对服务的满意度相关的行为模式来改进:推荐引擎好吗?意思是推荐给用户的歌真的符合他们的口味。从 GBT 的功能重要性来看,原始功能page_Thumbs_Uppage_Thumbs_Down相当重要,因此捕捉用户音乐品味的新功能确实可以改善模型

这个项目的代码可以在这个 github 资源库中找到,在我的博客上有一个意大利语的帖子

我的第一个数据产品的用户指南:中等邮政公制显示器

原文:https://towardsdatascience.com/user-guide-to-my-first-data-product-medium-post-metric-displayer-e99e74e52b3a?source=collection_archive---------16-----------------------

用数据更好地了解你的媒体文章

原点

作为一名媒体上的定期作家和数据极客,在忙碌的 2018 年之后,我想在我的媒体博客上反映一下我所取得的成就。此外,根据 2018 年的表现,我计划在 2019 年制定更积极的写作计划。

我想大多数媒体作者都知道媒体分析平台的反数据为中心的界面设计。对我来说太简单了。这种设计让我很不情愿去研究数据并做出决定。

这是我决定开发我的第一个数据产品的主要原因。在下面的文章中,我将向读者展示这个产品和我用来创建这个产品的代码。我将使用我自己的数据在中型分析平台,以及展示我的产品如何运行。

整个思考和执行过程也会被详细记录下来。任何热衷于了解他或她自己的 Medium post 性能的人,都可以随意使用我的代码来提供一些数据。

from https://medium.com/membership

问题陈述和痛点

问题陈述:以更健壮、更形象化的方式知道哪篇文章表现好,很烦。此外,文章可能无法分组或分类。在所有的指标中,哪些指标对于不同的文章组可能是最有区别的?

痛点:中型用户可能会发现很难充分利用 Medium 提供的分析平台(Stat 选项卡)。这些数据无法下载,也几乎没有告诉我们下一步该做什么。

约束

这个产品的约束非常明显。对我来说,我仍然不能以一种更自动化的方式从介质中抓取或输出每篇文章的性能数据。因此,用户需要手动记录这些数据,就像我在这个 excel 中所做的那样。列名应该与我的相同。用户只需要定期按季度(每季度或每半年)记录这些指标

I will put this file in my GitHub as well, feel free to download it

我的产品能彻底处理那些 excel 文件。一旦有了特定数据文件。我们准备好出发了。

技能和工具

工具:Python Jupyter 笔记本

技能:用 Pandas 进行数据处理和管理,用 Matplotlib 进行可视化,用 Sklearn 进行聚类加 PCA,为重复操作创建大量函数

产品展望

这个产品很简单。我还没有创建它的布局或界面,但相反,我将介绍这个产品背后的操作逻辑。中邮公制显示器包括许多小而方便的功能。一旦用户将 excel 文件(我们用于记录数据)传递给这些函数,就会自动生成结果。

它包含该产品的两个功能。第一个是仪表板和可视化产品。第二个是集群产品。

这是我的产品路线图的第一阶段。(我不确定我是否会继续扩展它的功能)。然而,我认为这个测试版的 Displayer 足够全面,可以为作者做出决定提供一些见解。这就是我决定在这个时候软发布我的产品的原因。

请随意获取我的 Github 代码,并愉快地使用这个产品!

[## 云汉风/medium_metric_data_product

我的第一个数据产品,为媒体作者提供数据解决方案来跟踪帖子的表现…

github.com](https://github.com/yunhanfeng/medium_metric_data_product)

第 0 部分:预检数据导入

在介绍产品本身之前,我们先来看看我们的数据集。

可以肯定的是 python 中需要的包是导入的。熊猫、Numpy、Matplotlib 是我熟悉的朋友。这次我用了 Goolgetrans 的翻译。背后的原因是我有时用中文写文章,而我的大部分读者来自台湾。他们也可能用中文写帖子。将中文标题翻译成英文将更符合 Matplotlib 的约束,因为 Matplotlib 不能显示中文。

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from googletrans import Translator

我后来读入 excel 文件并显示它的前几行,进一步检查列的类型和形状。从介质中提取和记录的数据来看,有七个基本特征。从我的媒体网站,我已经写了 45 篇文章了。

df = pd.read_excel('medium_performance_data.xlsx')
df.head()

df.dtypesdates              datetime64[ns]
title                      object
view                        int64
additional_view             int64
read                        int64
read_ratio                float64
fans                        int64
dtype: objectdf.shape
(45, 7)

第一部分:仪表盘和可视化产品

在这个产品中,我设计了八加一功能,使用户能够通过简单的 excel 文件输入返回不同指标的类似图表和图形。基于这些图表,作者能够对他们的文章表现的好坏有所了解,并进一步制定下一步的策略。

下面是 Medium post 上的用户参与度漏斗。基本上,我只是按照漏斗来设计我的产品。

功能 0

此功能主要处理中文标题的翻译问题。多亏了强大的谷歌翻译,它帮助把这些书名翻译成英文。

def translate(df):
    import numpy as np
    import matplotlib.pyplot as plt
    from googletrans import Translator

    translator = Translator()
    df['title'] =  df["title"].map(lambda x: translator.translate(x, src="zh-TW", dest="en").text)
    return df

功能 1

该函数返回总视图的静态值。它是所有中等职位的基本数字,显示了对你的表现的一般描述。

def total_view(file):
    import pandas as pd

    df = pd.read_excel(file)
    df = translate(df)
    total_view = df['view'].sum() + df['additional_view'].sum()
    return 'The total view of your medium post is {}'.format(total_view)

我把我的文件传入这个函数,它返回我的总浏览量大约是 15K。

total_view('medium_performance_data.xlsx')>> 'The total view of your medium post is 15086'

功能 2

函数 2 返回浏览量最多的前 5 篇文章。结果将以表格和条形图的形式显示。你也可以一瞥这 5 个对你的总浏览量的贡献。

def top_view(file):
    import pandas as pd df = pd.read_excel(file)
    df = translate(df)
    top_view = df.nlargest(5, 'view')[['title','view']]
    ax = top_view.plot.barh(x='title', y='view')
    return display(top_view) , ax

操作该功能

top_view('medium_performance_data.xlsx')

我的前 5 篇文章的结果显示如下。看来我写的关于 MSBA 申请的文章吸引了大部分的关注。

功能 3

与函数 2 类似,该函数返回带有附加视图的前 5 篇文章的表格和条形图。额外的看法,对我来说,是一个相当奇怪的衡量标准。来自 Medium 的定义是“来自 RSS 阅读器、FB 即时文章和 AMP 的观点,它们不计入阅读率。”并不是一个作者发布的每篇文章都会有额外的观点。根据我的经验,只有当你的文章被 Medium 上的其他出版网站策划时,附加浏览量才有可能增加。它提供了一些见解,如何好这些出站文章的表现。

def top_additional_view(file):
    import pandas as pd df = pd.read_excel(file)
    df = translate(df)
    top_view = df.nlargest(5, 'additional_view' [['title','additional_view']]
    top_view = top_view[top_view['additional_view']>0]
    ax = top_view.plot.barh(x='title', y='additional_view')
    return display(top_view) , ax

操作该功能。

top_additional_view('medium_performance_data.xlsx')

功能 4

Read 是关于敬业度的更深层次的指标。如果用户一直滚动到底部,则 Read 是指标,这表示用户通读了帖子。该函数采用文件名作为参数,并返回表格和条形图。

def top_read(file):
    import pandas as pd

    df = pd.read_excel(file)
    df = translate(df)
    top_read = df.nlargest(5, 'read')[['title','read']]
    top_read = top_read[top_read['read']>0]
    ax = top_read.plot.barh(x='title', y='read')
    return display(top_read) , ax

操作该功能。

top_read('medium_performance_data.xlsx')

结果与大多数观点的前 5 篇文章略有不同。阅读量最多的前 5 都是中文帖子。背后有多种可能的原因。

第一,我的大多数读者来自台湾,中文对我的大多数用户来说是一种相对熟悉的语言。他们倾向于读完更多的文章。

第二,它可能表明我的英文写作太长或太复杂,用户无法通读。我可能需要润色我的帖子,让它更简洁。

第三,除了语言问题,阅读量最多的前 5 个帖子都与信息相关的话题,如如何准备申请,如何提问以及 MSBA 课程的复习。也许这种话题可以引发更多的阅读兴趣。

功能 5

阅读率是另一个棘手的指标。阅读率=阅读/浏览(点击)。据说,中等算法将奖励阅读率较高的文章以较高的排名和优先级显示在用户面前。

该函数的工作方式与上面的相同,以显示表格和条形图的形式返回阅读率最高的前 5 篇文章。

def top_readratio(file):
    import pandas as pd

    df = pd.read_excel(file)
    df = translate(df)
    top_read = df.nlargest(5, 'read_ratio')[['title','read_ratio']]
    top_read = top_read[top_read['read_ratio']>0]
    ax = top_read.plot.barh(x='title', y='read_ratio')
    return display(top_read) , ax

操作该功能。

top_readratio('medium_performance_data.xlsx')

从某些方面来说,对结果的解释是很复杂的。

第一,文章越短,就越有可能获得更高的阅读率。我所有帖子中的第一篇文章只是一个链接。当然,它将获得最高的读取率。

其次,浏览量少的文章也可能导致阅读率高,就像我的文章“[创造]。”

结论是,有一些内生性影响这一指标。我建议用户用上面的函数交叉验证这个指标。

功能 6

该函数返回所有文章的平均阅读率。因为读取率是中等算法的关键指标。我建议作者偶尔使用这个功能来跟踪文章表现的进度。

def avg_readratio(file):
    import pandas as pd

    df = pd.read_excel(file)
    avg_rr = round(df.read_ratio.mean(),3)
    return 'The avg. read ratio of your medium post is {}'.format(avg_rr)

操作该功能。

avg_readratio('medium_performance_data.xlsx')>> 'The avg. read ratio of your medium post is 0.528'

还应该根据内容的特征和类别进行设置。一些轻松易消化的文章可能有更高的平均阅读率,反之亦然。我的文章,平均阅读比是 0.528,对我来说,还不错。

我将努力把这作为我的目标,来提高我的媒体网站的阅读率。写结构清晰、可读性强、简洁明了的帖子是一个很好的方法。

功能 7

下一个功能是关于显示粉丝数最高的前 5 篇文章。粉丝指标是表示对文章更深入参与的指标。读者为帖子鼓掌,并展示了他们的“喜欢”它是公制漏斗的最后一步,可以更难实现。

def top_fans(file):
    import pandas as pd

    df = pd.read_excel(file)
    df = translate(df)
    top_read = df.nlargest(5, 'fans')[['title','fans']]
    top_read = top_read[top_read['fans']>0]
    ax = top_read.plot.barh(x='title', y='fans')
    return display(top_read) , ax

操作该功能。

top_fans('medium_performance_data.xlsx')

功能 8

产品第一部分的最后一个功能是显示“过去几天的平均视图”我创建这个新指标来捕捉帖子的每日额外浏览量。公式是:从今天到文章发表那天的总浏览量/天数。对我来说,它计算的是这篇文章每天的浏览量。

def top_view_per_day(file):
    import pandas as pd

    df = pd.read_excel(file)
    df = translate(df)
    df['time_elapse'] =pd.datetime.now().date() - df['dates']
    df['time_elapse'] = df['time_elapse'].dt.days
    df['total_view'] = df['view'] + df['additional_view']
    df['view_per_day']  = round(df['total_view'] / df['time_elapse'], 2)

    top_read = df.nlargest(5, 'view_per_day')[['title','view_per_day']]
    top_read = top_read[top_read['view_per_day']>0]
    ax = top_read.plot.barh(x='title', y='view_per_day')
    return display(top_read) , ax

操作该功能

top_view_per_day('medium_performance_data.xlsx')

我认为这个指标非常重要。这表明,文章仍然带来了每天的流量。那些文章将用户导向作者的媒体网站。它帮助用户识别你的媒体博客的“摇钱树”。了解这些文章后,定期在社交媒体上推广它们或让它们被关联者引用是保持新鲜流量流入你的媒体的好策略。

第二部分:集群产品

就像我在功能 8 中提到的,识别哪些文章是摇钱树很重要。这正是我提出并创造这个集群产品的初衷。通过对所提供的特征进行无监督学习,可以将文章分割成不同的组。每个群体都有不同的特征。他们可以在用户获取、保留和参与方面扮演不同的角色。通过使用这种聚类产品,用户只需传递 excel 文件,并进一步输入他想要创建的聚类数,结果就会自动生成。有几个功能也与可视化集群相关。

我将在下一篇文章中介绍四加一函数。

功能 9

这个函数只是管理数据的辅助函数。我从原始数据框架中创建了“总视图”和“每日视图”。

def medium_data_munge(file):
    import pandas as pd

    df = pd.read_excel(file)
    df = translate(df)
    df['time_elapse'] =pd.datetime.now().date() - df['dates']
    df['time_elapse'] = df['time_elapse'].dt.days
    df['total_view'] = df['view'] + df['additional_view']
    df['view_per_day']  = round(df['total_view'] / df['time_elapse'], 2)
    return dfmedium_data_munge("medium_performance_data.xlsx").head()

功能 10 和 11

这两个函数用于聚类。我使用 K-means 对文章进行聚类。我记录了阅读量、阅读率、粉丝数、总浏览量、每日浏览量。并且分割基于这五个特征。

从这里开始的函数,用户需要将 excel 文件和集群号传递给函数。

函数 10 返回带有簇标签的数据帧。用户可能把它看作是一个助手功能或产品功能。它返回的数据帧很容易被看到和播放。

函数 11 返回每个集群的摘要。它让用户清楚地了解每个集群的性能和质量。我认为这非常有帮助,因为用户最终可以针对不同的集群设计合适的推广策略。每当你想重新分享或者盘活流量的时候,使用这个产品功能真的可以证明你的选择是正确的。我也建议不要在论证中使用太多的聚类,你可以输入不同的数字,然后看看哪个数字给出了最有解释力的结果。

### Function 10
def create_cluster_df(file, n):

    from sklearn.preprocessing import StandardScaler
    from sklearn.cluster import KMeans

    df = medium_data_munge(file)

    # Select proper feature
    features = ['read','read_ratio','fans','total_view','view_per_day']
    x = df.loc[:, features].values

    # Normalized data 
    x = StandardScaler().fit_transform(x) 

    # Conduct K-mean
    km = KMeans(n_clusters = n, random_state=0)
    km.fit(x)
    labels = km.labels_
    cluster = labels.tolist()

    final_cluster = pd.DataFrame(dict(cluster_label = cluster, title = df['title']))
    df_new = pd.merge(df, final_cluster, how = 'left', on = ['title'])

    return df_new### Function 11
def cluster_df_desc(file, n):
    # create dataframe with cluster label
    df_new = create_cluster_df(file, n)

    # summarize the clustered dataframe
    col = ['cluster_label', 'total_view' , 'read', 'read_ratio', 'fans','view_per_day']
    final_df = df_new[col].groupby(['cluster_label']).agg({'cluster_label' : 'size', \
                                                                                                      'total_view': lambda x:x.mean(), \
                                                                                                       'read': lambda x: x.mean(), \
                                                                                                       'read_ratio': lambda x: x.mean(), \
                                                                                                       'fans': lambda x:x.mean(), \
                                                                                                         'view_per_day': lambda x:x.mean()})
    return display(final_df)

操作功能 10

create_cluster_df("medium_performance_data.xlsx", 3).head()

操作功能 11

cluster_df_desc("medium_performance_data.xlsx",3)
cluster_df_desc("medium_performance_data.xlsx",5)

I demo n = 3 and n = 5 and show the result here

功能 12

这个函数是前一个函数的后续函数。一旦您返回理想的集群概述。你可能想想象一下。因此,我利用主成分分析(PCA)将五个特征维度转化为两个维度。并且不同组中的所有物品可以在这个 2D 平面上被标记。

只需传递文件和簇号,就可以得到结果。它还将返回主成分 1 和 2 的解释比率。我将在这里尝试 n = 3 和 n = 5。

def pca_vis(file, n):
    from sklearn.preprocessing import StandardScaler
    from sklearn.decomposition import PCA

    df_new = create_cluster_df(file, n)

    # Select proper feature
    features = ['read','read_ratio','fans','total_view','view_per_day']
    x = df_new.loc[:, features].values

    # Normalized data 
    x = StandardScaler().fit_transform(x) 

    pca = PCA(n_components=2)
    principalComponents = pca.fit_transform(x)

    principalDf = pd.DataFrame(data = principalComponents, columns = ['principal component 1', 'principal component 2'])

    finalDf = pd.concat([principalDf, df_new[['cluster_label']]], axis = 1)

    # plot the PCA two-dimensional graph
    fig = plt.figure(figsize = (6,6))
    ax = fig.add_subplot(1,1,1) 
    ax.set_xlabel('Principal Component 1', fontsize = 13)
    ax.set_ylabel('Principal Component 2', fontsize = 13)
    ax.set_title('2 component PCA', fontsize = 15)
    targets = list(range(0,n))
    colors = ['b', 'g', 'r', 'c', 'm', 'y', 'k', 'w']
    colors =  colors[:n]for target, color in zip(targets,colors):
        indicesToKeep = finalDf['cluster_label'] == target
        ax.scatter(finalDf.loc[indicesToKeep, 'principal component 1']
                         , finalDf.loc[indicesToKeep, 'principal component 2']
                         , c = color
                         , s = 50)
    ax.legend(targets)
    ax.grid()

    return 'The explained ratio for component 1 is {0:.2f} and for component 2 is {1:.2f}'. \
                   format(pca.explained_variance_ratio_[0], pca.explained_variance_ratio_[1] )

操作代码

pca_vis("medium_performance_data.xlsx",3)
pca_vis("medium_performance_data.xlsx",5)

功能 13

最后一个功能也与聚类有关。该功能创建了所谓的平行坐标图。它展示了不同聚类中每个特征的贡献程度。简而言之,它揭示了集群背后的逻辑。并且作者能够基于该结果做出进一步的决定。

例如,我将尝试 cluster = 3 和 5。

def parallel_coordinates(file, n):
    df_new = create_cluster_df(file, n)

    cols = ['total_view', 'read', 'read_ratio', 'fans', 'view_per_day' ]
    df_new_sub = df_new[cols]

    from sklearn.preprocessing import StandardScaler
    from pandas.plotting import parallel_coordinates

    ss = StandardScaler()scaled_df = ss.fit_transform(df_new_sub)
    scaled_df = pd.DataFrame(scaled_df, columns=cols)
    final_df = pd.concat([scaled_df, df_new['cluster_label']], axis=1)

    parallel_coordinates(final_df, "cluster_label")
    plt.title("Parallel Coordinates Graph on Each Metric")
    plt.show()

操作该功能

parallel_coordinates("medium_performance_data.xlsx", 3)
parallel_coordinates("medium_performance_data.xlsx", 5)

如果 n = 3,我可以得出结论,集群 1,表现最好的两篇文章在总浏览量、阅读量、粉丝量和每日浏览量方面都很出色,但它们的阅读率相对较差。集群 0 和集群 2 之间的区别主要基于读取率,这意味着该指标在我的大部分文章中发挥了很大的影响。今年我可能会把写作策略集中在提高阅读率上。

用我的数据产品做的一些策略

  1. 我平台上的中文文章可能会达到更高的阅读率。我仍然应该花时间写一些中文文章,使我的基于平台算法的媒体更加可见。
  2. 利用每日较高浏览量的文章将更多新鲜的一次性用户带入我的媒体,并促使他们关注以扩大我的关注者基础。
  3. 一些每日浏览量较高的文章属于第一类。它符合聚类结果,绝对是我的流量摇钱树。
  4. 专注于提高第 2 类文章的阅读率或防止文章落入第 2 类是 2019 年的关键目标。

结论

在媒体分析平台(统计选项卡)中有许多限制。然而,通过创建这个数据产品,我希望我可以让媒体社区受益,让作者具备一些数据驱动的思维模式,并根据这个产品产生的结果改进写作策略。

快乐分析!!!

Remember to follow me on Medium to get instant notification of my new article.Thank for the reading

基于购买历史的用户细分

原文:https://towardsdatascience.com/user-segmentation-based-on-purchase-history-490c57402d53?source=collection_archive---------16-----------------------

一个用例,说明我们如何使用机器学习,根据用户的购买力来确定不同产品的目标用户。

source: Lisa, via pixabay

介绍

这一分析的目标是使用折扣应用程序,根据他们获得的交易确定不同的用户群,以便为他们重新提供类似于他们过去获得的优惠。

机器学习算法 K-means 用于根据用户的购买行为识别用户群。这是算法提取内容的三维图。

3D image of clusters produced by K-Means, by Muffaddal

术语:

在深入分析之前,让我们定义一些正在使用的关键字。

交易收益:当用户使用 app 获得折扣时。
花费:用户购买物品时支付的折扣价。
保存:用户通过 app 保存的金额。
品牌:提供折扣的商家如必胜客、格力诺
交易:提供给不同店铺和品牌用户的折扣。

分析

数据集

使用 JQL 从 Mixpanel 中提取行为数据集。该分析使用了以下内容

Mixpanel Data Set, by Muffaddal

userId: 用户的唯一 id
save amount:用户在交易受益
上节省的金额 spentAmount :用户在交易受益
brandName :交易受益的品牌
count :用户受益的交易数量

使用上述数据集averagesavenamount,为每个用户计算 averageSavedAmountdealavaillcount,如下所示

Average Deal Availed Data set, by Muffaddal

机器学习— K-means 聚类 K-mean 算法的第一步是找到最佳数量的聚类进行分割。为此有许多方法,其中之一是使用类内平方和(wcss)的肘方法。

WCSS for up-to 10 clusters, by Muffaddal

基于肘方法,使用 4、5 和 6 个聚类来探索片段,并挑选 4 个聚类作为给定数据集的最佳聚类。

R code for K-Means clustering

如果你想了解更多关于用户聚类和用户细分的知识,我会推荐 数据营 Coursera上的这些课程。

K-means 提取了哪些片段?

以下是四个已确定细分市场的平均统计数据:

Average stats of each segment

Segments Characteristics

Graphical Representation of Segments Characteristics, by Muffaddal

细分市场 1 和 2 中的用户是高付费用户,细分市场 1 中的用户在每笔交易中也节省了同样高的费用(可能有买一送一的优惠)。然而,这些用户利用的交易数量少于 2(即分别为 1.3 和 1.4)。

另一方面,细分市场 3 和细分市场 4 的用户花费较少,因此储蓄也较少。然而,在所有 4 个细分市场中,细分市场 4 的用户拥有最大的每用户交易收益比率(平均每个用户收益超过 9 笔交易)。这是转变最多的一批用户。

每个细分市场的用户总数和交易数量是多少?

这是用户总数和每个细分市场用户的交易量。

Number of users in segments, by Muffaddal

Number of deals availed, by Muffaddal

57%的用户属于细分市场 3,只有 3%的用户来自转化率最高的细分市场(即细分市场 4)。

总体用户支出是多少?

这是各细分市场的支出分布情况

Spending of users in each segment, by Muffaddal

来自细分市场 4 的一些用户(细分市场 4 中的黄点)与细分市场 1 和 2 类似,但细分市场 3(包括 57%的用户)根本不喜欢高消费交易和/或品牌。

每个细分市场用户首选的品牌类型?

让我们看看这些细分市场用户利用什么类型的品牌来了解他们之间的区别。

Brands users availed, by Muffaddal

细分市场 1 的用户利用了汉堡、比萨饼和欢乐时光的组合,细分市场 2 的用户利用了比萨饼,而细分市场 3 的用户更喜欢汉堡包。而细分 4 用户(大多数转化用户)更喜欢果汁和其他类型的品牌。

每个细分市场都有哪些品牌?。

以下是这些细分用户使用过的十大品牌。

Top 10 Brands Availed by Each Segments, by Muffaddal

看看这些品牌,我们可以理解这些细分市场用户更喜欢什么类型的品牌和交易。第 1 和第 2 部分用户(高付费用户)使用了优质品牌,如 Sajjad、kababi、carbon、California 等,而第 3 和第 4 部分用户(低付费用户)大多选择了中低档品牌。

如何应用这些结果?

根据不同的用户群,我们可以:

1-定向广告针对每个细分市场的个性化广告会提高转化率,因为用户更有可能转化为特定品牌和优惠。因此,举例来说,先向付费能力较高的用户展示 Sajjad 的广告,然后再向付费能力较低的用户展示。

2- In-app 推荐
优化应用,在应用内推荐每个细分市场用户更感兴趣的交易和折扣。

摘要

总之,通过数据和适当的努力,我们能够识别用户及其喜好的有趣信息,并能够根据用户的偏好制定如何吸引用户的策略。

需要帮助进行用户细分吗?我们来连线。

相似读数

[## 使用 BigQuery ML 进行 RFM 分析

使用 BigQuery ML 中的 RFM 分析和 Data Studio 中的可视化进行用户细分。

towardsdatascience.com](/rfm-analysis-using-bigquery-ml-bfaa51b83086) [## 基于项目的推荐系统综合指南

本指南将详细介绍基于项目的推荐系统是如何工作的,以及如何在实际工作中实现它…

towardsdatascience.com](/comprehensive-guide-on-item-based-recommendation-systems-d67e40e2b75d) [## 找到类似的产品推荐给用户

在 R 中使用 recommenderlab 获得类似的产品推荐

towardsdatascience.com](/find-similar-products-to-recommend-to-users-8c2f4308c2e4)

使用一般化的翻译向量来处理拼写错误和词汇外(OOV)单词,如缩写

原文:https://towardsdatascience.com/using-a-generalised-translation-vector-for-handling-misspellings-and-out-of-vocabulary-oov-words-494cd142cd31?source=collection_archive---------27-----------------------

Photo by Andrea Sonda on Unsplash

介绍

在这篇文章中,我将分享一种管理拼写错误和缩写的新方法。这个想法不是我自己的,但我认为它真的很有趣,并决定在这里测试和展示我自己的成果。

这个想法来自艾德·拉什顿,他来自一个快速人工智能论坛的帖子,是我在做自己的研究时偶然发现的。我强烈建议你阅读他的初步测试。

我采取了额外的步骤来测量将 Ed 的方法应用于下游自然语言处理(NLP)任务的效果,以查看它是否会提高分类准确性。

像使用外部数据源来创建一个广义的转换向量或测试缩写/OOV 词的方法是我自己的。

但是在我开始之前,了解什么是单词嵌入以及它们为什么重要是很重要的。如果您需要快速复习,请花 3-5 分钟通读关于词汇外(OOV)单词嵌入系列的 第一部分

文章链接还谈到了为 OOV 单词生成单词嵌入,比如新加坡英语。这篇文章实际上是我关于如何最好地使用新加坡式英语的研究的延伸。

回忆一下,我们开始吧。

这种方法的基本原理来自于单词嵌入如何与另一个交互。这种“互动”的经典词语类比例子如下:

Figure 1 — Word Analogy “Equation”

直觉上,这个英语中的“等式”应该对你有意义。在向量空间中,数学将是这样的:

Figure 2 — Word Analogy Example in Vector Space — Source

为了向您展示这是真实的情况,我已经使用来自斯坦福的预训练单词嵌入运行了一些代码。这些单词嵌入在维基百科 2014 + Gigaword 上进行训练,以获得 60 亿个标记和 40 万个独特的词汇单词。

由于每个单词都表示在一个 100 维的空间中(即 100 个数字),为了可视化的目的,我应用了 T-分布式随机邻居嵌入(T-SNE)将维度减少到只有 2。

下面的图 3 是感兴趣的单词和数学方程的可视化,帮助你更好地理解单词之间的关系。

Figure 3 — Word Analogy Equation

正如您所看到的,经过适当训练的单词嵌入可以真实地表示单词之间的关系。模型生成的数字向量不仅仅是随机的。这些数字确实有一定的意义。

你可能不知道,我上面提到的是平移向量的实现。

平移向量是一种将坐标平面中的点/图形从一个位置移动到另一个位置的变换。

这是一个翻译向量,我将使用它来将拼写错误/缩写的单词移向最能解释这些单词意思的单词。

“等一下...你是说有一个翻译向量可以将拼写错误的单词移动到向量空间中相应的正确拼写上吗?”

答案是肯定的。

最重要的是,这个翻译工具甚至可以翻译缩写或 OOV 单词。这将使这些单词更接近于最能代表缩写或 OOV 单词真正含义的单词。

那么广义翻译向量是如何创建的呢?

这一系列的测试是由斯坦福大学使用手套单词嵌入法进行的。

在这一部分,我将首先分享处理拼写错误单词的实验。然后,我将转向我所做的处理缩写或 OOV 单词的实验。在此之后,我将试图解释为什么我认为这个翻译向量是有效的。最后测试这种方法对下游 NLP 任务的影响。

处理拼写错误的单词

为了处理拼写错误的单词,我最初认为拼写错误的单词的正确拼写应该出现在拼写错误的单词附近。

令我惊讶的是,我错了。事实完全不是这样。

以下是一些拼写错误的单词及其在向量空间中最接近的邻居的输出。

Input word: becuase
Closest 10:
becuase 1.0
becasue 0.768174409866333
beause 0.740034282207489
beacuse 0.7367663979530334
becaue 0.7192652225494385
athough 0.6518071889877319
althought 0.6410444378852844
becuse 0.6402466893196106
inspite 0.631598711013794
beleive 0.6224651336669922Input word: athough
Closest 10:
athough 0.9999999403953552
altough 0.7992535829544067
althought 0.7640241980552673
eventhough 0.7555050849914551
&#8220; 0.7399924993515015
addding 0.7239811420440674
lthough 0.7079077363014221
surmising 0.6986074447631836
howver 0.6851125359535217
aknowledged 0.6843773126602173Input word: aknowledged
Closest 10:
aknowledged 1.0
ackowledged 0.8641712665557861
inisted 0.8378102779388428
admited 0.8242745399475098
annonced 0.81769859790802
avowing 0.7911248803138733
testifed 0.7896023392677307
addding 0.7784746885299683
sasid 0.7712235450744629
acknowleges 0.7595445513725281

注意在上面所有的例子中,前 10 个邻居中没有一个是正确拼写的单词?

我开始在越来越多拼错的单词上运行最近邻,直到一个模式出现,我得出结论…

所有拼写错误似乎都在向量空间中被分组在一起。

注意:这里着重强调了“似乎”这个词。因为我真的不确定。

如果我粗略地把它画出来,它可能看起来像这样:

Figure 4 — Misspelled words location in vector space

下一步是创建一个翻译向量,使拼写错误的单词嵌入更接近正确的拼写,如:

Figure 5 — Translation of misspelled words to correctly spelled words

过程是这样的:

  1. 运行余弦距离得到最近的 10 个单词拼写错误的选择。
  2. 对于 10 个最接近的单词中的每一个,取每个单词的单词向量,并将其从正确拼写的单词的单词向量中减去。
  3. 在步骤 2 中计算所有这些单词向量的平均值。这成为步骤 1 中所选单词的翻译向量。
  4. 测试平移向量。
STEP 1:
Input word: becuase
Closest 10:
becuase 1.0
becasue 0.768174409866333
beause 0.740034282207489
beacuse 0.7367663979530334
becaue 0.7192652225494385
athough 0.6518071889877319
althought 0.6410444378852844
becuse 0.6402466893196106
inspite 0.631598711013794
beleive 0.6224651336669922STEP 2:
sum_vec = ((glove["because"]-glove["becuase"]) + (glove["because"]-glove["becasue"]) + 
       (glove["because"]-glove["belive"]) + (glove["because"]-glove["beause"]) + 
       (glove["because"]-glove["becaue"]) + (glove["because"]-glove["beleive"]) + 
       (glove["because"]-glove["becuse"]) + (glove["because"]-glove["wont"]) +
       (glove["because"]-glove["inspite"]) + (glove["because"]-glove["beleive"])
      )STEP 3:
translation_vec = sum_vec / 10STEP 4:
real_word = glove["becuase"] + translation_vecClosest 10:
because 0.9533640742301941
but 0.8868525624275208
though 0.8666126728057861
even 0.8508625030517578
when 0.8380306363105774
if 0.8379863500595093
so 0.8338960409164429
although 0.8258169293403625
that 0.8221235871315002
. 0.8172339797019958

看看上面第 4 步的结果。注意平移向量是如何工作的?单词“becuase”的拼写错误被推到了正确的拼写“因为”。

既然我们知道处理拼写错误的翻译向量是可能的…

现在的问题是:

我们能为所有拼错的单词创建一个通用的翻译向量吗?

是的,你可以。

创建广义翻译向量

我先从维基百科上拿了一个经常拼错的英文单词列表——https://en . Wikipedia . org/wiki/Commonly _ misselled _ English _ words

总共有 257 个拼错的单词。

接下来,我按照上面提到的步骤(步骤 1 到 4)运行每个单词。在 257 个单词中,只有 101 个出现在 GloVe 中。因此,计算了 101 个平移向量。

下一步很简单,要得到广义的翻译向量,只需得到所有 101 个翻译向量的平均值。

现在,在看不见的拼写错误的单词上测试广义翻译向量。即不在“经常拼写错误的英语单词”列表中的单词。

以下是一些结果:

TEST 1:
real_wd = word2vec["altough"] + generalised_translation_vector
Closest 10:
although 0.6854726149933246
though 0.6850398829597103
fact 0.6601790765388513
however 0.6519905808301287
moreover 0.6505953960788824
unfortunately 0.6351817153852294
why 0.6347064566357319
neither 0.6276211965351607
because 0.626889292147095
there 0.6217807488951306TEST 2:
real_wd = word2vec["belive"] + generalised_translation_vector
Closest 10:
belive 0.7508078651443635
believe 0.6821138617649115
we 0.6761371769103022
think 0.6593009947423304
i 0.6531635268562578
suppose 0.6463823815449183
know 0.643466951434791
why 0.6394517724397308
n't 0.6282966846577815
there 0.6273096464496348TEST 3:
real_wd = word2vec["howver"] + generalised_translation_vector
Closest 10:
moreover 0.6818620293021886
nevertheless 0.6726130620400201
neither 0.6667918863182073
unfortunately 0.6568077159269134
though 0.6563466579691621
indeed 0.6555591633099542
nor 0.6473033198348439
noting 0.6457127023810979
fact 0.6423381172434424
however 0.639381512943384

如你所见,仅仅在 101 个平移向量上,广义平移向量的表现并不太差。

然而,由于它只在 101 个翻译向量上建模,它在单词“howver”上表现不佳。如果我们对更多的平移向量进行平均,这应该很容易纠正。

这个一般化的翻译向量在缩写的 OOV 单词上表现如何?

为了测试这一点,我键入了一个缩写“ftw”来寻找它的最近邻居,而没有应用广义翻译向量。

结果就是这样。

Closest 10:
ftw 1.0
ftg 0.6485665440559387
ccts 0.6331672072410583
srw 0.6109601855278015
efts 0.6108307242393494
cmtc 0.6050553321838379
tfts 0.6022316217422485
okl 0.6015480756759644
jrtc 0.597512423992157
cacs 0.5950496196746826

如您所见,所有缩写似乎都被分组到了同一个向量空间中。这还没有真正的价值。

让我们应用广义平移向量,看看会发生什么。

real_wd = word2vec["ftw"] + generalised_translation_vectorClosest 10:
ftw 0.6879674996316458
training 0.5672708687073991
wing 0.5443954733951136
) 0.5178717182506045
fighter 0.4847256601149461
flying 0.4701913180805779
tactical 0.4680302804591241
combat 0.4674059145693783
squadrons 0.4593665765485848
foot 0.459181622011263

注意到这里有什么有趣的吗?如果你用谷歌搜索“ftw 战斗”,你会发现“ftw”代表“飞行训练联队”。

Figure 6 — Google search results for “ftw combat”

这表明广义翻译向量甚至对缩写也起作用,而不仅仅局限于拼写错误。

它设法将“ftw”的缩写翻译成它在文本中真正代表的意思。即军字。

现在你已经看到了结果,如果你像我一样,你会问自己这怎么可能。下一部分是我对我认为正在发生的事情的假设

为什么我认为广义翻译向量有效

这一段纯属假设。我不认为这些是真的。我在这里所说的一切都仅仅是基于对结果的回顾和对我认为正在发生的事情的推断。

回想一下上面的图 4 和图 5。

我认为正在发生的事情大概是这样的:

Figure 7 — Why Generalised Translation Vector works

首先,根据我的测试,本地化的翻译向量似乎工作得最好,即更好的准确性。

本地化的翻译向量指的是具有缩写或拼写错误的单词的聚类的向量。

但我认为广义平移向量是可行的,因为它只是所有局部平移向量的平均值。它只是将蓝色圆圈中的所有东西推回到橙色圆圈中。

这是基于这样的假设:所有拼错的、缩写或 OOV 单词都聚集在蓝色圆圈中。

因为每个拼写错误的单词、缩写词或 OOV 单词都在一起,所以拥有一个通用的翻译向量只会将这些单词推向真正代表它们实际意思的单词。

重要提示:

  1. 翻译向量只对它被训练的单词起作用。我曾试图从 GloVe 中提取一个通用的翻译向量,并尝试将其应用于一个完全不同的数据集,但没有成功。
  2. 为了纠正拼写错误,正确拼写的单词必须首先存在于语料库中。

看到目前为止的结果,你认为模型学到了什么?我的假设有意义吗?你的假设是什么?

广义平移向量的应用

说了这么多,做了这么多,你可能想知道的下一个问题是:

“那又怎样?我能用这些知识做什么?”

在这一部分,我将分享两组代码在一个简单的多分类评论毒性任务中运行的结果。即有毒、剧毒、淫秽、威胁、侮辱或人身攻击。

以下是训练集的大致情况:

Figure 8 — Toxic comments data set

训练集被分成 127,656 个训练样本和 31,915 个验证样本。

我用二元交叉熵损失函数和带有 Keras 的 Adam 优化器训练了一个简单的双向 LSTM 模型。

在第一种情况下,我使用了 GloVe 中预先训练的单词嵌入,而没有使用中的广义翻译向量。

结果如下:

Figure 9 — Validation Loss and Accuracy

在由 153164 个样本组成的测试集上,模型精度为: 93.7687%

使用上面相同的配置,我将 GloVe 单词嵌入改为我应用了广义翻译向量的嵌入。

为了确保我只翻译需要翻译的向量,我从20 新闻组数据集的现有词汇表中运行了 GloVe 嵌入。

我只翻译了没有出现在 61118 个正确拼写单词的词汇列表中的向量。

结果如下:

Figure 10 — Validation loss and accuracy after applying Generalised Translation Vector

在上面的同一个测试集上,模型精度为: 93.8267%

精确度的差异只有 0.058%。

从这个实验来看,对拼写错误或 OOV 单词应用广义翻译向量是否有助于提高任何下游 NLP 任务的准确性,这是不确定的。

然而,凭直觉,我相信它确实有帮助。也许不是这个任务本身,而是其他 NLP 任务?

快速小结

  1. 我发现 fast.ai 上的一个帖子很有趣,于是决定测试一下某人(Ed Rushton)处理拼写错误的新颖方法。
  2. 我进一步测试了这种方法在缩写/OOV 单词上的应用,并得出结论:它对这些单词也有效。
  3. 我进一步研究了它是否有助于提高下游 NLP 任务(如分类)的准确性,发现我的实验没有结论。

结尾注释

我确实发现这个练习非常有趣,并且很可能在将来我的其他 NLP 项目中使用它。

所有的赞扬和感谢都归于埃德·拉什顿,因为他提出了这样一种新颖的方法。

我将来想尝试的是:

与其创建一个通用的翻译向量,不如根据一个单词属于哪个簇来运行本地化的翻译向量。

例如,如果单词是拼写错误,运行本地(拼写错误)翻译向量。如果单词是缩写,运行本地(缩写)翻译向量。

我坚信这种本地化的方法是使这种方法更强大的下一步。

我希望我在这方面的实验能帮助你更深入地了解单词嵌入是如何工作的,也许还能激发你的兴趣,让你自己做测试。

下次再见,朋友们!

如果你正在寻找 NLP 数据集,点击这里查看我创建的精选列表!😃

LinkedIn 简介:蒂莫西·谭

运用生成性对抗网络创造新颖的艺术形象

原文:https://towardsdatascience.com/using-a-generative-adversarial-network-gan-to-create-novel-artistic-images-e06c65ff43ad?source=collection_archive---------14-----------------------

学习使用小的、不一致的和定制的数据集捕捉艺术家的风格

在这个项目中,我使用了一个生成性对抗网络(GAN)架构来生成新的艺术图像,这些图像捕捉了印度艺术家 Raja Ravi Varma[1848–1906]和 Sattiraju Lakshmi Narayana[1933–2014]的风格。(链接到源代码的 Github Repo)

简介:这个项目的目标是理解生成对立网络(GAN)架构,通过使用 GAN 来生成新的艺术图像,捕捉给定艺术家的风格。生成对抗网络(GAN)架构是由伊恩·古德菲勒(链接到论文)博士在 2014 年提出的。GANs 由发生器和鉴别器神经网络组成。生成器神经网络将随机噪声作为输入,并生成图像作为输出,而鉴别器神经网络将图像作为输入,并生成概率值作为输出。由鉴别器评估的概率值指示输入图像是训练集的一部分的概率。发生器的目的是用它产生的图像“欺骗”鉴别器,而鉴别器的目的是正确地“找到”发生器产生的图像。竞争网络的这种对抗性、零和性质导致生成器越来越多地产生在概率上更有可能属于训练集的图像。下面给出了 GAN 的示例架构。

其他作品:当我看到英伟达科学家在 2017 年发表的一篇题为“无监督图像到图像翻译网络”的论文时,我被介绍到了 GAN 架构。他们使用 GAN(耦合 GAN)架构的变体来训练模型,这些模型可以有效地获取(I)白天拍摄的照片的输入图像,并在晚上产生照片的令人信服的输出图像,(ii)动物,并产生变形为不同动物的动物的令人信服的输出图像,(iii)个体,并产生添加了特征(改变发型,添加附件)的个体的令人信服的输出图像。下面是他们论文中的一个例子。对于每一对图像,左边的图像是输入,右边的图像是输出。

为了进一步理解这个模型,我找到了伯克利科学家在 2017 年发表的一篇题为‘使用循环一致的对抗网络进行不成对的图像到图像的翻译’的论文。他们还使用 GAN(循环 GAN)架构的变体来训练模型,这些模型可以有效地获取(I)照片的输入图像,并以各种画家的风格产生照片的令人信服的输出图像,(ii)在夏天拍摄的照片,并在冬天产生照片的令人信服的输出图像。下面是他们论文中的一个例子。

到目前为止讨论的 GAN 模型本质上是将输入图像转换成具有一些期望特征的修改的输出图像。我想看看甘的建筑是否可以用来创造新的艺术形象,捕捉特定艺术家的风格。我随后在脸书找到了一个 2017 年由几个人独立完成的研究项目,名为‘GANGogh:用 GANs 创造艺术’。他们使用甘建筑来(I)了解各种艺术家的风格,然后(ii)创造一种新的应用学习的风格,以产生新的艺术。

我的贡献:我希望我通过这个项目的主要贡献是为(I)时间紧迫,(ii)处理能力不足,(iii)希望使用小型自定义数据集,以及(iv)制作新颖、印象主义的艺术图像(捕捉给定艺术家的风格)的开发人员提供一种了解 GAN 架构的方法。时间和处理能力对我来说是一个很大的限制,因为我不得不在一个很慢的虚拟机上很晚才开始我的项目工作。因此,我对大幅减少训练一个模型的时间很感兴趣。我通过使用一个非常小的定制数据集(大约 200 张图片)做到了这一点。然而,与这种选择相关的权衡是,生成器或鉴别器更有可能“压倒”另一个(即,生成器学习速度比鉴别器快得多,或者鉴别器学习速度比生成器快得多)。这使输出图像退化为噪声。我通过引入条件反向传播来解决这个问题。当高于某个阈值时,与网络相关的损失被反向传播。通过分析模型产生的损失,我发现这是有效的。这种方法允许生成新颖的印象主义图像,其用相对少的训练时间和数据集有效地捕捉给定艺术家的风格。注意,小数据集导致生成的图像本质上是印象式的。然而,这是可以的,因为我们通过一个新的印象派图像实现了捕捉艺术家风格的目标,并大大降低了处理成本。这个小数据集也让我们能够在没有太多作品的情况下,捕捉较小的地区性艺术家的风格。我使用 cifar10 模型进行基准测试。由于 cifar10 数据集包含 60,000 幅图像,处理时间明显更长,因此生成的图像印象不深,因此它是一个很好的对比。

结果:

讨论:我们可以看到产生的图像本质上是印象派的。Ravi Varma 模型和 Bapu 模型在以艺术家的风格产生新颖的印象主义图像方面特别有效。组合模型显然具有较差的印象质量。我们可以推断这是可能的,因为鉴别器在这种情况下可以学习得更快,因为在非常小的数据集(~400 张图像)中有两种截然不同的风格。这一推论得到了上面给出的损失图的支持。注意发生器和鉴频器损耗如何在对应于组合模型的图中的一点处彼此产生显著偏差。尽管有条件反向传播,这种情况仍然存在。显然,当我们试图以不止一位艺术家的风格创作出新颖的印象派作品时,我们需要更多的数据。考虑 cifar10 基准测试示例。我们可以看到,尽管有 10 个不同的类别标签,但输出图像的印象要差得多。这是因为数据集的规模要大得多(约 60,000 张图像)。然而,我们要考虑的关键指标是上面给出的每次迭代的训练时间。请注意,Cifar10 模型的训练时间比其他模型要长得多。因此,我们能够(I)大幅减少训练时间,(ii)使用小型定制数据集,以及(iii)以特定艺术家的风格创建新颖的印象派图像。

(视频演示链接)

写于 2018 年 4 月 25 日

使用先进的“智能”分析提高循环化学工艺的盈利能力

原文:https://towardsdatascience.com/using-advanced-and-smart-analytics-to-boost-profitability-in-the-cyclic-chemical-process-21dffe586d82?source=collection_archive---------21-----------------------

目的:针对典型的涉及循环过程的化工行业,通过优化可控参数来提高产量,从而增加利润。

背景

我认为,分析将对化学工业的许多领域产生重大影响,主要是在制造绩效方面。化学工业已经在 IT 系统和基础设施方面进行了投资,这些系统和基础设施可以高速生成和跟踪大量数据。然而,他们缺乏利用这种潜在智能的远见和能力。借助市场上更便宜、更先进的分析工具,人们可以利用机器学习&可视化来优化工厂参数,以提高其盈利能力。

高级分析可以帮助他们了解化学过程中发生的事情,这可能是许多化学工程师不知道的。这反过来有助于他们克服各种瓶颈,打破流程监控和运作中的一些刻板印象(传统思维)。

在本文中,我将谈论三个主要的智能和高级分析技巧,它们帮助我们创建了一个稳定的模型,该模型反过来被行业用来实现利润最大化。

  1. 改变时间序列数据的建模——有时数据表现出一种内在趋势(如收益率持续下降),这使得模型学习这些趋势非常困难。因此,我们在超时测试数据中观察到非常差的性能。为了克服这一点,我们预测了产量的变化,而不是产量的绝对值。这些值的变化有些稳定,因此模型相对容易学习。
  2. 智能特征工程 —特征工程是任何预测模型中最重要的一步。这是真正的数据科学家花费大部分精力的地方。在行业专家和基础数学的帮助下,我们创建了一组智能(但不是直观的)特征,这些特征被证明在预测产量方面非常重要。此外,同时帮助化学工程师了解工厂的功能。
  3. 在解决基于时间序列的建模时可以派上用场的特殊或非传统技术 -在建立预测模型期间,我们需要多次执行特定的分析,以帮助我们理解数据和过渡过程。在这一节中,我将讨论一些非传统的方法或技术,这些方法或技术可能有助于理解数据,从而有助于构建一个稳定而稳健的模型。

让我们深入研究第一部分,即改变建模,并了解它如何优于传统的时间序列建模。

改变建模

对于涉及数据趋势的情况,在没有任何能够捕捉该趋势的功能的情况下,训练模型变得极其困难。趋势中的每日特征将变成模型从未见过的值,因此增加了任何 ML 模型中的噪声和不准确性。为了解决这种情况,数据科学家通常会创建一个合成变量来捕捉趋势,如一年中的月份、经过的时间或简单的行号。在涉及衰减属性或未知速率的自回归属性的情况下,这种策略往往会失败。为了克服这个趋势问题,我们引入了变化建模。我们预测给定时间间隔内产量的变化。利用变化建模,我们对 x 和 y 特征相对于时间进行求导,以平滑趋势。这种方法使我们能够显著提高模型的预测能力。

△ P(time = t) = P(time = t) - P(time = t-1)P is the distribution which is dependent on time.

请注意,离群值处理和缺失值插补现在应该应用于这些衍生产品。

A graph showing a declining yield of a plant over the course of 2 years. It is called as ‘non-stationary’ behavior i.e. changing mean & variance which is not ideal for the time series modeling.

当我们对这种趋势求导时,结果看起来更稳定,更适合时间序列建模。

Constant mean and variance over time and mitigate the noises due to any reasons in data collection.

智能特征工程

我将谈论三种不同于传统的广泛特征-

  1. 由于建模变化而定义发生变化的特性:当你对 x 和 y 求导时,特性会发生一些疯狂的事情。
    通过研究二元关系和咨询行业专家,很多时候数据科学家需要创建一些特征转换。例如,一个特征的对数,乘以二,取一的平方等等。现在,根据变更建模,这种转换将会完全改变。这是变化-
y = log (x)                        ||          △y = △x / x
y = x²                             ||          △y = x △x
y = p X q                          ||          △y = p △q + q △p
y = 1 / x                          ||          △y = -△x / x²

2.从商业和数据科学的角度来看,其他一些很酷的功能可能会有所帮助:一些功能,如变化变量的滞后,采用二次微分来捕捉变化率以及绝对变量的滞后。输入所有这些变量有时会让您对模型性能感到惊讶。然而,在时间序列建模中,数据泄漏是一个非常严重的问题。
数据泄漏是指来自训练数据集之外的信息被用于创建模型。这些额外的信息可以让模型学习或知道一些它本来不知道的东西,从而使正在构建的模式的估计性能无效。屡试不爽的防止数据泄露的方法是问问你自己

如果在您希望使用模型进行预测时,任何其他特性的值实际上不可用,则该特性会给您的模型带来泄漏

3.利用高级算法获取创新特征,特别是针对时间序列建模:在特征工程自动编码模块中总是有新的进步,这些模块可以捕获时间序列数据的特殊特征。其中一个模块是“ tsfresh ”,它在 Python 中可用。
自动计算大量时间序列特征。此外,该软件包包含评估回归或分类任务的这些特征的解释能力和重要性的方法。要详细了解该包的工作和实现,请参考下一页。
需要注意的一点是:在使用这样的包时,企业很难解释这个特性及其在现实世界中的重要性。因此,当预测不是模型构建的唯一目的,而是涉及到预测的驱动因素时,我们不应该使用这样的库。

pip install tsfreshfrom tsfresh.examples.robot_execution_failures import download_robot_execution_failures, load_robot_execution_failuresdownload_robot_execution_failures()
timeseries, y = load_robot_execution_failures()

智能或非传统技术,在解决基于时间序列的建模时可以派上用场

在这里,我们将讨论我在各种时间序列问题中学习和实现的一些技术。这些技术是非传统的,很难在网上找到任何有用的内容。然而,在回答涉及化学过程的复杂问题时,尤其是循环问题时,它们被证明是超级方便的。

  1. 脉冲响应函数:了解当另一个不同的变量发生变化时,一个变量发生变化所需的时间。根据这一分析,您可以回答以下类型的问题—
    a .如果我对温度稍作改变,稳定产量需要多长时间?
    b .系统意识到氯含量变化的影响需要多长时间?

The y-axis shows the change in selectivity given a change in chlorine level is initiated at t= 0 hours. The x-axis shows the time from the change in chlorine levels. Grey region is the confidence interval of changes recorded in selectivity at t = T hours after the change in chlorines. This graph shows that the selectivity levels effect recorded after 8 hours of the change in chlorine and it finally stabilized after 12 hours.

在 R 中,我们有一个库“VARS”,它有一个函数 irf (脉冲反应函数),做的工作和上面提到的一样。下面是所用代码( R,tidyverse )的图示—

library(vars)# p represents the lag order. This have 17 orders of all lag variables.
m.var <- df.reg %>% 
  VAR(p = 17, type = "const") irf.var.cum.ccf <- irf(m.var, 
                       n.ahead = 12, # No of Steps
                       runs = 1000, #Runs for the bootstrapping
                       impulse = "d_ccf", #Variable which changes
                       response = "d_S44" #Variable wohse effect is recorded)# Generates the plot
irf.var.cum.ccf %>% 
  plot()

2。基础扩展:它是一种技术,使我们能够通过在线性模型中保持其他变量的长期影响来捕捉一个变量的近期影响。在时间序列模型中,当您希望一个变量的系数捕获更近期的样本和来自长期样本的其他系数时。你也可以尝试其他传统技术——

  • 对样本集进行加权,以便最近的时间段具有更高的权重(可能会导致整体预测能力的损失)
  • 创造特征或试图理解为什么这种积极和消极的行为会随着时间的推移而改变(非常困难且依赖于数据)
  • 改变训练周期的长度(可能不会产生期望的结果,如系数趋于零等。)

有时,一个 X 变量对 Y 的影响随着时间的推移而变化。例如,在 6 个月中,它对 Y 变量有积极的影响,而在接下来的 4 个月中,这种影响是消极的。你应该确保其他变量必须与 Y 变量有稳定的关系。

一个简单的线性模型应该是这样的—

𝑦(𝑡)=𝛽𝑋(𝑡)+𝜖
Where y(t) is some output (yield) that changes over time, t

可以有许多其他时变信号,但为了简单起见,我们假设只有一个:X(t)。你在尝试根据某个有误差的线性模型,学习 X(t)和 Y(t)之间的关系,ε。这种关系由系数β来描述。

复杂:根据你使用的数据周期,β值会发生变化,这表明 X 和 y 之间的关系实际上可能会随着时间的推移而变化。

解析:在这种情况下,我们需要引入一个叫做“指标函数”的新函数。指示器函数是一个简单的函数,当满足某些条件时为“1”,否则为“0”。

Mathematical representations of the equations mentioned to the right of the image

让我们把一月到六月的月份集合称为“A”。我们可以用一个指标函数来描述这一点,如右图所示。
类似地,我们可以创建一个类似的函数来描述 7 月到 12 月这几个月的集合,称这些集合为“B”。
现在,使用这些指标函数,我们可以通过重写我们的方程来说明随时间变化的关系(β)。

为了在实践中实现这一点,您将按照前面的描述设计特性,创建 X 的两个副本,并在适当的时间将值清零。

然后,您可以像往常一样拟合模型。

新的复杂因素:你的回归模型中不仅仅只有一个单一特征。你的回归方程实际上更像这样(尽管更复杂):

𝑦=𝛽_1*𝑋_1(𝑡) + 𝛽_2*𝑋_2(𝑡) + 𝛽_3*𝑓(𝑋_1(𝑡), 𝑋_2(𝑡)) + 𝜖

它被简化为只有两个独立变量,假设 x1 是我们目前讨论的变量。X_2 是植物发出的其他信号,f(X_1,X_2)是你根据 X_1 和 X_2 的相互作用设计的特征。

如果我们实现上面建议的更改,并将 X_1 的影响分成两个特性,您将得到:

𝑦(𝑡) = 𝛽_𝐴1*(𝑋_1(𝑡)∗𝕀_𝐴(𝑡)) + 𝛽_𝐵1*(𝑋_1(𝑡)∗𝕀_𝐵 (𝑡)) + 𝛽_2*𝑋_2(𝑡) + 
𝛽_3*𝑓(𝑋_1(𝑡),𝑋_2(𝑡)) + 𝜖

“如果我们相信 X_1 和 y 之间的关系随时间变化,我们是否也需要重新评估 X_1 和 X_2 随时间变化的关系?”

新决心:答案是,要看你自己搞清楚是否有必要改变这一点。没有快速的答案,但是你可以尝试一些事情:

  • 仅更改单个有问题的特征(X _ 1)-保持其他工程特征不变
  • 改变你单一的有问题的特性(x1)和一些包含 x1 的影响更大的工程特性
  • 改变所有依赖于 X_1 的特性

所有这些方法都是完全合理的,可能会也可能不会提高你的模型的拟合度。当然,你的解释会随着你采取的方法而改变。

如果你只实现了 X_1 上描述的单基函数,你实际上是在说:“我们相信 X_1 对收益率的影响会随着时间而变化——我们可以证明这一点。然而,受 X_1 影响的其它过程,例如 f(X_1,X_2),具有随时间的恒定关系,并且它们与产量的关系不随时间改变。”

你需要运用你对数据和过程的了解来判断这样的结论是否合理。

3。分位数回归:这种技术并不常用,但它比传统的线性回归有自己的优势。相对于普通的最小二乘回归,分位数回归的一个优点是,分位数回归估计对响应测量中的异常值更稳健。

分位数回归已由多位统计学家提出,并被用作在变量的均值之间没有关系或只有弱关系的情况下发现变量之间更有用的预测关系的方法。

Python 中的分位数回归实现

# Quantile regression package
import statsmodels.formula.api as smf# Building the formula
formula = 'Conversion_Change ~ ' + ' + '.join(X_columns)# Training the model
mod = smf.quantreg(formula, df_train)
res = mod.fit(q=.5)# Evaluation metrics on test dataset
r2_test = r2_score(y_test, res.predict(df_test))

参考

[1]https://en . Wikipedia . org/wiki/Quantile _ regression # Advantages _ and _ applications

[2]https://web.stanford.edu/~hastie/Papers/ESLII.pdf

[3]https://en.wikipedia.org/wiki/Indicator_function

[4]https://machine learning mastery . com/data-leakage-machine-learning/

https://tsfresh.readthedocs.io/en/latest/

善用人工智能

原文:https://towardsdatascience.com/using-ai-for-good-b55a62b209b0?source=collection_archive---------20-----------------------

如何用人工智能帮助发展中国家

最近,我看到了几篇文章,阐述了人工智能如何通过消除对重复性劳动密集型制造角色的需求来威胁发展中国家。工厂自动化可能会导致较贫穷国家的失业率上升,从而扰乱当地经济并引发其他社会问题。人工智能对发展中国家来说是个巨大的威胁吗?

Photo by bill wegener on Unsplash

人们无法否认人工智能改变生活和重塑人类生活方式的潜力。在美国等发达国家,人工智能在过去十年里迅速接管了大多数人的生活。从搜索引擎到自动驾驶汽车,人工智能通过提供半自动到全自动的高性价比解决方案,影响并颠覆了许多传统行业。以广告业为例,通过采用计算广告,广告变得越来越个性化。基于实时竞价(RTB)的显示广告允许公司直接瞄准并购买用户,而不是购买广告关键词或广告视图。所有这些复杂的广告系统最终归结为简单的 ML 技术,如梯度推进决策树和因式分解机。

如果人工智能如此强大,那么它怎么可能除了伤害发展中国家之外什么都不做?事实是,人工智能也可以被恰当地利用来帮助那些不幸的人。

总部位于加州的初创公司 Zipline 正在对人工智能产生积极影响,它发明了一种全国无人机送货系统,将血液和药物运送到卢旺达的偏远医疗中心,卢旺达是一个遭受贫困和疾病蹂躏的东非内陆国家。Zipline 新改进的空中机器人能够从一个交付中心每天交付 500 多件货物。配备自动化物流系统和尖端的计算机视觉技术,一架单索无人机可以在接到订单后不到 10 分钟内发射。目前,该公司正在将其项目扩展到坦桑尼亚,在那里,抗蛇毒、狂犬病疫苗和其他重要药物通过其无人机交付。除了 Zipline,Matternet 也是另一家总部位于加州的无人机创业公司,于 2017 年与瑞士邮政合作。他们的无人机送货系统已经成功地在瑞士的实验室和医院之间运送医疗用品。

Photo by Jason Blackeye on Unsplash

除了医疗产品,许多发展中国家都急需安全的食物来源。微软在 Telengana、Maharashtra、Karnataka 和 Madhya Pradesh 等印度小村庄的数字农业项目被证明是成功的。微软设计了一款基于 Cortana Intelligence Suite 的播种应用程序,该程序结合了机器学习和商业智能,可以通知农民最佳播种日期。农民不需要大量投资,因为他们需要的只是一部能够接收来自微软应用程序的短信的手机。该应用程序通过预测理想的播种日期极大地帮助了农民,从而提高了作物产量。它还允许农民通过准确预测虫害和其他潜在风险(如季风)来提前计划。

Photo by Dose Media on Unsplash

也许人工智能可以帮助发展中国家的最重要的方面是提高教育质量。许多发展中国家的孩子,比如贫穷的 8 岁中国男孩在严寒中步行近 5 公里去上学,并不容易获得教育。Thirdspace Learning、Duolingo 和 Carnegie Learning 等公司正在开发 1 对 1 人工智能辅导软件,提供个性化的即时教育。随着 Quizlet、Newton 和 Thinkster Math 等教育技术公司获得越来越多的百万美元投资,在不久的将来,人工智能有望被用于为第三世界国家的农村地区提供教育资源。

Photo by Andy Kelly on Unsplash

自从著名计算机科学家约翰·麦卡锡在 1956 年创造了“人工智能”这个术语以来,人工智能每秒钟都在进化和改变着我们的生活。虽然许多人已经利用人工智能发明了最先进和高利润的技术,但很少有人考虑过在发展中国家产生影响。人工智能可以通过哪些方式让世界变得更好?

吴恩达你怎么看?

使用人工智能来确定具象艺术还是抽象艺术在今天更受欢迎

原文:https://towardsdatascience.com/using-ai-to-determine-whether-figurative-or-abstract-art-is-more-popular-today-401bb18435bf?source=collection_archive---------21-----------------------

虽然智人在大约 10 万年前就有抽象思维的能力,但人类大脑花了更长的时间才发明了 T2 抽象画。直到 20 世纪初,像瓦西里·康丁斯基卡齐米尔·马列维奇希尔玛·阿夫·克林特这样的艺术家才创作出与现实世界毫无关联的抽象作品。抽象很快成为推动艺术创作的指路明灯,这一趋势在很大程度上延续至今。

但是抽象艺术到底有多受收藏家和艺术爱好者的欢迎呢?为了尝试回答这个问题,我们收集了去年 12 月 112,600 个 Instagram 帖子的数据库,这些帖子的地理位置和/或标签显示用户在迈阿密海滩举办巴塞尔艺术展期间在迈阿密。剔除自拍和其他无关图片后,产生了大约 74,760 张图片,这代表了 Instagram 用户亲自看到的所有艺术作品的集体视觉记录,他们也选择了与粉丝分享。基于我们早期的作品,我们然后通过一个为艺术设计和优化的人工智能工具来运行这些图像,以便按照流派(例如,抽象、具象)将艺术分为几大类,并识别出 10 种最常见的艺术作品。这些算法是由纽约的科技初创公司 Artrendex 开发的,Ahmed Elgammal 是该公司的创始人兼首席执行官。一些令人惊讶的结果出现了。

当今最流行的艺术表现方式是什么?

虽然抽象仍然流行,但它对艺术爱好者的相对重要性似乎在下降。在去年 12 月所有在 Instagram 上分享照片的迈阿密博览会参观者中,抽象艺术作品仅占帖子总数的 36%,低于去年的 52%。相比之下,去年 12 月的作品数量从 30%上升到 36%。第三个最受欢迎的类别是以某种方式涉及风景或室内的艺术作品,占 18%。主要基于文本的艺术品占 9%,而只有 1%的图像代表特定的物体——例如,一把螺丝刀或一双鞋。

我们将迈阿密的帖子与 Instagram 帖子的更大数据集进行了比较,这些帖子是我们在过去 18 个月里从其他顶级艺术博览会收集的。在过去的一年里,Instagram 用户对抽象艺术的兴趣有所下降,取而代之的是对外形、风景、内部装饰和基于文本的艺术的兴趣日益增长。虽然因果关系很难确定,但我们的感觉是,艺术家试图在抽象中创新,从而在市场上脱颖而出已经变得越来越困难。在拥挤的艺术市场中,调整更传统的比喻可能是一种更保险的脱颖而出的方式。

对这种变化的一个可能的解释是,在过去几年里,画廊和博物馆明显转向展示女性艺术家和有色人种艺术家的作品。这种艺术的一个显著特征是它倾向于表现和肖像。最近的例子包括在现代艺术博物馆举办的查尔斯·怀特回顾展;泰特现代美术馆和布鲁克林博物馆举办的“国家的灵魂:黑人权力时代的艺术”中的许多艺术家;恩迪卡·阿库尼里·克罗斯比和达纳·史高斯的画廊展览。这些艺术家中的许多人都以将与他们社区相关的人和地方的图像“画入画面”而闻名。抽象根本无法表达他们的艺术意图。正在展出的艺术家的这种转变——在可预见的未来很可能会继续——表明抽象艺术在艺术爱好者中可能会越来越不受重视。

2018 迈阿密艺术周期间最受欢迎的艺术作品有哪些?

当我们看到 10 件最具 Instagrammed 化的艺术作品时,对抽象的兴趣下降变得更加明显,其中只有一件是抽象的。

1 — KAWS X Campana (2018) by KAWS and Fernando and Humberto Campana

这是一个天上人间的混搭。费南多温贝托·坎帕纳——以用填充玩具装饰沙发、椅子和长凳而闻名的巴西设计师和兄弟——与布鲁克林的艺术家 KAWS 合作,创造了一系列限量版的椅子和沙发。每一件物品上都有 75 到 120 个由 KAWS 制作的填充玩具。

2 — Positive Vibes (2018) by Jack Pierson

在从事各种媒体工作的同时, Jack Pierson 最出名的作品是用来自垃圾场的不匹配字母拼出令人回味的短语的雕塑。去年 12 月,三家不同的画廊展出了他的单词雕塑,但公平的参观者显然更喜欢张贴“积极情绪”的图像,而不是拼出“富家子弟忧郁”或“想要更少”的雕塑。

3 — American Power (2017) by Tristan Eaton

特里斯坦·伊顿的喷漆肖像美国力量中描绘了 10 英尺高的大胆女性形象。虽然这位洛杉矶艺术家在 2017 年安装了这件作品,作为 Wynwood Walls 计划的一部分,但它在一年后继续吸引人们的注意,成为 2018 年迈阿密艺术博览会期间第三大被安装的作品。

4 — We Belong Here (2018) by Tavares Strachan

出生于巴哈马群岛,拥有耶鲁大学艺术硕士学位,塔瓦雷斯·斯特拉坎以其充满概念的大型装置作品而闻名。在迈阿密,他为 Faena Festival 创作了一个霓虹灯雕塑,Faena Festival 是一个新的艺术节,与迈阿密海滩的巴塞尔艺术博览会同时举行。就像杰克·皮尔逊一样,“我们属于这里”这句精辟的话既可以被解释为宣示性的陈述,也可以被解释为间接的问题。

5 — Hello Beautiful (2018) by Queen Andrea

安德里亚女王是纽约的美术家、壁画家和平面设计师。她是少数几个以男性为主的女性涂鸦艺术家之一。她的欢乐壁画是排名第五的艺术作品。

6 — Untitled (Yellow, Orange, Yellow, Light Orange) (1955) by Mark Rothko

在迈阿密海滩巴塞尔艺术博览会上出售的最昂贵的艺术品是马克·罗斯科 1955 年的一幅画,要价 5000 万美元。这个价格尤其引人注目,因为四年前画廊在苏富比以 3660 万美元买下了这幅画

7 — Large Fancy Room Filled With Crap (2018) by David Shrigley

在迈阿密海滩巴塞尔艺术博览会的所有展位中,有一件由大卫·施莱格利创作的霓虹灯作品,上面写着“堆满垃圾的大房间”施莱格里以讽刺性的雕塑、绘画和视频闻名,他的作品经常出现在大型艺术博览会上。在最近伦敦的 Frieze 艺术博览会上,他的蓝色霓虹雕塑“我的作品很糟糕,我是一个非常坏的人”是博览会上最受欢迎的作品。

8 — Smooth Egg with Bow (Magenta/Orange) (1994–2009) by Jeff Koons

杰弗·昆斯带蝴蝶结的光滑蛋(洋红色/橙色)几乎有 7 英尺高,出自他广受好评的“庆典”系列。这座雕塑有五个不同颜色组合的独特版本(蓝色/洋红色、洋红色/紫色、洋红色/橙色、红色/黄色和银色/红色),其中一个于 2016 年 5 月在佳士得以 740 万美元的价格售出。据报道,提供这件特殊作品的画廊要价约为 1000 万美元。

9 — Sora Versailles (2018) by Miya Ando

凭借这幅迷人而空灵的作品,陈美雅·安藤通过在建筑的各个侧面描绘日落和日出,改变了建筑的外观。从海滩木板路到邻近的街道,这是一个令人难忘的地方。

10 — Silence = Death (1988) by Keith Haring

Lévy Gorvy 将其在迈阿密海滩巴塞尔艺术博览会上的展台改造成了向基斯·哈林曼哈顿下城流行商店的致敬。这幅画是艺术家被诊断出患有艾滋病的那一年的作品。这幅画描绘了一些人在一个粉红色的三角形主题中表现出“视而不见,听而不见,说而不闻”的行为,这个主题因艾滋病活动家团体“行动起来”而闻名。


道格·伍德汉姆是艺术信托顾问的管理合伙人,这是一家总部位于纽约的公司,专注于向收藏家和机构提供与艺术相关的金融建议。在他职业生涯的早期,道格是佳士得美洲区总裁,也是麦肯锡公司的合伙人。他也是畅销书今日艺术收藏:给每个热爱艺术的人的市场洞察的作者(2017)。

艾哈迈德·埃尔加马尔是罗格斯大学艺术和人工智能实验室的主任,也是 Artrendex 的创始人兼首席执行官。

用人工智能预测罗斯科画作的拍卖价格

原文:https://towardsdatascience.com/using-ai-to-predict-rothko-paintings-auction-prices-1e26a83abd30?source=collection_archive---------24-----------------------

马克·罗斯科悬浮在单色区域中的彩色悬浮矩形是 20 世纪最容易辨认的画作之一。在高度受限的形式下,他创作出了令人惊讶的多样化作品,为世界各地的收藏家和博物馆所垂涎。他在艺术史经典中的广泛声望和稳固地位,加上拥有手段和欲望拥有它的人数的快速增长,使他的作品变成了极其昂贵的“战利品艺术”。自 2010 年以来,拍卖会上的买家已经在他的画作上花费了总计 11 亿美元。

罗斯科作品的相对一致性,特别是与毕加索和沃霍尔等其他艺术界偶像相比,使他成为使用人工智能工具开发预测模型以估计拍卖价格的理想候选人。我们在下面解释我们是如何开发这个模型的,使用了世界上亿万富翁的数量和他们控制的财富等变量。然后,我们使用该模型预测将出现在 5 月 16 日苏富比当代艺术晚间拍卖会上的三件罗斯科作品的销售价格。但首先,简单介绍一下罗斯科市场。

耶鲁辍学生

罗斯科是来自拉托维亚的移民,1913 年末他十岁时来到爱丽丝岛。他的家人定居在俄勒冈州的波特兰,他在那里上高中,之后他在耶鲁大学学习了两年,然后辍学。他于 1923 年搬到纽约,并在那里一直呆到 1970 年去世。

学者们倾向于把他的职业生涯分为三个时期。在早年(1924-1939)期间,他经常画神话主题或受超现实主义启发的作品,其中很少有特别杰出或有趣的。在过渡的(1940–1950),他从表现转向探索色彩和形式的并置如何被用来创造有趣的空间关系。他举世闻名的大部分画作都是在他晚年创作的,学者们称之为“经典时期”(1951-1970)。

在这第三个也是最重要的时期,罗斯科作品不多。华盛顿国家美术馆于 1998 年出版了一份他所有帆布和硬纸板作品的目录清单,其中仅包括这一时期的 386 件作品。这意味着平均每年只创作 20 幅画。

罗斯科还在纸上创作了许多作品,他认为这些作品是成熟的绘画,而不是素描。艺术家的儿子克里斯托弗·罗斯科(Christopher Rothko)写道,罗斯科坚持认为,他所有的纸上作品“……都要装在支架上,呈现出来时要无垫、无框、无釉。换句话说,他们应该像绘画一样被对待,没有任何东西阻碍我们的观点和方法。据我所知,我父亲在世时展出或出售的所有罗斯科的经典纸质作品都是装裱的,而不是装裱的,有些作品比其他作品更成功,但这种一致性清楚地表明了我父亲的愿望。”国家美术馆目前正在收集这位艺术家的纸质作品目录,预计将于 2022 年面世。因为纸更便宜,更容易使用,这位艺术家在纸上创作的经典画作可能比在画布上创作的更多,尽管准确的数字要到目录出版后才能清楚。

他的纸上作品和画布作品都会定期出现在拍卖会上。罗斯科的作品也私下出售,主要是通过佩斯画廊,自 1978 年以来一直代表艺术家的财产。

罗斯科价格预测模型

想象一下,站在一幅罗斯科作品前,认真地看着它。你会很快注意到矩形的数量,它们的颜色,以及它们与它们所绘制的单色场相比如何。这些是这幅画容易测量的方面。但罗斯科作品还有许多其他难以用语言表达的品质,更不用说量化了,这些品质有助于它的情感之美,比如矩形的边缘如何融入基色,绘画的亮度,以及颜色和形式并置创造的不寻常的空间关系。我们的眼睛看到这些信息,并将其传输到我们的大脑,引发情绪反应。

人工智能现在使机器能够在某些方面像人类一样看待世界,并允许它们将这些知识用于各种任务,包括驾驶自动驾驶汽车和使用视频监控系统监控时代广场的人们。计算机视觉的革命在很大程度上归功于一种叫做卷积神经网络(CNN)的模式识别算法。CNN 观察数字图像中的像素并从中寻找模式,而不需要机器先被告知要寻找什么。换句话说,这种技术提取图像本身的潜在特征,包括难以预先指定的特征。我们使用这种方法来分析罗斯科画作的数字图像,生成可用于预测销售价格的信息。

为了建立我们的模型,我们创建了一个数据库,包含了自 2000 年以来拍卖的这位艺术家的所有经典时期和晚期过渡时期的作品,总共有 118 件。该数据库不仅包括从 ArtNet 收集的全包销售价格(即,锤子价格加上买家溢价)和对象描述符(例如,尺寸、绘画制作日期、销售日期、画布或纸张上的绘画),还包括我们从网络上获取的每件作品的数字图像。作为数字图像的潜在替代品,我们还对每幅画的形式属性进行了“手动评分”:色块的数量、艺术家可能用来分隔这些色块的水平条纹的数量、画中的主色以及背景色。这四个变量通常会被鉴定人用来比较画作。除了这些“供给”变量,我们还收集了艺术品“需求”的各种衡量标准,如全球财富的增长、各种股票指数的增长,以及福布斯亿万富翁指数中亿万富翁的总财富和总数。然后,我们使用这些数据开发了一个模型来预测拍卖价格。

我们创建的模型惊人的准确,只有 5.5%的预测误差。这意味着,在我们数据库中的所有画作中,实际销售价格和预测销售价格之间的差异平均只有 5.5%。让这个表现最好的模型如此有趣的是,它的预测仅仅基于数字图像加上五个变量:绘画高度和宽度,是纸上还是画布上的作品,世界上亿万富翁的数量,以及他们控制的财富。我们数据库中的其他变量似乎都与价格无关,包括这幅画的制作日期。我们还将计算机生成的模型与我们自己的评估进行了比较,用上面提到的四个手动评分变量代替了数字图像。有了这些手动评分的变量,预测误差飙升至 20 %,作为一个模型,这是非常不够的。这种差异生动地提醒我们,机器可以比人的眼睛更敏锐地“观察”一幅画。

在将模型投入使用之前,对其进行一些一般性的观察。首先,亿万富翁的数量和他们控制的财富是解释销售价格的最重要的需求变量。其次,规模很重要。在其他条件不变的情况下,作品越大,越有价值。第三,在所有其他因素保持不变的情况下,纸上绘画相对于画布上的绘画有很大的折扣。最后,与深色的棕色和灰色相比,挂在墙上的鲜艳的橙色和紫色画作更容易打开买家的钱包。

5 月拍卖成交价预测

这让我们看到了马克·罗斯科的三幅作品,它们将在 5 月 16 日的苏富比当代艺术晚间拍卖会上拍卖。

旧金山现代艺术博物馆(SFMOMA)收藏了七幅罗斯科的作品,正在取消一幅 1960 年的未命名的古典时期画作。在宣布出售的新闻稿中,博物馆表示,它打算使用出售所得来购买作品,以帮助他们的收藏多样化。像今天的许多博物馆一样,SFMOMA 希望购买女性、有色人种和其他被忽视或边缘化群体的作品。

Untitled (1960), Oil on canvas, 69 x 50 1/8 inches

苏富比估计这幅画的拍卖价将在 3500 万美元到 5000 万美元之间。但中标者还需要支付苏富比的买方溢价,相当于拍卖价格的 25%,最高不超过 400,000 美元,超过 400,000 美元部分的 20%,最高不超过 4,000,000 美元部分的 13.9%。加上买方溢价后,苏富比预计这幅画的售价将在 4010 万美元至 5720 万美元之间。

在通过我们的算法运行这幅画后,该模型预测它将卖到 4230 万美元(锤子价加上买家溢价),接近苏富比拍卖估计的低端。这仍然是一笔令人震惊的巨款,将会给贪婪的 SFMOMA 策展人带来快乐。苏富比的专家可能认为这件作品会卖出更高的价格,因为博物馆拍卖的艺术品往往在拍卖会上卖出高价。但是这种可能性在我们的模型中是无法解释的。

为了好玩,我们还玩了模型,看看 SFMOMA 画作的变化会如何影响其价值。如果颜色比目前的棕色勃艮第更偏向橙色,预计售价将跃升至 6650 万美元,比现有作品高出近 60%。如果这是一幅纸上作品,它的价值将降至 2030 万美元,这反映了收藏家们长期以来对画布上的画作比对纸上画作的偏好。

两幅 1969 年的经典纸质画作也将于今年 5 月在苏富比拍卖。两幅作品中较大的一幅名为《无题(红色和酒红色盖过蓝色)】的预售估价为 900 万美元至 1200 万美元,或 1050 万美元至 1390 万美元(含买方溢价)。我们的人工智能模型预测这幅画的售价将达到 1660 万美元,高于拍卖估价的上限,这将使它成为该艺术家在拍卖中出售的第二昂贵的纸上作品。如果这幅画的一切都是一样的,除了它是在画布上,模型预测它会卖到 3340 万美元,几乎是它的纸质复制品的两倍。

Untitled (Red and Burgundy Over Blue), 1969, Oil on paper mounted on panel, 48 x 40 1/2 inches

第二幅纸上作品,无题(红上红),较小,但以其明亮的红色调色板而闻名。苏富比估计它将以 700 万美元到 1000 万美元之间的价格售出,或 820 万美元到 1170 万美元(含买方溢价)。鉴于其诱人的配色方案,我们的模型预测它的售价将达到 1370 万美元,也高于拍卖估价的上限。两幅作品都以高于拍卖估价的价格出售的前景,不仅反映了作品的内在质量,也反映了拍卖行长期以来的做法,即试图将估价保持在尽可能低的水平,以吸引更多的竞标者。

Untitled (Red on Red), 1969, Oil on paper mounted on canvas, 38 3/4 x 25 inches

马克·罗斯科是 20 世纪最受喜爱的艺术家之一。因为他的成熟作品属于受限制的视觉词汇,罗斯科画作的数字图像可以用来创建可靠的价格预测模型。我们急切地等待着即将到来的苏富比拍卖会的结果,看看这个模型表现如何。

本文发表于 2019 年 5 月 7 日《Artsy》杂志。原文发表于 2019 年 5 月 3 日https://dougwoodham.com。*

— — — — — — — — — — — — — — — — —

本文由道格·伍德汉姆和德文·刘撰写。

道格是纽约艺术信托顾问公司的管理合伙人,该公司专注于为收藏家和机构提供与艺术相关的金融建议。在他职业生涯的早期,道格是佳士得美洲区总裁,也是麦肯锡公司的合伙人。他也是畅销书今日艺术收藏:给每个热爱艺术的人的市场洞察 (2017)的作者。

Devin 是一名软件工程师,专门研究将人工智能应用于未来的工作。他目前正在湾区人工智能初创公司 Cresta 为大型企业公司实现重复性工作职能的自动化。他刚刚开始收集,并对探索人工智能和艺术的交叉感到兴奋。

利用气流和火花处理美国移民数据

原文:https://towardsdatascience.com/using-airflow-and-spark-to-crunch-us-immigration-data-aa7c95b37031?source=collection_archive---------13-----------------------

Photo by Matthew Smith on Unsplash

为了促进从 DevOps 工程师到数据工程师的转变,我完成了 Udacity 数据工程纳米学位。

我完成的最后一个项目涉及结合美国移民数据、世界气温数据和美国城市人口数据。使用这些数据集,以及一些简单的连接和聚合,我能够确定到达美国城市的平均年龄和性别。

然后将这些数据与每个城市的温度数据相结合,这样就可以将到达人数与天气趋势联系起来。人口统计数据还可以说明参与者的平均年龄和城市之间是否存在关系。或者,可以重新利用这些数据,看看到达者的种族和城市/州的人口统计数据之间存在什么关系。

在这篇文章中,我将解释我完成这个项目的步骤。我发现“逆向工程”解决方案非常有效。明确定义最终结果有助于确保我采取的每一步都有助于最终目标,并且没有浪费时间。

然后,我将讨论整个项目中出现的一些挑战。在 2015 年的 Macbook Pro 上处理 7gb 的数据集是不可能的。利用 AWS EMR 和气流提供动力,创建高效的管道。最后,如果有第二次机会(和更多时间),我将讨论性能改进,这将极大地提高代码的可伸缩性和运行时间。

数据第一,代码第二

在编写任何代码之前,我首先回顾了数据集,并明确定义了最终的数据结构应该是什么样子。为此,我首先回顾了三个数据集的模式以及它们应该在哪里连接。

在这里,我能够绘制一个模式来定义数据集之间的关系。从软件的角度来看,这是定义我如何结合数据来理解美国城市移民模式的关键。

在定义了数据集之间的关系之后,最终的数据结构被明确地定义了。下面的字典实际上并没有在项目中实现。然而,它使我能够为数据创建一个层次结构,并在项目结束时定义数据的结构。对于每个州,应该有一个每月到达的汇总,一些关于人的年龄和性别以及平均温度的平均值。

我花了大约 35%的时间来理解数据、创建模式和定义最终结果。这使我能够为这个项目创建一个清晰的目标,这个项目的实现将完全围绕这个目标。我现在将讨论为实现该项目而创建的步骤。

创建管道

定义了成功的最终结果后,我接着开发软件来汇总数据。数据集的大小(7gb)使得在本地执行部署不可行。因此,我利用了 AWS EMR,它为执行 Spark 作业提供了一个预配置的主从集群。

为了编排和协调管道,我使用了 Apache Airflow。Airflow 提供了一个 web-ui 和图表,记录了哪些功能或步骤需要在连续功能之前执行,以及哪些功能可以同时运行。

例如,在任何 Spark 作业触发之前,需要从 s3 下载数据集并解压缩。使用 Airflow 记录这种依赖性,如果下游任务失败(从 s3 同步文件),那么依赖的上游任务将不会被调用。这提高了管道的稳定性,防止失控代码被执行并导致意外问题。

提取

提取步骤相当简单,包括将 zip 文件从 S3 存储桶同步到主 EMR 节点上的挂载目录(文件系统指向不同的服务器)。一旦文件成功同步,更复杂的工作就开始了。

负荷

数据集成功下载到服务器后,我就可以开始实现管道了。数组样式的符号用于说明城市/温度任务和移民数据聚合可以并且理想情况下应该同时执行。

温度和人口统计数据加载

回到最终结果,需要确定美国城市每月的平均温度。然后,这个平均值必须与每个城市的人口统计数据相结合。

由于移民数据来自 2015 年事实核查因此,只选择尽可能接近今年的温度数据是有意义的,并在相同的加载步骤下将其与人口数据相结合。

移民和人口统计数据同时加载。虽然这打破了单一的责任,数据集的连接是简单的。在数据清理方面也没有预先的工作,所以将这些数据集的加载分组到一个任务中是有意义的。

最后一步记录数据应该如何保存到磁盘。Partition by 确保数据按照指定的列以降序排序并保存到磁盘。如果您知道将通过查询这些列来选择数据,这将显著提高未来的读取性能。

Binary Search (LogN) can be applied when data sorted is sorted into buckets. More performant hash searches can be applied if uniqueness of buckets is guaranteed.

移民数据加载

汇总移民数据更加复杂,原因有二:

  • 数据集要大得多,而且分布在几个文件上,需要一个额外的库来加载。
  • 需要对数据集进行汇总和转换,以确定移民的平均年龄和性别。

为了解决这个问题,我使用了一种接口输出的方法。在这里,首先定义函数的最终结果,然后定义它们的输入。一旦这些都清楚了,你就可以把中间部分,或者说代码,作为实现细节来对待,这些细节必须对输出有所贡献。

我从工作中的一位资深朋友那里学会了将代码定义为一系列清晰的函数/对象。它极大地提高了我的生产率和代码质量。这也非常符合 TDD 的工作风格,在这种风格下,每个功能都应该有一个可以清楚评估的特定输出。

这种方法使我能够定义从磁盘文件加载数据所需完成的确切步骤,并根据数据创建一个统一的数据帧。

从这个数据框架中,我创建了代表每个需求的子集:

  • 每个州移民的平均年龄
  • 每个州所有女性移民的数量
  • 每个州的移民总数

使用女性和所有移民数据框架,我可以通过连接女性和所有移民数据框架,并使用女性计数/所有移民计数创建一个新列来确定性别分布。

该数据框架随后与年龄数据框架相结合,以创建一个包含每个州所有抵达者的平均年龄和性别分布的数据集。

最终加入

在管道的这一点上,我已经连接了温度和人口统计数据。移民数据按州汇总,确定了移民的平均年龄和男女比例。

从这一点来看,所有需要的是一个结合了温度、人口统计和移民数据的综合集合。由于所有的数据集都是按照州来划分的,所以加载数据集并通过州代码将它们连接起来既简单又高效。

这些代码行完成后,我创建了一个数据结构,它标识了以下内容:

  • 每个州移民的平均年龄
  • 各州移民的平均性别
  • 每个日历月每个州/城市的平均温度
  • 每个城市/州的人口统计数据

满足要求!

转学?

我不明白的一件事是如何处理这些数据!在当前状态下,它位于 EMR 集群上,实际上没有任何商业价值,也不能用于任何下游流程。

由于时间限制,我把这一部分漏掉了。Udacity 课程每月 300 英镑,所以我自然想完成它。

正是因为这个原因,您还会看到零单元测试,可以说是将代码呈现为非生产就绪。

尽管如此,该软件实现了最终目标:证明我在数据工程领域的熟练程度。它很好地完成了这项任务,在完成课程的几周内,我就能在 Sainsbury's 获得一份数据工程师的工作,在那里我将学习所有这些东西是如何在规模上实际使用的。

结束语

在本文中,我展示了如何通过首先定义确切的最终目标来分解一个(相当)复杂的软件需求。这有助于确保我随后提交的每一段代码都有助于相同的最终目标。通过显式定义每个函数的接口和输出,我能够将注意力从函数逻辑的实现细节上移开。

最终的结果是,每一行代码都有助于一个产生清晰输出的功能,这个功能在最终目标的实现中有一个清晰的角色。

除非我能想到更好的方法来思考复杂系统,否则我会坚持:

  • 在计划任何软件之前,明确定义最终结果
  • 明确规划软件以创造最终结果
  • 清楚地将功能输入和输出定义为软件的构件

*要查看所有代码,并运行管道 请单击此处。 *

利用蚁群和遗传进化优化拼车出行时长

原文:https://towardsdatascience.com/using-ant-colony-and-genetic-evolution-to-optimize-ride-sharing-trip-duration-56194215923f?source=collection_archive---------5-----------------------

城市交通正在经历一场快速而重大的变革。自从互联网和智能手机诞生以来,我们的联系越来越紧密,并且能够规划和优化我们的日常通勤。与此同时,大量数据被收集并用于提高现有交通系统的效率。优步和 Lyft 等实时拼车公司正在利用这些数据改革出租车行业,为更加互联和集中控制的交通结构奠定基础,并建立拼车等创新系统。

在这个项目中,我解决了出租车的行程时间优化问题。这可以被框定为旅行推销员问题,一个众所周知的计算机科学问题。目标是找到访问一组位置的最短路径。对于这个问题,需要优化技术来智能地搜索解空间,找到接近最优的解。更具体地说,我首先使用机器学习来预测每一对接送地点之间的旅行时间。然后我使用进化算法,即蚁群和遗传算法,为数据集中的车辆找到最佳旅行路线。

问题描述

资料组

我使用的数据是纽约市出租车和豪华轿车委员会的出行记录数据,可以通过以下网址访问:https://www1 . NYC . gov/site/TLC/about/TLC-Trip-Record-data . page .我有 2016 年黄色出租车、绿色出租车和出租车辆的月度数据。该数据集有近 150 万条出行记录,具有以下 11 个属性:

  • id —每次行程的唯一标识符
  • vendor_id —表示与行程记录相关的供应商的代码
  • 拾取日期时间 —血糖仪启用的日期和时间
  • dropoff_datetime —血糖仪脱离的日期和时间
  • 乘客计数 —车内乘客数量(驾驶员输入值)
  • pickup_longitude —电表接合的经度
  • pickup_latitude —仪表接合的纬度
  • dropoff_longitude —电表脱离的经度
  • dropoff_latitude —仪表脱离的纬度
  • store_and_fwd_flag —该标志表示在发送给供应商之前,行程记录是否保存在车辆存储器中,因为车辆没有连接到服务器:Y =存储和转发,N =不是存储和转发行程
  • trip_duration —以秒为单位的行程持续时间(也是目标变量)

我进行了简单的数据预处理技术,如消除重复、检查纬度和经度界限、删除明显的异常值、将数据字段转换为合理的单位等。为我的实验获取一个干净的数据集。

数据可视化

这个项目的一个重要组成部分是可视化数据,并找出下一步用于机器学习模型的最佳特征。取货时间是我首先关注的一个特性。

图 1 是一天中不同小时的取件时间分布。可以看出,最受欢迎的接送时间是下午 6 点到 10 点,超过 70,000 次。另一方面,最不活跃的接车时间是凌晨 2 点到 6 点,不到 35,000 次。

图 2 是一周中工作日的取件时间分布。似乎周五是最受欢迎的打车日,有近 220,000 次出行,而周日则是另一端,约 165,000 次。

图 3 是图 1 和图 2 结果的拾取时间热图。最活跃的接送时间是从周四到周日的下午 6 点到 9 点。最不活跃的接送时间是从周三到周日的下午 2 点到 5 点。

我研究的下一个特征是旅行持续时间

图 4 是按分钟计算的出行持续时间分布。我观察到分布严重左倾,超过 75%的行程在 3 到 12 分钟之间。超过 10,000 次的行程持续 5 到 7 分钟。

图 5 显示了按分钟与按纬度和经度划分的旅行持续时间分布的比较。经度的分布也非常左偏,峰值大约在 1 公里处。按纬度分布更为正态分布,峰值在 0 公里处。

图 6 是一天中不同时段的出行时长热图。最长的旅行通常发生在周三至周五的下午 2 点至 4 点。最短的行程发生在周一和周二的上午 8 点到 9 点。

我还对取车下车地点感兴趣。

我绘制了接送位置的空间密度,如图 7 所示。这看起来有点像你从太空中看到的图像,曼哈顿和两个机场(LGA 和 JFK)“点亮”得很清楚。

我进一步在图 8 的地图上展示了典型的旅行。洋红色圆圈是上车地点,绿色圆圈是下车地点,青色箭头线是行程长度。我可以看到接送地点的不均匀分布,因为曼哈顿以外(皇后区和布鲁克林区)有更多的接送地点。

机器学习

我的下一步计划是建立一个机器学习模型来预测接送地点之间的旅行时间。有了数据和目标,简单的线性回归就不够强大了。在庞大的数据集中有一些随机异常值,并且可能有一些分类特征,我决定使用梯度提升树,它可以轻松捕捉非线性关系,适应复杂性,并处理分类特征。使用的输入要素有:乘客计数、接送经度、接送纬度、接送经度、接送纬度和商店和转发标志。输出目标是 trip_duration。

我通过 XGBoost 实现了这个模型,XGBoost 是一个优化的分布式梯度增强库,旨在高效、灵活和可移植。这个模型很容易建立,但很难微调和解释。我使用均方根对数误差作为评估指标,因为它降低了误差幅度。根据这一指标,我选择了不同的超参数并比较了结果。我为我的 XGBoost 模型使用的最终参数是:{ fbooster = GB tree;目标=线性;learning _ rate = 0.05max _ depth = 14 子样本= 0.9;colsample _ bytree = 0.7colsample _ bylevel = 0.7 无声= 1;feval = rmsleg}

我们获得的平均绝对误差为 4.83。XGBoost 模型被保存为 pickle 文件,然后将被用作下一步的输入:优化

提议的解决方案

因为这个问题涉及最小化旅行时间,同时还要访问每个地点,所以它类似于旅行推销员问题(TSP)。旅行商问题是一个组合 NP-hard 优化问题。这意味着这个问题没有多项式时间的解。添加的位置越多,可能的解决方案就越多。解决这个问题的强力方法包括检查每个可能的位置组合。如果我要评估每条可能的路径,其中 n 代表位置的数量,那么它的运行时间如下:O(n)=[(1/2)(n-1)!]

考虑到这个运行时间,一旦我开始向问题定义添加更多的位置,解决方案空间很快变得难以处理。因此,我使用元启发式直接搜索解空间。我不会遍历每一条可能的路径,而是会生成可能的路径,并以一种有指导的随机方式搜索它们。

蚁群优化

蚁群优化(ACO)算法是一种生物启发的元启发式算法,它以模拟蚂蚁搜索可能路径的方式来搜索解决方案空间。蚂蚁在它们的行进路线上留下信息素,这取决于路线的质量。由于我试图最小化旅行成本,我将使我的信息素质量τ等同于更低的旅行时间。完整图中的每条边都有一个对应的逆旅行时间成本 eta信息素 tau

每一代都有一定数量的蚂蚁随机出现在图中的起点。然后,每只蚂蚁通过遍历该图来构建解决方案。它通过以加权概率选择下一个位置来实现。计算从位置 I 到位置 j 的概率的公式是:

其中τ表示 n 乘 n 信息素矩阵,并且η表示 n 乘 n 逆行进时间成本矩阵。信息素矩阵中的所有值首先被初始化为 1/n。我发现用 1 初始化信息素矩阵对我的结果几乎没有影响。相应的指数 alph a 和β用于控制信息素和旅行时间成本在两个节点间概率计算中的影响。在分母中,我有这些值的总和,其中 h 表示蚂蚁可以访问的所有可能的位置。这些是特定蚂蚁还没有访问过的节点。将这些项加在一起,计算从节点 I 到节点 j 的加权概率。

每只蚂蚁生成相应的解后,更新信息素矩阵。如何做到这一点取决于所采用的策略。在这个解决方案中,我通过首先将它乘以 p (剩余系数)来更新每个信息素边缘。这代表了信息素“蒸发”或降低其影响的速率。然后,我们添加到信息素边缘 q/c ,其中 q 代表信息素强度,而 C 代表生成路径的总成本。因为行驶时间成本是分母,所以行驶时间较长的路径被选中的概率较低。这个过程重复 g 次,其中 g 代表世代数。

遗传进化

遗传进化(GE)是另一种生物启发的元启发式方法,它从进化过程中采取步骤。它利用连续世代的变异、交叉和选择功能。这些代构成了解决方案的群体。该优化算法遵循以下步骤:

  1. 创建一组路径。
  2. 使突变
  3. 交叉
  4. 确定适合度(行驶时间)
  5. 为下一代选择父代
  6. 重复步骤 2

通过随机生成 n 条路径来创建初始群体。变异和交叉操作基于变异率 m交叉率 c 。这两个值都在 0 和 1 之间。当遍历当前种群中的每条路径时,我随机选择一条不同的路径并对其进行变异。这种变异是通过遍历路径中的每个位置,并随机与前一个索引的位置进行交换来完成的。这种随机交换由变异因子 m 加权。

在我创造了突变体之后,我开始杂交。我遍历当前路径和变异路径中的每个索引,并根据交叉率 c:

行程路径中的顺序问题。仅仅在这里结束我的跨界行动是不够的。如上图所示,位置 1 和 12 出现了不止一次。因此,我需要删除重复的。然后,我找到丢失的位置,将它们打乱,并添加到路径中:

一旦我有了最终的后代路径,我就可以评估它与当前路径的适合度。如果它的旅行时间更短,那么它将被选择作为下一代的父路线,取代当前路线。这个过程重复 g 次,其中 g 代表世代数。

实验结果

在我对每种优化算法的试运行中,我发现蚁群优化比遗传进化表现得更好。这是意料之中的,因为蚁群优化算法是专门为解决旅行推销员问题而设计的。对于两种算法的每次试验,我都使用了 15 个不同的位置。

ACO 结果

对于蚁群优化的试验,我使用了以下值: alpha = 1.0,beta = 10.0,p = 0.5,q = 10.0 ,同时我改变了蚂蚁的数量和世代数 g。

下图是用 10 只蚂蚁和 g = 100 生成的。从每代平均成本图中可以看出,ACO 没有陷入局部最小值。它继续探索其他可能的解决办法。这从平均成本的巨大差异中可以明显看出。

通用电气结果

对于遗传进化优化的试验,我使用了以下值:突变率 m= 0.5,交叉率 c = 0.7 同时我改变了群体 p 的大小和世代数 g。从结果中,我可以看到世代越多,群体越大,算法找到的解决方案越好。然而,相比蚁群优化,这种解决方案仍然是劣势。

讨论

实验结果表明,蚁群算法是优化我们的问题的较好算法,该问题类似于旅行商问题。无论我在我的遗传进化程序中使用哪个参数作为种群 p突变率 m交叉率 s ,它都无法找到成本像 ACO 一样低的路径。我认为这是由多种因素造成的。

首先,考虑两种算法中的解路径是如何生成的。在蚁群中,旅行时间成本 n_ij 是蚂蚁做出的每个决定的考虑因素。这是因为在概率计算中使用了逆传播时间矩阵来确定蚂蚁接下来应该访问哪个位置。遗传进化仅在应用了它的变异和交叉操作之后评估成本。旅行费用对遗传进化的随机成分没有影响。突变和交叉是随机进行的,尽管受到交叉和突变率的影响,但不考虑这些变化是否会给我们带来更低的值。只有在选择阶段,我才会检查后代是否有更好的价值。

这可以解释为什么蚁群不仅表现得更好,而且表现得如此显著,以至于它的第一代产生的结果比遗传进化快了一百多分钟。另一个要考虑的因素是我如何实现我的变异和交叉操作。可能有更好的方法来实现它们,在选择之前也考虑路径的成本。

看到蚁群每一代的平均成本是很有趣的。它向我展示了算法没有陷入局部最小值。相反,它仍在寻找各种其他途径,没有一条比它找到的更好。由于蚂蚁的决定是基于加权概率,这是有意义的。将此与遗传进化的平均成本图进行比较,可以告诉我们该算法可能如何收敛。我从这条曲线上看到的趋势是一个下降的斜率,看起来很快就会变平。

结论

虽然旅行推销员问题本身可能很古老,但它在优步和 Lyft 等现代服务中的应用让我想起了它的相关性和丑陋的阶乘运行时间。随着生物启发优化算法的最新进展,我仍然可以找到可行的解决方案,而不需要多项式时间的解决方案。

在这个问题领域中,遗传进化优化还有进一步的工作要做。挑战在于找到一种更有效的方法,将路径成本纳入变异和交叉操作。但正如这个项目的结果所表明的,我可以肯定地说,蚁群优化确实是为了解决这类问题而产生的。

注:你可以从这个 GitHub repo 中查看该项目的完整代码:【https://github.com/khanhnamle1994/trip-optimizer

— —

如果你喜欢这个作品,你可以在 GitHub 上找到我自己的代码,在https://jameskle.com/上找到更多我的写作和项目。也可以在 推特*上关注我直接发邮件给我 或者 在 LinkedIn 上找我 *

利用人工智能进行糖尿病再入院预测

原文:https://towardsdatascience.com/using-artificial-intelligence-for-diabetic-readmission-prediction-368ddbab53c8?source=collection_archive---------9-----------------------

医院再入院预测仍然是一个高度鼓励的研究领域,主要是因为医疗保险和医疗补助服务中心(CMS)的再入院减少计划。总体目标是通过识别导致再次住院的关键风险因素,减少早期再次住院的人数。这在重症监护室(ICU)中尤其重要,在 ICU 中,由于患者病情恶化,患者再次入院会增加死亡的可能性。传统方法使用简单的逻辑回归或其他线性分类方法来识别提供高预测准确性的关键特征。

Figure 1: Readmission in USA

然而,这些方法是不够的,因为它们不能捕捉不同特征之间的复杂模式。在本文中,我们提出了一个混合进化模拟退火 LASSO 逻辑回归(ESALOR)模型,以准确预测医院再入院率和识别重要的危险因素。提出的模型结合了进化模拟退火法(如下图所示)和 Lasso 的稀疏逻辑回归模型。ESALOR 模型在公开可用的糖尿病再入院数据集上进行测试,结果表明,与包括支持向量机(SVM)、决策树、朴素贝叶斯和逻辑回归在内的传统分类方法相比,所提出的模型提供了更好的结果。

Figure 2: Coupling ES and SA.

考虑到所提供的信息,建议的模型可以总结为以下步骤:

步骤 1 特征选择:使用过滤器和包装器特征选择方法的组合来选择特征的最佳子集。

第二步公式化:确定问题的套索-逻辑回归公式化。

第三步初始化:采用进化策略算法初始化模拟退火模型。

步骤 4 优化级别:使用基于混合进化策略的模拟退火方法来优化 LASSO 模型的参数(系数)。我们优化了所提出模型的参数。

第五步确定解决方案:我们通过比较所有解决方案找到最优方案。

步骤 6 预测:使用具有最佳系数的 LASSO 模型预测新患者的再次入院。

Table 1: Comparison of ESALOR model with traditional classifiers with testing data.

结果(如上表所示)通过观察再入院的性能指标进行比较,我们的模型用于做出更好的预测。在比较四种方法时,我们的方法也显示出比文献中其他方法更好的结果。更具体地,对于 SVM、ANN、LR 和 NB 的结果,如在表 2 中看到的,对于测试水平,预测准确度为大约 74 %。大多数方法的精度和召回值都小于 0.7。与此同时,这些方法的 F 值(需要大于 0.8)被建立在 0.65 左右。因此,当使用诸如 SVM、人工神经网络、LR 和 NB 等优秀方法时,预测性能不足以用于再入院。

然而,我们提出的模型的性能远远优于其他方法,如 F-measure。这意味着所提出的模型适用于不平衡数据,因为没有针对每个子类的不平衡学习。因此,提出的模型在预测再入院率方面表现更好。

结论

随着医疗保险和医疗补助中心(CMS)引入报销罚款,医院对降低再住院率产生了强烈的兴趣。在这项研究中,我们提出了一个混合分类框架,称为进化模拟退火 LASSO 逻辑回归(ESALOR ),以改善糖尿病患者再入院的分类。ESALOR 模型可以帮助医疗服务提供者识别导致糖尿病患者再次住院的关键风险因素。通过使用确定的风险因素,医生可以制定新的策略来降低糖尿病患者的再住院率和护理成本。

使用人工智能方法在扑克中获胜

原文:https://towardsdatascience.com/using-artificial-intelligence-methods-to-win-in-poker-5559cc522f3b?source=collection_archive---------6-----------------------

这篇文章最初写于 2015 年,回顾了当时扑克研究的最新水平以及脑机接口技术如何影响它。

Victoria Peak, Hong Kong. Ori Cohen.

在扑克中获胜的概念很简单,理论上,你所要做的就是获得获胜的一手牌;价值最高的五张牌的组合。但由于其多种形式和多种动态,在实际操作中,扑克是一种依赖于偶然性的复杂游戏,需要对策略的深刻理解;有些是数学上的,有些是基于个人经验。

使用人工智能(AI)解决游戏是一种常见的做法。游戏不允许随机性,遵循预定义的规则,并使用一个相对简单的因素来衡量性能和胜算(例如,在国际象棋中,你通过拿下国王来获胜,在跳棋中,你通过锁定对手或抓住他的所有棋子来获胜),这些游戏是人工智能的经典测试平台。这些游戏可以在计算机上完美地定义[1],因此完全可以通过使用数学公式、统计方法、机器学习方法(ML)或策略和启发式方法来解决。用今天的 CPU 处理术语来说,它并不昂贵,而且相对容易完成。像国际象棋和跳棋这样的游戏已经被成熟的人工智能软件完全解决了,这些软件能够像人类大师甚至更高的水平进行游戏。通过利用人工智能编程建立一个所有动作的深度树,他们能够以很高的速度遍历树,并选择最佳的动作来获胜。相比之下,像扑克这样的游戏引入了运气的元素,或者换句话说,当你或你的对手从一副牌中抽出一张牌时,这张牌会提高还是阻碍你获胜的机会是未知的。因此,扑克是一种比那些不涉及随机元素的游戏更难解决的游戏,并且不能通过使用适用于非随机游戏的完全相同的技术来解决。

几项有影响力的研究集中在赢得扑克游戏的不同方法上。在这篇综述中,我们将介绍这些方面。通常,在扑克中获胜可以通过模拟对手并利用他们的弱点,通过使用学习专家策略并实时应用它们的算法,或者通过“读取”对手的想法来确定对手是否在虚张声势,所有这些方法都是为了在扑克中获胜而研究的。

扑克是一个不完美信息游戏,有竞争对手,有风险管理,有成功概率,有欺骗。不像在国际象棋中忽略对手建模是无关紧要的,在扑克中承认他们是非常有价值的,因此许多努力被投入到对手建模中[4,5,6,7,8]。有几种方法可以预测敌方可能采取的行动:1。专家系统——为了硬连接我们自己的或固定的策略,这种方法通常作为基线测量是好的。2.试探法——一种解决问题的方法,其结果是决策的近似值,而不是最佳值。3.统计学——根据对手的记录预测对手的行为。但是,这种方法容易受到不断改变下注习惯的对手的影响。4.神经网络(NN)——一种通用系统,能够预测对手的下一步行动,基于 ML 方法,并大致受我们大脑生物学的启发。神经网络相对容易创建,准确,并且明显优于前三种,但我们无法从它们那里获得学习信息(图 1a)。一般来说,NN 接收大量输入(我们下一步行动的可能性)并处理它,直到选择一个输出(下一步行动)。5.决策树(DT)-是经典 ML 中的另一种方法,可以对对手的未来行动进行分类,方法是在每个树节点(图 1b)提出一个问题,然后沿着树向下爬到拥有最终决策的末端叶子。DT 不像 NN 那样健壮,但是是人类可读的,并且获得相似的结果。

Figure 1: a (left) A Neural Network predicting an opponent future action. b (right) A subset of a decision tree model. [4]

Loki [4]和 Poki [5]是两个扑克程序,旨在观察对手,模拟他们的行为,并动态适应他们的游戏,以利用他们薄弱的游戏模式。这种“技能”在现实世界中提供了巨大的好处,因为它可以增强玩家发现虚张声势或从游戏中理解对手意图的自然能力。对手建模程序旨在检测经常弃牌和不经常弃牌的玩家,他们的游戏有多被动或激进,他们根据手中的牌下注或加注的行为,以及他们对动态策略的适应程度。洛基和波基在击败强大的扑克玩家方面无疑是一个进步,但它们肯定有其局限性,因为人类玩家也擅长对手建模,并可以实时改变他们的策略。然而,艾伯塔小组一直在研究扑克,最近宣布,他们首次创建了一个名为 Cepheus [9,10]的计算机程序,解决了“单挑限制德州扑克”(HULHE)。这个高度复杂的游戏有超过 10 个⁴决策点,挑战人工智能研究超过十年。实现仙王座需要 68 天,使用 4800 个 CPU 的高性能计算机集群,加上数据压缩和最先进的计算算法。呼和是一个需要人类玩家使用欺骗和虚张声势的游戏,显然不是机器式的特点;仙王座能够在不欺骗人类玩家的情况下和他们进行比赛,并且不让他们知道他们是在和一台机器比赛。

另一种使用人工智能在扑克中获胜的方法是通过脑电图(EEG)检测虚张声势。脑电图是一种从大脑读取电信号的方法,通常使用一个基于电极的帽子,戴在一个人的头上,如图 2 所示。测量隐蔽的人类状态[11],可以用 EEG 来执行,EEG 提供被注册为生理特征的健壮信号,并且可以通过 ML 方法来分类。虚张声势是一种故意误导游戏中其他对手的行为,是一项复杂的任务,需要有预谋的风险评估、虚假意图的行为和持续的跟进,尤其是在保持镇静方面。人工智能方法被用来分类玩家是否在虚张声势,这种方法可以帮助玩家通过了解对手的心理状态并抵消其隐藏的意图来赢得扑克比赛。经验结果表明,平均有 81.4%的概率可以检测到虚张声势。换句话说,在 200 毫秒的时间框架内,10 个人中有 8 个人可以持续检测到虚张声势。时间足够短,以赢得大多数使用诈唬或其他隐蔽状态作为策略工具的游戏。脑电图也可以记录额外的改善,如果眼球运动或肌肉紧张将被考虑在内,这两者都可以用脑电图记录。

Figure 2: an electrode array used to read electric signals from a person’s brain [from wikipedia]

已经有的消费者解决方案用于读取 EEG 大脑信号。虽然脑电图已经使用了 20 多年,但消费产品仍处于起步阶段。我假设脑电图设备将会进一步小型化,让非技术人员也能使用,并进行微调,以高精度读取房间内特定的大脑模式。自动诈唬分析方法也将得到改进,从而可以在锦标赛和私人高赌注游戏中秘密使用这种技术。然而,即使有这些进步,总有办法检测或阻止新技术无线工作,并防止扑克玩家拥有不公平的优势。虽然扑克在许多方面仍然是一种具有挑战性的游戏,但过去的经验告诉我们,随着研究和硬件的进步,人工智能的未来可以在我们的有生之年解决其他扑克变种。

参考资料:

[1] S .罗素和 p .诺维格。人工智能:现代方法。普伦蒂斯霍尔,1995 年。

[2] M .坎贝尔、A. J .霍恩和 F . h .徐。深蓝色。人工智能,134(1–2):57 { 83,2002}。

[3] J. Schaeffer、J. Culberson、N . Treloar、B. Knight、P. Lu 和 D. Szafron。世界锦标赛口径跳棋计划。人工智能,53(2–3):273 { 290,1992}。

[4] 戴维森。扑克中的对手建模:在敌对和不确定的环境中学习和行动(2002)

[5] D .比林斯,A .戴维森,j .谢弗,d .萨弗朗。扑克的挑战。人工智能,2002 年第 134 期,201–240 页。

[6] A .戴维森、d .比林斯、j .谢弗和 d .萨夫龙。改进了扑克中的对手建模。国际人工智能会议(ICAI,2000 年),第 1467 页{1473,2000}。

【7】比林斯、达瑟等,《对手建模在 扑克 》AAAI/IAAI。1998.

[8]f . sou they,m . p . Bowling,b . Larson,c . Piccione,n . Burch,Billings d .,& Rayner,C. (2012 年)。贝叶斯的虚张声势:扑克中的对手建模。 arXiv 预印本 arXiv:1207.1411

[9] Tammelin,Oskari 等人,“解决德州扑克的单挑限制。”

迈克尔·鲍林、尼尔·伯奇、迈克尔·约翰逊和奥斯卡里·塔梅林。单挑限注德州扑克 扑克 解决了。科学,347(6218):145–149,2015。

[11]Jessika Reiss land、Christian Kothe、Sabine Jatzev、Matti Gä rtner、Sebastian Welke 和 Thorsten O. Zander。BCI 检测故意隐藏的用户状态——或者:我们能检测出游戏中的虚张声势吗?

Ori Cohen 博士拥有计算机科学博士学位,专注于机器学习和脑机接口(BCI)。他领导着 Zencity.io 的研究团队,试图积极影响市民的生活。

利用人工智能创造人、车和猫

原文:https://towardsdatascience.com/using-artificial-intelligence-to-create-people-cars-and-cats-5117189d0625?source=collection_archive---------12-----------------------

我们如何利用生成性对抗网络制作超现实的图像

None of the people in these images are real, they’ve just been generated by a neural network! Source.

想想你平常的一天是什么样的。除非你整天锁在房间里看《网飞》或者睡觉,否则当你去你想去的地方时,你很可能会经过很多人。有些人长头发,有些人短头发,有些人大鼻子,有些人小眼睛。

关键是,我们多久会停下来思考一下我们每天所看到的不同特征。你有没有想过,“是什么让一张脸变成了一张脸?”它是有两只眼睛、一个鼻子、一张嘴和一些头发的东西吗?如果是这样,难道我们不能编写一个超级简单的计算机程序,通过组合这些特征来生成新的面孔吗?

不完全是,我们遗漏了很多细节。比如皱纹、阴影和微笑。当我们被要求描述一张脸的特征时,我们可能通常不会想到的东西,但为了让它看起来真实,这些东西必须存在。

Something is off but I can’t put my finger on it… Source.

那么,如果它不只是告诉神经网络将两只眼睛、一个鼻子、一张嘴和一些头发放在一个大肉球上,并希望它看起来合理,那么我们如何才能真正生成人脸呢?

猫捉老鼠的游戏

首先,让我们花一点时间来了解生成性敌对网络(GANs)是如何工作的。

GAN 实际上由两个神经网络组成,一个生成器和一个鉴别器。生成器的工作是根据它所知道的生成新数据,鉴别器的工作是查看生成的数据是否合法。因此,在我们的例子中,生成器会尝试创建新的人脸图像,鉴别器会尽最大努力确定人脸的真假。

假设我们在和一家美术馆打交道。制造者是试图创作假艺术品并出售的人,鉴别者是试图鉴别艺术品真假的馆长。一开始,他们都不擅长自己的工作,但他们都从经验中学习。随着时间的推移,伪造者慢慢变得更擅长根据接受与否伪造艺术品,策展人也变得更擅长辨别真伪。

这基本上是一个生成性对抗网络如何训练的,生成器接受一个随机数,并根据输入吐出一个图像。鉴别器评估发生器的输出,并试图预测图像是否真实。如果猜测正确,网络会将其考虑在内,并更新它们的权重。如果它猜错了,也会发生同样的事情。

最终,目标是让这两个网络达到这样一个点,即生成器非常擅长生成假货,以至于鉴别器将始终徘徊在 50%左右的置信度。

然而,在训练 GAN 时需要注意的一点是,当一方过于擅长自己的工作时,可能会出现问题,因为另一方将无法学到任何东西。如果馆长能够正确地猜测每一件艺术品,伪造者将无法知道它做错了什么。如果伪造者做得太好,策展人总是会被骗,也不会学到东西。

绘制概率分布图

好吧,这很酷,对吧?你可以训练两个相互竞争的神经网络,让它们相互竞争,最终你会得到一个生成模型,它在创建可信的图像方面做得非常棒。但是让我们更深入地了解一下这实际上是如何工作的。

生成式对抗网络实际上做的是映射数据的概率分布。

这到底是什么意思?

我们可以把图片想象成一个高维概率分布的样本。每当你拍照时,你都是在从像素的概率分布中取样。基本上存在产生一些像素排列的概率或可能性,GAN 基于数据绘制概率分布。

对于我们的例子,基本上是学习什么使一张脸成为一张脸。眼睛、鼻子和嘴巴等不同的特征在这个概率分布中有一个表示。因此,改变输入到模型中的噪声将改变对应于这些数字的图像的一些质量。通过从这个分布中采样,我们可以得到一个模型,根据它所知道的图像某一部分中像素的概率来生成全新的图像。

使用 DCGAN 生成新的人脸

An image from the DCGAN paper. Source.

DCGAN 基本上是常规 GAN 的改进版本,但有一些重要的变化:

  • 最大池函数被步长卷积取代,让网络学习自己的空间下采样和上采样。
  • 去除卷积特征之上的全连接层。一个例子是全局平均池,它经常增加模型的稳定性,但损害收敛速度。最佳解决方案是将最高卷积特征直接连接到发生器和鉴别器的输入和输出。
  • 通过将输入标准化为零均值和单位方差,使用批量标准化来稳定学习。这有助于渐变在更深的模型中流动,但不应该应用于所有层。当 batchnorm 不应用于生成器输出层和鉴别器输入层时,可以避免模型不稳定。
  • ReLU 激活在发生器中用于所有层,除了使用 Tanh 的输出。据观察,这有助于模型更快地学习并覆盖训练分布的颜色空间。
  • LeakyReLU 激活用于所有层的鉴别器中。

如果您对实现 DCGAN 感兴趣,有一个很棒的 PyTorch 教程,它使用了 CelebFaces 属性数据集(CelebA),这是一个包含超过 200,000 张名人脸部照片的数据集。

以下是数据集中的一些图像示例,这些图像被调整为 64x64,以便于训练:

这两个模型的结构如下:

Generator(
  (main): Sequential(
    (0): ConvTranspose2d(100, 512, kernel_size=(4, 4), stride=(1, 1), bias=False)
    (1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    (2): ReLU(inplace)
    (3): ConvTranspose2d(512, 256, kernel_size=(4, 4), stride=(2, 2), padding=(1, 1), bias=False)
    (4): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    (5): ReLU(inplace)
    (6): ConvTranspose2d(256, 128, kernel_size=(4, 4), stride=(2, 2), padding=(1, 1), bias=False)
    (7): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    (8): ReLU(inplace)
    (9): ConvTranspose2d(128, 64, kernel_size=(4, 4), stride=(2, 2), padding=(1, 1), bias=False)
    (10): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    (11): ReLU(inplace)
    (12): ConvTranspose2d(64, 3, kernel_size=(4, 4), stride=(2, 2), padding=(1, 1), bias=False)
    (13): Tanh()
  )
)Discriminator(
  (main): Sequential(
    (0): Conv2d(3, 64, kernel_size=(4, 4), stride=(2, 2), padding=(1, 1), bias=False)
    (1): LeakyReLU(negative_slope=0.2, inplace)
    (2): Conv2d(64, 128, kernel_size=(4, 4), stride=(2, 2), padding=(1, 1), bias=False)
    (3): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    (4): LeakyReLU(negative_slope=0.2, inplace)
    (5): Conv2d(128, 256, kernel_size=(4, 4), stride=(2, 2), padding=(1, 1), bias=False)
    (6): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    (7): LeakyReLU(negative_slope=0.2, inplace)
    (8): Conv2d(256, 512, kernel_size=(4, 4), stride=(2, 2), padding=(1, 1), bias=False)
    (9): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    (10): LeakyReLU(negative_slope=0.2, inplace)
    (11): Conv2d(512, 1, kernel_size=(4, 4), stride=(1, 1), bias=False)
    (12): Sigmoid()
  )
)

那么现在发生了什么,我们已经在一堆人脸上训练了一个神经网络,结果一定很好,对吗?这取决于你对好的定义。

老实说,如果你不仔细看,有些看起来可能是真的脸。不过,其他人看起来像是直接从噩梦中走出来的。

不会是这个吧?一定有更好的方法让假人看起来像真的。英伟达的一些研究人员可能已经找到了秘方。

Nvidia 的 StyleGAN

结果公布后,英伟达用于生成新图像的生成对抗模型在新闻中得到了大量炒作和报道,这是有充分理由的。大多数照片都非常逼真,几乎无法与真实照片区分开来。

“These people are not real — they were produced by our generator that allows control over different aspects of the image.” Source.

老实说,这个模型得出的结果相当疯狂。如果我不是一名高中生,我肯定会尝试自己训练这个模型,但在它真正开始产生可识别的图片之前,我可能已经 40 岁了。他们毫不夸张地推荐一款配有 8 个特斯拉 V100 GPUs 的 NVIDIA DGX-1。因此,除非你手头有 15 万美元的闲钱,或者有一个企业级深度学习系统,否则你可能也不走运。

但是它实际上是如何工作的呢?

关于 StyleGAN 的论文提出了一个重要的问题。即使 GAN 产生的图像的分辨率和质量越来越好,我们仍然很难解释这些机器到底在做什么。它仍然像一个黑匣子。我们也不理解潜在空间,特征到变量的映射,没有定量的方法来比较生成器。

通过从经典的风格转移中获取灵感,我们的目标是以一种允许我们看到图像合成过程的方式重新创建生成器,并让我们调整每层图像的风格以操纵不同的功能。

在高层次上,Nvidia 的 StyleGAN 做了一些类似的事情,它在没有任何人类帮助的情况下学习图像的不同方面,在训练模型后,可以在不同层次上组合这些风格,以获得具有粗糙、中等和精细风格的最终图像。

看看这个恶心的造型吧!

这张图片展示了一些混合的风格:

生成模型的未来

Nvidia 的 StyleGAN 是生成式对抗网络的一个重大突破。网络生成的一些图像与实际照片几乎无法区分。但是 GANs 有哪些实际应用呢?

  • AI 为视频生成图形

  • 甘斯超分辨率

  • 用于文本到图像生成的 GANs】

mediu

感谢阅读!如果您喜欢,请:

  • 在 LinkedIn 上添加我,关注我的媒体,了解我的旅程
  • 在我的个人网站查看我的一些其他项目
  • 留下一些反馈或者给我发邮件(alex@alexyu.ca)
  • 与你的网络分享这篇文章

利用人工神经网络分析总统演讲

原文:https://towardsdatascience.com/using-artificial-neural-networks-to-analyze-presidential-speeches-6fbd446c5bad?source=collection_archive---------18-----------------------

深入分析

大多数分类任务都是为了区分不同层次的独特性而设计的,但是如果我们已经知道了不同之处,还想寻找相似之处呢?

在大多数分类任务中,总的目标是简单地最大化一些准确度的度量,无论是 F1 分数、平衡准确度等。在这些情况下,我们寻求理解错误的唯一目的是为了在将来最小化它们的频率。总的来说,我们希望将数据集分成尽可能清晰和不同的组。但是如果我们想反其道而行之呢?如果我们已经有了非常清晰的数据,但我们想了解它们是如何组合在一起的,该怎么办?在这种情况下,我们从误差中获得的信息可能比从预测的准确度中获得的信息更多。

考虑两个著名的,但非常独特的电影制作人:昆汀·塔伦蒂诺和韦斯·安德森。为了简单起见,让我们说前者的电影可能被描述为暴力,,而后者将被描述为古怪。有了这些知识,看看你是否能正确识别这些电影对白的作者:

  • 如果你在梦里开枪打我,你最好醒来道歉
  • “我爱你,但你不知道你在说什么。”
  • “在我们像一群疯子一样互相攻击,把自己撕成碎片之前,让我们先打开麻袋,看看里面究竟是什么。这甚至可能不值得麻烦。”

在这里,我们看到前两个引号非常容易识别。第一个来自塔伦蒂诺经典落水狗,第二个来自安德森的月出王国。然而,第三部更具挑战性,因为它既有点暴力又有点古怪。我的妻子是这两个编剧兼导演的超级粉丝,她还没有看过这部电影,猜测它来自塔伦蒂诺。事实上,它来自安德森的最新电影《狗之岛》。有趣的是,虽然前两个引语很容易看出它们之间的区别,但第三个引语突出了它们的一些相似之处。

给出一系列这样的引用,你很可能会犯更多的错误。但这些错误实际上可以帮助我们更好地理解两个截然不同的人有什么共同点,尽管乍一看可能并不明显。

在今天的政治气候中,分歧的领域是明显的,我们都可以非常清楚地确定争论的焦点。真正的挑战在于找到共同点,并找到合作的机会。这是深度学习算法可以帮助我们完成的任务吗?这就是我们要努力解决的问题。

我们将采用与任何其他文本分类任务基本相同的方式来完成这项任务,真正的区别在于我们稍后如何解释结果。语法实验室储存了从华盛顿到奥巴马的总统演讲语料库,以及唐纳德·特朗普和希拉里·克林顿在 2016 年总统竞选期间的辩论和演讲的文字记录。所有工作都是使用 Jupyter 实验室和相关库在 Python 中完成的。

首先,我们将利用 2016 年的竞选数据建立和训练一个网络,然后看看这种方法在其他总统比较中的适用程度。由于大多数演讲将涵盖广泛的主题,我们希望能够在我们的预测误差中识别出明确的主题,因此每篇演讲被分成 50-100 个单词的部分,并保存到带有适当标签的数据帧中。

预处理

由于这不是本次分析的主要重点,我将快速强调一些关键步骤。如果你想更深入地了解这个话题,我鼓励你看看这篇的博文,它对我帮助很大。简而言之,大多数预处理包括以下步骤:

  1. 去除标签:所有的演讲都以一致的方式格式化,日期、标题、以及除了预定演讲者之外的其他人所说的话的标签都被包含在 < >中。在保存到数据帧之前,所有这些文本都从样本中移除,并且不包括在每个样本的字数中。
  2. 扩展缩略:像“不会”和“应该”这样的词被识别出来,并用完整的词“不会”和“应该”代替一个标准的收缩列表和它们的对应物被用来完成这项任务。
  3. 删除特殊字符:撇号、连字符等。
  4. 文本词汇化:获取单词变体的基本形式(即 running = > run,cats = > cat,等等)。).
  5. 删除停用词:使用了自然语言工具包(nltk)中的标准英语停用词列表,删除了单词 nonot ,因为它们会改变周围单词的解释。
  6. 标记化:将字符串转换为单个单词的列表。
  7. 创造二元模型:许多单词作为短语的一部分比它们本身有更多的含义。对于专有名词来说尤其如此,比如美国,乔治·华盛顿,等。但是它对像核武器这样的术语同样重要。我们不是将所有的单词转换成二元模型,而是只希望转换那些有一定规律性的短语。幸运的是,Gensim 库有一个工具可以让这变得非常简单,这个工具叫做短语。请参见下面的代码来查看实现。
*Output:
Maximum Sample Word Count: 88

Sample:
maggie elizabeth walk stage lot folk hang window glad get good view also exciting* ***two_week*** *leave* ***consequential_election*** *lifetime*

数据不平衡

事实证明,特朗普花在竞选演讲上的时间比克林顿多得多,导致数据严重失衡。如下图所示,特朗普语料库的样本量是克林顿的近 4 倍。

如果用这种状态下的数据训练一个模型,它可以学会 100%的时间简单猜测特朗普,并达到 80%的准确率,这将是相当误导的。为了解释这一点,必须从特朗普的语料库中抽取一部分样本,其规模相当于克林顿的语料库。

使用手套矢量化

从这里开始,我们可以使用斯坦福大学的单词表示全局向量来将单词转换成向量。使用 100 维的向量来表示语料库中的每个单词,然后链接到每个样本中的每个单词。这可以通过下面的代码块来完成。

W2vVectorizer 类将在以后为基准目的训练模型时调用。

标杆管理

为了有一个有效的方法来衡量神经网络的性能,必须建立一个使用传统机器学习方法的基准。在这个项目中,使用了支持向量机、对数回归和随机森林。

Output:*[('Random Forest', 0.7851123595505618),  
('Support Vector Machine', 0.7202247191011235),  
('Logistic Regression', 0.7789325842696628)]*

从这里,我们可以看到一个随机森林模型获得了 78.5%的最高准确率。出于这个项目的目的,我们并不真正关心错误偏向哪个方向,因为数据集已经平衡,所以没有理由担心模型被不适当地偏向以获得异常高的准确性分数。

网络建设

因此,我们对数据进行了预处理、清理、平衡和标记,我们有了一个基准。现在是时候卷起袖子准备好玩的东西了!为了分析这些数据,我们将尝试递归和卷积神经网络(RNN 和 CNN 的),每种网络都首先需要创建一个嵌入层,它可以有效地将我们的样本转换为向量序列集。

现在,与其简单地创建一个 RNN 和 CNN 来进行分析,不如我们可以实现网格搜索来找到性能最佳的模型,这不是很好吗?不幸的是,没有理想的方法来实现一个 SKLearn 管道而不丢失以后可能是无价的信息,所以我们将从头开始创建这个网格搜索。我们首先从卷积网络开始。

构建卷积神经网络

首先:CNN 通常用于图像处理任务,所以你可能想知道为什么我们在这里应用它。据报道,CNN 实际上也很擅长 NLP 任务。我们将简单地使用一维层作为解释序列的方式,而不是使用三维层。当词库作为向量被收集时,网络可以识别紧密相连的词之间的共性。理论上,这应该允许我们的网络有效地识别语音模式。稍后将详细介绍。

目前,我们需要一个可以构建、训练和评分一个 CNN 的函数。它将使用默认参数和固定架构进行设置,该架构已被多个来源确定为 NLP 任务的有效起始架构。总共有 10 层,包括嵌入层。

需要注意的一点是,默认设置是经历 100 个时期。考虑到我们正计划实现网格搜索,这似乎有点极端。然而,提前停止已经在耐心水平为 5 的情况下实现。换句话说,如果损失函数在连续 5 个时期后没有产生改进的结果,训练将停止,并且记录结果。

除了模型、历史和结果,还将提供处理时间,以便我们可以跟踪完成每一步的时间。

CNN 网格搜索

从这里开始,只需要为我们的超参数定义网格并记录结果。

你可能想知道为什么要尝试;除了语法在这里。嗯,整个笔记本允许选择任何字长的样本序列。考虑到这一点,举例来说,试图从 20 个单词中汇集 35 个单词将会导致错误。因此,考虑到给定源数据,某些超参数集可能是无效的。

另一项值得注意的是,我们的模型被保存,并在网格搜索的每次迭代中被覆盖。这样做的原因是有 72 个网格要搜索,我们不想浪费内存保存每一个。取而代之的是,结果被存储,并且模型将使用最高性能的参数被再次创建。这将使我们能够更好地了解最佳表现模型的培训进度和历史,并使我们能够更有效地将结果与 RNN 进行比较。

构建递归神经网络

从这里开始,我们将使用与上面相同的方法构建一个带有网格搜索的递归神经网络。一个关键的区别是,RNN 氏症可以使用两种不同类型的神经元:长短期记忆(LSTM)或门控循环单位(GRU)。这些选项会影响网络本身的架构,但这可以通过一个简单的条件语句来说明。

从这里开始,RNN 和 CNN 网络之间唯一真正的区别是网格本身。

可视化结果

一旦我们的 RNN 和 CNN 网络经过训练和测试,我们就可以开始看结果了。具体来说,我们希望比较基准测试、表现最佳的 RNN 和表现最佳的 CNN 之间的准确度分数。

从这里,我们可以看到我们的递归神经网络优于卷积神经网络,并且大大优于基准。通过将模型保存到一个名为 best_model,的变量中,并对其调用 predict 方法,我们可以开始更详细地研究结果,从创建混淆矩阵开始。这里需要做的就是调用顶层模型的 predict 方法,并将其传递给一个函数,该函数将为我们创建可视化效果。

Output:
Confusion matrix, without normalization
F1 Score: 93.08%

在网络做出的 1,780 个预测中,有 123 个是不准确的,第一类和第二类误差相当均衡。由于我们并不真正关心错误类型的平衡,F1 分数被用作衡量性能的主要指标。从这里,我们可以从结果中创建一些单词云,以了解我们的网络在哪里、为什么以及如何出错,希望它能揭示我们两位候选人的共同点。

字云可视化

从这些结果中创建词云的关键是确保我们的原始样本与每一步的转换保持紧密结合。例如,参见下面的代码,它说明了原始文本样本是如何通过排序和训练/测试分割保持完整的:

这里的关键是文本样本和 bigram 数据被添加到 dataframe 的最后两列,即第 21 行和第 22 行。然而,只有向量被传递到嵌入中,如第 34 行所示。因此,我们可以稍后从测试集的模型中调用 predict 方法,我们的原始文本数据将被绑定到同一个索引。

此时,只需将字符串列表转换成由逗号分隔的单个单词字符串。在这个实例中,我们有三个不同的字符串:一个用于每个候选项(p1_cloud & p2_cloud),一个用于错误数据(error_cloud)。从这里开始,你所要做的就是找到并下载你想要的矢量图像,然后使用下面的代码创建你想要的形状的单词云:

关于为每个候选人的词云选择词,我选择关注它们之间使用频率差异最大的词。换句话说,像美国这样的短语对任何总统候选人来说都会被频繁使用,而且不会突出任何独特性。候选词之间使用差异最大的词被使用。

对于错误,由于目标正好相反(突出相似之处),使用了简单的频率计数,因为说话者的身份不太重要。

以下几对总统也完成了上述所有步骤,准确性和词云结果如下:

综合来看,我们可以看到我们的模型达到了 84.3%到 94.3%之间的平均准确率。这可能是由于模型性能的不一致性,但也可能是由于每对模型之间不同程度的相似性和差异。换句话说,林肯和华盛顿的准确率较低,表明他们比特朗普和克林顿有更多的共同点。相反,西奥多·罗斯福和安德鲁·杰克逊之间的差异很可能大于特朗普和克林顿。

需要说明的是,这些仅仅是第一印象,还需要进一步的调查来确认事实是否如此。目前,我们将继续关注特朗普和克林顿。

解读结果

不出所料,结果突出了这两位候选人之间的明显区别。一方面,我们有克林顿,她努力吸引妇女和年轻人,并花了很大力气强调她的执政经验。另一方面是特朗普,他的竞选活动似乎主要侧重于直接攻击克林顿。尽管他确实提到了移民、监管和贸易,但它们在他的词汇索引中的重要性远没有人们想象的那么明显。

通过查看与预测误差相关的单词 cloud,我们希望能够找到一些共同的主题。不幸的是,它并没有像预期的那样工作,尽管通过搜索术语机会的错误确实产生了一些有希望的结果。看看希拉里·克林顿的下面这段话:

但是你们的政府可以做一些常识性的事情,给美国人更多的成功机会。我们为什么不做呢?因为强大的特殊利益集团和将意识形态置于政治进步之前的倾向导致了国会的僵局。当你看到什么都没做时,你怎么能不沮丧,甚至生气呢?许多人觉得没有人站在他们一边,没有人支持他们,这在美国是不应该的。

我们的网络将此错误归类为特朗普的话,这表明特朗普和克林顿都同意,代表们没有有效地代表或代表他们选区的最佳利益:政府已经崩溃,需要修复。

因此,可能是我们的网络仅仅需要更多的改进,但也可能是错误云这个词需要不同的编译。可能两者都有一点,需要一些时间来解决,特别是在网络优化方面。幸运的是,有一项在这方面向前推进的战略。

下一步:模型细化

我们想找出是否存在一组特定的超参数来最大限度地提高测试精度。为了进行这样的分析,我们需要数据。为了实现这一点,随机选择了 500 对总统,对其进行了基准测试,并使用 2 个神经网络(1 个 CNN 和 1 个 RNN)和随机选择的超参数集进行了测试。所有的结果和数据都保存在一个数据框架中(其子集可以在下面找到),并进行初步的探索性分析。

我首先关注的是样本大小对准确性的影响,因为阶级不平衡是一个大问题。正如我们在上面所看到的,与詹姆斯·加菲尔德的所有比较只选择了 86 个样本,这是因为他唯一有记录的演讲是他的就职演说,在他就任总统仅 100 天后就被暗杀了。从这些分析中无法得出有意义的结果。从下面可以看出,要得到有意义的结果,至少需要 500 个样本。任何低于这个数字的结果都会变化很大,平均准确率接近随机水平。

然而,要清楚的是,某些结果产生 0%的准确度分数的事实导致了对代码中的错误的怀疑,该错误还没有被识别。这种影响似乎范围有限,不会对总体结论产生重大影响,但我确实认为,为了透明起见,这一点值得一提。这将在未来的更新中解决。

看一看网络架构,我们还可以探究所选不同模型的有效性。在这种情况下,循环网络被细分为长短期记忆(LSTM)模型和门控循环单元(GRU)模型。

在这里,可以观察到递归网络大大优于卷积网络,尽管后者在大多数情况下确实取得了最好的成绩。这可能是因为这些网络具有工作得非常好的特定超参数集,或者当存在某些样本特征时,它们通常工作得更好。无论哪种方式,都绝对是值得进一步探索的东西。

从更长远的角度来看,理想的做法是采用贝叶斯方法来构建网络,更新架构,并根据每一组新的结果以增量和编程的方式调整参数。实际上,这是一种训练机器制造机器的方法。但那将是另一天的挑战。

结论

从目前的观察来看,这个项目的目标在原则上似乎是合理的,我们有一个模型构建方法可以帮助我们实现这个目标。不幸的是,该方法目前的有效性仍然需要大量的手动搜索来找到共同的主题,但进一步调整模型,我们可以提高准确性,从而缩小我们的 spotlight 搜索的焦点。

然而,当收集随机选择的 500 位总统的数据时,当准确性达到足够的水平时(定义为分数超过 90%或网络优于基准时),错误数据会继续被跟踪。由此,可以创造出最后一个词云,人们可能会将其解读为反映了美国总统政治历史上的共同主题。尽管需要做更多的工作来弄清楚我们要去哪里,但反思我们去过哪里总是一个好的做法。

参考

可以在 Github 上找到这个项目的存储库以及所有相关的 Jupyter 笔记本。

使用 Azure 认知服务对特朗普的推文进行情感分析

原文:https://towardsdatascience.com/using-azure-cognitive-services-for-sentiment-analysis-of-trumps-tweets-part-1-f42d68c7e40a?source=collection_archive---------11-----------------------

一个关于如何使用 Azure 认知服务(文本分析 API)的广泛教程,通过 Databricks (Python,Scala)执行情感分析

Photo by Con Karampelas on Unsplash

第一部分——提取推文

情感可以在任何地方表现出来,比如评论、新闻、现实生活中的对话、新闻等等。通过采用机器学习方法来准确识别情感极性的能力开启了一系列可以为企业带来巨大价值的业务用例。如果机器可以自动确定情感,而不是人类通过分析内容来推断情感,这是一个低效率的过程,需要大量的成本和时间来评估;企业可以利用这种洞察力来调整他们的战略(例如,对于一家零售公司,他们可以加快定制营销,以降低流失风险并限制负面口碑的影响,这可以是一个反馈循环,以重新审视产品/服务并改进它,正如比尔·盖茨曾经说过的一句名言:“你最不满意的客户是你最大的学习来源”)

考虑到这种情况,如果必须建立大规模执行情感学习的能力,一种选择是使用传统的机器学习方法来建立分类器,该分类器预测输入(可以是从其原始形式转换成机器学习算法可理解的形式(包括单词包或 TF/IDF 或任何其他表示,例如 word2vec)的文本)是否属于离散的二进制类别(肯定或否定)。人们可以使用传统的监督机器学习算法,如朴素贝叶斯、逻辑回归、SVM、决策树或基于集成的随机森林来完成任务,并且可以基于所选的评估度量来实现相对较好的性能水平。或者,人们可以探索像多层感知器这样的深度学习方法,以实现类似的目标。但不管你的数据科学团队有多先进或完善,除非你是微软或谷歌或类似的公司,否则在性能和效率方面,与大公司(如微软)使用的方法竞争并不容易。云服务的一个优点是,它们基于数十年的研发投资,提供即时消费的分析服务,如 Azure Cognitive Services 或 AWS intensive。人们可以将这些服务用于情感分析用例,以快速实现价值。在我的上一篇文章中,我们探讨了 Azure 认知服务在内容审核中的使用,而这篇文章是关于使用 Azure 认知服务套件中的另一个服务进行情感分析!

为了让事情变得有趣,我将演示如何使用 Azure 认知服务对唐纳德·特朗普发布的推文进行情感分析。我不确定你,但许多人可能会先入为主,有偏见地认为他的推文确实带有“特定极性”。这项练习将努力验证这一假设,并分析他最近的推文,看看他们有什么情绪。

该员额将由两部分组成。在第一部分中,我将演示如何使用 Python 检索数据(本例中是 Trump 的 tweet ),在下一部分中,我将重点介绍如何使用 Scala 和 Databricks (Spark)以可扩展的方式分析 tweet。同样,代码实现不会是产品级的,只是为了证明其功能。

让我们从第一部分开始,即数据提取。为此,您将需要以下内容:

  1. Python(我用的是 Python 3.5)
  2. 开发环境(IDE 或笔记本。我正在使用数据块)

工作流看起来会像这样:

提取推文- >执行一些处理- >在文件系统中持久化 - >在 Spark 中读取推文- >与 Azure 认知服务集成- >生成情感预测- >执行分析

粗体部分将是这篇文章的范围。其余的将在第二部分讨论。我们开始吧,好吗?

如果你还没有注册社区版的 Databricks,你可以访问下面的链接。注册后,您必须在使用笔记本电脑之前启动一个集群。有了 community edition,可用的集群非常小,但对我们来说已经足够了。要创建集群,请单击左侧菜单上的“集群”,然后单击“+创建集群”按钮:

它将为您提供创建集群的选项。为群集指定您选择的名称。参数的默认值应该没问题。完成后,单击“创建集群”。安装群集需要几分钟时间。

该群集将安装最少的软件包。为了提取推文,我们将使用 tweepy。要使用它,您首先必须在集群中安装它。为此,单击 Workspace -> Users。

单击您的电子邮件 id,然后右键单击级联部分->创建->库

然后在该部分中,选择 PyPI,在包区域中写入“tweepy ”,并单击“创建”

完成后,点击 Databricks 主页中的“新建笔记本”:

给你的笔记本命名,选择 Python,点击“创建”

完成后,您就可以使用笔记本了。如果你以前用过 Jupyter 笔记本,UX 看起来会有些相似。

现在,随着环境的初始化和供应,需要满足另一个依赖性:为了能够与 Twitter 集成,您需要创建一个 Twitter 应用程序。我不会深入讨论这个步骤的细节,但是这个链接提供了一步一步的操作步骤。一旦你注册了一个 Twitter 应用,你需要以下四个相关的凭证:

API 密钥

API 密钥

访问令牌

访问令牌秘密

现在我们已经准备好实际编码了!在我们进行的过程中,我会尽力解释这些代码。

让我们从导入所需的模块和初始化所需的变量开始。

from tweepy import OAuthHandler
from tweepy import API
from tweepy import Cursorconsumer_key = "" #twitter app’s API Key
consumer_secret = "" #twitter app’s API secret Key
access_token = "" #twitter app’s Access token
access_token_secret = "" #twitter app’s access token secret

使用 twitter 应用程序时的身份验证机制是 OAuth,tweepy 的 API 使得使用 OAuthHandler 类来执行身份验证变得很方便,在 OAuth handler 类中,您可以指定与 Twitter 应用程序相关的凭据。然后用 tweepy。API 是 Twitter 为其余步骤提供的包装 API:

auth = OAuthHandler(consumer_key, consumer_secret)
auth.set_access_token(access_token, access_token_secret)
auth_api = API(auth)

tweepy 返回的对象。API 类提供了许多可以用来提取 tweets 的方法。在这篇文章中,我们将使用的是 user_timeline()函数,它允许我们指定 Twitter 句柄、推文数量:

trump_tweets = auth_api.user_timeline(screen_name = ‘realDonaldTrump’, count = 600, include_rts = False, tweet_mode = ‘extended’)

许多参数是不言自明的。具体来说,将 include_rts 设置为 False 会将 retweets 从帐户中排除,而 tweet_mode 作为 extended 会提供 tweets 的完整文本,否则会被截断。trump_tweets 是一个 tweepy.models.ResultSet 类型的对象。它就像一个可遍历的 iterable,其中的每个元素都包含属性 full_text,该属性包含所需的 tweets 文本。因此,让我们使用 Python 的列表理解来完成这项任务,如下所示:

final_tweets = [each_tweet.full_text for each_tweet in trump_tweets]

以下是我试图提取时的推文。您的可能会有所不同。

现在让我们以文本文件的形式保存这个列表,这样我们可以在管道的第二阶段使用它们。因为我们将在第 2 部分的 Databricks 中使用 Spark 分析 tweets,所以在这种情况下使用分布式文件系统或对象存储是有意义的。这就是 Databricks DBFS (Databricks 文件系统)让事情变得更简单的地方。这个主题本身需要大量的理解,但在这个阶段,知道 DBFS 也是一个分布式文件系统就足够了,它根据云环境物理化在对象存储上(Blob 代表 Azure,S3 代表 AWS)。您还可以在 DBFS 挂载您的对象存储,并可以访问其名称空间下的对象存储。最后,您还可以使用本地文件系统 API(例如 Python 的)在 DBFS 上进行读/写(由 FUSE mount 提供)。因此:

with open(‘/dbfs/FileStore/tables/trump_tweets.txt’, ‘w’) as f:
 for item in final_tweets:
 f.write(“%s\n” % item)

您可以通过多种方式验证数据是否已成功写入。其中一种方法是再次读取该文件,以确保它已被正确写入:

read_tweets = []
with open(‘/dbfs/FileStore/tables/trump_tweets.txt’,’r’) as f:
 read_tweets.append(f.read())

下面是一个输出示例:

这篇博文的第一部分到此结束,其中重点介绍了使用 Python(通过 tweepy 模块)从特定用户提取 tweets 的过程,以及使用 Databricks 笔记本的配置步骤。

第二部分—面向情感分析的 Azure 认知服务集成

在您从指定的 twitter 句柄(本例中为 @realDonaldTrump )中提取所需的一组推文之后,这个分析管道的下一部分是与 Azure 认知服务集成,以获得情绪预测。我们将在数据块中使用 Spark 来实现大规模处理(有一些警告)。如前所述,Azure 认知服务是一套服务,对于推文的情感分析,我们将使用 Azure 文本分析 API 。此外,为了扩大这篇文章的影响,增加你的技能,我将演示你如何在使用 Scala 时做到这一点!所以让我们开始吧。

依赖性管理:

首先,你需要注意一些依赖关系:
1。Azure 认知服务中的文本分析 API—如果你有 Azure 订阅(免费试用也适用于本例),你需要在 Azure 认知服务中提供文本分析 API。这个过程应该类似于我之前的帖子,在那里我演示了如何使用 Azure Cognitive Services 的内容审核服务。在提供了文本分析 API 之后,您需要获取以下详细信息:

文本分析 API 端点
API 认证密钥

一旦完成,您的文本分析 API 就可以从基于 REST 的客户机上使用了,它是用您选择的语言编写的(在这里是 Scala)。

2。Scala 库— 我们将依靠几个 Scala 库来完成这项工作。具体来说,我们将需要以下几个:

scalaj (向 Azure 文本分析 API 发送 REST 调用)
spray json (解析 Azure 文本分析 API 的 json 响应,我们将使用这些响应进行后续处理)

由于我们使用数据块,因此为您的环境管理这些依赖项的过程将是相似的。也就是说,您必须创建一个库,并将其附加到您启动的集群。对于 JVM 语言,maven 通常是您可以找到许多此类依赖项的首选存储库。要在 Databricks 中管理这些库,您必须为它们提供 maven 存储库坐标(由(group id:artifact id:Version)组成)。当您指定这些 maven 存储库坐标时,依赖关系管理(就像 Databricks 中使用的那样)能够在 maven 存储库中找到这些坐标,下载并在您的环境中安装/供应它们。下面举例说明如何在 Databricks 中指定 Spray Json 库的 maven 坐标:

您必须为 scalaj 库做同样的事情。
现在来看实施部分,监督您将要实施的工作流程总是有帮助的,因此我们的工作流程将由以下步骤组成:

阅读来自 DBFS 的推文- >删除推文文件中仅包含 URL 的任何行(因为它们不会包含任何情绪信号)- >以 Azure Text Analytics API 端点所需的 REST 调用的形式格式化每个推文行- >将 REST 调用发送到 Azure Text Analytics API 端点- >处理分析洞察的结果

有了这个工作流,让我们来考虑每个步骤的实现。作为一个好的实践,我们将首先创建一些帮助函数,它们将帮助我们执行上面提到的许多任务。

Scala 函数将 tweets 数据格式化为 REST POST 调用格式:

创建一个 Databricks 笔记本,选择 Scala 作为语言,并在一个单元格中编写以下代码:

def requestFormatter(givenTweet:String):String={
  s"""{
    "documents":[
        {
        "language":"en",
        "id":1,
        "text":"${givenTweet}"
        }
    ]
  }"""
}

让我们了解一下这段代码中发生了什么:
1。我们创建了一个名为 requestFormatter 的函数,它接受一个 String 类型的参数(givenTweet)。
2。该函数返回字符串
3。该函数根据 Azure Text Analytics API 的要求创建一个 Json,该 Json 由一个键-值对组成,键为“文档”,值为由语言、id 和文本字段组成的对象列表。这些字段不言自明。列表中的 id 字段应该是唯一的。在这种情况下,文本是实际数据(tweet)将嵌入的字段。此外,因为 documents 是一个列表,所以您可以有多个语言、id 和文本字段的对象,并且您可以在一个 REST 调用中发送多达 5000 个对象。然而为了简单起见,我只是在一个 REST POST 调用中发送一个对象。

Scala 函数发送 REST POST 调用:

在另一个单元格中,键入以下代码:

def sendPostRequest(textAnalyticsUrl:String,subscriptionKey:String,requestBody:String):String={
  import scalaj.http.Http
  Thread.sleep(3000)
  val result = Http(textAnalyticsUrl).postData(requestBody)
  .header("Content-Type", "application/json")
  .header("Ocp-Apim-Subscription-Key", subscriptionKey).asString
  result.body
}

下面是我们在这个函数中所做的:
1。函数 sendPostRequest 接受三个参数(textAnalyticsUrl 表示 Azure 文本分析 API 端点 URI,subscriptionKey 表示您之前检索的将用于 REST 调用身份验证的密钥,requestBody 是将作为 REST 调用的一部分发送的数据
2。我们为这个实现引入了 3 秒的延迟,这样 Azure 就不会阻塞我们的请求。有更好的方法来解决这个限制。
3。然后,我们发送一个 REST POST 调用,指定 URI、标头(“Content-Type”、“application/json”、“Ocp-Apim-Subscription-Key”、subscriptionKey),并用我们将通过前面的函数获得的 json 填充请求体。
4。最后,我们从这个函数中以字符串形式返回 REST 响应的结果,其形式如下:

{
 “documents”:[{“id”:”1",”score”:0.85717505216598511}],
 “errors”:[]
}

其中 documents 对象包含一个列表,特别是对应于文档 id 的分数。返回的分数从 0 到 1 不等,它是调用 Azure Text Analytics API 后的预测结果。接近 0 的值代表消极情绪,接近 1 的值代表积极情绪。

Scala 函数移除 Tweets 中的 HTTP 行函数:

该函数用于删除 tweets 文件中可能存在的 HTTP 行。

def removeHttpLines(textLine:String):Boolean={
  import scala.util.matching.Regex
  val pattern = "^http".r
  pattern.findFirstIn(textLine) match {
    case Some(x)=>false
    case _ => true
  }
}

1.该函数需要一个参数(字符串类型的 textLine)并返回布尔值(true 或 false)。
2。它利用正则表达式并在文本文件中寻找一个特定的模式,其中一行以“http”开始。它确实可以进一步细化,但为了简单起见,让我们使用它。
3。然后,它试图在文本文件中找到该模式。在这里,Scala 的模式匹配结构用于匹配两种可能性:如果找到匹配,即 Some(x ),那么返回值将为 false,否则将返回 true。我们返回这些值的原因将很快变得显而易见。

现在有了这些函数,让我们实现剩下的逻辑,有趣的是,由于 Scala 是一种函数式编程语言,它可以用一行代码来表示:

val tweetsSentimentsRdd = sc.textFile("/FileStore/tables/trump_tweets.txt").filter(removeHttpLines).map(x=>requestFormatter(x)).map(y=>sendPostRequest(url,subscriptionKey,y))

让我们来破译这里发生了什么:
1。首先,我们使用 SparkContext (sc) textFile 函数,该函数用于从文本文件中读取数据(通常来自 HDFS,在本例中是实现其接口的 DBFS)。它接受字符串形式的文件路径,这就是我们指定 tweets 文件的位置。此函数返回字符串类型的 RDD,其中每个元素对应于文件中的每一行。下一步是过滤掉任何只包含 http URLs 的行。这就是我们使用 Spark 的滤镜变换的地方。在它的参数中,我们传递了一个函数(再次感谢函数式编程),特别是 removeHttpLines,它将对数据的每一行进行操作,并将只返回那些从该函数中产生 true 的行(即,在它们的开头没有 http)。
3。下一部分转换过滤文本的每一行(即删除 http 行),并(使用 requestFormatter 函数)将每条 tweet 转换为所需的 Json 字符串,格式如下:

{
 “documents”:[
 {
 “language”:”en”,
 “id”:1,
 “text”:”tweet text will come here”
 }
 ]
 }

3.接下来的部分使用函数 sendPostRequest 调用 Azure 文本分析 API 端点

在执行时,由于 Spark 的懒惰执行模型,不会发生任何执行。由于数据很小并且是 PoC 设置,因此使用“收集”操作是安全的(但是在生产设置中尽量避免这种情况,因为它会将 Spark 的所有分布式执行器节点的数据返回到驱动程序,从而导致内存溢出问题)。

val tweetsSentimentList = tweetsSentimentsRdd.collect()

现在我们有了 Scala 集合形式的响应。列表中的每个元素都是一个字符串(Json ),由来自 Azure Text Analytics API 的响应组成,在当前状态下,我们对此无能为力。如果要回答几个问题像:

分数的最大值和最小值是多少?
这条推文语料库的平均情感分是多少?
本语料库中特朗普最积极的推文有哪些?

为了回答这些分析问题(以及许多其他问题),可以对这种形式的数据进行的一种处理是将现有的 Json 字符串转换为针对这种处理进行了优化的 Scala case 类。有很多方法可以做到这一点,但是我求助于使用 spray json 库来做到这一点:

为此,首先我们必须为 Json 创建一个解析器。这包括创建表示 Json 结构的 case 类,如下所示:

case class ResponseBody(id:String, score:Double)
case class AzureTextAnalyticsResponse(documents: List[ResponseBody], errors: List[String])

然后使用 spray json 构造来指定 json 的结构,包括 key 的值以及不同的部分如何相互嵌入

object ResponseJsonUtility extends java.io.Serializable {
 import spray.json._
 import DefaultJsonProtocol._object MyJsonProtocol extends DefaultJsonProtocol {
 implicit val responseBodyFormat = jsonFormat(ResponseBody,"id","score") //this represents the inner document object of the Json
 implicit val responseFormat = jsonFormat(AzureTextAnalyticsResponse,"documents","errors") //this represents the outer key-value pairs of the Json
 }//and lastly, a function to parse the Json (string) needs to be written which after parsing the Json string returns data in the form of case class object.import MyJsonProtocol._
 import spray.json._

 def parser(givenJson:String):AzureTextAnalyticsResponse = {
 givenJson.parseJson.convertTo[AzureTextAnalyticsResponse]
 }
}

现在创建了这些函数和对象,剩下的就是在 Scala 集合中使用它们来获得想要的结果:

val tweetsSentimentScore = tweetsSentimentList.filter(eachResponse=>eachResponse.contains(“documents”)).map(eachResponse=>ResponseJsonUtility.parser(eachResponse)).map(parsedResponse=>parsedResponse.documents(0).score)

到现在为止,upstated 的表达对你来说应该很熟悉了,但是这里仍然是对步骤的分解理解。首先,我们将执行过滤,只考虑 Json
2 中具有“documents”部分的元素。然后我们解析每个 Json 字符串并转换成 AzureTextAnalyticsResponse 案例类
3。然后,我们只需访问每个解析后的 Json 对象的分数,就可以得到一个只包含情感分数的列表

一旦我们有了这个,那么做进一步的分析就变得方便了,例如我们可以计算平均情绪得分如下:

(tweetsSentimentScore.sum)/(tweetsSentimentScore.length)

分数结果是 0.629,这意味着被分析的推文平均有轻微的正面情绪:-)

同样,我们可以获得特朗普推文的最大情绪得分:

tweetsSentimentScore.max

结果是 0.99,这意味着相当多的推文有相当高的积极度:-)

因此,总之,我们可以使用这种方法来做一些分析,以解决不同的问题。此外,这是一个非常基本的实现,有很多增强的机会,所以我们很想知道你用这些基础知识做什么。如果你很难理解 Scala 和 Spark 的一些概念,可以看看我最近的由 Apress 出版的《大数据分析的 Scala 编程》一书

提高价格弹性准确性的贝叶斯建模

原文:https://towardsdatascience.com/using-bayesian-modeling-to-improve-price-elasticity-accuracy-8748881d99ba?source=collection_archive---------9-----------------------

使用贝叶斯方法提高价格弹性,以包装消费品行业为例

介绍

一般来说,贝叶斯数据分析(BDA)和贝叶斯推理对我个人来说,在现实世界中理解和应用总是令人生畏。如果你对它不熟悉,或者想更新一下,我找到了这本很棒的书,它把所有的东西都联系在了一起。

使用 Python 进行贝叶斯分析——第二版,作者 Osvaldo Martin。

也许和我一样,你可能摆弄过文本分析的潜在狄利克雷分配,但从未真正理解它背后的概率主题建模。或者你可能看过一个教程,用抛硬币或其他一些我们在现实世界中无法应用的基本例子来解释先验和后验概率。

因此,我设定了一个目标,在业余时间花两周时间研读 BDA,并通过一个相对真实的例子来分享我所学到的东西;至少在我的行业——消费品包装。

动机

站在一家消费品公司的立场上,我们意识到大量资金被投入到支付给零售商如沃尔玛、Wholefoods 和其他杂货连锁店的促销、传单和折扣上。因此,这些投资获得我们期望的投资回报率是至关重要的。估算投资回报率的一个重要工具是弹性系数,这是一个价格变化对需求影响程度的比率。此外,预测或估计价格变动后的需求是准确了解促销投资回报率的基础。

组织通常在类别、细分市场(价格促销组)或单个 SKU 级别具有这些弹性系数。然而,就准确性而言,最好的是——你猜对了——在 SKU 级别,因为每个产品在一个细分市场中的表现略有不同。

目标和假设

因此,没有进一步的拖延,我们的目标将是获得一个特定产品的弹性系数在 SKU 水平使用 BDA,当我们所有的是:

1.弹性系数 a t 分段水平

2.加拿大一个省内多家商店的产品销售额和销售量。

因此,我们将使用我们对细分层次弹性的先验知识以及我们观察到的销售金额和数量来估算 SKU 层次的弹性值。

第一步:清洁

将数据加载到数据框中并进行标准数据输入。

计算产品的单位价格,因为我们以后需要用它来计算弹性。

接下来,我们将使用贝叶斯线性回归来获得 SKU 水平的弹性值,但首先我们需要将 PPU 和销售量转换成对数空间。这是因为一旦因变量和自变量都转换成对数-对数,弹性就是对数 PPU 的系数。很酷吧?

关于为什么双对数模型是描述需求弹性的最合理模型,有很强的微观经济学论据。潜在需求曲线描述了最像经济学家假设的需求行为。它确保需求不会随着价格的上涨而降到零以下,另一方面,需求会随着价格的下降而呈指数增长。[2]

移除一些额外的异常值。

第二步:贝叶斯广义线性模型

现在我们终于可以使用广义线性模型(GLM)“from _ formula”函数来创建贝叶斯线性模型了。这个函数的好处在于,它在“~”方面遵循与 R 相同的语法。我不得不将 log_PPU 改为 x,因为在我的 pymc3 版本中有一个错误,独立变量必须被称为 x。比我更聪明的人可能知道一个修复方法,但我只是跟着它走。

通过使用 family 属性,我们可以将可能性的分布,或者换句话说,观察数据的建议形状更改为非正态分布,但是对于此示例,让它保持正态分布。例如,将其转换为二项式会导致逻辑回归。

然后,我们从该模型中采样 4000 次,每个内核在 4 个内核中进行 500 步老化,这相当于 18,000 个样本。把烧伤想象成向一块软木板投掷飞镖,你最初投掷的飞镖很糟糕,几乎没有在木板上出现,但是经过几次尝试后,你会变得更好,并开始在同一区域持续击中它们。你最初几次扔得太差,不能代表你的真正技术,所以你把飞镖从板上拿下来,没人知道!

我们可以根据对数数量和对数 PPU 的散点图绘制 16,000 条回归线。

Trace Plot — x is our coefficient of the PPU, since in the previous step we renamed PPU to x.

上面的轨迹图表示模型的核密度估计和收敛。基本上,由于我们运行 4 个独立的马尔可夫链,3 个折线图中的 4 条彩色线越接近相同的模式,我们的模型就越有代表性(没有大的漂移或其他奇怪的模式)。

我们关心的是轨迹图中 PPU (x)值的分布,它实际上是我们运行的 18,000 次回归的 x 系数,如您所见,它的平均值为-2.66。

步骤 3:贝叶斯建模

现在你可能想知道为什么不做一个常规的 OLS 回归,如果这就是我们到目前为止所做的。原因是现在我们有一个可能的弹性值的分布,平均值为 2.66,标准偏差约为 0.067。因此,没有什么可以阻止我们从这个新的正态分布中进行采样,以获得尽可能多的弹性值!

在这一点上,我们还没有将我们的先验知识结合到这个模型中,即在细分水平上的弹性是什么。所以,让我们现在就开始吧!

我决定使用 pymc3 处理得很好的坚果采样做一个简单的贝叶斯推断。我们的观测数据样本现在将是我们从 GLM 获得的弹性值,我们在分段水平的弹性先验信念将在我们的模型参数中表示。

一行一行地走。

第 1 行:出现次数是我们从正态分布中取样的观察值。这些参数来自我们从 GLM 得到的分布。通常,观察值是实际的数据点,而不是分布。然而,我们有点创造性,使用了上面讨论过的 GLM 分布。我还将负 2.66 翻转为正,因为弹性通常表示为正数。

第 4 行: prior_mu 表示我们在段级别被给定的弹性值,具体是参数 mu=2.2。我选择 sigma 或方差为 0.01 的正态分布,只是因为我没有更好的方差估计。值得注意的是,prior_mu 的平均值和 sigma 也可以是分布本身。当这种情况发生时,它被称为有自己参数的超先验。所以,我们可以很快进入一个海龟一直到的情况。

第 5 行: prior_sig 表示我们的先验信念有多大的方差。为此,我选择了一个逆伽马分布,因为它不可能是负的,而且分布大多在 0 到 0.5 之间。这很有帮助,因为我不希望我们先前的信念 2.2 有太大的波动。

第 6 行:这是橡胶接触路面的地方,我们将观察结果与先前的信念联系起来。我再次选择了正态分布,并使用了参数观察到的,它有一个非常简单的作用,它允许我们将数据输入到我们的模型中。

第 10 行:之后,我们在 2 个核心上采样 3000 次,并丢弃前 500 个样本以说明老化期(总共 7000 个)。

就结果的可视化而言,首先我们有一个迹线图,它在左边显示了核密度估计,这是基于观察到的和先前的数据的弹性条件的可能值的分布。

请注意, prior_mu 值是我们的弹性系数,它既不是 2.2 也不是 2.66,而是在中间的某个位置。这清楚地显示了我们先前的和我们观察到的数据点对模型的影响。尝试用增加观察数据的出现次数,看看这个分布如何变化!

第四步:视觉化

Plot_join 基本上和 trace plot 是一样的,只是它们不是两个独立的图表,而是组合在一起的。但是它看起来真的很酷吗?

plot_posterior 给出了平均值和 94%的最高概率分布(HPD ),也就是说,我们讨论的参数弹性在 94%的时间里都在此范围内。

结论

通过 GLM 对该特定产品的弹性进行建模的对数-对数方法似乎是合适的,因为它在细分水平提供的弹性范围内(在 2.2 和 2.6 之间)。老实说,这是最让我吃惊的!

然而,给定足够的观察值,我们将很快看到观察到的弹性值优先于分段水平值。在我们的案例中,我们有超过 2000 个跨越多年的销售点交易,因此如果我们将观察到的发生次数从 500 次增加到 2000 次,我们会看到 2.6 是平均值模型值。

https://github.com/mattbitter/W2_BayesianGLM

参考

[1]伊利亚·卡佐夫,动态定价算法指南 (2019),网络

[2]丹尼尔·吕 Data,U 回归食品:利用销售数据确定价格弹性 (2018),网络

[3]戴夫·贾尔斯,计量经济学学生 MCMC 第四部分 (2014),网络

[4]威尔·科尔森,用贝叶斯推理估计概率 (2018),Web GitHub

[5] Will Koehrsen,Python 中的贝叶斯线性回归:使用机器学习预测学生成绩第 2 部分 (2018),网络媒体

[6]埃罗·卡雷拉,黑客的概率编程和贝叶斯方法 (2018),Web GitHub

使用 BERT 和 CNN 在 Reddit 上检测俄罗斯巨魔

原文:https://towardsdatascience.com/using-bert-and-cnns-for-russian-troll-detection-on-reddit-8ae59066b1c?source=collection_archive---------10-----------------------

这篇文章旨在对我和杰夫·吴在斯坦福大学的 CS 224N 期末项目做一个高层次的概述。对我们工作的技术细节感兴趣的人可以得到文件海报

背景和数据集

在 2016 年选举季,俄罗斯巨魔利用社交媒体瞄准美国选民。特别是一个名为 troll farm 的互联网研究机构,伪装成保守的特朗普支持者,分享旨在分裂美国人、压制选民和吹捧特朗普为优秀候选人的内容。根据网络安全公司 The New Knowledge 的数据,爱尔兰共和军和类似的巨魔农场制作的内容数量惊人,从 2015 年到 2017 年,共有 1040 万条推文,1100 个 YouTube 视频,116,000 个 Instagram 帖子和 61,500 个独特的脸书帖子。随着另一场总统选举的临近,正确识别俄罗斯巨魔并删除其内容的问题变得比以往任何时候都更加紧迫。

当谈到解决俄罗斯巨魔的问题时,一个社交媒体网站似乎被排除在对话之外:Reddit。Reddit 拥有许多政治留言板,如 r/politicsr/The_Donald ,这使得它特别容易受到政治干预,但标记的 troll 数据数量极其有限。唯一的来源是 Reddit 2018 年 4 月的透明度报告,其中包括与互联网研究机构关联的 944 个账户。其中一些帐户是多产的,有数百条评论和数万个 Reddit 因果点,表明这些 trolls 在被 Reddit“淘汰”之前已经深深地嵌入了 Reddit 文化。

目前的技术水平

Brandon Punturo 在 1 月份发布了一篇很棒的文章,该文章探索了传统机器学习技术在透明报告数据集上的使用,以及使用 Google BigQuery 获得的 Reddit 评论选集。他使用 AUC 作为性能指标来衡量他的分类器有多准确,并对假阳性和假阴性进行惩罚。他的分类器使用随机森林分类器成功实现了 0.74 的 AUC 分数,这是一个令人印象深刻的壮举。他考虑了每条评论的元数据,包括发布时间、发布的子编辑、评论收到的投票以及评论正文。

除了评论本身,这些额外的元数据有助于理解用户的上下文,但他的方法没有利用自然语言处理的深度学习的最新研究。通过单独查看评论,您可以使用这些方法来理解隐藏在巨魔和非巨魔评论中的潜在信息,并使用这些信息对它们进行分类。

神经架构

与传统的机器学习或统计技术相比,神经网络已被证明在特定的语言任务上取得了优异的性能。在基本水平上,这些网络通过使用由权重连接的隐藏神经元来发挥作用,权重代表神经元之间的连接强度。每次对样本评论训练神经层时,预测和真实输出之间的差异会通过称为反向传播的过程导致权重的更新。反向传播与 ReLU 或 sigmoid 函数等非线性层一起构成了神经网络的主干,并提供了在同一 Reddit 数据集上实现最先进(SOTA)性能的机会。

针对这个问题,我们设计了一个包含四个主要组件的神经架构:

  1. BERT 预训练嵌入层
  2. 神经中间层
  3. 脱落层
  4. 分类层

嵌入层给出了每个单词的张量表示以及它们在 n 维空间中的相互关系。神经中间层接受这些嵌入,并将其传递到神经网络的隐藏层,而退出层在训练期间保留中间层内的一定百分比的神经元,以防止过度拟合。然后,这些内容的张量输出被整形,并通过分类层产生逻辑,这些逻辑表明一个评论成为巨魔的可能性有多大。

1.伯特嵌入层

来自数据集的每个 Reddit 评论首先通过 BERT 层运行,以创建句子的嵌入表示。单词嵌入是给定词汇表中的单词或短语到相应的实数稀疏向量的映射,表示该单词与 vocab 中所有其他单词的关系。10 月,谷歌发布了一份关于变形金刚双向编码器表示的白皮书,这是一种新的单词嵌入类型,它共同取决于句子中单词的左右上下文。当用作神经架构中的嵌入层时,这种语言模型表示已被证明在问答数据集小队上实现了最先进的性能,并且也开始应用于其他 NLP 任务。

BERT 对这个数据集特别感兴趣的一个主要原因是因为我们正在处理这样一个小数据集(大约 14000 个 troll 和非 troll 评论),很难仅从这个语料库建立一个语言模型。通过使用 BERT 产生的单词嵌入,我们可以将 Google 获得的未标记数据训练的预训练模型与根据我们的标记数据训练的下游神经层相结合。这个过程被称为迁移学习,并且已经被证明在大量的 NLP 应用上实现了 SOTA 性能。

我们将比较各种中间神经层和 BERT 与普通迁移学习的性能改善,这意味着没有中间神经层。

2.中

对于神经网络的中间层,有许多不同的可行选择。将其中的每一个与 Puntoro 的随机森林模型和带有 BERT 和分类器的香草迁移学习的基准进行比较,可以展示每一个的有效性。

http://www.wildml.com/2015/09/recurrent-neural-networks-tutorial-part-1-introduction-to-rnns/

传统的神经网络具有前馈结构,本质上从头开始考虑每个新的输入,而不考虑先前的输入。递归神经网络连接了隐藏状态,每当对输入张量做出决定时,隐藏状态就会更新,从而创建一个反馈回路,使过去的决定影响未来的决定。这种保留先前样本信息的特性使得 rnn,尤其是长短期记忆网络成为该架构中间层的良好选择。LSTMs 是 rnn 的类型,其具有额外的隐藏单元来维持长上下文中的信息,解决消失梯度问题。

http://www.wildml.com/2015/11/understanding-convolutional-neural-networks-for-nlp/

卷积神经网络执行类似的任务,但它是通过对每个评论进行操作并将它们卷积成低维向量来完成的,这些低维向量通过使用过滤器来捕获关于存储在每个评论中的 n 元语法关系的信息。然后,这些卷积通过最大汇集层,以压缩来自卷积的信息,从而从每个卷积中捕获最重要的信号。通常,已知 CNN 比 LSTMs 更擅长分类任务,因为它们能够更有效地捕捉单词之间的短期和长期依赖性。部分原因是因为 rnn 倾向于将太多的权重放在输入的最后状态,这对于分类来说是不理想的。

https://www.aaai.org/ocs/index.php/AAAI/AAAI15/paper/view/9745/9552

最后,还有第三种类型的模型架构,称为递归卷积神经网络,旨在利用两种架构的优势,并且在从单词的左右上下文中捕捉含义时特别有效。这种类型的模型是在 2015 年推出的,不如前两个模型出名,但它代表了我们中间层的第三个有趣的选项。

3.脱落层

丢弃层的目的是在向前和向后训练过程中忽略随机选择的神经元。这通过忽略神经元之间的一些连接来限制神经元之间的相互依赖,从而减少对训练数据的过度拟合。在传统的机器学习术语中,这相当于损失函数的正则化。

4.分类层

这最后一层获取 dropout 层的输出,并将其重新整形为大小为 batch_size x 2 的 logits 张量,其中每个评论被赋予被分类为 troll(列 1)或非 troll(列 2)的未标准化的可能性。为了使这些分数正常化,我们使用 Softmax 函数来获得总和为 1 的概率。使用交叉熵损失的反向传播使用这些逻辑来执行,并且相应地更新网络中的权重。

结果

不同类型的模型表现明显好于预期,我们对每个中间层模型的开发 AUC 分数明显优于随机森林分类器和 BERT 基线。

我们执行了随机超参数搜索,以优化 RCNN 中隐藏单元的数量、每个样本的填充/截断注释长度以及退出率。我们发现了优化的超参数,使我们能够用 RCNN 实现 0.846 的测试 AUC,用 CNN 和 3 的波束大小实现 0.843 的测试 AUC。

尽管这个模型在我们的数据集上是准确的,但还是有几个值得注意的失效模式。其中之一是,某些包含像“希拉里”这样带有政治意味的词语的简短评论往往会产生更多的误报。通过观察几个带有这些触发词的较短输入句子,以及几个带有其他翻转词的较长句子,我们注意到假阳性和假阴性经常出现在单个神经元上。

值得注意的是,上面和我们的论文中执行的输出分析是在测试集上完成的,这不是最佳实践。虽然我们使用测试数据纯粹是为了理解我们模型的定性故障模式,而不是以任何方式调整权重,但是通常最好完全不要管它,而是在开发集上执行这个分析。

结论

这个项目的一个主要目标是改进最先进的 Reddit 检测,这是我们通过多种类型的神经网络成功实现的。然而,这仍然是在一个非常有限的数据集上完成的,并且这将无法扩展其分类巨魔的能力的可能性相当高。我们的希望是,Reddit 今年 4 月发布另一份透明度报告,以便其他研究人员可以建立类似的模型,进一步解决 Reddit 上的俄罗斯巨魔问题。自然语言处理,即使有迁移学习技术,也只能达到现有的标记数据的质量——现在 Reddit 基本上是一个数据沙漠。

在那之前,有大量有趣的子主题可供阅读(风险自负)。

使用卷积神经网络生成和声

原文:https://towardsdatascience.com/using-convolutional-neural-networks-to-generate-harmony-1a1cdfd7ec56?source=collection_archive---------19-----------------------

探讨了主观质量的数据表示和时间分辨率以及生成笔记的负对数似然性。

使用神经网络(NN)生成音乐已经在数据科学方面讨论过几次,但通常是在使用递归神经网络(RNNs)和一些卷积神经网络(CNN)生成序列的背景下。这篇文章是关于一种使用卷积来产生和声的方法,这种方法可以用四种乐器在任何给定的时间产生一个音高。

Transposition of BWV 364 using Music21, Image by MuseScore

使用卷积神经网络的主要优势是,像图像识别一样,音乐在时间(主题/主题)和音高(变调)下是不变的。因此,当数据被组织为表示时间和音高的矩阵时,卷积是寻找音乐中的模式(如和弦进行或节奏)的理想操作。具体来说,对于这个项目,时间被组织成离散的时间,其基础是以特定频率对给定乐器(声音)的音高进行采样。正如我们很快会看到的,频率的选择对模型的表现有影响。

这个项目最终确定了八分音符离散时间尺度和 128 个半音音高矢量。midi 文件功能。对于数据集来说,163 首巴赫合唱曲是基于对有四个声部和 4:4 拍号的合唱曲的音乐 21 语料库的分析而选择的。这种数据表示和模型架构首先由谷歌人工智能团队完成,他们还发表了一篇关于他们技术的有趣论文。这个项目使用了许多这样的技术,但是是用 Keras 和 Music21 实现的。

使用 CNN 的基本思想是为不同的模式(节奏、和弦等)使用几个过滤器。)来生成每个离散时间步长的所有可能音高的概率分布。通过从未知音符重复采样并生成新的概率分布,可以从无输入或部分输入中生成一段音乐。

数据准备

Music21 的语料库处理 musicXML 格式的音乐文件,因此需要构建一个助手类,以便将这些文件转换成表示钢琴卷首的 numpy 数组(在 github 存储库中的 utils.py 中可以找到)。我建立的另一个方法是通过从音高(半音阶有 12 个音符)中增加或减去音程[1,11]上的一个数字,将钢琴卷转置为随机键。这样,通过从巴赫合唱曲之一中随机选择 4 个小节,并将其转换为随机键,就可以生成一批输入。

Piano Roll for a Single Voice as Input

然后,四个钢琴卷帘窗(女高音、女低音、男高音和男低音各一个)与四个遮罩矩阵堆叠在一起,这四个遮罩矩阵表示包含每个声部的已知音高的时间步长。然后,通过获取一批巴赫合唱曲并删除该批中每首作品的相同音符来训练该模型。然后,定制损失函数最小化擦除值的正确音高的负对数似然的总和(除以擦除音符的总数,以避免对具有更多擦除音符的批次或具有不同排序的批次进行更重的加权)。

在 Keras 中实现这一点需要使用自定义的生成器来批量生成输入,以及自定义的损失函数,这使得模型有点难以保存和加载。幸运的是,一旦一个模型被训练。json 和. h5 文件可以加载一个模型用于推理目的。

模型架构

该模型使用了 64 个卷积层和 128 个滤波器。他们最终能够使用扩张卷积来节省计算能力。因为我必须在没有大量 GPU 的单台计算机上训练这个模型,所以我使用的架构是 20 个卷积层和 64 个 5x5 过滤器。和原论文一样,每两层使用 BatchNormalization 和 skip connections 。对于卷积层,ReLU 激活与填充一起使用,以在时间和音高方面保持输入的原始大小。

Iterated Model Architecture

最后一层是卷积层,输出四个通道并使用 softmax 激活。这样,输出可以被训练成四个声部,其概率分布在每个时间步长的 128 个音高上。然后,通过对与输入中被擦除音符的实际音符相对应的概率的负对数求和来计算损失。

使用吉布斯采样生成音乐

一些论文研究了音乐生成的不同采样和重采样方法。Bach2Bach 的架构使用伪吉布斯采样程序来重写部分生成的乐谱。Coconet 的论文研究了不同的技术,发现创建最佳生成音乐样本的技术是使用退火概率从被擦除或未知的音符中采样。这个退火概率的公式很容易理解,它是:α_n = max(α_min,n(α_ max-α_ min)/BN,其中α值表示输入中被擦除的音符在下一次采样迭代中被擦除的概率。b 表示采样应在α_min 以上发生的步数,N 是总步数,通常设置为声部数(4)乘以时间步数(32)。

吉布斯采样的工作方式以及它如此有效的原因与概率分布收敛于一段连贯的音乐有关。如果我们将大部分被擦除的乐谱(或随机噪声)输入到模型中,概率分布通常会分布在几个音高上,因为每个音高取决于它之前和之后的内容,以及其他声部中发生的事情。实际上,我们试图在没有足够的其他变量背景的情况下建立一个联合概率分布模型。

因此,我们从概率分布中采样,以获得每个未知时间步长的音高,然后以概率α_n 再次擦除所有这些音高。这样,在吉布斯采样开始时发生的块采样使音乐不会简单地停留在同一音符上。随着过程的进行,越来越少的音符被重新采样,这使得被擦除音符的概率分布收敛于音乐上连贯的音高。

时间分辨率的影响:

使用负对数似然的度量,可以看出较高的时间分辨率有利于音乐质量。例如,为了训练网络,当使用十六分音符分辨率时,最小损失函数是 0.168,或者相对于被擦除的音符大约 85%的平均概率。四分之一音符分辨率的最佳损失函数是 0.487,平均概率约为 61%。然而,十六分音符分辨率可以通过在其自身声音中高度加权当前时间步长之前和之后的音高来获得更好的成功,因为在十六分音符分辨率中,四分音符代表四个时间步长。一个更好的度量是看吉布斯抽样程序是否减少了平均负对数似然。

TOP: 1/16th resolution, melody input. MID: 1/8th resolution, melody input. BOT: 1/8th resolution, random input.

对于经过训练的模型,1/16 音符分辨率似乎是过拟合的,因为它在训练数据上表现得非常好,并且可以在那里实现低 NLL,但是 NLL 在 Gibbs 采样过程中不收敛。最佳行为表现在八分音符分辨率,其中一段旋律被输入到模型中,而其他声音未知。

GitHub 和参考资料

该项目的代码库和音乐样本可以在下面的 GitHub 库中找到。

参考资料:

[1]库斯伯特和阿里萨。music21:计算机辅助音乐学和符号音乐数据工具包。2010.在国际音乐信息检索学会的会议录中。

[2] G .哈杰雷斯、f .帕切特和 f .尼尔森。DeepBach:巴赫合唱曲生成的可操纵模型。2010.在第 34 届机器学习国际会议论文集。

[3] C .黄,t .库伊曼斯,a .罗伯茨,等艾尔。卷积对位法。2017.第 18 届国际音乐信息检索学会会议论文集。

使用卷积神经网络预测肺炎

原文:https://towardsdatascience.com/using-convolutional-neural-networks-to-predict-pneumonia-550b773cacff?source=collection_archive---------26-----------------------

细胞神经网络及其应用简介。

这篇博客文章将从卷积神经网络的简要介绍和概述开始,然后过渡到应用这一新知识,通过 x 射线图像预测肺炎,准确率超过 92%。虽然这样的精度没有什么好兴奋的,但对于这样一个简单的卷积神经网络来说,这是一个值得尊敬的结果。

当需要显示代码示例时,代码将首先显示,然后在每个代码示例下面会有一个关于代码的解释。

数据集 : 肺炎 x 光数据集

中枢神经系统和视觉皮层的简史

卷积神经网络(CNN)或 ConvNets 是通常用于图像和音频识别和分类的神经网络。CNN 来源于动物大脑的视觉皮层。研究表明,猴子和猫的视觉皮层有神经元对视野的小子域做出反应。每个神经元负责视野的一小部分,称为感受野。视觉皮层中的所有神经元将一起覆盖整个视觉空间 (Hubel,1968)

人类大脑的视觉皮层是由具有相似功能的多列神经元组成的。这些神经元列的阵列构成了所谓的模块(神经科学挑战,2016) 。每个模块只能够对视野的一小部分做出反应,因此,视觉皮层由许多这些模块组成,以覆盖整个区域。虽然这并不完全是我们的卷积神经网络的功能,但它与动物的视觉皮层有明显的相似之处。

CNN 简介

像所有常见的神经网络一样,CNN 拥有可调权重和偏差的神经元。正常的神经网络是完全连接的,这意味着每个神经元都连接到上一层的每个神经元。CNN 并不像普通的神经网络那样完全连接,因为它的计算量太大,而且根本不需要达到预期的效果。当处理具有大输入大小的图像数据时,使用完全连接的神经网络不是非常有效。

为了想象大量的参数,想想我们的胸部 x 光图像。这些图像的输入形状为 64x64x3,或 64 宽,64 高,有 3 个颜色通道。如果使用完全连接的神经网络,这将意味着单个隐藏层中的单个神经元将由 12,288 个连接组成(64 x 64 x 3 = 12,288) (CS231n,2018) 。这是只有一个完全连接的神经元。想象一下在一个有许多神经元的神经网络中所有权重的数量!很容易理解为什么完全连接的神经网络不是分类图像的最有效的方法。这就是 CNN 派上用场的地方,除了 CNN 的架构实际上包括一些完全连接的层。

CNN 架构简介

像所有的神经网络一样,CNN 有一个输入和输出层,有许多隐藏层,它们将应用一个激活函数,通常是 ReLu。一个 CNN 设计将包括三个主要层:卷积层、池层和全连接层。下面将介绍每一层:

卷积层

卷积层负责从输入数据中寻找和提取特征。卷积层使用过滤器,也称为内核,用于这一特征提取过程。由于 CNN 没有完全连接,神经元只连接到输入空间的预定子区域。这个区域的大小被称为过滤器的大小,或感受领域。神经元的感受野就是它接收输入的空间。

对于本例,我们将使用大小为 3x3 的过滤器。我们只设置感受野的宽度和高度,因为过滤器的深度必须与输入的深度相同,并且是自动设置的。在我们的例子中,我们的输入有 3 个颜色通道。因此,输入的深度是 3。这意味着这个卷积层中的每个神经元将有 27 个权重(3x3x3 = 27)。

卷积层通过在输入空间滑动这些滤波器来卷积输入,同时计算权重和输入的点积。过滤器内的像素将被转换成代表整个感受野的单一值。

汇集层

汇集层,也称为下采样层,通常位于神经网络的卷积层之后。汇集层的作用是减少输入的空间维度。这将导致参数数量的减少,也将有助于我们的模型泛化,避免过度拟合。这篇博文将使用最常用的池层类型 max pooling 。还有其他版本的池层,如平均池,但这篇文章的重点是最大池。

Max Pooling: 卷积层会在输入的某个区域中找到一个特定的特征,并为其分配一个较高的激活值。然后,池图层将缩小该区域并创建一个新的制图表达。最大池层通过使用每个子区域中的最大值来创建原始区域的抽象。

最大池将覆盖每个子区域,应用最大过滤器,从每个子区域提取最高值,并创建一个维度减少的抽象。

下面的例子显示了一个 4x4 矩阵作为我们的输入。我们将使用 2x2 滤波器来扫描输入矩阵,我们还将使用步长 2。2x2 池大小或过滤器将决定我们缩小空间维度的数量。对于 2x2 的池大小,我们每次将缩小一半。扫描输入矩阵时,步幅将决定移动的步数。例如,步长为 2 时,我们将从红色的 2x2 到绿色的 2x2 扫描输入矩阵,依此类推。被扫描的区域每次将移动两个街区。

全连接层

像正常的神经网络一样,CNN 的全连接层中的每个神经元都连接到前一层中的每个神经元。完全连接的层负责在特征提取后对数据进行分类。全连接层将查看由卷积层或池层创建的高级功能的激活图,然后确定哪些功能与每个类相关联。

对于我们的数据集,我们有两类:肺炎和正常。完全连接的图层将查看先前图层找到的要素,然后确定哪些要素最有助于预测图像所属的类别。

肺炎简介

仅在美国,每年就有大约一百万人会因肺炎而去医院就诊。在这 100 万人中,每年约有 5 万人死于肺炎 (CDC,2017)

肺炎是一种传染性炎症疾病,影响所有年龄段人群的肺部,通常由病毒或细菌感染引起。肺炎会影响肺部的一侧或两侧,并导致肺泡(气囊)充满液体、细菌、微生物和脓液 (NIH,2018)

肺炎有多种诊断方法,一种常见的确诊方法是通过胸部 x 光检查。胸部 x 光是确定一个人是否患有肺炎的最好的测试,也是最准确的。虽然检测肺炎至关重要,但有时可能是一项艰巨的任务。肺炎通常在 X 射线中模糊地显示出来,也可能与当地的其他疾病混合在一起。

Image Source

数据准备和分析

代码的第一部分将专门用于准备数据。这一部分更多的是关于模型的实际构建,而不是细节。我将这个数据准备和分析部分的所有代码,不包括视觉效果,放在一个名为 pneumonia_dataset 的单独文件中,以便稍后导入到应用 CNN 预测肺炎部分。从这个文件导入数据集将在本节的开头解释。

import os
import numpy **as** np
import matplotlib.pyplot **as** plt
from glob import glob
from keras.preprocessing.image import ImageDataGenerator

前几行是导入准备和可视化数据所需的库。

path  **=** "./chest_xray"
dirs  **=** os**.**listdir(path)
**print**(dirs)

输出:

Output:

['.DS_Store', 'test', 'train', 'val']

这里我们设置了 chest_xray 文件夹的路径,以备后用。然后,我们从 chest_xray 文件夹中打印出目录。请注意,该文件夹分为三个子文件夹:测试、训练和 val 或验证。每个文件夹都包含我们将需要用于培训和测试的胸部 x 光图像。

train_folder **=** path **+** '/train/'
test_folder  **=** path **+** '/test/'
val_folder   **=** path **+** '/val/'

train_dirs **=** os**.**listdir(train_folder)
**print**(train_dirs)

输出:

Output:

['.DS_Store', 'PNEUMONIA', 'NORMAL']

接下来,我们将为每个文件夹设置路径。我们可以使用之前设置的“path”变量,并将其与每个子文件夹的名称连接起来。然后,我们将希望看到培训文件夹的内容。为了查看目录,我们将对培训文件夹使用listdir()功能,然后打印结果。

train_normal **=** train_folder **+** 'NORMAL/'
train_pneu   **=** train_folder **+** 'PNEUMONIA/'

然后,我们可以使用我们的培训文件夹,并设置每个类的路径。在这种情况下,我们有两个类别:正常的图像和肺炎的图像。如果我们想要可视化具体为“正常”或“肺炎”的图像,那么我们将创建一个包含这些图像的路径的变量,以供以后参考。

pneu_images   **=** glob(train_pneu **+** "*.jpeg")
normal_images **=** glob(train_normal **+** "*.jpeg")

现在,我们已经将培训文件夹分为“正常”和“肺炎”,我们可以从每个类中提取所有图像。这个数据集中的图像都是 jpeg 图像,所以对于每个路径,我们将在末尾添加.jpeg,以确保我们提取图像。

**def** **show_imgs**(num_of_imgs):

    **for** img **in** range(num_of_imgs):
        pneu_pic   **=** np**.**asarray(plt**.**imread(pneu_images[img]))
        normal_pic **=** np**.**asarray(plt**.**imread(normal_images[img]))

        fig **=** plt**.**figure(figsize**=** (15,10))

        normal_plot **=** fig**.**add_subplot(1,2,1)
        plt**.**imshow(normal_pic, cmap**=**'gray')
        normal_plot**.**set_title('Normal')
        plt**.**axis('off')

        pneu_plot **=** fig**.**add_subplot(1, 2, 2)
        plt**.**imshow(pneu_pic, cmap**=**'gray')
        pneu_plot**.**set_title('Pneumonia')
        plt**.**axis('off')

        plt**.**show()

我们将创建一个名为show_imgs()的函数来可视化我们训练集中的胸部 X 射线图像。该函数将采用一个参数来指定要显示多少幅图像(num_of_imgs)。然后,我们将使用一个范围为“num_of_imgs”的 for 循环来显示指定的图像数量。

我们将并排显示正常图像和肺炎图像,因此我们将添加两个子图:一个用于正常,一个用于肺炎。这些图像的颜色映射将是“灰色”。如果你想改变颜色图,去 Matplotlb 的颜色图参考页面。

对于显示的每个图像,我们将通过设置每个子图的标题将其标记为“正常”或“肺炎”。

show_imgs(3)

我们可以这样使用我们的show_imgs()函数。我们将调用这个函数,并给它一个参数:我们希望显示的两个类的图像数量。

train_datagen **=** ImageDataGenerator(rescale            **=** 1**/**255,
                                   shear_range        **=** 0.2,
                                   zoom_range         **=** 0.2,
                                   horizontal_flip    **=** True,
                                   rotation_range     **=** 40,
                                   width_shift_range  **=** 0.2,
                                   height_shift_range **=** 0.2)

这被称为图像预处理,或数据增强。我们将使用 Keras 的ImageDataGenerator()类进行数据扩充。数据扩充有助于我们扩大训练数据集。训练数据越多,种类越多越好。随着更多的训练数据和轻微操纵的数据,过度拟合变得不那么成问题,因为我们的模型必须更一般化。

  • 第一步是重新调整我们的数据。重新缩放图像是一种常见的做法,因为大多数图像的 RGB 值范围为 0–255。这些值对于大多数模型来说太高,无法处理,但是通过将这些值乘以 1/255,我们可以将每个 RGB 值压缩到 0–1 之间的值。这对于我们的模型来说更容易处理。
  • 接下来我们有shear_range,它将随机应用剪切映射,或剪切变换到数据。数值“0.2”是剪切强度或剪切角度。
  • zoom_range也被设置为“0.2”。这是为了随机放大图像。
  • horizontal_flip设置为“真”,因为我们想随机翻转数据集中的一半图像。
  • rotation_range是图像可以随机旋转的度数。
  • width_shift_rangeheight_shift_range是随机平移图像的范围。
test_datagen **=** ImageDataGenerator(rescale **=** 1**/**255)

这是我们重新调整测试集的地方。测试集不需要应用于训练数据的所有相同变换。只有训练数据可以被操纵以避免过度拟合。测试集必须是原始图像,以便在真实的、经过最小程度处理的图像上准确预测肺炎。

training_set **=** train_datagen**.**flow_from_directory(train_folder,
                                   target_size**=** (64, 64),
                                   batch_size **=** 32,
                                   class_mode **=** 'binary')

val_set **=** test_datagen**.**flow_from_directory(val_folder,
                                   target_size**=**(64, 64),
                                   batch_size **=** 32,
                                   class_mode **=**'binary')

test_set **=** test_datagen**.**flow_from_directory(test_folder,
                                   target_size**=** (64, 64),
                                   batch_size **=** 32,
                                   class_mode **=** 'binary')

输出:

Found 5216 images belonging to 2 classes.
Found 16 images belonging to 2 classes.
Found 624 images belonging to 2 classes.

现在,我们将采用我们的测试、训练和验证文件夹的路径,并使用来自 Keras 的flow_from_directory()生成批量扩充数据。

  • 第一个参数是要提取的目录。
  • 第二个参数是目标尺寸,即调整大小后图像的尺寸。
  • 第三个参数是“class_mode”,设置为“binary”。这将返回 1D 二进制标签。由于只有两个类,该数据集需要二进制分类。

现在我们已经准备好了数据,我们可以继续构建模型,训练它,然后测试它,并以准确度分数的形式获得我们的结果。

应用细胞神经网络预测肺炎

from keras.models import Sequential
from keras.layers import Conv2D, MaxPooling2D, Flatten, Dense, BatchNormalization, Dropout

import pneumonia_dataset

Keras 是一个运行在 TensorFlow 之上的高级 python 神经网络库。Keras 能够快速有效地实现和实验深度学习和机器学习算法,同时仍然非常有效。Keras 将是我们这篇博文选择的深度学习库,因此我们将导入一些所需的层和模型,以使我们的卷积神经网络功能良好。

最后一个导入语句是我之前在数据准备和分析部分提到的肺炎 _ 数据集文件。

training_set, test_set, val_set **=** pneumonia_dataset**.**load_data()

输出:

Training Set:
Found 5216 images belonging to 2 classes.

Validation Set:
Found 16 images belonging to 2 classes.

Test Set:
Found 624 images belonging to 2 classes.

pneumonia_dataset 文件将返回一个训练集、测试集和一个验证集,我们将对它们进行适当的命名。这将返回我们的数据如何在每个集合中分割的摘要,包括每个集合中的图像数量以及这些图像将适合多少个类别。

model **=** Sequential()

model**.**add(Conv2D(32, (3, 3), activation**=**'relu', input_shape**=**(64, 64, 3), padding**=**'same'))
model**.**add(MaxPooling2D(pool_size**=**(2, 2)))

model**.**add(Conv2D(32, (3, 3), activation**=**'relu', padding**=**'same'))
model**.**add(MaxPooling2D(pool_size**=**(2, 2)))

model**.**add(Conv2D(64, (3, 3), activation**=**'relu', padding**=**'same'))
model**.**add(MaxPooling2D(pool_size**=**(2, 2)))

model**.**add(Flatten())
model**.**add(Dense(128, activation **=** 'relu'))
model**.**add(Dropout(0.5))
model**.**add(Dense(1, activation **=** 'sigmoid'))

这是令人兴奋的部分。

  • 首先,我们使用 Keras 的“顺序”模型创建我们的模型。这个模型是层的线性堆叠,这意味着我们将逐层创建我们的模型。
  • 第一个卷积层:第一个卷积层是我们的输入层。
  • 第一个参数是在层中使用的卷积滤波器的数量,设置为“32”。这也是这一层中神经元或节点的数量。
  • 第二个参数是过滤器的大小,或感受野。想象一下,我们正在创建一个大小为(3,3)的窗口,或者宽度为 3,高度为 3,我们的卷积层被限制在任何给定的时间进行查看。
  • 我们将设置的第三个参数是激活函数。我们的非线性激活函数是 ReLu,或校正线性单位。ReLu 功能是*f(x) = max(0, x)*。因此,所有负值都转换为零,而所有正值保持不变。ReLu 是最流行的激活函数之一,因为它减少了消失梯度问题,并且计算成本更低。这并不意味着 ReLu 函数是完美的,但是它将完成大多数应用程序的工作。
  • 第四个参数是输入形状。这个参数只需要在第一个卷积层中指定。在第一层之后,我们的模型可以处理剩下的部分。输入形状只是将被馈送到 CNN 的图像的形状。我们的输入图像的形状将是(64,64,3)(宽度,高度,深度)。
  • 最后一个参数是填充,设置为“same”。这将填充输入,使输出具有与初始输入相同的长度。
  • 第一个最大池层:该模型的最大池层只有一个参数。
  • 第二卷积和最大池层:第二卷积层和最大池层将与上面的前几层相同。第二卷积层将不需要指定输入大小。
  • 第三卷积层:在第三卷积层,第一个参数会被改变。在前两个卷积层中,该层中的滤波器或神经元的数量被设置为“32”,但是对于第三层,它将被设置为“64”。除了这一点变化之外,其他一切都将保持不变。
  • 第三个最大池层:第三个最大池层将与前两个最大池层相同。
  • 展平:展平是将多维数据转换为全连接层的可用数据所必需的。为了让全连接层工作,我们需要将卷积层的输出转换为 1D 向量。我们的卷积层将使用 2D 数据(图像)。在将它送入分类器之前,必须将其整形或展平为一维。
_________________________________________________________________ Layer (type) Output Shape Param # ================================================================= max_pooling2d_16 (MaxPooling (None, 6, 6, 64) 0 _________________________________________________________________ flatten_5 (Flatten) (None, 2304) 0 _________________________________________________________________
  • Dense — ReLu: 密集层是完全连接的层,意味着每个神经元都连接到前几层的所有神经元。我们将使用 128 个节点。这也意味着完全连接的层的输出大小为 128。对于这个完全连接的层,将使用 ReLu 激活功能。
  • Dropout: Dropout 用于正则化我们的模型并减少过度拟合。丢弃将暂时“丢弃”完全连接的层中的随机节点。节点的这种丢失将导致由未被丢失的节点组成的变薄的神经网络。由于没有特定的节点是 100%可靠的,因此丢弃减少了过度拟合,并有助于模型一般化。“. 5”表示某个节点被丢弃的概率为 50%。要阅读更多关于辍学的内容,请查阅本文。
  • Dense — Sigmoid: 我们最终的全连接层将使用 sigmoid 函数。我们的问题包括两类:肺炎和正常。这是一个二元分类问题,其中 sigmoid 可用于返回介于 0 和 1 之间的概率。如果这是一个多类分类,乙状结肠激活功能将不会是选择的武器。然而,对于这个简单的模型,sigmoid 函数工作得很好。sigmoid 函数可以定义为:

model**.**compile(optimizer**=**'adam', loss**=**'binary_crossentropy', metrics**=**['accuracy'])

我们现在可以使用 Keras 中的 compile 方法来配置模型。

  • 第一个参数是优化器,它将被设置为“adam”。亚当优化器是目前深度学习中最流行的算法之一。《Adam:一种随机优化的方法》的作者表示,Adam 结合了另外两种流行的优化器的优点:RMSProp 和 AdaGrad。你可以在 Adam 论文的第 6.3 节中读到关于 CNN 的 Adam 的有效性。
  • 第二个参数是损失函数。这个模型将使用二元交叉熵损失函数。我们的模型将进行二元分类,因此我们可以将此损失函数写成如下所示,其中“y”为 0 或 1,表示类别标签是否是正确的分类,其中“p”是模型的预测概率:

  • 最后一个参数是度量函数,它将判断模型的性能。在这种情况下,我们希望返回精度。
model_train **=** model**.**fit_generator(training_set,
                         steps_per_epoch **=** 200,
                         epochs **=** 5,
                         validation_data **=** val_set,
                         validation_steps **=** 100)

输出:

Epoch 1/5
200/200 [==============================] - 139s 697ms/step - loss: 0.2614 - acc: 0.8877 - val_loss: 0.5523 - val_acc: 0.8125
Epoch 2/5
200/200 [==============================] - 124s 618ms/step - loss: 0.2703 - acc: 0.8811 - val_loss: 0.5808 - val_acc: 0.8125
Epoch 3/5
200/200 [==============================] - 124s 618ms/step - loss: 0.2448 - acc: 0.8984 - val_loss: 0.7902 - val_acc: 0.8125
Epoch 4/5
200/200 [==============================] - 121s 607ms/step - loss: 0.2444 - acc: 0.8955 - val_loss: 0.8172 - val_acc: 0.7500
Epoch 5/5
200/200 [==============================] - 119s 597ms/step - loss: 0.2177 - acc: 0.9092 - val_loss: 0.8556 - val_acc: 0.6250

现在是训练模型的时候了!这将使用 Keras 的fit_generator()方法来完成。这将根据从训练集生成的批数据来训练模型。

  • 第一个参数是每个时期的步数。这将被设置为 200。每个时期的步骤将告诉模型在结束特定时期之前从发生器产生的样本批次的总数。
  • 第二个参数是历元的数量,或训练迭代。Keras 文档指出,一个历元被定义为对所提供的全部数据的迭代,如 steps_per_epoch 所定义的。
  • 第三个参数是模型将使用的验证数据。该模型不会根据验证数据进行训练,但这将有助于测量每个时期结束时的损失。
  • 最后一个论点是验证步骤。我们的验证数据来自一个生成器(见上面的代码),所以必须设置从生成器生成的样本批次数,类似于每个时期的步骤数。
test_accuracy **=** model**.**evaluate_generator(test_set,steps**=**624)

**print**('Testing Accuracy: {:.2f}%'**.**format(test_accuracy[1] ***** 100))

输出:

Testing Accuracy: 90.22%

既然已经对模型进行了训练,那么是时候根据测试数据来评估模型的准确性了。这将通过使用 Keras 的evaluate_generator()方法来完成。该评估将返回测试集丢失和准确性结果。

  • 与拟合生成器一样,评估生成器的第一个参数是从中提取样本的文件夹。因为我们正在测试模型的准确性,所以将使用测试集。
  • 第二个参数是在完成之前从生成器中提取的样本批次数。

然后,我们可以打印精度,并将其缩短为仅显示两位小数。精确度将作为 0-1 之间的值返回,因此我们将它乘以 100 以获得百分比。

之后,模型就完成了!我们已经在从胸部 x 光图像预测肺炎方面取得了一些成功!

所有东西放在一起(20 个时代)

Output:

Found 5216 images belonging to 2 classes.
Found 16 images belonging to 2 classes.
Found 624 images belonging to 2 classes.
Epoch 1/20
200/200 [==============================] - 142s 708ms/step - loss: 0.5141 - acc: 0.7369 - val_loss: 0.6429 - val_acc: 0.6250
Epoch 2/20
200/200 [==============================] - 137s 683ms/step - loss: 0.4034 - acc: 0.8058 - val_loss: 0.6182 - val_acc: 0.7500
Epoch 3/20
200/200 [==============================] - 134s 670ms/step - loss: 0.3334 - acc: 0.8483 - val_loss: 0.6855 - val_acc: 0.6875
Epoch 4/20
200/200 [==============================] - 129s 644ms/step - loss: 0.3337 - acc: 0.8516 - val_loss: 0.8377 - val_acc: 0.6875
Epoch 5/20
200/200 [==============================] - 139s 696ms/step - loss: 0.3012 - acc: 0.8672 - val_loss: 0.6252 - val_acc: 0.8750
Epoch 6/20
200/200 [==============================] - 132s 662ms/step - loss: 0.2719 - acc: 0.8808 - val_loss: 0.6599 - val_acc: 0.6875
Epoch 7/20
200/200 [==============================] - 125s 627ms/step - loss: 0.2503 - acc: 0.8969 - val_loss: 0.6470 - val_acc: 0.7500
Epoch 8/20
200/200 [==============================] - 128s 638ms/step - loss: 0.2347 - acc: 0.9016 - val_loss: 0.8703 - val_acc: 0.6875
Epoch 9/20
200/200 [==============================] - 131s 656ms/step - loss: 0.2337 - acc: 0.9075 - val_loss: 0.6313 - val_acc: 0.6875
Epoch 10/20
200/200 [==============================] - 124s 619ms/step - loss: 0.2159 - acc: 0.9133 - val_loss: 0.7781 - val_acc: 0.7500
Epoch 11/20
200/200 [==============================] - 129s 647ms/step - loss: 0.1962 - acc: 0.9228 - val_loss: 0.6118 - val_acc: 0.8125
Epoch 12/20
200/200 [==============================] - 127s 634ms/step - loss: 0.1826 - acc: 0.9306 - val_loss: 0.5831 - val_acc: 0.8125
Epoch 13/20
200/200 [==============================] - 128s 638ms/step - loss: 0.2071 - acc: 0.9178 - val_loss: 0.4661 - val_acc: 0.8125
Epoch 14/20
200/200 [==============================] - 124s 619ms/step - loss: 0.1902 - acc: 0.9234 - val_loss: 0.6944 - val_acc: 0.7500
Epoch 15/20
200/200 [==============================] - 128s 638ms/step - loss: 0.1763 - acc: 0.9281 - val_loss: 0.6350 - val_acc: 0.6875
Epoch 16/20
200/200 [==============================] - 139s 696ms/step - loss: 0.1727 - acc: 0.9337 - val_loss: 0.4813 - val_acc: 0.8750
Epoch 17/20
200/200 [==============================] - 145s 724ms/step - loss: 0.1689 - acc: 0.9334 - val_loss: 0.3188 - val_acc: 0.7500
Epoch 18/20
200/200 [==============================] - 133s 664ms/step - loss: 0.1650 - acc: 0.9366 - val_loss: 0.4164 - val_acc: 0.8750
Epoch 19/20
200/200 [==============================] - 132s 661ms/step - loss: 0.1755 - acc: 0.9316 - val_loss: 0.5974 - val_acc: 0.8125
Epoch 20/20
200/200 [==============================] - 132s 662ms/step - loss: 0.1616 - acc: 0.9395 - val_loss: 0.4295 - val_acc: 0.8750
Testing Accuracy: 92.13%

结论

卷积神经网络在测试集上取得了 92.13%的准确率。你可以自己决定这是否应该被称为“成功”。对于一个简单的模型,我认为这是非常合理的。

使用数据科学进行行为游戏设计

原文:https://towardsdatascience.com/using-data-science-for-game-design-bcb7a00ad40b?source=collection_archive---------37-----------------------

这是一个关于数据科学专业知识和对人类心理学的理解如何帮助我获得有趣的见解来设计更好的游戏的故事。

Screenshot of a game. (https://www.flickr.com/photos/bagogames/31959169544)

背景

上周,作为谷歌初创公司的导师,我有机会与来自中东欧的 10 家游戏工作室合作。这些初创公司拥有 200 万到 1000 万活跃用户,每月经常性收入在 15 万到 20 万之间,团队规模在 10 到 80 人之间。尽管它们在收入和用户群方面有所不同,但它们都面临着同样的挑战:

  1. 留存率低:在大多数情况下,95%的用户在 21 天后离开。在一个游戏中,保留时间为 1 天— 50%,7 天— 30%,14 天— 20%,21 天— 10%(见图 1)。

Figure #1: Retention of users in one of the games.

2。应用内货币化水平低:付费用户数量很低,行业标准是 3%左右,而游戏只有 0.15%到 1%。他们的大部分收入来自广告。

3。无病毒效应:几乎没有病毒效应,所有新用户都是通过付费渠道获取的。

出了什么问题?

当问到“你真的知道谁是你的用户吗?”,没有一家创业公司自信地说是。游戏工作室有一些想法,但他们不确定用户的动机和用户是如何细分的。

为什么这样他们有大量数据,但没有进行适当的数据分析。例如,他们不分析数据,因此他们可以看到用户行为的模式,这可以帮助他们获得关于用户的有意义的见解,将用户分组,在他们离开之前找到行为模式,等等。

这些创业公司如何提高用户留存率?

我们做某件事总是有理由的——包括玩游戏。关键在于理解心理学玩家如何反应,他们的潜在动机是什么。

第一步:是什么促使人们玩你的游戏?

数据无法完全回答这个问题。人们可以看到用户的某些行为模式,并使用试探法或常识来得出结论。例如,两个常见的动机是

  • 感觉像个胜利者
  • 消磨时间

太好了!所以这创造了两个用户群。下一步是绘制他们在游戏中的旅程,并与动机联系起来。

第二步:为每个细分市场绘制用户旅程图

每个用户群在游戏中都遵循一条特定的路径,主要是由他们的动机驱动的。通过数据分析,人们可以发现给定的用户群遵循什么样的路径。比如说,在一个游戏中,我们发现那些以获胜为主要动机的人,大体上遵循以下路径

  • 跳过教程—开始游戏—赢得—获得免费积分—赢得—进入下一层— …

第三步:描绘动机

尝试将动机与用户旅程联系起来。最有可能的是,在游戏过程中动机会改变,这会导致用户改变行为。例如,在一个游戏中,开发人员发现那些主要动机是想赢的用户在连续输了 3-4 场后最终离开了。看起来用户觉得他们不能再赢了,变得沮丧并离开。

第四步:创建一个激励结构来保持最初的动机

我们如何让他们回到理想的旅程,或者保持用户开始游戏的动机?对于上面提到的情况,其中一个人由于沮丧而离开,如果用户面临多次失败,游戏可以让她赢——这将增加他们留在游戏中的动机。

所有上述步骤都非常直观和简单,但令我惊讶的是,没有一个游戏工作室遵循上述步骤。

但是如何增加应用内购买呢?

当用户看到无法免费获得的价值时,他们愿意付费。在游戏中,当有人想要打破“游戏规则”或者获得新的体验时,最适合开口要钱。让我们用一个简单的例子来说明——假设规则是“每个人都必须通过教程来获得一些积分”。如果有人想跳过教程(因为缺乏耐心),开发者可以让用户购买通过完成教程获得的积分,允许他们继续游戏并跳过教程。

为了帮助游戏赚钱,找到那些用户(或部分用户)愿意打破规则的地方。

如何处理那些以消磨时间为主要动机的用户?要求他们“打破规则”进入下一个阶段并不会真正有所帮助。这些用户可能喜欢帮助他们改善体验的东西,比如定制背景,这是他们很可能愿意花钱购买的东西。

创造一种病毒效应怎么样?

这里的规则也是一样的,一旦我们知道了动机,我们就可以要求他们做一些事情,比如在适当的时候邀请朋友。例如,如果我们知道用户很高兴,并给出了积极的评价,那么我们可以要求他们在这一点上邀请其他朋友,并创建一个激励结构(给予免费积分或只是做好事的内在动机)。

结论

我上面解释的是数据科学如何结合对人类心理学的一些理解来帮助游戏工作室解决保留、支付和病毒式传播问题的一个例子。

基于玩家行为,针对每个细分市场,绘制动机地图。然后创建一个激励结构来保持动机,并为他们提供类似支付或邀请朋友来实现目标的行动,这使他们玩游戏。

我还要补充一点,有些试图建立这样一个基于用户地理位置的行为模型,假设是某些地区/国家的人以某种方式行为。这可能是真的,但请记住,你的用户可能不会反映该国人民的平均行为。例如,有富裕的印度人,也有贫穷的印度人。富有的印度人的行为可能与欧洲人相似,完全有可能你所有的游戏用户都属于富有的印度人。

我希望你喜欢这篇文章。随意分享,喜欢。

利用数据科学改善社会

原文:https://towardsdatascience.com/using-data-science-for-societys-betterment-783163e40a3b?source=collection_archive---------36-----------------------

Tech4Good 是技术界的一种趋势。数据科学是这场精彩比赛的领跑者。

越来越多的企业家和学者正在开发技术来解决社会问题,识别和治疗疾病,弥合经济差距,并倡导变革。Tech4good 和 DataScience4Good 是越来越多地被采用的运动。

Photo by Clark Tibbs on Unsplash

技术总是遵循什么如何的叙述。技术开始回答为什么的时候到了!

每个领域现在都有它的“数据尤里卡时刻”,给使命驱动的组织全新的机会来利用数据。从解决贫困到改善医疗保健到教育民主化,数据科学有可能使天平向弱势群体和穷人倾斜。

许多组织正在迅速利用数据科学做好事。让我们来看看,并从中获得灵感。

1。数据种类

DataKind 将高影响力组织与领先的数据科学家聚集在一起,使用数据科学为人类服务。

Data Kind Home Page

从一小时的活动到长达一年的活动,他们设计了一些项目,让数据科学家和社会变革者能够共同应对严峻的人道主义挑战。它还向数据科学家介绍了“数据换利益”运动,并向他们展示了他们的技能有多么有价值。

他们执行的项目类型

我们一丝不苟地专注于将各种形式的数据科学带给那些与我们共享可持续地球愿景的人,在这个星球上,我们都可以获得我们的基本人类需求。我们设想这样一个世界,解决这些问题的组织可以像华尔街和硅谷一样访问数据科学资源。

—杰克·波威,DataKind 创始人兼执行董事

2。良好数据

“数据为善”是加拿大的一个行善者的集体,他们想用他们的力量为善,而不是为恶,通过数据来帮助社区变得更好。

Data For Good Homepage

他们是一个加拿大非营利组织,在全国各地都有分会,帮助其他非营利和非政府组织,利用他们的数据做出更明智和更好的决定,以促进他们社区的繁荣。

他们通过自己的数据技能帮助了以下事业。

3。民主数据

Data for Democracy 是一个由热情的志愿者组成的全球社区,致力于促进数据和技术领域的信任和理解。它最初是一个小型的基层团队,共同的目标是利用数据推动积极的变革,但很快发展成为一个拥有 4000 多名员工(人数还在增加)的全球性组织。

以下是他们做的一些项目—

4.暑期项目

许多大学与社会组织合作,提供暑期项目来实施数据科学 4Good 项目

数据科学造福社会奖学金是芝加哥大学的一个夏季项目,旨在培训有抱负的数据科学家从事数据挖掘、机器学习、大数据和具有社会影响的数据科学项目。研究员与政府和非营利组织密切合作,解决教育、卫生、能源、公共安全、交通、经济发展、国际发展等领域的现实问题。

在三个月的时间里,他们学习、磨练并应用他们的数据科学、分析和编码技能,在快节奏的氛围中合作,并向来自工业界和学术界的导师学习。

每年大约有 16 名 DSSG 大学的学生研究员被挑选出来从事具有具体相关性和社会影响的数据密集型项目。在为期 10 周(6 月至 8 月)的项目中,学生应在现场与团队成员密切合作。

佛罗里达州 DSSG 实习生从事影响佛罗里达州非营利组织的数据科学项目。DSSG 项目是一个为期 12 周的带薪实习项目。学生被安排在多学科团队中,并与导师一起解决现实世界中的问题。

5.竞争

许多比赛鼓励数据科学家尝试解决一些最大的挑战,以获得高额奖金。Kaggle 是此类比赛的最大中心,但也有其他玩家,如 DrivenData、IBM Challenges 等。

无论媒介是什么,我们都必须通过任何必要的工具参与帮助我们的社会进步。数据科学将对我们的社会产生深远的影响。

利用数据科学进行税收改革

原文:https://towardsdatascience.com/using-data-science-for-tax-reform-2d584a884c82?source=collection_archive---------21-----------------------

财务压力和人员减少导致税务机构尽可能实现自动化。

最大的创新是将大数据分析应用到现代税收管理中,大数据分析是对大量数据的自动化分析。利用数据科学推动财务运营已经开始改变政府最高层的税收管理。

事实证明,将大数据应用于税务管理可以有效帮助税务人员识别欺诈和预测违规行为。但是一些公司正在努力适应一个比以往任何时候都需要更多数据的世界——以发票、海关申报和账户报表的形式。

数据科学和税收

使用电脑打击税务欺诈并不是什么新鲜事——美国国税局自 1962 年就开始使用电脑了。然而,大数据分析的使用是一项新的发展。这一策略似乎正在发挥作用——尽管自 2011 年以来员工和预算每年都在减少,但美国国税局报告称发现的欺诈案件增加了 400%,从刑事欺诈起诉中获得的收益增加了 1000%。

国税局正在从过去无法访问或无法获得的来源获取数据。政府服务部门正在从社交媒体账户中挖掘数据,以帮助创建纳税人档案,并在此基础上进行分析——这可能被用于在纳税季检测欺诈行为。来自社交媒体帖子和个人资料的信息,以及从其他来源和国税局报税档案中提取的数据,被用来确定某个人不遵守税法的可能性。

这种整理公共和私人数据的做法引起了隐私倡导者的关注,尤其是因为除了国税局以外,没有人能完全确定哪些信息被用来做这些决定。(国税局在法律上没有义务说。)目前,纳税人不能审查或质疑国税局存储的关于他们的数据。然而,很难想象,如果大数据的使用能让国税局更好地发现欺诈,它会逆转这一进程。

大数据和企业税

作为推动使用越来越多的数据来防止欺诈和收税的一部分,税务当局要求企业提供更多信息。在这样做的同时,这些机构也在标准化他们接收客户和供应商发票、报关单和银行对账单等数据的方式。这对公司来说是一个问题,因为公司的税务和财务数据通常分散在多个系统和格式中。

税务部门也在增加他们期望从企业获得的数据量。例如,在巴西,公司必须遵守 29 种不同的提交要求。有些提交必须一个月一次。

某些公司结构可能会比其他公司更好地应对税务管理方面的这些变化。例如,私人员工持股退休计划(或 S 公司员工持股计划)可能比可比的标准普尔 500 指数公司更容易提供税务信息。

100%员工持股计划拥有的 S 公司员工持股计划不直接或间接支付任何当前公司所得税。(标准普尔 500 公司支付 20%到 25%的税率。)由于这些公司纳税的方式,管理层应该少花时间对公司的会计账目吹毛求疵,寻找机会减少纳税。更简单的会计可以使这些公司更容易向税务机关提供他们需要的各种信息。

大数据分析也可能改变企业会计的运作方式。公司可以使用税务管理人员使用的同样的技术来审计他们自己。会计师可能会发现,近似国税局的税务分析将有助于他们确保他们工作的企业的合规性。

大数据将如何改变税收管理

目前还不清楚这些变化对个人和企业的长期影响。受隐私倡导者启发的立法可能会限制国税局从公共和私人来源收集的数据量。企业可能会抵制对财务数据日益增长的需求。

然而,每当预算下降时,自动化就成了一个诱人的前景。更少的员工做更好的工作是难以抗拒的,特别是对于像国税局这样现金短缺的政府服务机构。

企业和个人都应该为未来做好准备,未来税收管理将由来自各种来源的数据驱动。

图像经由 Rawpixel

如何利用数据科学更好地了解您的客户

原文:https://towardsdatascience.com/using-data-science-to-better-understand-your-customers-part-1-of-2-398d11049785?source=collection_archive---------30-----------------------

客户在你的业务布局中占多大比重?这是一个反问句。我们都知道,大多数企业的兴旺只是因为他们的客户。因此,在为客户服务之前,你必须充分了解他们。了解你的客户有助于你提供量身定制的服务。这提高了客户参与度,增加了销售额。

This picture is definitely worth a thousand words. Source: economictimes

你了解你的顾客吗?嗯,这个问题很模糊。如果你不能从客户的某些定性方面来回答这个问题,那么你现在就需要开始工作了。我确信所有的企业主在他们的脑海中都有一个理想顾客的形象,不管这个形象有多模糊。通常这种形象是凭直觉编造出来的。它可能没有任何同义反复的证据支持。

数据从不说谎。它只不过是事实和数字的集合,有时它可以向我们展示一面镜子。本文将解释如何使用数据科学的“魔力”来获得对客户的一致理解。确切地说,我们将学习如何对这个商场客户数据集应用聚类算法。然后,我们将从输出中进行推断,以更好地了解经常光顾商场的顾客。感谢您忍受如此冗长的前奏,并因您的耐心为您获得项目源代码

什么是客户分桶?

客户细分或客户分组是将公司的客户分成反映每个组中客户相似性的组(也称为分组)的做法。对客户进行细分的目标是决定如何与每个细分市场中的客户建立联系,以最大化每个客户对企业的价值。

吸引客户使您能够以最大化销售的方式迎合每个客户群体。对于营销人员来说,细分目标客户可以让你以一种能产生最大影响的方式来塑造你的沟通。

在这个项目中,我们将使用聚类分析,根据客户的年收入将他们分成不同的类别。为此,我们将使用 Kmeans,这是目前最好的聚类算法之一。K-means 聚类是一种无监督学习算法,它在数据中寻找组。组数用字母 k 表示。

让我们开始吧。

请随意跟随。数据集可以在这里下载。

偷看数据。

商场客户数据集是一个相对较小的数据集,因为它仅包含 199 行和 5 列。如果你看一下这一段下面的图片,你会注意到这五个栏目的标题是客户 ID、流派、年龄、年收入(k$)和支出分数(1-100)。

我们将从导入必要的库开始。

import pandas as pd
import numpy as np
from sklearn.cluster import KMeansimport matplotlib.pyplot as plt 
plt.rc(“font”, size=14)

现在,我们将导入数据集。

data_path = "Mall_Customers.csv"
df = pd.read_csv(data_path)

也许这只是我,但我发现出于某种原因,一些列标题令人不安。让我们开始改变这些。

df.rename(columns={'Genre':'Gender',
                   'Annual Income (k$)':'Annual_Income',
                   'Spending Score (1-100)':'Spending_Score'
                  }, 
                   inplace=True
          )

在这个项目中,我们将使用客户的年收入和支出得分(1 到 100 分)对客户进行聚类。因此,我们将只使用这两列。

X = df.iloc[:, [3, 4]].values

现在我们已经在数据方面做好了准备,是时候开始我们的集群工作了。在我们运行我们的聚类算法之前,有必要确定将我们的客户分成多少个聚类。有几种不同的方法可以确定该数据集的理想聚类数。为此,我们将使用肘法。

肘法

计算集群数量的一种方法是使用肘方法。该方法包括对不同 K 值的数据运行 K 均值聚类算法,并计算每个 K 值的误差平方和(S.S.E .)

然后,将这些值绘制在图表上,我们可以看到,随着 K 值的增加,S.S.E .趋于减小。当 K 的值等于数据点的数量时,S.S.E .变为 0,因为这样每个数据点就是它自己的聚类。我们的目标是找到一个 K 值很小且 S.S.E 很低的点。

在本实验中,我们将对 0 到 10 范围内的不同 K 值运行 K 均值,并将 S.S.E .存储在一个名为 distortions 的列表中。

distortions = []
K = range(1, 10)
for k in K:
    kmeansModel = KMeans(n_clusters = k, init = 'k-means++',    random_state = 23)
    kmeansModel.fit(X)
    distortions.append(kmeansModel.inertia_)plt.plot(K, distortions)
plt.title("The Elbow Method")
plt.xlabel("Number of Clusters")
plt.ylabel("S.S.E.")
plt.show()

现在,让我们看一下图表。

在此图中,您可以观察到,在 K 的每次迭代之后,S.S.E .急剧下降。您还可以观察到,在 K 达到 5 之后,它是一个下坡。因此,5 似乎是 K 的最佳值,这意味着我们将把客户分成 5 个集群。

现在我们已经计算出了集群的数量,我们可以继续创建这些集群。

kmeansModel = KMeans(n_clusters = 5, init = 'k-means++', random_state = 23)
Y = kmeansModel.fit_predict(X)

由于数据集很小,所有这些过程都不需要花时间来完成。一旦创建了集群,我们就可以将它们绘制在图表上。每个聚类点使用不同的符号进行标记,每个聚类的质心使用实心红点进行标记。

Just look at them!

只要看一下图表,我们就能了解到经常光顾购物中心的五种不同类型的顾客。如果我们给他们命名,那么他们可以被命名如下:
i .低收入,高消费(红色)。
二。低收入、低消费人群(蓝色)。
三世。平均收入,平均支出(橙色)。
四。高收入,高消费,和(绿色)
诉高收入,低消费(紫色)。

这些群体中的每一个成员都有更多的共同特征,因此我们有一个同质群体。这些群体中的每一个人都可能有相似的需求和愿望。记住这一点,所有的营销/销售活动都可以满足这些需求和愿望,以吸引更多这样的客户。例如,迎合低收入群体的每周折扣销售或迎合高消费群体的购买奖励积分,将他们转变为常客。可能性是无限的,只受我们想象力的限制。

结论

了解一个企业的客户群是至关重要的。深入了解客户行为的方法之一是根据他们的行为(本实验中的收入和支出)将他们分成不同的类别。)相似的人往往行为相似,这就是客户细分的症结所在。因此,通过围绕这些桶计划所有的销售和营销活动,它将承诺更高的投资回报和愉快的客户体验。

用数据科学预测下一个 NBA MVP

原文:https://towardsdatascience.com/using-data-science-to-predict-the-next-nba-mvp-30526e0443da?source=collection_archive---------18-----------------------

统计模型能自信地告诉我们谁将获得每个赛季的 MVP 吗?

Michael Kovac/Getty Images

每年,都会有一名杰出的 NBA 球员被一百多家体育媒体评选为年度最有价值球员(MVP)。正如体育运动中的其他事情一样,围绕谁应该或不应该获奖的讨论可能会非常激烈。把范围缩小到少数几个球员并不难,但是球迷和媒体很难完全同意谁应该是获奖者。除了那次斯蒂芬.库里。

有些人认为 MVP 应该是拥有最令人印象深刻的数据的球员。其他人认为,一个真正的 MVP 没有最好的个人表现,而是提高周围其他人的水平(见勒布朗詹姆斯)。

但是谁是对的呢?我们可以无休止地辩论这个问题,但毫无结果。或者,我们可以看看数字是怎么说的。为了解决这场辩论,我决定使用各种篮球统计数据来模拟谁将成为 2019 年 NBA MVP。

数据收集

用硒网刮篮球参考

任何数据科学项目的第一步都是获取完整的数据集进行分析。幸运的是,我们面对的是篮球,一项充满数据的运动。

NBA 的数据主要有两个来源:NBA 自己的统计网站或球迷喜爱的第三方篮球参考网站。这里的主要区别是数据格式化的方式:虽然 NBA 网站包括一个 JSON API,但 BBallRef 允许您直接下载 CSV 文件。第一个需要 JSON 请求,第二个需要一点聪明的 web 抓取。因为我希望从后者中获得一些经验,所以我选择了 BBallRef。

在 Python 中使用 Selenium——一个自动化浏览器的工具——我构建了一个简单的 scraper,它按照年份列表加载每个页面,切换内置的“下载为 CSV”按钮,并将 CSV 输出保存到磁盘。幸运的是,BBalRef 页面遵循一个模板,允许使用相同的 scraper,而不管年份或数据类型。完整的注释函数如下所示。这似乎也是一个很好的时机来提及我的完整代码库是在 GitHub 上完全可用的

一旦 scraper 完成,我所要做的就是让它发挥它的魔力,收集从 1976 年到 2018 年的赛季排名,高级,总,每场比赛的个人球员统计数据和奖励数据。下一步是处理数据。

数据处理

使用 R 来加载、清理和合并数据

虽然简单的球员统计数据以及姓名、球队和赛季的数据集并不是特别难处理,但我的数据确实有一些被证明具有挑战性的特点。首先,让我们只看总玩家统计。下面是单个条目可能的样子。

Example row from 2018 total statistics

好吧,这看起来很简单,但是有一个问题:玩家名字的格式。它采用“詹姆斯·哈登\ \哈德贾 01”的格式,而实际上我们只需要“詹姆斯·哈登”这成为在 r 中练习简单文本清理的绝佳机会。

这就是我们需要做的。当然有一种更有效的方法来完成这项任务,但有时最好接受多几行代码,以使代码更易读。

从这里开始,我们需要遍历数据集中的每一年,加载那一年的 CSV,清除球员姓名,进行一些更简单的数据类型管理(为了方便读者,我省略了这些内容),并将结果合并到一个电子表格中。该电子表格保存了自 1976 年以来每个赛季每个球员的总数据,格式如上所示。我也为每场比赛统计,以及高级统计,奖项统计和赛季排名做了同样的事情。

接下来,我想在个人统计中添加一个Team.Wins栏,因为团队获胜经常会成为讨论个人奖项的因素。因此,我将每个球员的赛季与我的赛季排名数据中适当的球队和赛季进行了匹配。让我们看看积分榜数据是如何格式化的。

Example row from complete standings data

虽然这在技术上只是匹配团队名称和获取Wins列的问题,但我们在团队名称格式上有问题。球员数据将休斯顿火箭队编码为HOU,而积分榜数据使用全名Houston Rockets。这对任何 NBA 球迷来说都不是问题,但我的电脑没有足够的信息来将球队名称与其缩写匹配起来。

解决方案简单而繁琐:手动将每个缩写映射到每个完整的团队名称。考虑到这些年来团队频繁更换名称,这尤其具有挑战性。谁知道有堪萨斯城国王队(KCK)?创建这个映射后,向球员数据添加一个Team.Wins列只需要遍历每个球员/赛季对并找到合适的值。

如果你想看看这段代码是什么样子,完整的数据处理代码可以在这里找到以及代码库的其余部分。处理完我们的数据后,是时候进行汇总分析了。

数据分析

汇总统计和初步分析

在建模之前,对数据集进行一些汇总分析始终是一种很好的做法。在本文的其余部分,我们将只查看 2000 年以后的数据。首先,让我们用我们的总数据做一个简单的summary(),具体看看上场时间,投篮得分,3 分,篮板,助攻,抢断,盖帽和得分。我使用 dplyr tibble格式来轻松选择相关的列。

Summary of individual player season totals

正如所料,我们看到任何给定的统计值都有很大的范围。让我们快速地看看我们使用dim函数处理了多少个观察值。

Dataset dimensions for individual player season totals

我们看到我们有将近 6500 个 36 列的观察值。因为我们着眼于 18 年的范围,这给了我们每年大约 360 次观察。接下来,为了了解哪些栏目可能是有用的预测指标,我创建了一个关联图,来看看哪些篮球统计数据与 MVP 投票最相关。

Plot of correlation between player season totals and number of first place MVP votes received

第一次尝试的信息并不丰富。上图显示了第一名票数和得分、投篮命中率和罚球命中率之间微弱的正相关关系。这些统计数据本身也是内在相关的(更多的领域目标=更多的点)。这表明得分多会增加你成为 MVP 的几率,但这是一个相当明显的结论。让我们用更高级的数据再试一次。

Plot of correlation between player season advanced stats and number of first place MVP votes received

我们的结果在这里更有趣,表明玩家效率等级(PER)、获胜份额、正负以及对替代玩家(VORP)的价值与收到的投票更密切相关。让我们通过观察过去的 MVP 获得者在这些统计中的排名来进一步形象化这一点。

Plots of VORP vs. PER and BPM vs. WS with MVP recipients shown in red (players with less than 41 games played omitted)

这两幅图用红色显示了 MVP 获得者,清楚地展示了高级统计在捕捉 MVP 级别球员的品质方面的有效性。然而,他们似乎不足以判断获胜者,在这两张图中有几个 MVP 落在了中间位置。

在这个阶段,我在建模之前采取的最后一步是通过将每个统计数据除以该季节的最大值来按季节归一化每个统计数据。也就是说,现在每个统计值都位于(0,1)之间,stat leader 将标杆设置为 1。这主要是为了避免异常低或高的统计数据伤害模型。现在我们终于可以开始建模了。

建模

建立并调整一个模型来预测 NBA MVP

我们从一个简单的逻辑回归模型开始,这个模型使用了球员赛季总数数据集中的一些相关变量和 r。

tot.log <- glm(MVP~G+X3P+DRB+AST+BLK+PF+PTS+Team.Wins,
data=dat_totals,family = binomial(link = "logit"))

为了澄清这里发生了什么,MVP~告诉 R 使用以下所有变量来预测 MVP 得主。family=binomial部分告诉 R 我们打算执行一个简单的(0,1)分类。当我们这样做的时候,让我们也用高级统计数据来拟合一个模型。

adv.log <- glm(MVP~PER+TS.+X3PAr+FTr+TRB.+AST.+STL.+BLK.+
                 TOV.+USG.+WS+BPM+VORP+Team.Wins,
                data=adv.shortlist,family = binomial(link="logit"))

和以前一样,我们传递我们想要预测的变量,后面跟着预测值。现在让我们看看我们的模型有多好。为了衡量模型的性能,我们首先必须使用这些模型进行预测,然后看看这些预测有多准确。为了简化这一点,我在 R 中创建了函数来完成这两项任务,如下所示。

第一个函数对每个球员进行预测,然后找出每个赛季预测赔率最高的球员,授予他 MVP。第二个函数将选择的 MVP 与正确的选择进行比较,并返回精确度。现在让我们测试我们的两个模型的准确性。

Accuracy and error count for total stats and advanced stats models

我们的 total stats 模型报告了 84%的准确率,而 advanced stats 模型只能在大约三分之二的时间里正确预测 MVP 冠军。我很惊讶地看到高级统计模型表现更差,因为在我们的初步分析中,高级统计显示与 MVP 投票有更高的相关性。为了更好地判断这里发生了什么,让我们看看高级统计模型的模型系数。

Model coefficients for advanced stats logistic regression classifier

奇怪的是,模型系数表明更高的 PER 和 BPM 实际上会降低一个球员成为 MVP 的几率。这显然是错误的,所以一定是哪里出错了。让我们通过查看每个赛季的 PER leader 来进行调查。

PER leaders by season

虽然这份名单中肯定有一些像沙奎尔·奥尼尔和勒布朗·詹姆斯这样的名字,但其他人像大卫·温盖特和贾内尔·斯托克斯似乎很突出。幸运的是,这里的问题是显而易见的:游戏和上场时间异常低的玩家放弃了高级的统计计算。

这里简单的解决方法是简单地忽略未能满足最低游戏数的观察结果。这绝对是值得的一步,但我们可以走得更远。为什么要考虑那些根本没有机会获奖的球员呢?通过训练我们的模型让每个球员每个赛季都踏上球场,我们淡化了模型突出精英球员的能力,而是让轮换球员充斥其中。

此时,我决定实现一个两阶段的模型管道。首先,我们确定哪些球员甚至在争夺这个奖项,然后我们预测候选名单中的哪个球员最有可能获得 MVP。由于我们的数据集包含每个玩家获得的投票份额,我们可以很容易地编码一个二进制的Shortlist变量如下。

dat_totals$Shortlist<-dat_totals$Share!=0

然后,我们拟合一个简单的逻辑回归模型,并预测入围的球员。

tot.short.mod <- glm(Shortlist~G+MP+X3P+DRB+AST+
    BLK+TOV+PF+PTS+Team.Wins,
    data=dat_totals,family = binomial(link = "logit"))
## grab shortlist
tot.shortlist<-dat_totals[which(predict(tot.short.mod,type="response")>.75),]

在对高级统计数据集进行了同样的操作后,我们就可以像之前一样进行建模了。让我们看看我们的准确度是否提高了。

Accuracy and error count for total and advanced stats models

我们的两阶段管道似乎是成功的,因为我们的 total stats 模型保持了相同的准确性,而高级模型显著提高了。在这两种情况下,我们每个赛季在近 400 名球员中有 84%的几率正确预测出 NBA MVP。

当然,我们正在犯一个重大的数据科学错误:仅仅根据训练数据来衡量模型性能。我们的模特完全有可能过于合身,对未来几季毫无用处。为了测试这一点,我们必须采用交叉验证。

交叉验证

按季节留一交叉验证(有很多连字符)

虽然通常您可能只是将数据分成训练集和测试集,但在这种情况下会有点棘手,因为我们每个季度只有一个积极的观察结果。删除季节的子集会创建一个太小而无用的测试集。相反,我采用了留一法交叉验证。

为了做到这一点,我必须将每个模型训练 n 次,其中 n 是季节数。每次,从训练集中选出一个季节,并且仅针对该季节进行预测,结果是模型从未看到过其预测数据的每个季节的预测。为了简化这个过程,我编写了一个 R 函数来快速运行这个过程。

有了这个方便的助手功能,我们现在可以交叉验证以前模型的准确性。

Leave-one-out cross-validation error for each model

不出所料,在应用交叉验证后,我们看到了模型准确性的下降。也就是说,我们仍然有一个相当准确的模型,特别是先进的统计数据。但是为什么要在那里定居呢?

在这一阶段,我们拥有适合和测试各种不同模型所需的所有工具。在我寻找理想模型的过程中,我对总统计数据、每场比赛统计数据和高级统计数据以及由总统计数据和高级统计数据组成的合并数据集进行了线性、逻辑和多项式回归。每个模型的结果如下所示。

Accuracy and leave-one-out cross-validation accuracy for each model fit

我们可以看到,在交叉验证后,许多模型的表现非常相似,我们的最高 CV 准确率为 73%,这是由两个不同的模型共享的,两个模型都使用高级统计数据。我们还可以在其他情况下看到过度拟合,例如三次多项式模型,它具有最高的未验证准确性,但一些验证得分最低。

我们值得信赖的逻辑高级统计模型是与最高准确性相关的模型之一,所以让我们坚持使用它。现在是关键时刻了:预测 2019 年 NBA MVP。

预言;预测;预告

预测 2019 NBA MVP

为了预测 2019 年 NBA MVP,我们必须首先加载该年的高级数据。幸运的是,我们已经在数据加载和处理文件中为此准备了一个函数。

一旦数据被加载,我们只需通过我们的两阶段管道运行数据。首先选出前 10 名候选人组成入围名单,预测每个选手的赔率。下面的代码完成所有这些工作,然后将最终预测转换成百分比。

现在剩下要做的就是焦急地看着我们的结果。

MVP prediction results for 2019

最终,我们的模型几乎未能正确预测 2019 年的 MVP 得主:扬尼斯·阿德托昆博,但哈登和詹尼斯之间的预测得分接近,反映了 MVP 比赛实际上有多接近。事实上,詹尼斯获得了大约 35%的投票份额,而哈登达到了近 30%。

我们的候选名单模型也表现得相当好,几乎完美地预测了前 10 名得票数。候选名单中唯一的错误是将凯里·欧文排除在科怀·伦纳德之外。因此,虽然我们没有准确地做出正确的最终预测,但我们的两阶段流水线仍然表现得相当好。

未来的工作

模型改进和数据可视化

虽然我们已经在本文中介绍了大量不同的技术和方法,但是我仍然想探索许多途径来改进这个项目。最明显的一个是使用更复杂的模型。支持向量机或随机森林可能会大大超过我的简单逻辑回归分类器。

我想做的更有雄心的改进是加入社交媒体数据。围绕 MVP 的争论经常围绕着一个拥有优越数据的球员可能会输给一个更强大的媒体叙事(见 2015 年的詹姆斯·哈登或 2011 年的勒布朗)。找到一种量化社交媒体言论的方法可能是探索这个问题的一个有趣途径,也可能改善我们的结果。

最后,这个项目的最终目的是创建一个网站,通过在每场比赛后更新预测来跟踪整个赛季的 MVP 赔率。虽然我已经部分构建了 HTML 界面,但我仍然需要对系统进行编码,以便在每场比赛后使用 NBA API 更新预测。

感谢阅读!请告诉我您是否喜欢这篇文章,以及我是否应该在将来撰写第 2 部分。如果你感兴趣,我的整个代码库都可以在这里找到

利用数据科学为我下次墨西哥之行省钱

原文:https://towardsdatascience.com/using-data-science-to-save-money-on-my-next-trip-to-mexico-1b1b5920535b?source=collection_archive---------15-----------------------

我如何使用基本的数据工作来确保我的旅行价格合理。

我和妻子在阳光明媚的地方度假已经有 4 年了。上次我们度蜜月时,在墨西哥度过了一段美好时光。我们在里维埃拉玛雅一个非常好的全包式度假村度过了 10 天。从那以后,一栋房子,两个孩子,一份新工作和许多其他事情。经过一番思考,我们决定是时候回到海滩上去了。因此,明年 12 月(2019 年),我们(我的妻子,我们 3 岁的孩子,我们 4 个月大的孩子和我)将再次前往里维埃拉玛雅。

别担心,我不会把我的数据博客变成一个旅游和生活博客。我想和你分享一下我是如何确保这次旅行价格合理的。

这就是有趣的地方,当我们今年夏天(6 月)签署合同时,合同说,如果价格下降,我可以,一次,要求价格匹配。因为旅行是在+-6 个月后,这看起来是一个非常有趣的功能。顺便说一句,这是我们选择那家旅游公司的原因之一。坦率地说,我们为整个家庭支付了 4317 加元。

不那么容易的部分

几周后,我回去查看价格。它还是一样的。然后我意识到,我怎么能追踪价格。没有办法我可以花时间去,通过一系列的网络界面点击查询价格。那将意味着一天 2-3 分钟的烦人时间,我真的没有那个时间。

下面是获取价格更新的样子:

The full process of getting the price update.

显然,旅游公司并不认为跟踪价格是一个很好的功能。在搜索了几次之后,没有办法做到这一点。至少用网站上的一个工具。

如果它低于我的原价,我是接受这个价格还是再等一会儿。因为记住,我只能做一次价格匹配。拥有所有历史价格真的很有用,如果/当它低于原价时,我可以观察趋势并做出更明智的决定。

所以现在我需要每天花几分钟获取价格,然后再花几分钟将价格复制到某种电子表格中。任何做过这种事情的人都知道,在最初的几天,甚至几周,这种方法还行。但是在某个时候,你开始错过日期,复制粘贴错误,等等。

手动处理数据或多或少相当于没有处理。

写剧本就行了。

我的想法是,我可以获得 URL,从 python 或其他什么地方下载 HTML,然后用一些 regex 魔术来提取价格。

当然,这不可能那么容易。首先,URL 并没有真正改变。所有价格的东西都是另一页上面的某种模式。所以复制 URL 基本上会把你带回主页。

现在,当我开始查看 Chrome 开发者工具时,我认为我可以在某个地方看到数据。数据必须正确…正确…

在每一个文件中挖掘了几次之后,我找到了金块。

看起来我们走在正确的道路上。我们有一个 JSON 文件和定制的 URL 来获取它。显然,当我在新页面中直接使用这个 URL 时,它不起作用。我收到相当于页面不可用的信息。真的,看起来他们不想让我们这么做。他们设置了许多路障来阻止我们做这件事。谢谢奥巴马。

然后,我在 chrome 开发工具中发现了一个非常简洁的选项。

复制为卷曲。您最终得到一个非常长的命令,可以粘贴到您的终端并获得 JSON。

终于,有东西起作用了。我现在有办法提取价格了。

正如你所看到的,这个查询非常糟糕。真的,就像他们不希望我们自动提取价格一样。至少,现在,我们有一本很好的字典可以使用。

现在如何处理这个值

既然我们可以访问这个值,我们如何提取它。我决定创建一个每 6 小时运行一次的 AWS Lambda 函数来提取价格。以这个价格,一天 4 次,我们做 3 件事:

  1. 我们检查价格是否合理。由于我支付了 4300 多一点,如果价格低于 4 千美元,我给自己发了一封电子邮件。以确保需要时我能迅速行动。
  2. 我将值(带有时间戳)存储在数据库中。(DynamoDB)
  3. 我将该值(带有时间戳)存储在 AWS S3 中

为什么是 2 和 3,我不确定我将如何使用它,因为 AWS 有一些关于什么可以访问什么的规则,而且因为存储非常便宜,我存储了两次。

价格

因此,可悲的是,价格还没有低于 4300 美元,公平地说,我怀疑它会。旅行现在根据天数定价 4700/5000。

为了构建这个视图,我使用了一个叫做 Dash 的神奇工具,它允许你用不到 100 行代码构建这个视图。有兴趣可以去看看这里的 app:https://voyage . coffeeanddata . ca

发现

有几天,我没有收集到任何新的数据点。事实上,cURL 命令从服务器获得了一个 404。我花了一段时间才意识到我没有新数据。

因为我没有在代码中实现任何验证。Lambda 脚本会无声无息地失败,我也不会收集新的数据点。

因此,我在代码中添加了一个验证,当 cookie 需要更新时,它会向我发送一封电子邮件。我假设 cookie 中加密了一些过期信息。因此,简单地获得一个新令牌似乎就足够了。

明智地选择

到目前为止,我从数据中得到的另一个有趣的点是曲线的这一部分:

连续几天,早上 7 点左右,价格飙升了 200 美元。这是我下次预订旅行时会注意的事情。

结论

可悲的是,我没有存下任何钱…到目前为止。我将在两个多月后飞往墨西哥,所以我会继续在我的网站上跟踪价格。旅游公司似乎正在努力阻止我们自动提取价格。

价格看起来很不稳定,我很想知道是什么影响了每小时的价格。

如果你感兴趣,所有的代码都可以在我的 Github 回购:https://github.com/marcolivierarsenault/triptracker

你可以在这里查看我的 web app:https://voyage . coffeeanddata . ca

原载于 2019 年 10 月 28 日https://coffeeanddata . ca

利用数据科学揭露 Twitter 上国家支持的巨魔

原文:https://towardsdatascience.com/using-data-science-to-uncover-state-backed-trolls-on-twitter-dc04dc749d69?source=collection_archive---------14-----------------------

国家运营商在社交媒体上发起的造谣运动已成为对民主的严重威胁。以下是如何用三步法揭开它们的面纱。

面对越来越大的公众和政治压力,脸书和 Twitter 等社交媒体巨头被迫加大对其平台上国家支持的虚假信息活动的打击力度。

FB 已经对来自伊朗和以色列的违规账户采取了行动,而 Twitter 发布了数百万条被认为是俄罗斯、伊朗、委内瑞拉和孟加拉国政府支持的运营商所为的推文

然而,尚不清楚的是这些账户和社交媒体帖子的识别过程。比如说,在新加坡,人们该如何在社交媒体上揭露这些经营者?

我在 General Assembly(新加坡)的最后一个项目中解决了这个问题,当时我参加了一个为期 12 周的数据科学训练营。通过结合使用数据科学技术,我相信以下三个步骤可以用来帮助揭示国家运营商在社交媒体上的工作:

  • 步骤 1:建立巨魔的“数字指纹”——探索性数据分析和可视化可以有效地识别国家运营商的数字踪迹和作案手法。
  • 第二步:建立一个机器学习模型和 web 应用程序,更有效地对可疑的推文/帖子进行分类。
  • 第三步:使用 SHAP 获得模型预测正确或错误的详细信息。这一步的见解可以反馈到第一步,在调查中形成良性循环。

更新—2020 年 9 月

我上传了一份新的报告,内容是关于如何使用一个微调过的 transformer 模型来检测 state troll tweets。详细的笔记本和数据可以在这里找到。可以在这篇文章中找到有关步骤和测试的概述。

重要的事情先来

我的项目专注于 Twitter,尽管我认为这种方法可以广泛应用于 FB 或 Instagram 帖子。这篇文章是对结果的概括,我不会深入研究代码。

我的项目回购可以在这里找到:http://bit.ly/StateTrolls(最好克隆或下载笔记本。它们巨大的文件大小使它们在线加载很痛苦。)

我还开发了一个简单的网络应用程序来检测俄罗斯的国家巨魔,你可以在这里试试:【http://bit.ly/TrollDetector

这个项目中使用的国家支持的推文(Twitter 官方发布)可以在这里下载

背景

那么,这些国家支持的巨魔是谁,他们的目标是什么?迄今为止最知名的肇事者是俄罗斯的互联网研究机构(IRA)及其多年来影响 2016 年美国大选的努力。

对其活动的详细讨论可以占据几个中等篇幅,因此谨慎的做法是在此强调关于这一主题的两个更广泛的报告:

爱尔兰共和军的成功引发了世界各地的效仿行为,包括伊朗、委内瑞拉和孟加拉国的类似行动。在一个全面的解决方案出台之前,这个问题只会变得更糟。

本项目中使用的数据

上面的图表总结了我如何为这个项目收集和筛选数据。

这类项目中的关键挑战一直是建立“地面真相”的困难,也就是说,你如何知道哪些是国家巨魔的推文?在我的案例中,我依赖于 Twitter 官方发布的大量 state troll 推文(Twitter 没有披露其识别这些推文/账户的内部流程)。

我过滤掉了非英语的推文,以及转发,这样分类模型就不会以语言为基础区分推文。这显然是我的项目的一个限制,因为语言和 RTs 是 Twitter 上国家巨魔行为的一个关键方面。

对于真实的推文,我使用 Tweepy从 35 个经过验证的账户中收集了超过 81,500 条推文——包括新闻媒体、像川普和希拉里这样的政治家,以及美国的活跃用户。

清理后的数据被用于建立两个分类模型(稍后将详细介绍),一个用于检测俄罗斯国家巨魔的推文,另一个用于挑选伊朗的推文。每个模型都接受了 50,000 条推文的训练——真实推文/巨魔推文各占一半。这些模型还在看不见的推文测试集上进行了测试,这些推文包含来自俄罗斯、伊朗和委内瑞拉的不同比例的国家巨魔推文。

第一步:建立“数字指纹”

t-SNE plots of samples tweets from 10 troll and real accounts.

国家巨魔可能在幕后运作,但他们的最终目标迫使他们在社交媒体上留下清晰的数字痕迹,正如 10 个巨魔和真实账户的推文的 t-SNE 图(上图)所示。

从我对俄罗斯爱尔兰共和军推文的探索性数据分析来看,很明显,在时间、活动和伪装方式方面有明确的结构模式。虽然一些特征是爱尔兰共和军在 2016 年选举中的目标所独有的,但我认为在 Twitter 这样的开放平台上运作的国家巨魔会留下大致相似的痕迹。

就其本身而言,这些线索都不符合“确凿证据”的条件。但综合来看,它们描绘了一幅相当一致的行为图景。让我们来看看其中的一些关键特征:

1.1 账户创建日期

现在,Twitter 是一个成熟的平台,用户增长正在放缓。它的受欢迎程度在 2009 年达到顶峰,这意味着在美国等成熟市场,新用户注册量的突然激增应该会敲响警钟。

分析俄罗斯巨魔账户的创建日期,很明显,可疑的大多数是在 2014 年创建的。一个勤劳的国有运营商可以通过缓慢地传播他们的账户创建日期来隐藏他们的踪迹。但是人们不应该低估人类马虎的能力。

1.2 真实与国家支持的推文/账户的结构特征

Comparison of number of followers for top state-backed accounts (left), versus the number of accounts they follow (right).

如果你了解社交平台上的用户体验,辨别可疑行为就会变得更容易。在 Twitter 的背景下(以及该平台内容的消防性质),没有一个正常的真实用户会关注成千上万的其他用户,因为那会完全破坏用户体验。

上面的图表显示了我的数据集中前 10 个俄罗斯巨魔账户的关注者数量(左),以及他们关注的可疑的高数量的账户(右)。因此,关注者对关注者的比率是巨魔账户的一个关键迹象。

这种模式与真实用户形成鲜明对比,如下图所示:

来自国家巨魔的推文也大多较短,由大约 11-14 个单词组成,少于 70 个字符。参见我的笔记本,了解与真实 tweets 相比,巨魔 tweets 更详细的结构特征。

1.3:藏在众目睽睽之下

也许俄罗斯国家巨魔最有趣的一面是他们伪装自己的方式——在这种情况下,他们试图伪装成美国当地的新闻机构。看看真实和巨魔推文的主题建模结果之间的相似之处。

“news” is the No 1 most relevant term in the topic models for real tweets (left) versus troll tweets (right).

乍一看,真实和巨魔推文的主题模型看起来如此相似,这似乎很奇怪。为什么“娱乐圈”、“政治”和“纽约”这些无关痛痒的术语会在巨魔推文主题模型的 30 个最相关术语中占据很高的位置?

但是当你从用户的角度考虑它的时候,它是完全有意义的。突发新闻和信息更新是美国人使用 Twitter 的主要方式。

因此,俄罗斯巨魔潜入目标明确的宣传的最佳方式之一是欺骗真实用户,让他们认为巨魔账户是新闻和有用信息的合法来源(可以是体育或娱乐更新)。最终,他们的目标不是用巨魔内容的弹幕淹没普通用户,而是把假的和真的混在一起,这样用户在很长一段时间后就分不清两者了。

关于俄罗斯虚假信息运动的新知识报告称之为“媒体海市蜃楼”。看看下面这组推文。不知情的用户可能不会立即意识到这些是俄罗斯运营商发布的 troll tweets。

显然需要大量的市场调查来补充这些 EDA 技术和图表。例如,只有在了解政治日历的情况下,对特定年份或月份的账户创建量异常激增的洞察才有意义。

但是底线是清楚的:有一种方法可以让这些国家巨魔疯狂。他们的目标和社交平台的开放性将迫使他们留下数字痕迹和独特的行为模式。

在试图使用机器学习模型将可疑的推文与真实的推文区分开来之前,拼凑他们的“数字指纹”是必不可少的第一步。

步骤 2:构建+训练-测试分类器

你能多快把上面的六条推文整理成巨魔和真实推文?600 或 6000 条推文呢?手动识别和分类巨魔推文在大规模应用中并不现实。这就是分类器发挥作用的地方。

您可以构建一个非常复杂的模型,使用从步骤 1 中收集的特征组合以及 tweet 文本的内容来辨别 troll/real tweet。但是这确实会使配套 web 应用程序的构建变得复杂(稍后将详细介绍)。这也使得在步骤 3 中分析单个预测变得更加困难。

出于这些原因,我已经尽可能简单地保持了我的模型的设计。我只使用了 1 个预测值——一个“干净的 tweet”列,其中原始 tweet 文本已被清除标点符号等——而目标列为“bot _ or _ not”(0 表示真实 tweet,1 表示 troll tweets)。

上图总结了笔记本 3.0 中俄罗斯巨魔探测器模型的工作流程,以及笔记本 3.2 中伊朗巨魔探测器模型的工作流程。这是一个简单的过程,包括对原始的英文推文进行标准化的清理,然后通过一个管道进行处理,其中包括一个 CountVectorizer、一个 TFIDF 转换器和一个分类器。

在这个项目中,我选择了更常见的分类器——朴素贝叶斯、逻辑回归和随机森林。您可以选择更复杂的分类器,但是考虑到训练集的大小(50,000 行),完成管道运行所需的时间可能会呈指数增长。

总的来说,逻辑回归模型是我尝试的三个模型中最好的。它拥有最好的 f1 分数——精确度和召回率的平衡——以及最快的平均拟合时间。

让我们从模型 1 开始,它用俄罗斯巨魔推文训练,看看它在 3 个不同的 100 条推文的看不见的测试集上的表现如何,其中巨魔推文的比例从 50%逐渐减少到大约 10%:

L-R: Confusion matrices for Model 1 Vs 3 unseen test sets with 50% Russian troll tweets, 30% troll tweets and 10% troll tweets.

模型 1 出人意料地善于从真实的推文中挑出新的俄罗斯巨魔推文,即使巨魔推文的比例逐渐减少。在整个测试过程中,它的 f1 分数保持在 0.8-0.9 之间。该模型正确地挑选出了绝大多数看不见的 troll 推文,甚至在 90-10 的测试集中获得了 1.0 的完美回忆分数(上图中最右边)。

但它对其他国有运营商的推文有用吗?我用来自伊朗和委内瑞拉的 troll tweets 对 Model 1 进行了测试,结果很糟糕:

L-R: Confusion Matrices for Model 1 Vs unseen test sets with Iranian troll tweets (L) and Venezuelan troll tweets (R).

Model 1 的召回分数在与伊朗和委内瑞拉 troll tweets 的未知测试集的测试中惨败。虽然它继续很好地挑选出美国用户的真实推文,但它未能捕捉到大多数伊朗或委内瑞拉的推文。

这些结果似乎表明,每个国家支持的运营商的工作都非常具体。与其试图建立一个庞大的“全球”模型来捕捉所有的国有运营商,不如建立更小、更灵活的模型来更好地识别特定的国有运营商。

我建立了第二个模型来测试这一论点,这一次是在伊朗巨魔的推文中结合经过验证的美国和国际用户的真实推文来训练模型。以下是类似测试条件下的结果,伊朗巨魔推文的比例从 50%逐渐降低到 14%左右:

L-R: Confusion matrices for Model 2Vs 3 unseen test sets with 50% Iranian troll tweets, 30% troll tweets and 10% troll tweets.

Model 2 的表现也很出色,它能够挑选出以前从未见过的新的伊朗巨魔推文。它的 f1 分数在所有 3 次测试中都高于 0.9。

正如上面的 3 个混淆矩阵所示,该模型非常善于挑选出巨魔推文,在 90-10 的集合中获得了完美的召回分数,它挑选出了所有 14 条巨魔推文,并且在 100 条推文中仅错误分类了 1 条。

结论是显而易见的(尽管在一开始并不完全明显):一个根据特定国家支持的运营商的推文训练的模型不会很好地推广。为了抓住国家巨魔,你需要为他们所在的每个市场量身定制解决方案。

第 2.1 步:使用网络应用程序快速办理登机手续

Go to http://chuachinhon.pythonanywhere.com/ to try out the web app.

抓住这些国家支持的运营商需要团队的努力,并不是每个参与其中的人都有技能通过机器学习模型运行大量可疑的推文。每当你想检查一些潜在的可疑推文时,运行一个模型也是没有效率的。

为此,我开发了一个简单的网络应用——【http://chuachinhon.pythonanywhere.com/】T2——用户只需要输入一条可疑推文的文本,就可以快速检查它是否是俄罗斯巨魔的推文。该应用程序很简单,如果你需要将它们放在 10 个不同国家或市场的团队手中,你可以轻松地构建 10 个不同的版本。

它不会像数据科学家的计算机上的最新模型那样准确,但它可以作为一种快速诊断工具,可以补充第一步中使用的其他工具,以识别 state troll 的数字指纹。

第三步:用 SHAP 分析预测

至少有两种方法可以进一步分析模型的预测,例如通过检查预测的概率或绘制最常出现的关键词的频率。

但这两种方法都无法提供 SHAP 所能提供的粒度水平,即揭示哪些特征促使模型预测一条推文是真实推文还是巨魔推文。SHAP 还可以用于深入了解模型的预测哪里出错了,以及是什么导致了不正确的分类——这是在巨魔更新他们的策略时更新模型的重要洞察。

SHAP 的详细解释,或者说沙普利附加解释,超出了这篇文章的范围。在这个项目的背景下,用几个例子来说明 SHAP 是如何工作的可能更容易。

SHAP 示例 1

这是一条被 Model 1 准确归类为真正的推文的推文:“特朗普在白宫会见中国副总理刘鹤时,可能会宣布峰会日期。”

根据通过的训练数据集的平均模型输出,每个模型都有一个唯一的基值。在这种情况下,模型 1 的基值是 0.4327。

不同的矢量化要素会将模型的预测推向不同的方向。如果最终输出低于基准值,则被归类为真正的 tweet。如果输出高于基本值,它被认为是一个 troll tweet(在我如何在这个项目中标记输出的上下文中)。

在上面的例子中,我们可以看到像“中国”、“峰会”、“总理”这样的事实词推动模型将推文归类为真实的推文,而有趣的是,“特朗普会见”这些词则推动模型向相反的方向发展。

SHAP 实施例 2 和 3

让我们再看两条推文,其中 Model 正确地分类为俄罗斯巨魔推文:“@HillaryClinton # HillaryForPrison”和“@ HillaryClinton 滚蛋”。

在上面的第一条推文中,“hillaryforprison”标签是推动模型将这条推文归类为巨魔推文的最强特征。在第二条推文中,脏话及其与希拉里·克林顿名字的组合是推动模型将其归类为巨魔推文的最强因素。

虽然该模型对美国政治或新闻没有天生的理解,但它已经获得了足够多的真实和虚假推文的例子,能够区分这两组推文。

当然,这种模式可以被巨魔推文打败。让我们看看模型 1 预测错误的一些例子。

SHAP 实施例 4 和 5

俄罗斯巨魔探测器 Model 1 错误地将这条推文归类为巨魔推文(高于基础值),而实际上它是一条真正的推文:“当克林顿被抓到使用她的私人电子邮件服务器时,我在国家安全委员会社区认识的大多数人都很愤怒……”

“生气”、“私人邮件”和“被抓”这些词促使 Model 1 将这条推文归类为巨魔推文——而事实上,这条推文是弗莱彻学院教授、《华盛顿邮报》专栏作家丹·德雷兹纳(Dan Drezner)写的。

Model 1 在面对伊朗巨魔的推文时也多次失败,因为它没有接受过训练。它将这条推文归类为真实的,而实际上它是一条巨魔推文:“西班牙,意大利警告不要投资以色列定居点。”

像新闻标题一样写的简短而真实的推文似乎会绊倒机器学习模型。同样,该模型似乎很难处理稍微复杂一点的推文,比如涉及电子邮件服务器的推文。

我对此的看法很简单:有效识别社交媒体上国家支持的虚假信息活动,需要将人工输入/分析与机器学习和数据分析工具的智能使用很好地结合起来。

对人类来说似乎显而易见的事情,对一台没有地缘政治知识的机器来说可能并非如此,而机器在发现模式方面可能会更有效率,而这需要人类花很长时间来手工整理。

限制

上面的图表总结了我揭露 Twitter 上国家支持的巨魔的方法的一些局限性。从建模的角度来看,语言可能是最棘手的问题。

一方面,您不希望您的 troll 检测器成为一个美化的语言分类器。另一方面,通过只在英语推特上训练模型,你错过了国家支持的巨魔的一个关键特征。

熟悉深度学习技术的数据科学家可能会在这一领域有更好的解决方案。

最大的限制是这个过程完全是反应性和诊断性的。没有办法先发制人的国家巨魔的工作,至少没有公开可用的工具。

这是我第一次尝试将我新生的数据科学技能应用于像在线虚假信息这样的复杂问题。这里和笔记本上的错误都是我的,我欢迎该领域专家的反馈,或者任何一般性的更正。

最后,非常感谢本杰明·辛格尔顿对这个长期遭受折磨的项目的帮助。特别的大声喊出来还要感谢 Susan Li 她出色的 NLP 和 Flask 教程,这对我帮助很大。

以下是该项目的主要资源链接:

Github 回购:【https://github.com/chuachinhon

穆勒报告:《关于俄罗斯干涉 2016 年总统选举的调查报告》

为什么要帮助西雅图 Airbnb 的主人和客人做出更明智的决定?!

原文:https://towardsdatascience.com/using-data-to-help-seattle-airbnb-hosts-and-guests-make-smarter-decisions-39749cc43ae?source=collection_archive---------28-----------------------

Photo by Zhifei Zhou on Unsplash

在任何地方旅行之前,首先想到的问题是住宿。在过去的八年里,Airbnb 证明了它是解决这类旅行问题的最便捷、最便宜的解决方案。它也允许房主通过分享他们的房子来增加他们的收入。

动机:

Airbnb 为短期住宿提供了一个极好的解决方案。但现在是时候利用数据,引导新主机估算更合理的价格,同时实现收入最大化。还有,帮助客人了解哪些住宿因素他们更应该注意,以节省一些钱。西雅图 Airbnb 开放数据可以在这里找到。

我试图集中回答可能对双方都有帮助的问题,因为我们每个人都可以既是主人也是客人。根据 Airbnb 的定价提示,约 60%的主机收入来自物业因素和设施,另外 40%来自全年的需求。所以,我决定应用机器学习和时间序列技术来分析这些关键因素;价格、收入和需求。

利率上升的主要驱动因素是什么?

2016 年的平均挂牌价约为每晚 137 美元。但是它会随着不同的月份和工作日而变化。夏天甚至接近 160 度。西雅图是一个寒冷的地方,由于需求较高,夏季价格较高是有道理的。

西雅图 Airbnb 上列出的周末住宿地点似乎比其他工作日更贵。

因此,时间和市场是主要驱动因素,并应被视为机器学习模型中的回归变量,这在统计上具有重要意义。房屋和公寓是最受欢迎的房产,但价格合理,每晚不到 150 美元。但是,一些功能,如船,阁楼,公寓和联排别墅是昂贵的,很少上市。

为了确定更高评级的驱动因素,我清理、缩放和格式化了数据,为预测分析做好准备,还删除了具有相似性能和多重共线性的变量。然后使用随机森林回归找出最重要的列表特征,以解释是什么导致了价格范围的变化。

随机森林通过测量两个性能指标来选择关键特征,减少节点杂质,提高准确性。所有可能的价格驱动因素都给出了分数。权重越高,列表特征区分价格值的效果越显著。关于随机森林如何排列每个元素的值的细节超出了这个项目的范围。

首先,我拟合了随机森林模型,然后通过调整模型超参数来增强它,以达到最高的精度。

该建议解决方案的结果表明,以下特征有助于在采油树中做出关键决策,并且可以解释价格范围中 90%的变化:

这个回归变量中的基本元素是卧室数量、浴室数量、床位数量、包括的客人数量、评论数量、季节、邻居、取消费用和政策严格性。

一般来说,这些特征可以分为三大类:一个是物业特点,以前的评论,以及季节性和每周的需求,我将在下一部分进行更多的分析。

【2016 年 Airbnb 的需求和价格如何变化?

正如我之前提到的,西雅图从 2016 年 1 月到 2017 年 1 月的平均价格表明,市场是价格范围中的一个重要因素。在夏季,更高的需求导致更高的费率,并在 2016 年初和 2017 年急剧下降。

我分解了每日价格序列,以确定价格趋势和季节性,并了解对 Airbnb 业务至关重要的基于时间的模式。此外,本部分的另一个基本目标是调查是否有可能使用 2016 年的数据确定一个显示未来模式的预测模型。

平均价格有季节性,不是固定不变的。为了检查数据是否满足时间序列预测的平稳性要求,我将数据分成两部分,并比较每组的均值和方差。由于均值和方差差异较大,且差异具有统计学意义;我对这个系列进行了对数变换,使其保持平稳。

自相关图显示了每个滞后时间的价格;它与其过去的值高度相关,并且可以通过使用时间序列技术来预测。但我决定使用 Prophet,而不是经典的统计时间序列方法。

Prophet 是由脸书推出的一种程序,用于基于加法模型预测时间序列数据,其中非线性趋势符合不同的季节性和假日效应。你可以在这里阅读更多关于先知的信息。此外,Prophet 具有易于解释的参数,可以调整这些参数来改进趋势和季节性预测。

在这里,我训练了一个线性趋势的加性回归模型,每周,每天和每年的季节性,考虑了假期的影响。一般来说,我假设我的时间序列有三个主要部分:趋势、季节性和节假日。

成分图显示,周末、夏季和节假日对价格上涨有积极影响。还有,2017 年日均价格会从 137 涨到 150 以上。

在下图中,蓝线代表预测值,而黑点代表每天的实际值。从图中可以看出,该模型似乎可以捕捉季节性,并很好地拟合历史数据,但我建议添加 2017 年和 2018 年的数据集,如果可以验证模型预测能力的话。

Prophet 中趋势变化点和不确定性区间的数量可以调整,以克服过度拟合和欠拟合。

哪些上市更有利可图并带来更多收入?

为了回答这个问题,我定义了一个度量收入的指标,因为原始数据集中没有这样的数据点。我假设主人的收入是通过每晚的价格乘以预定房间的最少次数来估算的。我将所有列出的资产分为两组,一组表现更好,每年带来超过 10000 美元的收入,另一组表现相反。这个阈值可以根据平均收入的分配情况而改变。然后,我比较了顶部和底部上市绩效的具体特征。

结果显示,公寓和房屋带来了更多的收入,但不仅仅是因为价格高,而是因为它们被预订得最多。

下面的条形图比较了不同酒店中表现最佳和表现最差的 5 家酒店的数字汇总。

为了确定哪些因素导致一个列表比其他更有利可图,我应用了不同的分类器梯度推进,逻辑回归,支持向量机和 K 近邻。然后,我调整了梯度增强分类器超参数,以达到更高的精度并克服过度拟合。大约 83%的房源是分类的,收入低于 10000 美元,17%在 2016 年赚得更多。因此,我应用了 SMOTE 等重采样技术,以确保分类器能够捕捉所有不寻常的列表。特性重要图表示,如果一个主机成为超级主机,在一两个小时之间做出响应并增加容纳更多人的能力将比其他人赚更多的钱。

在 520 个低表现者列表中,大约 466 个被该分类器准确预测。ROC 曲线下的面积显示,对于新数据集,对这两组进行分类的模型准确度为 89%。

这个模型可以通过在精确度和召回率之间定义一个更加可释放的折衷来改进。此外,可以使用另一个收入度量或阈值来增强评估度量。

最后,我想说明的是,这个项目是 Udacity 的数据科学纳米学位课程的一部分。如果你对审查代码或改进它感兴趣,我的 Github 的链接是可用的这里

使用深度学习进行基于手指静脉的生物认证

原文:https://towardsdatascience.com/using-deep-learning-for-finger-vein-based-biometric-authentication-3f6601635821?source=collection_archive---------10-----------------------

这个手指静脉识别项目是在 AlgoDeep AI 平台 上完成的。更多详情可以阅读 本文 关于执行这个项目的全过程从研究到部署。AlgoDeep 的首席运营官 鲁迪·德卢亚 a 是这两篇文章的合著者,也是手指静脉识别项目的合作者。

当伊森·亨特在《碟中谍 5》中使用英国首相的生物识别技术解锁红盒子时,你是否惊叹于认证系统?

Retina Scan (images from Mission Impossible 5)

动作和科幻电影中出现了多种生物认证系统,如视网膜扫描仪、虹膜扫描仪、人脸识别、指纹、声音识别,甚至步态识别。生物认证系统是近年来的研究热点。一些解决方案发展迅速,已经应用于现实生活中的安全场景。

生物认证系统

生物认证系统是通过测量个人身体的特定特征或行为来验证个人身份的实时系统。虹膜扫描仪等生物识别设备收集个人的生物识别数据,并将其转换为数字形式。通过使用算法来匹配模式,生物认证系统可以通过将数据与数据库中其他注册的生物数据进行比较来完成识别或验证个人的任务。设计了生物认证系统的两种主要模式,识别或验证,。在识别模式中,输入数据与数据库中所有注册的模式进行比较。系统可以判断这个人是否来自数据库。当处于验证模式时,将生物测定输入数据与一个人的特定模式进行比较。它旨在确定他们是否是同一个人,并防止多人使用同一身份。

基于手指静脉的生物认证系统

Credit to Teiss

然而,正如我们在电影和科幻小说中看到的那样,一些生物认证系统可以被假冒的资源所欺骗。在丹·布朗的小说《天使与魔鬼》中,哈萨辛挖出了列奥纳多的眼睛,偷走了安装在装有视网膜扫描仪的门后的安全反物质。虽然视网膜的生物特征对每个人来说都是独一无二的,但黑客也可以找到破解认证系统的方法。在不同的生物特征中,安全级别也不同。与其他方法相比,我们今天讨论的基于手指静脉的生物认证系统更难被欺骗,因为它只能识别活人皮肤下的独特手指静脉模式。

手指静脉数据的收集

Finger-vein capture device. From the paper [2]

How to capture finger veins [3]

使用特殊的捕获机器来收集手指静脉数据。该捕捉设备主要由近红外光源、透镜、滤光器和图像捕捉设备组成。由于手指静脉隐藏在皮肤之下,可见光无法看到它们。这种捕捉设备使用可以穿过人体组织的近红外光。此外,血红蛋白和黑色素等色素会阻挡近红外光。

使用深度学习进行手指静脉识别

从第一个著名的神经网络 LeNet 识别 10 个手写数字的图像,到更复杂的神经网络在 ImageNet 中对 1000 类图像进行分类,深度神经网络(DNNs),特别是卷积神经网络(CNN)在计算机视觉中的能力是众所周知的。CNN 通常表现良好,甚至优于传统的计算机视觉方法,因为它们非常擅长自动从图像中提取特征。

手指静脉识别可以看作是一个图像分类问题。用 CNN 处理手指静脉识别问题一定很有趣!我们应该如何设计实验来适应生物认证系统的需求?根据以前使用的手指静脉识别方法,其中许多方法进行特征提取,然后计算两个特征之间的距离。根据特征距离的分布来固定阈值。如果距离值高于阈值,则这两个特征不被归类为来自同一个人。否则,如果距离低于阈值,这两个特征被视为来自同一个人。

CNN-based finger-vein recognition system. Image from [3]

手指静脉数据集

一些研究机构提供公开的手指静脉数据集。我们使用的数据集是来自 SDUMLA-HMT 数据库的手指静脉数据集。感谢山东大学文学硕士实验室提供的山东大学文学硕士-HMT 数据库。该数据集注册了 106 个人的手指静脉图像。双手的三个手指,食指、中指和无名指被抓获。每个手指有 6 张图片。因此,总共由 3,816 个图像组成。图像的格式是 320x240 像素大小的“bmp”。

Image from [5]

图像预处理—感兴趣区域(ROI)提取

正如我们从上面的图像中可以观察到的,捕获的图像不仅包含手指,还包含作为捕获机器的背景。提取 ROI 的目的是保存手指部分,去除背景。必须找到上限和下限来获取 ROI。

Image from [6]

我们通过以下步骤建立了我们的 ROI 系统:

  • 将图像裁剪为 240x240 像素
  • 将图像分成两半,并应用过滤器来检测上下边界
  • 仅保留上限和下限之间的区域
  • 做线性拉伸

From left to right: cropping, masking limits, keeping areas and linear stretching

手指静脉识别的迁移学习

通常,在大数据集上提供令人满意的结果的 CNN 模型具有巨大的参数。如果要从零开始训练一个复杂的 CNN 模型,是非常耗时耗资源的。通常,我们没有足够的数据来从头开始训练。我们也应该考虑过度拟合的问题。如果模型太复杂,而我们的数据集又很小,那么它就很有可能过度拟合。

迁移学习就是来解决这个问题的。迁移学习旨在将现有模型(基于大量数据的预训练模型)应用于其他领域或其他类型的任务。例如,我们可以使用在大型猫狗数据集上预先训练的模型来对大象和猴子进行分类,或者对卡通猫狗进行分类。

正如我们可以想象的,将预先训练的模型直接应用到其他领域或其他任务可能不会很好地工作,因为模型在训练时看不到来自该领域的信息。我们通常有两种选择。一方面,预训练的 CNN 模型可以被视为特征提取器。可以通过使用提取的特征作为输入来构建线性分类器。另一方面,经常采用微调的方法对一些高层进行微调。早期图层中的功能更加通用。而后面的层中的特征包含原始数据集的更具体的信息。冻结早期层可以为我们带来许多任务的通用和有用的功能。微调后续图层可以生成更多存在于数据集中的特定要素。

Image from [6]

在我们的案例中,我们尝试微调 VGG-16 预训练模型中的一些后续层。事实证明,当我们从最后一个卷积层进行训练时,我们的结果最好。

手指静脉识别实验

实验主要受本文“使用 NIR 图像传感器的基于卷积神经网络的手指静脉识别”的启发。提出了手指静脉识别的两种情况。第一种情况使用手指静脉图像作为输入。分类器允许对不同的手指进行分类。另一种情况旨在使用不同的图像来分类真实匹配(相同类别的输入和登记的手指静脉图像之间的匹配)和冒名顶替者匹配(不同类别的输入和登记的手指静脉图像之间的匹配)。两种情况都使用预训练的 CNN 模型,并用手指静脉数据集微调该模型。正如我们之前介绍的,生物认证系统有两种可能的模式,识别和验证。实验的第一种情况对应于识别模式,第二种情况对应于验证模式。

进行实验的过程如下:

  • 数据预处理:将数据集分成训练、验证和测试数据集,通过小范围地随机平移和旋转图像来扩充训练集,如果我们考虑 ROI,则将 ROI 应用于三个数据集。(对于第二种情况,区别真实和冒名顶替匹配的图像)。
  • 设置模型:冻结 VGG-16 中的早期图层,仅微调后面的图层。

数据预处理

第一步是分割数据集。SDUMLA-HMT 数据集包含 636 个类(3 个手指* 2 只手* 106 个人)。每个手指是一个类,它由 6 个图像组成。对于我们实现的两种情况,我们使用了不同的分割策略。

对于第一种情况,在开始时,数据集被分成三个数据集,前三个图像用于训练集,第四个图像用于验证集,其余的用于测试集。然而,使用这种分割数据的方法会导致测试集的过度拟合。通过检查错误分类的类的图像,我们观察到一些类的最后两个图像不同于其他四个图像。这意味着训练集和验证集的分布与测试集的分布不对应!在分割数据集之前,我们已经检查了一些类。但是,碰巧我们只检查了图像相似的类。要学习的一个教训:在训练之前,一定要确保验证集和测试集的分布是相同的。

对于第二种情况,数据集被随机分成两半。每个部分现在包含 318 人。第二部分被分成两半,一部分用于验证集,另一部分用于测试集。

接下来,由于每个类别的三个图像不足以训练合格的模型,所以使用数据扩充方法来增加训练集中的图像数量。数据扩充是一种正则化方法。当数据集的大小不足以概括结果时,可以应用数据扩充来生成更多数据并降低过度拟合的风险。一些动作可以增强图像,例如旋转、平移、翻转、亮度修改。在我们的数据扩充方法中,通过轻微的平移、旋转和亮度修改,为训练集中的每个图像生成 12 个图像。

对于第二种情况,生成差异图像以进行真实和冒名顶替者匹配。从训练集的每个类中,选择一个用于注册的图像。对于剩余图像中的每一个,通过减去该图像和来自相同类别的登记图像来计算真实差异图像,并且通过减去该图像和从不同类别中随机选择的登记的一个图像来计算冒名顶替者差异图像。最后,真实差图像和冒名顶替差图像的数量相同。在第二种情况下,该模型引入了一个二元分类器,用于对真实匹配和冒名顶替匹配进行分类。

模型架构

VGG-16. Image from [6]

VGG-16 是一个非常深的卷积神经网络,它有 1.38 亿个参数。这种深度架构的训练需要大规模数据集。然而,我们的训练数据比 ImageNet 小得多。因此,一个预先训练的 VGG-16 模型在我们的数据集上进行了微调。尝试从不同层面进行训练。如果训练更多的早期层,过度拟合的风险将会上升。然而,如果只训练输出层,性能是不令人满意的。最后,选择从最后一个卷积层微调的模型。

结果和分析

进行了许多实验来找出更好的超参数和更好的训练策略。虽然模型还可以进一步改进,但我们目前得到的结果是有希望的。

分类器的结果

我们对两种模型进行了实验。第一个模型是用于识别的多类分类模型。另一个模型是用于验证的二元分类模型。二元分类模型的输入是差异图像。这两个模型都是从预训练的 VGG-16 模型的最后一个卷积层进行微调的。以下结果来自未经 ROI 预处理的模型。我们也对具有 ROI 数据的模型进行了实验,但是我们发现结果不在预期之内。由于我们使用的数据集是低质量的数据集,并且一些 ROI 预处理图像的质量没有保证,因此该模型不能很好地对类别进行分类。

Results of classifiers

生物认证系统的度量

与通过准确性评估的分类模型不同,生物认证系统有其度量标准来衡量认证的质量。三个最常用的指标是错误拒绝率(FRR)、错误接受率(FAR)和等错误率(EER)[11]。

  • 错误拒绝率(FRR): 系统无法检测到输入模式与数据库中匹配模板匹配的概率。它测量被错误拒绝的有效输入的百分比。(#错误剔除样本数/#匹配样本数)
  • 错误接受率(FAR): 系统错误匹配输入模式和数据库中不匹配模板的概率。它衡量被错误接受的无效输入的百分比。(#错误接受的样本数/#不匹配的样本数)
  • 等误差率(EER): 接受和拒绝误差相等的比率。该值表示错误接受的比例等于错误拒绝的比例。相等错误率值越低,生物统计系统的准确度越高。

对于识别模型,FAR、FRR 和 EER 的计算基于图像之间的欧几里德距离。首先,我们计算类内和类间距离来定义阈值范围。距离阈值的跨度在 83 和 2024 之间。然后,绘制一个远 FRR 图来确定能效比。最终的 EER 是 4.1%。

Intra-class and Inter-class distance of the identification model

FAR-FRR plot of the identification model

对于验证模型,如果直接使用欧氏距离作为特征距离的度量,将会导致难以解释的结果。这里的类间和类内距离是相同类的差异图像的距离和不同类的差异图像的距离。很难解释“两个不同图像的距离”的含义。差异图像提供了关于两个图像之间的差异的信息,并且该差异可大可小,这取决于原始图像。因此,差异图像的特征的欧几里德距离在这里似乎不适合作为度量。此外,在二元分类问题中,FAR 和 FRR 是容易估计的。FAR 是 FP(假阳性)/ #匹配样本,FRR 是 FN(假阴性)/#非匹配样本。我们使用预测的概率作为度量,然后计算 FAR 和 FRR。我们得到的误差是 1.9%。

结论

我们知道深度学习方法是数据驱动的。数据质量是获得成功实验结果的关键因素。我们使用的数据集质量不是很好,但结果仍然很有希望。识别模型和验证模型的最终结果都优于参考文献中的结果。与其他模型不同,深度学习方法实现起来很快,构建起来更简单,无需投入太多复杂的功能处理和工程。然而,与其他论文中的一些结果(不总是使用深度学习方法)相比,我们仍然需要在数据预处理、模型架构和超参数选择方面进行改进。

参考资料:

[1]尹一龙,,孙希伟.SDUMLA-HMT:一个多模态生物特征数据库。第六届中国生物识别大会(CCBR,2011 年),LNCS 7098,第 260-268 页,中国,2011 年。

[2]杨国荣,X,殷玉英.基于个性化最佳位图的手指静脉识别.传感器(巴塞尔)。2012.

[3]沙希德、卡希夫和伊德、韩刚和、刘和杨、和库雷希、伊姆兰和古、杰和尹、一龙。手指静脉识别技术的系统综述。信息(瑞士)。2018.

[4]孟,龚,方,张,张.基于卷积神经网络的手指静脉识别.在 MATEC 网络会议 EDP 科学。2017

[5]http://mla.sdu.edu.cn/info/1006/1195.htm 的 HMT 数据库

[6]https://www . analyticsvidhya . com/blog/2017/06/transfer-learning-the-art-of-fine-tuning-a-pre-trained-model/

[7]范道明、朴 YH、阮道泰、权熙、朴韩国。采用近红外图像传感器的非介入式手指静脉识别系统及各种因素下的精度分析。传感器(巴塞尔)。2015.

[8]费格森、马克斯&阿克、罗内&李缇娜、容村& H .劳、金乔。基于卷积神经网络的铸件缺陷自动定位。2017.

[9]西蒙扬,卡伦&齐塞尔曼,安德鲁。用于大规模图像识别的非常深的卷积网络。2014.

[10]洪亨,李明波,朴元淳。基于卷积神经网络的近红外图像传感器手指静脉识别。传感器(巴塞尔)。2017.

[11]生物统计学原理http://www.biometria.sk/en/principles-of-biometrics.html

使用深度学习进行图像类比

原文:https://towardsdatascience.com/using-deep-learning-for-image-analogies-aa2e7d7af337?source=collection_archive---------20-----------------------

我将回答以下问题:

狗对于狼就像猫对于 __?

通过使用经过训练的深度卷积神经网络对照片进行分类。

A dog is to wolf as a cat is to ___ ?

卷积神经网络

我会使用预先训练好的 VGG16 图像分类模型。该模型由一个接一个堆叠的 CNN 层组成,由 max pooling 层连接。网络的输入是 244×244×3 的图像(即图像宽度和长度是 244 像素,3 个通道),在应用所有卷积层之后,我们得到 7×7×512 的阵列。

(diagram taken from deeplearning.ai course by Andrew Ng, “Convolutional Neural Networks”)

在网络的末端,我们有一个额外的展平层、两个完全连接的密集层和一个 softmax 层,它输出图像属于第 I 个标签的概率 P(x∈i),其中 i=1,…,1000(标签数)。

单词嵌入和类推

另一个与语言处理和深度学习相关的概念是单词嵌入。给定一个大的文本语料库,比方说有 100,000 个单词,我们建立一个嵌入或映射,给每个单词一个在 n=500 维的较小空间中的向量。

这种维度的减少给了我们一个单词的紧凑表示。事实上,单词嵌入对许多任务都很有用,包括情感分析、机器翻译,还有单词类比(例如这里的)也就是说,解决一个类比形式的问题“一个男人是国王还是一个女人是 ____?”。特别是,一旦我们有了嵌入,解决类比就非常简单了——我们使用向量空间的结构来应用线性运算。

图像类比

我试图采用使用单词嵌入的概念来解决使用文本的类比,使用预先训练的图像分类模型来解决使用图像的嵌入。想法是使用网络在最后完全连接的层之前,得到一个特征提取地图

这个方法似乎很有效,并为我们的类比提供了一个解决方案:

狗之于狼如同猫之于 猞猁

这也给出了一个不寻常的方法来解决一个单词类比问题,对不对?

下面是代码的概述。我们首先加载 VGG16 模型和图像。

然后,我们以与使用单词嵌入相同的方式解决类比,但是使用我们的 CNN 特征提取图:

这是结果:

我们有将近 50%的可能性得到“山猫”。

总而言之,我们的类比完成得很好!如果你不知道什么是猞猁,这里有一张参考照片:

lynx

使用深度学习来分类具有深度连接的关系状态

原文:https://towardsdatascience.com/using-deep-learning-to-classify-relationship-state-with-deepconnection-227e9124c72?source=collection_archive---------16-----------------------

《PyTorch》中浪漫情侣的形象分类

Model scheme of DeepConnection.

如果最近深度学习的爆发有一个根域,那肯定是计算机视觉,即图像和视频数据的分析。因此,当你在研究深度学习时尝试一些计算机视觉技术并不令人惊讶。长话短说,我和我的搭档( Maximiliane Uhlich )决定将这种形式的深度学习应用于浪漫情侣的图像,因为 Maximiliane 是一名关系研究员和情侣治疗师。具体来说,我们想知道我们是否能准确地分辨出任何一对特定的情侣,在图像或视频中描绘的,在他们的关系中是否幸福?事实证明,我们可以!由于分类准确率接近 97%,我们的最终模型(我们称之为 DeepConnection)能够清楚地区分不幸福和幸福的夫妇。你可以在我们的预印本中阅读完整的故事,以下是我们所做的粗略概述。

对于我们的数据集,我们做了一些网上搜集(使用这个方便的 Python 脚本)快乐的&不快乐的夫妇的图像。最终,我们得到了一个大约 1000 张图片的训练集。这并不多,所以我们调用了数据增强和转移学习的力量来拯救我们。数据扩充,图像方向,色调和强度的微小变化,以及许多其他事情,会阻止你的模型学习一些不相关的联系。例如,如果幸福夫妇的图像平均比不幸福夫妇的图像更明亮,我们不希望我们的模型描绘出这种联系。我们利用了(great) ImgAug 库,并进行大量的数据扩充,以确保我们的模型是健壮的。基本上,在每批的每个图像上,至少应用一部分增强技术。下面您可以看到一个示例性的数据批次,其中相同的图像有 48 次,具有代表性的数据扩充轮廓。

Exemplary batch with data augmentation.

到目前为止,一切顺利。因为我们在这里讨论图像,所以我们决定使用 ResNet 类型的模型作为 DeepConnection 的基础,并在庞大的 ImageNet 数据集上进行了预训练。在对各种图像进行预训练后,这个模型已经学习了许多有用的形状和形式,并通过这种迁移学习取得了领先。顺便说一下,我们所有的模型都在 PyTorch 中,我们使用了 Google Colab 上的免费 GPU 资源进行训练和推理。该基础模型本身已经是分类的良好开端,但我们决定更进一步,将 ResNet-34 基础模型的最后一个自适应池层替换为空间金字塔池层( SPP )。这里,处理后的图像数据被分成不同数量的方块,只有最大值被传递用于进一步分析。这使得该模型能够关注重要的特征,使其对不同的图像尺寸具有鲁棒性,并且不受图像扰动的影响。之后,我们放置了一个幂平均变换( PMT )层,用几个数学函数来变换数据,以引入非线性,并允许 DeepConnection 从数据中捕捉更复杂的关系。这两项增加都提高了我们的分类准确性,我们最终在单独的验证集上获得了大约 97%的准确率。您可以在下面查看 SPP / PMT 和后续分类层的代码。

class SPP(nn.Module):
  def __init__(self):
    super(SPP, self).__init__()

    ## features incoming from ResNet-34 (after SPP/PMT)
    self.lin1 = nn.Linear(2*43520, 100)

    self.relu = nn.ReLU()
    self.bn1 = nn.BatchNorm1d(100)
    self.dp1 = nn.Dropout(0.5)
    self.lin2 = nn.Linear(100, 2)

  def forward(self, x):
    # SPP
    x = spatial_pyramid_pool(x, x.shape[0], [x.shape[2], x.shape[3]], [8, 4, 2, 1])

    # PMT
    x_1 = torch.sign(x)*torch.log(1 + abs(x))
    x_2 = torch.sign(x)*(torch.log(1 + abs(x)))**2
    x = torch.cat((x_1, x_2), dim = 1)

    # fully connected classification part
    x = self.lin1(x)
    x = self.bn1(self.relu(x))

    #1
    x1 = self.lin2(self.dp1(x))
    #2
    x2 = self.lin2(self.dp1(x))
    #3
    x3 = self.lin2(self.dp1(x))
    #4
    x4 = self.lin2(self.dp1(x))
    #5
    x5 = self.lin2(self.dp1(x))
    #6
    x6 = self.lin2(self.dp1(x))
    #7
    x7 = self.lin2(self.dp1(x))
    #8
    x8 = self.lin2(self.dp1(x))

    x = torch.mean(torch.stack([x1, x2, x3, x4, x5, x6, x7, x8]), dim = 0)

    return x

如果你有敏锐的眼睛,你可能已经注意到了最终分类层上的八个变体。看似浪费的计算实际上是相反的。这个概念最近被提出来作为多样本丢失,并且在训练期间极大地加速了收敛。它基本上是防止模型学习虚假关系(过度拟合)和试图不丢弃来自漏失掩码的信息之间的折衷。

我们在项目中做了一些其他的调整,最好在 GitHub 上查看预印本或相关代码以获取更多信息。简单地提几个:我们用混合精度训练模型(使用 Apex 库)来大大降低内存使用,使用早期停止来防止过度拟合,并根据余弦函数学习速率退火。

在达到令人满意的分类精度(相应地具有较高的召回率和精确度)后,我们想知道我们是否可以从 DeepConnection 执行的分类中学习一些东西。因此,我们从事模型解释,并使用一种称为梯度加权类激活映射的技术( Grad-CAM )。基本上,Grad-CAM 采用最终卷积层的输入梯度来确定显著的图像区域,这些区域可以被可视化为原始图像之上的上采样热图。如果你想看看那是什么样子,看看下面的图,然后是 Grad-CAM 代码。

Grad-CAM for all three models, with saliency heatmaps for representative images. Model prediction and confidence are displayed on top of the images.

我们在论文中进一步讨论了这一点,并将其嵌入到现有的心理学研究中,但 DeepConnection 似乎主要集中在面部区域。从研究的角度来看,这很有意义,因为交流和情绪主要通过面部表情来传达。我们还想看看,除了 Grad-CAM 获得的视觉感之外,我们是否可以通过模型解释获得实际特征。为此,我们创建了激活状态图来可视化最终分类层的哪些神经元被任何给定的图像激活。

State-of-activation plot of DeepConnection for representative images. For every neuron in the last layer, its happy and unhappy weights are colored according to the incoming activation. Activation in the bottom right corner are strongly indicative for happy and the top left corner is most relevant for unhappy couples.

与其他模型相比,DeepConnection 还发现了具体的不快乐特征,并且不仅仅使用不快乐特征的缺失作为不快乐的分类。但是需要进一步的研究来将这些特征映射到人类可以理解的方面。我们还在之前模型没有看到的夫妇的视频帧上尝试了 DeepConnection,效果相当好。

总的来说,模型的稳健性是它的一大优势。精确分类适用于同性恋夫妇、有色人种夫妇、图像中有其他人的夫妇、面部不完全可见的夫妇等等。对于图像中出现其他人的情况,DeepConnection 甚至可以识别这些人是否快乐,但仍然将预测集中在这对夫妇本身。

除了进一步的模型解释,下一步将是使用更大的训练数据集,该数据集有可能训练更复杂的模型。将 DeepConnection 用作夫妻治疗师的助手也很有趣,在治疗期间或之后,可以获得关于(拍摄的)夫妻当前关系状态的实时反馈,以供分析。此外,我鼓励你和你的伴侣一起输入你自己的形象,看看 DeepConnection 对你们的关系有什么看法!我很高兴地报告,这至少祝福了我们的关系,所以我想这是一个好的开始!

让我知道你是否有任何想法,如何推进这项工作,或者你希望看到什么添加/改进!

如果你感兴趣的话,这里有预印本GitHub repo 的链接。

使用深度学习通过确保驾驶员的注意力来拯救生命

原文:https://towardsdatascience.com/using-deep-learning-to-save-lives-by-ensuring-drivers-attention-e9ab39c03d07?source=collection_archive---------18-----------------------

现实生活中的卷积神经网络

Photo by melissa mjoen on Unsplash

仅在 2017 年,就有 3166 人在涉及分心司机的机动车事故中丧生。— NHTSA

驾驶机动车本身就是一项复杂的任务。然而,当我们把注意力分散加入其中时,它会变得更加困难,因为道路上的司机缺乏注意力。那么,如果我们能识别司机何时分心呢?这样做将有助于我们发现它,并提醒司机,以防止事故发生!

在这篇文章中,我将使用卷积神经网络来解决检测分心驾驶员的问题,甚至将他们除安全驾驶之外所做的活动分类。这里有一个 Kaggle 内核的链接。

导入库

我使用 Keras 和 Tensorflow 作为后端来创建卷积神经网络,因此,我导入了必要的库。

os.environ[‘KERAS_BACKEND’] = ‘tensorflow’keras后端设置为tensorflowos.environ[‘TF_CPP_MIN_LOG_LEVEL’] = ‘3’隐藏所有 tensorflow 日志。

导入数据集

csv 文件driver_imgs_list.csv包含所有训练图像的列表,以及对人和类名的引用。类名是对图像中的人正在进行的活动类型的引用。

Top 5 rows of the dataframe

图像概述

我决定通过显示每个类的图像来查看图像数据集。由于标签classname不是描述性的,我决定用一张地图给每张图片添加标题。

train文件夹有 10 个文件夹,每个文件夹对应一类图像。我遍历所有文件夹,并从每个文件夹中绘制第一幅图像。使用plt.subplot(5, 2, image_count),我定义将有 10 个图像组成 5 行和 2 列。image_count 定义了从 1 到 10 范围内的图像计数。

Drivers doing different things

构建模型

我将创建一个具有 3 个Conv2D层(每个层后面是MaxPooling2D层)、1 个Flatten层和 3 个Dense层的卷积神经网络。在进行了几次试验并从其他内核中获得线索后,我最终确定了神经元。因为这是一个多类问题,我有最后一个密集层,有 10 个神经元,损失是使用categorical_crossentropy识别的。

Classifier model

创建培训数据

使用ImageDataGenerator,我将增加我可以训练模型的图像数量。此外,我将使用flow_from_directory方法从相应的文件夹中读取对应于每个类的图像,并创建 80%和 20%的训练和验证分割。请注意,我通过将所有值除以 255 来重新调整每张图像。

现在,我将根据这些数据训练模型,并获得验证准确性和损失。

训练模型

fit_generator,我来训练模型。

该模型达到了 97%的验证准确率。

结论

Photo by Maxwell Ridgeway on Unsplash

使用卷积神经网络,我能够以 97% 的准确率识别驾驶员何时分心驾驶。下一步,我们可以通过增加 CNN 的复杂性和层数来进一步改进模型,并实现其对最终输出的影响。

使用深度神经网络进行 YouTube 推荐

原文:https://towardsdatascience.com/using-deep-neural-networks-to-make-youtube-recommendations-dfc0a1a13d1e?source=collection_archive---------7-----------------------

这是 Paul Covington、Jay Adams 和 Emre Sargin 在 2016 年发表的论文《用于 YouTube 推荐的深度神经网络》的概述。

YouTube 拥有业内最大、最先进的推荐系统之一。作为世界领先的网站之一,为了让客户满意,它必须推荐相关视频。YouTube 与其他利用推荐系统的服务(如网飞、Hulu、Spotify)略有不同,因为用户每秒钟向该平台上传数千小时的视频。YouTube 的语料库在不断变化,他们无法控制添加的内容。这就需要一个强大的模型,能够处理不断传入的数据,并实时输出质量建议。下面这个模型就是作者对这种需求的回应。

系统概况

The Recommendation System’s Architecture

他们设计的推荐系统有两个阶段。第一个是用于候选生成的神经网络,而后者用于排序。 候选生成 网络事件取自用户 YouTube 历史。这只能使用协同过滤来提供广泛的个性化。然后,通过标识符(如观看的视频数量、人口统计信息和搜索查询标记)对这些用户进行比较。 排名网 的操作稍有不同。它使用“描述视频和用户的丰富特征集”为每个视频分配一个分数。这种两层系统允许系统处理数百万个视频,但也可以向个人用户提供有意义的内容。

阶段 1:候选人生成

作为分类的建议

作者将推荐系统称为“极端多类分类,其中预测问题变成了对特定视频的准确分类”。在这种情况下,嵌入数据是收集的关于视频的稀疏数据:(即用户、交互、观看时间等……)深度神经网络能够处理这些数据,并使用它来区分视频和用户。为了训练具有数百万个类别(视频)的模型,作者使用数据样本,然后使用权重来校正采样。使用这种技术,他们能够以更少的计算能力获得相似的精度。

模型架构

该模型的灵感来自于一个连续单词包语言模型的架构。神经网络被输入学习到的关于每个视频的高维嵌入,这些视频被组织在固定的词汇表中。

为了跟踪用户观看数据,数据被转换成不同的视频 id 数组,这些数组通过前面提到的视频的嵌入被映射成密集向量表示。然后,使用梯度下降反向传播来学习嵌入信息以及其他模型参数。

管理新数据

在这个具体的例子中,神经网络有几个优点。使用神经网络作为矩阵分解的一般化允许将任意数据(连续的和分类的)容易地添加到模型中,这是该模型由于不断变化的语料库而需要的。

可以通过将搜索查询历史标记为一元词和二元词(指定短语中有多少单词的类别)来使用它。然后对这些见解进行平均,并创建一个相当密集的搜索历史,然后该模型可以使用它来帮助预测用户未来可能喜欢的内容。用户的人口统计特征,这在预测没有观看任何视频的用户时是有帮助的,被改变成二元选项[0,1]。

新鲜度:

作为一个平台,最近的相关内容对 YouTube 至关重要,它有助于保持用户参与和更新,然而,模型通常偏向于根据过去的数据进行预测。为了纠正这一点,他们将训练数据的年龄设置为一个特征,并将其设置为非常接近零(基本上使所有数据都来自同一个时间点)。这有助于模型在训练的最新部分进行优化和预测——在数据末尾进行预测意味着它可能会预测下一个视频,因为它最接近当前,这些视频也仍然与用户相关。

语境:

用户以各种方式使用 YouTube。他们可以直接在网站上观看,也可以观看嵌入在网站或其他社交媒体网站上的视频。该模型使用所有这些信息来收集关于用户的数据,并通过其网络传播这些数据。为了提高性能和避免过度拟合,需要从模型中限制几个与上下文和信息有关的关键见解。其中一个见解是为每个用户创建固定数量的输入,因为如果有无限的输入,那么高容量用户将主导损失函数,并且模型将过度拟合他们的倾向。

这个怎么重要

YouTube 上有各种类型的视频和流派。一些节目有时间顺序,这意味着它们将按顺序观看,而音乐视频通常以该艺术家最受欢迎的歌曲开始,然后用户转向该艺术家较小的利基作品。如果这些推荐受到高流量用户的影响,这可能会中断低流量用户查看其订阅源中的视频的方式。他们可能会错过利基市场或可能不会看到最受欢迎的视频基于行动的较高比率的用户在该空间。

反过来,通过预测用户将要观看的下一个视频,而不是使用历史数据来随机选择使用维持数据的视频,可以获得更多的成功。这种方法有其缺陷,因为它会将未来的数据泄露给模型,从而导致过度拟合。

特性实验:

向试图解决如此重大问题的模型添加质量特性有助于极大地提高准确性和可伸缩性。超过 100 万个视频和 100 万个搜索令牌以小数形式嵌入包中,最多可包含 50 个最近观看的手表和 50 个最近搜索。关键问题是使用这些特性来帮助创建每个用户的每个动作的时间标记。

第二阶段:排名

推荐系统的第二部分涉及视频排名。为了推荐优质内容,YouTube 需要一种方法来确定用户正在观看和欣赏哪些内容。

特色工程

作者观察到,在预测推荐时,之前与一个或多个类似视频的互动非常重要。这很直观,因为如果观众喜欢特定类型的内容,他们可能会观看该细分市场中的许多视频。他们还注意到,来自特定频道的视频对于决定下一步推荐什么也非常重要。另一方面,如果用户被推荐了视频,但忽略了它们——那么下次页面刷新时,视频将会来回移动并改变。作为 YouTube 的用户,我已经经历过很多次了。

其他功能是以典型的机器学习方式设计的。分类变量是一次性编码的,而连续特征是标准化的(神经网络在标准化数据下表现更好),并通过模型学习。在最初的分离之后,模型开始变得复杂。特征被分成单价和多价组,这意味着它们分别贡献单个值或多个值。特征也被分类为印象和查询。印象每秒计算一次,而查询特征每个请求只计算一次。

建模预期观看时间

能吸引观众注意力的视频通常被认为质量较高。为了推荐高质量的视频,需要对模型进行训练,以便它可以预测观众将观看视频的时间。通过预测视频将被观看多长时间,该模型可以对视频进行排名。在它对视频进行排名后,它将能够决定是否推荐该视频。

为了预测观看时间,作者使用了加权逻辑回归。它被加权的原因是只有正面的视频被赋予权重。积极的视频是用户实际上已经点击了视频,这有助于算法只学习用户与之交互的视频。

结论

作者的“深度协同过滤模型能够有效地吸收许多信号,并模拟它们与深度层的交互”,优于 YouTube 之前使用的任何模型。

关键见解:

  • 使用训练样本的年龄作为输入特征消除了对过去的固有偏见,并有助于模型表示流行视频的时间相关行为。
  • 排名是一种更经典的机器学习方法,但深度学习模型优于经典的线性预测模型。
  • 通过用正面例子的观察时间和负面例子的单位加权训练例子来修改逻辑回归,允许更准确地学习赔率。

YouTube、Spotify 和网飞是我生活中的主要玩家。我每天都使用这些服务进行娱乐或教育。我很少在 YouTube 上手动搜索视频,非常依赖他们的推荐系统。学习一个看似简单的概念背后复杂的数学过程让我大开眼界。数据科学每天都在影响着人们的生活,我迫不及待地想要开始。

链接到研究论文:

使用降维来可视化工作极化

原文:https://towardsdatascience.com/using-dimensionality-reduction-to-visualize-job-polarization-cf2a9ceac90e?source=collection_archive---------20-----------------------

PC1 and PC2 extracted from the MDS Embedding using 2003 data. Each point represents a job, and each color represents a job zone. The smaller the job zone, the less education requirement/experience it requires.

在本帖中,我们使用来自美国政府支持的网站 O*NET 的数据,说明了如何使用包括主成分分析(PCA)和多维标度(MDS)在内的降维技术来可视化自 2003 年以来工作活动的两极分化,该网站提供了一组描述工作和员工特征的丰富变量。

让我们简要回顾一下 O*NET 的数据结构,以理解为什么使用降维技术会有用。数据集是围绕每项工作所需的知识、技能、能力和工作活动的不同组合来组织的。它包含了覆盖整个美国经济的近 1000 个职业的数百个标准化和特定职业变量。

为了进行这一分析,我们使用了 2003 年 11 月和 2018 年 8 月的工作活动文件,来比较在这 15 年间不同工作岗位上的活动是如何变化的。有 41 种不同的工作活动,如“处理和移动对象”和“解决冲突和与他人谈判”。在该文件中,为每个职业-活动-规模组合分配一个数据值。一般来说,数据值越高,活动对工作越重要。例如,在 2018 年的文件中(如下面的截图所示),使用“重要性”衡量标准,职务“首席执行官”执行活动“获取信息”的数据值为 4.72。

主成分分析

为了理解在不同工作中执行的工作活动是如何变化的,人们可以随着时间的推移对每项工作分别跟踪这 41 项活动中的每一项,但这可能会很快失控。PCA 可以通过减少我们需要跟踪的活动数量来帮助解决这个问题。具体地,它通过将数据变换到新的坐标系来实现,使得第一坐标(即,第一主分量)表示具有最大数据方差的投影,第二坐标上的第二大方差,等等。

下面的代码使用 scikit-learn 库在 python 中实现了 PCA。它首先标准化特征比例:

from sklearn.decomposition import PCA
from sklearn.preprocessing import StandardScaler#df is the dataframe that contains the value of each of the 41 activities for all jobsx = df.loc[:, features].values
x = StandardScaler().fit_transform(x)pca = PCA(n_components=num_dim)
#num_dim is the number of dimension we want to examine. We set num_dim to be 2.
principalComponents = pca.fit_transform(x)

下图描绘了两个时期的主要组成部分。为了说明需要不同教育水平的工作因其所从事的工作活动而有所不同,我们通过工作所属的工作区对每个工作(由散点图上的点表示)进行了颜色编码。教育是确定工作领域的标准之一,其他标准包括经验和培训。工作区域越高,工作需要的准备就越多。属于工作区 1 的职业有时需要高中文凭,而工作区 5 的职业通常需要研究生学位。

如果两极分化日益加剧,高技能群体和低技能群体从事的活动将会更加不同。这正是我们在比较这两个时期的地块时所看到的。2018 年,相似颜色的工作更紧密地聚集在一起,这表明属于不同区域的工作之间的工作活动几乎没有重叠。实际计算显示,需要较少准备的工作(1 区和 2 区的工作)在 2018 年的 PC1 值比 2003 年大。2003 年,第 4 区(黄色部分)的工作要求相对更高的教育水平,更分散在 x 轴上。相反,在 2018 年,他们大多位于 0 的左侧,这意味着他们更多地聚集在一起。

PC1 and PC2 using PCA, 2003 on the left, 2018 on the right

为了更严格地检验这种模式,我们可以计算不同工作区的工作之间的距离。我们首先确定工作区聚类的质心,然后计算工作区质心之间的距离。2003 年,工作区 1 和 5 之间的距离为 5.7,2018 年增加到 6.7。工作区 1 和 4 之间以及工作区 2 和 5 之间距离也有类似的增加。

解读主成分

PCs 本身没有任何实质意义,因此为了将主成分与工作活动联系起来,我们可以检查 PCs 和工作活动本身之间的标准皮尔逊相关性。对于 2003 年,PC1 与“检查设备、结构或材料”以及其他体力劳动密集型活动的相关性最强。另一方面,PC2 与“处理信息”和“获取信息”等认知活动的相关性最强。

请注意,虽然与 PC1 相关性最高的前 3 项活动在 2003 年和 2018 年都是相同的,但 PC2 却不是这样。对于 PC2 来说,“决策和解决问题”在 2018 年出现,但在 2003 年没有,而“获取信息”在 2003 年出现,但在 2018 年没有。因此,尽管这两个维度捕捉了两个时期类似性质的活动,但它们并不完全相同。

PC1 使用 PCA:

使用 PCA 的 PC2:

多维标度

另一个让研究人员可以看到不同工作岗位之间日益增长的两极分化的方法是 MDS。MDS 试图做的是保持工作之间的成对距离,同时将矩阵投影到更低的维度。MDS 模型的输入是作业之间的距离矩阵,而不是 PCA 中每个作业的数据值。因此,要将职务活动数据转换为适合 MDS 的距离矩阵,我们首先将数据值矩阵乘以它本身。下面的代码说明了这一步,以及距离矩阵在嵌入中的拟合:

from sklearn.manifold import MDS### multiplying the x matrix with itself
t = np.dot(x, np.transpose(x))
mds = MDS(n_components= n_dimension, max_iter=3000, eps=1e-9, random_state=12345,
dissimilarity=”precomputed”, n_jobs=1)
pos = mds.fit(t).embedding_

之后,我们可以像以前一样从 MDS 嵌入空间中数据集的位置提取前两个主分量:

# select the top 2 dimensions of data
clf = PCA(n_components=2)
pos = clf.fit_transform(pos)

与 PCA 分析类似,2018 年的第一个主成分捕捉了“搬运和移动物体”等更为体力劳动密集型的活动。然而,在 2003 年,第一个主成分从以前的 PCA 分析中捕捉到不同类型的活动。与体力劳动密集型活动不同,PC1 与更多的管理活动最相关,例如“制定目标和策略”以及“向他人提供咨询和建议”。这种差异揭示了使用 PCA 时不明显的另一个方面。

PC1 使用 MDS:

使用 MDS 的 PC2:

下图显示了 2003 年(左)和 2018 年(右)MDS 植入的主要组成部分。作为第一印象,不同颜色的工作在 2003 年比 2018 年更加相互混合,这意味着沿着两个主要维度,属于不同工作区的工作之间的活动重叠更多。此外,属于作业区 4 或 5 的作业在 2018 年都没有 PC1 < 0(所有红绿点都位于 PC1 中 0 的左侧)。这两种模式表明,随着时间的推移,每项工作所执行的活动变得更加分散。

PC1 and PC2 using MDS, 2003 on the left, 2018 on the right

总之,这两种方法都说明了需要不同准备程度的工作所执行的工作活动的日益两极分化,但它们也可以揭示数据微妙之处的差异。

使用 Docker & Kubernetes 托管机器学习模型

原文:https://towardsdatascience.com/using-docker-kubernetes-to-host-machine-learning-models-780a501fda49?source=collection_archive---------5-----------------------

Source: https://www.pexels.com/photo/baltic-sea-blue-sea-cargo-ship-container-port-2945314/

第 4 章“生产中的数据科学”节选

Docker 是在云中部署 ML 模型的绝佳工具。如果你想在云中建立一个生产级的部署,AWS 和 GCP 有很多选择。在我正在编写的书的第 4 章中,我将重点放在为模型服务的 ECS 上,但也将在最后探索 Google Kubernetes 引擎。这篇文章省略了关于部署容器的 AWS 部分,但是包括了本章的其余部分。

[## 生产中的数据科学

从初创公司到数万亿美元的公司,数据科学在帮助组织最大化…

leanpub.com](https://leanpub.com/ProductionDataScience)

第 4 章—可重现模型的容器

部署数据科学模型时,能够重现用于培训和服务的相同环境非常重要。在第 2 章中,我们在两个环境中使用了相同的机器,在第 3 章中,我们使用了一个requirements.txt文件来确保用于模型服务的无服务器生态系统与我们的开发环境相匹配。Docker 之类的容器系统提供了一种构建可复制环境的工具,并且它们比虚拟机之类的替代方法要轻得多。

容器的概念是,它是一个隔离的环境,您可以在其中设置执行任务所需的依赖关系。任务可以是执行 ETL 工作、服务 ML 模型、建立 API 或者托管交互式 web 应用程序。容器框架的目标是提供轻量级实例之间的隔离。使用容器框架,您可以指定代码需要的依赖项,并让框架处理管理不同执行环境的跑腿工作。Docker 是容器的事实上的标准,有大量的工具建立在这个平台上。

弹性容器环境(如弹性容器服务器(ECS ))提供了与无服务器功能类似的功能,在这种环境中,您希望从托管数据科学模型中抽象出服务器的概念。关键的区别在于,无服务器生态系统受限于特定的运行时,通常具有内存限制,这使得使用深度学习框架具有挑战性,并且是云特定的。使用 ECS,您负责设置用于服务模型的实例类型,您可以使用服务模型所需的任何语言,并且可以根据需要占用尽可能多的内存。ECS 作为一个专有的 AWS 工具仍然有问题,但是更新的选项,比如 EKS,是建立在开源的可移植的 Kubernetes 之上的。

以下是我见过的一些关于容器的数据科学用例:

  • 可重复的分析:容器提供了一个打包分析的好方法,这样其他团队成员可以在几个月或几年后重新运行你的工作。
  • web 应用程序:在第二章中,我们用 Dash 构建一个交互式 Web 应用程序。容器提供了一种很好的方式来抽象出部署应用程序的托管问题。
  • 模型部署:如果您想要将您的模型公开为一个端点,容器提供了一种将模型应用程序代码从模型服务基础设施中分离出来的好方法。

本章的重点将是最后一个用例。我们将从第 2 章中取出 web 端点,并将应用程序包装在 Docker 容器中。我们将从在 EC2 实例上本地运行容器开始,然后探索使用 ECS 来创建模型的可伸缩、负载平衡和容错的部署。然后我们将展示如何使用 Kubernetes 在 GCP 上实现类似的结果。

既然我们正在探索可扩展的计算环境,那么在使用 ECS 和 GKE 时关注云成本就非常重要。对于 AWS 来说,关注提供了多少 EC2 实例是很有用的,在 GCP 上,计费工具提供了对成本的良好跟踪。关于编排的部分是专门针对 AWS 的,并且使用了一种不能移植到不同云环境的方法。如果 AWS 不适合您的模型部署,可以直接跳到 Kubernetes 一节。

4.1 码头工人

Docker 和其他平台即服务工具提供了一个称为容器的虚拟化概念。容器运行在主机操作系统之上,但是为在容器内运行的代码提供了一个标准化的环境。这种虚拟化方法的关键目标之一是,您可以为目标环境编写代码,任何运行 Docker 的系统都可以运行您的容器。

容器是虚拟机的轻量级替代,虚拟机提供类似的功能。关键的区别在于,容器的运行速度更快,同时提供了与虚拟机相同的隔离级别。另一个好处是容器可以重用其他容器中的层,这使得构建和共享容器变得更快。当您需要在一台机器上运行 Python 运行时或库的冲突版本时,容器是一个很好的解决方案。

使用 docker,您可以创建一个名为 Dockerfile 的文件,用于定义容器的依赖关系。构建 Docker 文件的结果是一个 Docker 映像,它打包了运行一个应用程序所需的所有运行时、库和代码。 Docker 容器是运行应用程序的实例化映像。Docker 的一个有用特性是新图像可以建立在现有图像的基础上。对于我们的模型部署,我们将扩展ubuntu:latest图像。

本节将展示如何在 EC2 实例上设置 Docker,为构建第 2 章中 echo 服务的映像创建 Docker 文件,使用 Docker 构建映像,并运行容器。要在 EC2 实例上安装 Docker,可以使用amazon-linux-extras工具来简化这个过程。下面的命令将安装 Docker,在 EC2 实例上启动服务,并列出正在运行的容器,这将返回一个空列表。

sudo yum install -y python3-pip python3 python3-setuptools
sudo yum update -y
sudo amazon-linux-extras install docker
sudo service docker start
sudo docker ps

我们将部署的应用程序是第 2 章中的 echo 服务。这个服务是一个 Flask 应用程序,它解析 GET 或 POST 中的msg属性,并返回一个 JSON 有效负载,回显所提供的消息。与之前的应用程序的唯一区别是 Flask 应用程序现在运行在端口 80 上,如下面的echo.py片段中的最后一行所示。

*# load Flask* 
import flask
app = **flask.Flask**(__name__)*# define a predict function as an endpoint* 
@**app.route**("/predict", methods=["GET","POST"])
def **predict**():
    data = {"success": False} *# get the request parameters*
    params = flask.request.json
    **if** (params == None):
        params = flask.request.args *# if parameters are found, echo the msg parameter* 
    **if** (params != None):
        data["response"] = **params.get**("msg")
        data["success"] = True *# return a response in json format* 
    return **flask.jsonify**(data)

*# start the flask app, allow remote connections*
**app.run**(host='0.0.0.0', port = 80)

现在我们已经安装了 Docker 和一个我们想要容器化的应用程序,我们需要编写一个 Docker 文件来描述如何构建一个映像。执行该任务的 docker 文件如下面的代码片段所示。第一步是使用FROM命令确定要使用的基本图像。ubuntu映像提供了一个支持apt-get命令的 linux 环境。MAINTAINER命令添加了与图像相关的元数据信息,添加了图像维护者的名字。接下来,使用RUN命令安装 python,设置一个符号链接,并安装 Flask。对于包含许多 Python 库的容器,也可以使用 requirements.txt 文件。Copy命令将我们的脚本插入到映像中,并将文件放在根目录中。最后一个命令指定了执行应用程序所要运行的参数。

FROM ubuntu:latest
MAINTAINER Ben Weber RUN apt-get update \  
  && apt-get install -y python3-pip python3-dev \  
  && cd /usr/local/bin \  
  && ln -s /usr/bin/python3 python \  
  && pip3 install flask  

COPY echo.py echo.py ENTRYPOINT ["python3","echo.py"]

编写 docker 文件后,可以使用 docker 提供的build命令来创建图像。下面代码片段中的第一个命令展示了如何使用文件./Dockerfile构建一个标记为echo_service的图像。第二个命令显示实例上可用的 Docker 图像列表。输出将显示我们用作图像基础的 ubuntu 图像,以及我们新创建的图像。

sudo docker image build -t "echo_service" .
sudo docker images

要将图像作为容器运行,我们可以使用下面代码片段中显示的 run 命令。-d标志指定容器应该作为守护进程运行,即使关闭终端,守护进程也将继续运行。-p标志用于将主机上的端口映射到容器用于通信的端口。如果没有这个设置,我们的容器将无法接收外部连接。ps命令显示了正在运行的容器列表,现在应该包括 echo 服务了。

sudo docker run -d -p 80:80 echo_service
sudo docker ps

为了测试容器,我们可以使用与之前相同的过程,在 web 浏览器中使用 EC2 实例的外部 IP,并将一个msg参数传递给/predict端点。因为我们设置了从主机端口 80 到容器端口 80 的端口映射,所以我们可以通过 open web 直接调用容器。来自 echo 服务容器的调用和结果示例如下所示。

http:**//**34.237.242.46/predict?msg=Hi_from_docker{"response":"Hi_from_docker","success":true}

我们现在已经完成了构建 Docker 映像并在 EC2 实例上将该映像作为容器运行的过程。虽然这种方法确实提供了一种在一台机器上隔离不同服务的解决方案,但是它不提供伸缩性和容错性,而这是生产级模型部署的典型要求。

4.3 的 Kubernetes

谷歌云平台提供了一项名为谷歌 Kubernetes 引擎(GKE)的服务,用于服务 Docker 容器。Kubernetes 是一个容器编排系统,最初由 Google 开发,现在是开源的。这个平台有各种各样的用例,但是我们将把重点放在使用托管 Kubernetes 托管我们的 echo 服务的特定任务上。

使用 Kubernetes 托管 Docker 容器类似于 ECS,第一步是将您的图像保存到 Docker 注册表中,该注册表可以与编排系统交互。这个注册服务的 GCP 版本被称为容器注册。为了将我们的映像从 AWS 上的 EC2 实例发送到 GCP 容器注册中心,我们将再次使用 docker login 命令。为了让这个过程工作,您需要我们在第 1 章中设置的 GCP 凭证 json 文件。下面的代码片段展示了如何将 json 文件传递给 docker login 命令,标记图像以将其上传到注册表,并将图像推送到容器注册表。

cat dsdemo.json | sudo docker login -u _json_key 
                               --password-stdin https:**//**us.gcr.io
sudo docker tag echo_service us.gcr.io/[gcp_account]/echo_service 
sudo docker push us.gcr.io/[gcp_account]/echo_service

您需要用完整的 google 帐户 ID 替换这个脚本中的gcp_acount参数。执行完这些步骤后,echo 服务映像应该在 GCP 控制台的注册表视图下可见,如图 4.8 所示。通常,如果您使用 GCP 来服务模型,很可能您将使用 Google Compute instances 而不是 EC2,但是最好练习不同云平台中的组件之间的接口。

图 4.8:GCP 集装箱登记处的回波图像。

与使用 ECS 所需的所有步骤相比,使用 GKE 托管容器的过程得到了简化。我们将首先使用 GCP 控制台在 Kubernetes 上设置一个容器,然后将服务公开给 open web。要部署 echo 服务容器,请从 GCP 控制台执行以下步骤:

  1. 搜索并选择“Kubernetes 引擎”
  2. 单击“部署容器”
  3. 选择“现有容器图像”
  4. 选择echo_service:latest
  5. 将应用程序命名为“echo-kge”
  6. 单击“部署”

我们现在已经部署了一个 Kubernetes 集群,并准备好为 echo 服务提供服务。在 GKE 上部署 Kubernetes 集群可能需要几分钟的时间。一旦部署完成,您应该会在集群列表下看到 echo 集群,如图 4.9 所示。

图 4.9:通过 Kubernetes 部署的 echo 图像。

要使用该服务,我们需要通过从 GCP 控制台执行以下步骤将集群公开到开放的 web:

  1. 从 GKE 菜单中,选择您的集群
  2. 点击“工作负载”
  3. 选择“echo-gke”工作负载
  4. 选择“操作”选项卡,然后选择“公开”
  5. 对于服务类型,选择“负载平衡器”

执行完这些步骤后,集群将配置一个可以用来调用服务的外部 IP,如图 4.10 所示。GKE 将根据需要自动进行负载平衡和扩展服务,以匹配工作负载。

图 4.10:部署到开放 web 的 echo 服务。

http:**//**35.238.43.63/predict?msg=Hi_from_GKE{"response":"Hi_from_GKE","success":true}

上面的代码片段显示了一个使用该服务的示例。我们能够快速获取 Docker 映像,并使用 GKE 将其部署在 Kubernetes 生态系统中。使用 Kubernetes 来托管 Docker 图像是一件好事,因为它是一个可移植的解决方案,可以跨多个云环境工作,并且被许多开源项目所采用。

4.4 结论

使用容器来确保您的分析和模型在不同的环境中是可重复的是非常有用的。虽然容器有助于保持单个机器上的依赖关系干净,但主要的好处是它们使数据科学家能够编写模型端点,而不用担心容器将如何被托管。这种关注点的分离使得与工程团队合作将模型部署到生产中变得更加容易,或者使用本章中显示的方法,数据和应用科学团队也可以拥有模型到生产中的部署。

服务模型的最佳方法取决于您的部署环境和预期的工作负载。通常,在公司工作时,您会受限于特定的云平台,因为您的模型服务可能需要与云中的其他组件进行交互,例如数据库或云存储。在 AWS 中,托管容器有多种选择,而 GCP 在 GKE 上作为单一解决方案。要问的主要问题是,使用无服务器功能技术还是弹性容器技术来为您的模型提供服务更具成本效益。正确答案将取决于您需要处理的流量、最终用户可以容忍的延迟量以及您需要托管的模型的复杂性。容器化的解决方案非常适合服务于复杂的模型,并确保您可以满足延迟要求,但与无服务器功能相比,可能需要更多的 DevOps 开销。

本·韦伯是 Zynga 的一名杰出的数据科学家。我们正在招聘

使用电子健康记录预测具有门控循环单元的未来诊断代码

原文:https://towardsdatascience.com/using-electronic-health-records-ehr-for-predicting-future-diagnosis-codes-using-gated-recurrent-bcd0de7d7436?source=collection_archive---------9-----------------------

背景:AI 医生的详细综述:通过递归神经网络预测临床事件(Choi et.al 2016)

由:闪耀的拉塞尔-普勒里道林-普勒里

电子病历(EMRs)有时也称为电子健康记录(EHRs ),主要用于以电子方式数字化存储患者健康数据。虽然这些系统的使用在今天似乎很常见,但最显著的是由于 2014 年通过了《经济和临床健康法案卫生信息技术》。美国医疗机构的适应性实施非常缓慢。尽管如此,EMR 电子病历系统现在拥有丰富的纵向患者数据,可以使我们更接近开发以患者为中心的个性化医疗保健解决方案。也就是说,EHR 的数据可能非常杂乱和稀疏。尽管存在这些挑战,但如果利用得当,EHR 数据可以提供关于患者旅程、治疗模式的真实世界数据洞察,预测患者的下一个诊断代码或再入院风险和死亡率等。

截至 2018 年,据报道,仅医疗保健数据就占全球数据产量的 30%左右。因此,众所周知,许多公司和投资者将医疗保健视为下一个重大投资。然而,为了在患者层面提供真正的解决方案,我们需要了解如何利用和处理我们手头的大量数据。为此,本教程将重点讨论如何处理人工智能算法中使用的 EHR 数据。希望有了这种使用模拟数据的洞察力,我们可以让更多的数据科学家和爱好者参与到医疗保健数据的民主化中来,并使 EHR 数据在患者层面上变得可行。

为了这个三部分教程的目的,我们生成了一些人工 EHR 数据来演示 EHR 数据应该如何被处理以用于序列模型。请注意,这些数据与临床无关,仅用于培训目的。

本教程分为以下几个部分:

第一部分:生成人工 EHR 数据

第二部分:预处理人工生成的 EHR 数据

第三部分:艾博士 Pytorch 极简实现

完全实现: 使用快速 AI API

如果你需要快速查看 GRUs 的内部运作,请参见 门控循环单元查看

Github 代码:https://github.com/sparalic/Electronic-Health-Records-GRUs

第 1 部分:生成人工电子健康记录(EHR)数据

病人入院表

此表包含患者入院历史和时间的信息。生成的特征有:

  1. PatientID -永久留在患者身上的唯一标识符
  2. Admission ID -具体到每次就诊
  3. AdmissionStartDate -入院日期和时间
  4. AdmissionEndDate -特定入院 ID 护理后的出院日期和时间

患者诊断表

诊断表非常独特,因为它可以包含同一就诊的多个诊断代码。例如,患者 1 在他/她的第一次就诊(Admission ID :12)期间被诊断患有糖尿病(PrimaryDiagnosisCode :E11.64)。但是,这个代码在后续的访问中也会出现(Admission ID :34,15),这是为什么呢?如果一个病人被诊断出患有不可治愈的疾病,他/她这个代码将会与所有后续的就诊相关联。另一方面,与紧急护理相关的代码会随着PrimaryDiagnosisCode :780.96(头痛)来来去去。

用于将数据从字典解析到数据帧的辅助函数

DataFrame of artificially generated EHR data

为入场 ID 创建一个哈希键

为什么要做这一步?除非您的 EHR 系统对每个就诊患者都有唯一可识别的入院 ID,否则很难将每个患者 ID 与唯一的Admission ID相关联。为了证明这一点,我们特意创建了两位数的Admission ID s,其中一个为两位患者重复(Admission ID : 34)。为了避免这种情况,我们采取了预防措施,创建了一个散列键,它是唯一PatientID的前半部分与患者特定Admission ID的唯一组合。

用假 EHR 数据生成的最终入院和诊断表

Admission table with artificially generated data

Diagnosis table with artificially generated d

将表格写入 csv 文件

第 2 部分:预处理人工生成的 EHR 数据

在本节中,我们将演示如何处理数据,为建模做准备。本教程的目的是详细介绍如何使用 Pytorch 对 EHR 数据进行预处理以用于 RNNs。这篇论文是为数不多的提供代码基础的论文之一,它开始详细研究我们如何建立利用时间模型预测未来临床事件的通用模型。然而,尽管这篇被高度引用的论文是开源的(使用 https://github.com/mp2893/doctorai 的来写),它还是假设了很多关于它的读者。因此,我们在 python 3+中对代码进行了现代化,以方便使用,并提供了每个步骤的详细解释,以允许任何人使用计算机和访问医疗保健数据,开始尝试开发创新的解决方案来解决医疗保健挑战。

重要免责声明:

这个数据集是在本系列的第 1 部分中用两个病人人工创建的,以帮助读者清楚地理解 EHR 数据的基本结构。请注意,每个 EHR 系统都是专为满足特定提供商的需求而设计的,这只是大多数系统中通常包含的数据的一个基本示例。此外,还需要注意的是,本教程是在与您的研究问题相关的所有期望的排除和纳入标准都已执行之后开始的。因此,在这一步,您的数据将会得到充分的整理和清理。

负载数据:快速回顾一下我们在第 1 部分中创建的人工 EHR 数据:

步骤 1:创建患者 id 的映射

在这一步中,我们将创建一个字典,将每个患者与他或她的特定就诊或Admission ID对应起来。

步骤 2:创建映射到每个独特患者的诊断代码并进行访问

该步骤与所有后续步骤一样非常重要,因为将患者的诊断代码保持在正确的就诊顺序非常重要。

步骤 3:将诊断代码嵌入就诊映射患者入院映射

该步骤实质上是将分配给患者的每个代码添加到字典中,其中包含患者入院 id 映射和就诊日期映射visitMap。这使我们能够获得每位患者在每次就诊期间收到的诊断代码列表。

步骤 4a:提取患者 id、就诊日期和诊断

在此步骤中,我们将创建所有诊断代码的列表,然后在步骤 4b 中使用该列表将这些字符串转换为整数以进行建模。

步骤 4b:为每个独特的患者创建每次就诊时分配的独特诊断代码的字典

在这里,我们需要确保代码不仅被转换为整数,而且它们以唯一的顺序保存,即它们被用于每个唯一的患者。

步骤 6:将数据转储到一个 pickled list 列表中

完整脚本

第 3 部分:AI Pytorch 医生最小实现

我们现在将把从本系列的 GRUs 教程第 1 部分中获得的知识应用到一个更大的公开可用的 EHR 数据集。本研究将利用 MIMIC III 电子健康记录(EHR)数据集,该数据集由超过 58,000 例住院病历组成,其中包括 38,645 例成人和 7,875 例新生儿。该数据集收集了 2001 年 6 月至 2012 年 10 月期间在贝斯以色列女执事医疗中心的特护病房住院患者。尽管被去识别,该 EHR 数据集包含关于患者的人口统计学信息、在床边进行的生命体征测量(约 1 次/小时)、实验室测试结果、账单代码、药物、护理人员注释、成像报告和死亡率(住院期间和之后)的信息。使用在(第 1 部分&第 2 部分)中人工生成的数据集上演示的预处理方法,我们将创建一个用于本研究的同伴队列。

模型架构

Doctor AI model architecture

检查 GPU 可用性

这个模型是在支持 GPU 的系统上训练的…强烈推荐。

加载数据

数据预处理数据集将被加载,并按75%:15%:10%比率分成训练、测试和验证集。

填充输入

输入张量用零填充,注意输入被填充以允许 RNN 处理可变长度输入。然后创建一个掩码来提供关于填充的算法信息。注意这可以使用 Pytorch 的实用程序pad_pack_sequence函数来完成。然而,考虑到这个数据集的嵌套性质,编码的输入首先被多对一热编码。这种偏离过程创建了高维稀疏输入,然而该维度随后使用嵌入层被投影到低维空间中。

GRU 级

这个类包含开始计算算法的隐藏状态所需的随机初始化的权重。请注意,在本文中,作者使用了使用 skip-gram 算法生成的嵌入矩阵(W_emb ),这优于该步骤中所示的随机初始化方法。

用于处理两层 GRU 的自定义层

这个类的目的是执行最初的嵌入,然后计算隐藏状态并执行层间的分离。

火车模型

这个模型是 Edward Choi 创建的 Dr.AI 算法的最小实现,而功能性的它需要大量的调整。这将在后续教程中演示。

最终注意事项/后续步骤:

这应该作为启动和运行模型的起始代码。如前所述,需要进行大量的调优,因为这是使用定制类构建的。本教程的第 2 部分展示了本文的完整实现。

参考资料:

  1. 艾医生:通过递归神经网络预测临床事件(【https://arxiv.org/abs/1511.05942】)

利用 Fastai 进行图像分类

原文:https://towardsdatascience.com/using-fastai-for-image-classification-54d2b39511ce?source=collection_archive---------10-----------------------

了解如何使用 fastai 快速构建最先进的图像分类器

我最近偷看了杰瑞米·霍华德关于深度学习的 2019 课程。我以前从未使用过Fastai库,所以我对它的抽象程度感到非常惊讶,它允许你在几分钟内用少得可笑的代码创建最先进的神经网络。在接下来的文章中,我将提供一个关于用Fastai构建 CNN 图像分类器的简短教程,它应该同时作为对我自己的关键概念的有用总结和对新手的清晰概述。

我选择了 Kaggle 的植物幼苗数据集作为示例数据集。

关于 Fastai

如果你还没听说过Fastai,我推荐你看看他们的主页。在他们的使命声明中,他们不仅希望加速和帮助深度学习研究,还希望降低每个人的准入门槛。这句台词来自他们 2017 年 9 月为Fastai推出的PyTorch(来源):

Everybody should be able to use deep learning to solve their problems with no more education than it takes to use a smart phone. Therefore, each year our main research goal is to be able to teach a wider range of deep learning applications, that run faster, and are more accurate, to people with less prerequisites.

即使你看了Fastai的 2019 年课程,你也可以感受到这种雄心,这让我对该领域的发展方向有了良好的感觉。正如在研究中经常发生的那样,知识和工具只对特定的少数人开放。这在深度学习研究中更加明显,你需要强大的 GPU 中的海量 RAM 来解决大量问题(查看这个无关的视频关于 GPU vs CPU)。

此外,现在许多云计算平台都提供了对Fastai的支持,比如 PaperspaceCradleAWS 等等。但是由于这些服务都是要花钱的,我将坚持谷歌最近刚刚宣布的Colaboratory,让你免费使用谷歌的 GPU。是的,零成本!活着真是太不可思议了。

设置 Google Colab

为了避免网上的冗余,请查看由 Manikanta Yadunanda 撰写的这篇中的帖子,快速了解如何使用谷歌合作实验室(Colab)和Fastai。自从这篇介绍写完之后,Google 已经在 Colab 中包含了官方的FastaiPyTorch支持,所以你可能甚至不需要在连接到运行时之后安装它。您可以使用下面的代码行检查是否所有重要的pip包都已安装。如果没有,取消最后一行的注释,用它来为 Python 3.6.x 和 CUDA 9.x 安装FastaiPyTorch

克隆此笔记本

要访问这个笔记本并自己运行计算,您可以直接从我的 GitHub 库导入它。只需进入文件…打开笔记本…,选择 GitHub 选项卡,并在搜索栏中输入“verrannt/Tutorials”。选择‘fastai-plant-sleeves-classification . ipynb’就大功告成了。就这么简单。检查 Colab 是否配置了Fastai支持后,您可以继续数据准备部分。

数据准备

获取数据

由于我们使用 Kaggle 作为我们的数据集供应,您需要一个 Kaggle 帐户来下载数据集。如果你有一个,到你的帐户设置中去,获得一个新的 API 密匙,你可以在 Kaggle CLI 中使用。

以下代码安装 CLI 并注册新的 API 密钥。然后我们下载植物幼苗数据集并解压。确保您位于 fastai 目录的/content 文件夹中。

检查数据

让我们检查数据。我们从 Kaggle 下载并提取的文件夹有 12 个子文件夹,每个子文件夹对应一种类型的幼苗,里面有各自的图像。这些将是我们分类任务的标签。

如果我们打印这些文件夹内容的长度,我们可以看到每个文件夹包含不同数量的图像。差异很大,例如,“松散的丝般弯曲”的图像最多(762),而“普通小麦”的图像最少(253)。我们将在后面看到这是否意味着预测精度的不同。

这将输出以下内容:

No. of labels: 12
-----------------
Small-flowered Cranesbill, 576 files
Common wheat, 253 files
Charlock, 452 files
Sugar beet, 463 files
Maize, 257 files
Black-grass, 309 files
Loose Silky-bent, 762 files
Fat Hen, 538 files
Cleavers, 335 files
Shepherd’s Purse, 274 files
Scentless Mayweed, 607 files
Common Chickweed, 713 files

让我们来看看这些图像。对于 12 个标签中的每一个,我们将随机打印一个幼苗。

好吧,他们看起来很好,很容易区分,除了“松散的丝般弯曲”和“黑草”。这些对网络来说可能更难识别,但是我们会看到的。我们开始吧!

创建 Fastai 模型

我们现在可以使用Fastai库创建 CNN 模型。自从对 v1 进行重大更新以来,它变得更加清晰和一致,因此我们只需要导入我们的度量标准的视觉模块和准确性。

from fastai.vision import *
from fastai.metrics import accuracy

有一个非常好的类来处理与视觉任务的输入图像相关的一切。它被称为[ImageDataBunch](https://docs.fast.ai/vision.data.html#ImageDataBunch),具有不同的功能,以不同的方式将数据呈现给网络。由于我们的图像被放在名称与图像标签相对应的文件夹中,我们将使用ImageDataBunch.from_folder()函数创建一个包含图像数据的对象。这非常有用,可以非常容易地将数据读入我们的模型,稍后您会看到这一点。

更方便的是,Fastai可以自动将我们的数据分成训练集和验证集,所以我们甚至不需要自己创建它们。

我们现在需要的唯一超参数是指向我们数据集的路径变量、输入的大小和每个梯度下降迭代的批量大小。为了简单起见,ImageDataBunch对象会将所有图像缩放到一个尺寸*尺寸的平方图像,除非另有指示。

关于图像大小的一个快速提示:图像越大,CNN 能够从中提取的细节就越多。同时,更大的图像意味着更长的计算时间。同样,你的 GPU 可能会因为批量过大而耗尽内存。如果是这种情况,您可以将批量大小减半。

path = “./plant_seedlings-data/”
size = 224
bs = 64

我们将创建一个名为data的变量,在其中放置ImageDataBunch对象。我们用上面讨论过的from_folder()函数创建这个对象。在获取数据、图像和批次大小的路径中,还需要:

  • 一个名为get_transforms()的函数参数,它在调用时返回可用图像转换的列表。
  • 参数valid_pct,控制将被随机选择在验证集中的图像的百分比
  • 参数flip_vert除了控制水平翻转外,还控制垂直翻转和 90°旋转。(因为我们的植物图像是从上面拍摄的,所以我们可以毫无问题地执行这些操作,这在例如面部数据上是不可行的。)

为了规范化我们对象中的数据,我们简单地在对象上调用normalize()。这里可以使用 ImageNetCIFARMNIST stats 作为模板,如果留空,这个函数将简单地从我们的对象中抓取一批数据,并计算它的统计数据(平均值和标准差)并相应地归一化数据。因为我们将为在 ImageNet 上训练的模型使用 ResNet 架构,所以我们将使用 ImageNet stats。

data.**normalize**(imagenet_stats)

这将输出一个摘要:

ImageDataBunch;

Train: LabelList
y: CategoryList (4432 items)
[Category Small-flowered Cranesbill, Category Small-flowered Cranesbill, Category Small-flowered Cranesbill, Category Small-flowered Cranesbill, Category Small-flowered Cranesbill]...
Path: plant-seedlings-data
x: ImageItemList (4432 items)
[Image (3, 237, 237), Image (3, 497, 497), Image (3, 94, 94), Image (3, 551, 551), Image (3, 246, 246)]...
Path: plant-seedlings-data;

Valid: LabelList
y: CategoryList (1107 items)
[Category Maize, Category Black-grass, Category Common Chickweed, Category Cleavers, Category Charlock]...
Path: plant-seedlings-data
x: ImageItemList (1107 items)
[Image (3, 529, 529), Image (3, 945, 945), Image (3, 171, 171), Image (3, 125, 125), Image (3, 163, 163)]...
Path: plant-seedlings-data;

Test: None

就是这样,两行代码优化了我们的训练数据集,增加了不同种类的转换和规范化!我想请你在这里停一会儿,花一秒钟来欣赏它的美丽。高水平图书馆之美;仅仅两行代码,我们就极大地增加了数据集的多样性。我已经可以听到我丑陋的 batchnorm 代码在垃圾桶里哭泣。

现在剩下的就是创建实际的网络并训练它,这再简单不过了。

Fastai在其视觉模块中为我们提供了一个名为[create_cnn()](https://docs.fast.ai/vision.learner.html#create_cnn)的功能。这个函数创建了一个叫做learner的对象,我们将把它放入一个适当命名的变量中。请注意,我们将 ResNet 架构指定为迁移学习的基础模型。一旦调用,经过训练的架构将通过Fastai API 下载并存储在本地。

我们将使用准确性作为我们的衡量标准。如果您查看文档,您可以看到其他可用指标的列表。定义回调函数ShowGraph只是告诉学习者,无论它做什么,它都应该返回一个图,这对我看模型是否仍在改进非常有用。

learner = **create_cnn**(data, models.resnet18, metrics=[accuracy], callback_fns=ShowGraph)

寻找学习率

我们创建的学习者对象带有一个内置函数,可以为训练找到最佳的学习率或学习率范围。它通过拟合几个时期的模型并保存损失减少最多的学习率来实现这一点。

我们希望选择一个学习率,其损失仍在减少,即我们不希望学习率具有最小损失,而是具有最大斜率。

在下面的图中,存储在我们的学习器记录器对象中,我们可以看到学习率在 0.001 和 0.01 之间的情况。

learner.lr_find()
learner.recorder.plot()

首次拟合和评估

现在让我们用 0.001 到 0.01 之间的学习率来拟合 8 个时期的模型

learner.fit_one_cycle(8, max_lr=slice(1e-3, 1e-2))

看起来已经很好了!在最初几个 1/5 的迭代中,损耗减少了很多,之后会减少,但会持续减少。

让我们看看算法在哪里犯的错误最多:

interpreter = ClassificationInterpretation.from_learner(learner)interpreter.**most_confused**(min_val=2)## OUTPUTS:
[(‘Black-grass’, ‘Loose Silky-bent’, 28),
 (‘Loose Silky-bent’, ‘Black-grass’, 7),
 (‘Shepherd’s Purse’, ‘Scentless Mayweed’, 4)]

这向我们展示了这种算法最常混淆“黑草”和“松丝弯”这两个类别。我们已经在之前展示的样本图像中看到,这些图像看起来最相似,因此这是有意义的。

改进模型

解冻和微调

在我们解冻层并再次学习之前,我们保存权重,以便在我们搞砸的情况下可以返回。

learner.save(‘stage-1’)
#learner.load(‘stage-1’)learner.unfreeze()
learner.fit_one_cycle(12, max_lr=slice(1e-5, 1e-4))

我们将坚持这一点,因为验证错误比测试错误更严重,看起来这种趋势只会增加。如果我们从这一点开始继续训练,模型将开始过度拟合训练数据

干得好,我们成功地为一个定制数据集训练了一个最先进的图像分类器,仅用几行代码就达到了 96.5%的准确率!

来源
【1】Fastai MOOC
【2】Fastai 库
【3】植物幼苗数据集

用 FIPS 形象化情节

原文:https://towardsdatascience.com/using-fips-to-visualize-in-plotly-14fa7a6ddcf0?source=collection_archive---------13-----------------------

最近我和 Plotly 一起做了两个可视化项目,可视化加州每平方英尺的平均租金和全美数据科学家的平均工资。我使用了两种不同的方法在地图上显示数据——地图上的散点图和氯普图。

为什么 Plotly?
Plotly 是 Python 中强大的可视化软件包之一。使用 Plotly 的一个好处是你可以用 Python 生成 d3 图,因为 Plotly 是建立在 d3 之上的。学习 d3 需要很长的时间,但 Plotly 可以帮助消除恼人的时刻,并更专注于理解数据。Plotly 有一个丰富的地图可视化库,并且易于使用。地图是 Plotly 中可以缓解你的挫折感的类型之一。

地图散点图
当数据单位是城市时,在地图上制作散点图是个好主意,所以我选择用这种方法来显示美国各地数据科学家的平均工资,因为平均工资是基于城市的。

制作这个可视化的过程和在 Plotly 中制作散点图差不多,只是背景是一张地图。这意味着数据是基于经度和纬度绘制在地图上的,分别对应于 x 和 y 值。

准备好包含平均工资和城市的数据框后,获取每个城市的经度和纬度,并存储在同一个数据框中。下一步是分配你想要的颜色来区分薪水的高低。最后一步是定义可视化的情节和布局。Plotly 很好,因为你可以去 plotly.graph_objs,在那里你可以找到美国地图的散点图。

Figure 1: Data Scientist H1B Base Salary across the United States

这个可视化引用自官方 Plotly 文档中的例子,你可以在文章底部找到链接。如果你想看看我的代码,你也可以在文章底部找到链接。

地图上的散点图最适合基于城市的可视化数据,并且非常容易中断。如果你尝试在美国地图上可视化数据,这没有问题,因为有大量的非美国地图可用。然而,如果数据集中的城市彼此非常接近,效果就不太好。例如,如果在湾区有太多的数据点,一些点会相互堆叠,观众可能很难发现该区域的差异。

Choropleth Map
在地图上可视化数据的另一种方法是 Choropleth Map。Choropleth 地图是一种基于县的地图,它在地图上填充了县的颜色。看起来是这样的:

Figure 2: Choropleth to visualize average income per farm across the US

choropleth 图的一个优点是数据点不会相互叠加。您可能认为这很难绘制,因为您不能使用经度和纬度在地图上绘制,但是您可以使用 FIPS 来定位县。

FIPS 县代码
FIPS 县代码代表联邦信息处理标准,美国联邦政府为全国各县分配一个编号。Plotly 的 choropleth 地图的一个很好的特点是 Plotly 将 FIPS 县代码作为参数。FIPS 县代码有 5 个数字,前 2 个数字代表州,后 3 个数字代表县。例如,旧金山县的 FIPS 县代码是 06075。06 代表加州,075 代表旧金山。由于 FIPS 县代码是为每个县指定的,所以您不会在 Plotly 中错误的数据上绘制数据。你可以在联邦政府网站上找到 FIPS 县代码的列表,我在这篇文章的底部提供了链接。

Choropleth 地图示例 在我研究生院的一个项目中,我的教授给了我一组来自 Craigslist 的加州租金数据,我决定找出加州每平方英尺租金的中位数。数据集包含少量加州以外的数据,FIPS 的好处是我可以排除没有以 06 开始的 FIPS 的观察值,因为 FIPS 以其他值开始不是加州。

一旦数据准备就绪,您可以从 plotly.figure_factory 导入 create_choropleth,并传递 FIPS、值和颜色来创建 choropleth。我最终的视觉效果是这样的:

Figure 3: Median rent per Square foot by county across California

你也可以在这个图像上找到我的代码。

绘制 choropleth 地图的缺点是我只发现它对美国地图有用。有一次我试图在英国地图上绘制一个 choropleth 地图,但是我找不到任何支持它的包或选项。目前的版本在美国非常适合可视化,但在美国以外的地方就不行了。

我已经提到了 Plotly 支持的两种地图可视化方式——地图上的散点图和 choropleth 地图。这两种地图服务器的地图用途不同,取决于您是要按城市还是按县进行绘图。如果你想按城市绘制数据,你应该在地图上用散点图,并准备好经度和纬度。通过韵文,如果你想按县绘制数据,choropleth 地图是一个好方法,你应该准备好 FIPS 县代码。如果数据集来自联邦政府,很可能 FIPS 县代码已经与数据配对。因此,Plotly 的 choropleth map 是一个方便的软件包,可以可视化来自联邦政府的美国国家数据。

参考
地图上的 Plotly 散点图:
https://plot.ly/python/scatter-plots-on-maps/

FIPS 县来源:
https://www . census . gov/geographies/reference-files/2013/demo/popest/2013-geocodes-all . html

https://www . nrcs . USDA . gov/wps/portal/nrcs/detail/national/home/?cid=nrcs143_013697

我的 Github:
https://github.com/jacquessham

全美工资数据(散点图):
https://github.com/jacquessham/ds_salary_opt

加州各县每平方英尺租金中位数(Choropleth 地图):
https://github.com/jacquessham/california_rent

使用正向选择过滤掉机器学习数据集中不必要的特征

原文:https://towardsdatascience.com/using-forward-selection-to-filter-out-unnecessary-features-in-a-machine-learning-dataset-e36c62431781?source=collection_archive---------22-----------------------

在我们之前的帖子中,我们看到了如何执行反向消除作为一种特征选择算法,从我们的数据集中剔除无关紧要的特征。在这篇文章中,我们将探讨特征选择的下一种方法,即前向选择。你可能已经猜到了,这是逆向淘汰的反义词。但在此之前,请确保您熟悉P 值的概念。

类似于逆向淘汰,即使在这里我们也有几个步骤可以遵循。我们像往常一样一个一个去。但是在进入之前,你需要知道这将是一个比逆向消去法更乏味的工作,因为你必须在这里创建一堆简单的线性回归模型。根据数据集中要素的数量,需要创建的线性回归模型的数量可能会很快增长到一个巨大的数字。记住这一点,让我们开始吧。

第一步

第一步非常类似于逆向淘汰。这里,我们选择一个显著性水平或 P 值。正如你已经知道的,5%的显著性水平或 0.05 的 P 值是常见的。所以让我们坚持下去。

第二步

这是一个非常繁琐的步骤。在第二步中,我们为数据集中的每个要素创建一个简单的回归模型。所以如果有 100 个特征,我们就创建 100 个简单的线性回归模型。因此,根据数据集中要素的数量,这可能会变得非常枯燥和复杂。但这也是这个过程中最重要的一步。一旦我们拟合了所有简单的线性回归模型,我们将计算所有模型的 P 值,并确定具有最低P 值的特征。

第三步

在上一步中,我们确定了具有最低 P 值的要素。我们会将该特性添加到所有其他特性的简单线性回归模型中。所以在第二步,我们有简单的回归模型,每个模型有一个特征。在这一步中,我们将少一个线性回归模型,但每个模型都有两个特征。完成后,我们将再次拟合模型并计算 P 值。

第四步

在这一步中,我们获得了上一步中创建的所有模型的 P 值。我们再次识别具有最低 P 值的特征。我们检查这个最低的 P 值是否小于显著性水平,或者在我们的例子中是 0.05。如果是这样,我们将把这个新特性作为一个特性添加到所有其他模型中。所以基本上,我们用一个新的特性重复步骤 3。我们将继续这个循环,直到我们从模型中得到的最低 P 值不再小于显著性水平。一旦我们到达这个阶段,我们就打破了这个循环。

一旦我们打破了这个循环,我们将得到我们想要的模型,这是我们在打破循环的迭代之前的迭代中创建的模型。让我解释一下。假设我们让循环运行 10 次迭代。在第 10 次迭代中,我们发现最低 P 值大于显著性水平。我们将在这个模型之前考虑模型,这个模型是来自第 9 次迭代的模型。我们不考虑最后一个模型,因为它没有意义,因为 P 值大于 0.05。我希望你能理解。

无论如何,你现在有了你要找的模型。这种向前选择方法的唯一问题是迭代的次数和您最终构建的模型的数量,这很容易变得难以维护和监控。但这是这个过程的必要部分。我希望我解释得够清楚了。请在下面的评论中告诉我是否有任何遗漏,或者你是否需要我做更多的解释。

Twitter 上关注我,了解更多数据科学机器学习,以及通用技术更新。还有,你可以关注我的个人博客

在 SkLearn 中使用 FunctionTransformer 和 Pipeline 预测 Chardonnay 评级

原文:https://towardsdatascience.com/using-functiontransformer-and-pipeline-in-sklearn-to-predict-chardonnay-ratings-9b13fdd6c6fd?source=collection_archive---------7-----------------------

发现管道

学习编码的最大好处之一是,当你发现新概念时,你会掉进无数个兔子洞。我在 DataCamp 上做的一个练习让我接触到了 Scikit-Learn 中的 Pipeline,它让我大吃一惊!管道允许你顺序转换数据,实现 fit() 。做完练习后,我就开始应用我所学到的知识,精心制作了一个管道来清理葡萄酒评论数据集,并预测霞多丽的评级。这是对我在创建管道和预测模型时所经历的过程的深入回顾。我讨论创建特征、应用分类编码器、构建管道和生成预测。完整的代码和 github repo 的链接可以在文章的底部找到:

导入从属关系和数据

数据来源于 Kaggle 上的葡萄酒评论数据集。我已经写了几篇关于探索数据集的文章,并且已经将它存储在一个 SQLite 数据库中。数据仅被部分清理,并且需要被转换,以便可以在机器学习模型中使用。

import numpy as np
import pandas as pd
import sqlite3
import category_encoders as ce
import refrom sklearn.feature_selection import chi2, SelectKBest
from sklearn.model_selection import train_test_split
from sklearn.feature_extraction.text import HashingVectorizerfrom sklearn.pipeline import Pipeline, FeatureUnion
from sklearn.impute import SimpleImputerfrom sklearn import ensemblefrom sklearn.preprocessing import MaxAbsScaler
from sklearn.preprocessing import FunctionTransformerconn = sqlite3.connect('db/wine_data.sqlite')
c = conn.cursor#create Dataframe
df = pd.read_sql("select country  \
                 ,description     \
                 ,rating          \
                 ,price           \
                 ,province        \
                 ,title           \
                 ,winery from wine_data where variety = 'Chardonnay'", conn)
df.head(2)

注意有多少列包含文本数据。

为了在机器学习模型中使用它们,必须使用编码来转换文本。对葡萄酒厂、国家、省份和头衔等分类数据进行编码有几种策略,我将在类别编码器一节中介绍它们。在我对它们进行编码之前,我需要创建一些可能有助于预测模型的特征。

创建新功能

可以进行特征工程来提取数据中潜在的预测质量,并将其作为一列添加到数据集中。我已经创建了一组函数,接收数据帧并输出转换后的数据帧。使用 Scikit Learn 的函数转换器,我可以使用管道中的函数来转换数据帧。我试图使用全局变量让函数动态化。

从标题中提取年份

我想添加的一个特性是在 标题 列中找到的葡萄酒年份。函数 extract_year 接收一个数据帧并返回一个添加了 year 列的数据帧。

def extract_year(dataframe):#set the column name containing the year using a global variable
    global year_column
    years = dataframe[year_column]
    #years.reset_index(inplace=False)
    #years.fillna("", inplace=True)
    l = []
    i = 0 #use for loop to extract the year from each title row
    for year in range(len(dataframe)):
        temp = re.findall(r'\d+', years[i]) 
        res = list(map(int, temp)) 
        try: 
            if len(str(res[0])) == 4:
                l.append(res[0])
            elif len(str(res[0])) != 4:
                l.append(0)
        except:
            l.append(0)
        #print(res[0])
        i+=1
    dataframe['year'] = lreturn dataframe

统计描述中的单词

在浏览数据集时,我注意到评论较短的葡萄酒往往评级较低。正因为如此,我将把描述的字数添加到模型中,看看它是否是一个预测器。我使用一个依赖于名为 word_count_column 的全局变量的函数来指示使用数据帧的哪一列。它接收一个数据帧并返回一个添加了 word_count 列的数据帧。

def word_count(dataframe):
    global word_count_column
    dataframe['word_count'] = dataframe[text].apply(lambda word: len(str(word).split(" ")))
    return dataframe

Data Frame with Added Features

我们可以看到这两个函数工作并产生了所需的数据帧。

添加了这两个数字特性后,就该考虑对列 【国家】职称酒厂 中的分类数据进行编码了。

类别编码器

由于机器学习模型将数字作为输入,因此必须对文本进行转换。用于编码数据的策略会对模型的准确性产生很大影响。为了轻松尝试各种编码策略,我推荐使用与 Scikit Learn 一起工作的类别编码器包

包中可用的类别编码器与 Pipeline 兼容,因为它们是转换器。

pip install category_encoders
OR
conda install -c conda-forge category_encoders

包里有 15 个左右的编码器。我建议在模型管道中尝试这些方法,看看不同的策略如何影响模型的准确性。

尽管它们与 Pipeline 兼容,但我创建了一个函数,这样我就可以传入额外的逻辑。我传入一个数据框和两个全局变量来控制在转换中使用哪个类别和目标列。

# encoder = ce.JamesSteinEncoder(cols=[...]) --maybe 
# encoder = ce.LeaveOneOutEncoder(cols=[...]) --maybe
# encoder = ce.MEstimateEncoder(cols=[...]) --maybe
# encoder = ce.OrdinalEncoder(cols=[...]) --maybe
# encoder = ce.TargetEncoder(cols=[...]) --maybedef category_encode(dataframe):
    global category_columns
    global category_target
    x = dataframe[category_columns]
    y = dataframe[target]
    ce_ord = ce.OrdinalEncoder(cols=category_columns)
    dataframe[category_columns] = ce_ord.fit_transform(x, y)
    return dataframe

Example of Ordinal Encoder

请注意,分类文本列已经转换为数字列。

描述 列可以在模型中使用,但是需要经过不同的转换方法。相反,我将使用一个函数从数据帧中选择数字列,并忽略 描述 列。

get_numeric_data = FunctionTransformer(lambda x: x[numeric], validate=False)

建造管道

管道很棒,因为它们在转换过程中强制执行顺序,使得工作流紧凑且易于理解。这也可以使作品更容易复制。

请记住,pipeline 使用转换器,因此我们需要在函数上使用 FunctionTransformer,以使它们兼容。

创建转换函数

使用 FunctionTransformer,很容易使特征工程和列选择过程中使用的函数与管道兼容。

get_year = FunctionTransformer(extract_year, validate=False)
get_word_count = FunctionTransformer(word_count, validate=False)
get_encoded_text = FunctionTransformer(category_encode, validate=False)
get_numeric_data = FunctionTransformer(lambda x: x[numeric], validate=False)

因为有些函数依赖于索引值,所以我需要创建一个函数来重置索引,以便在将数据分成训练集和测试集之后管道能够正常工作。

def reset_index(dataframe):
    dataframe = dataframe.reset_index(inplace = False)
    return dataframeget_reset_index = FunctionTransformer(reset_index, validate=False)

设置全局变量

我创建的函数使用全局变量而不是硬编码的值,因此它们更容易重用。因此,需要设置所有的全局变量:

year_column = 'title'
word_count_column = 'description'
category_columns = ['country','province','title','winery']
target = 'price'
numeric= ['price', 'year', 'word_count', 'country', 'province', 'title', 'winery']

选择模型

管道可用于选择您想要使用的模型。要了解更多关于建立模型选择渠道的信息,我推荐阅读 Rebecca Vickery 的这篇文章。为了简单起见,我只使用 Scikit Learn 中的梯度提升回归器。

#create Gradient Boosting Regressor model 
model = ensemble.GradientBoostingRegressor(
    n_estimators = 100, #how many decision trees to build
    learning_rate = 0.5, #controls rate at which additional decision trees influes overall prediction
    max_depth = 6, 
    min_samples_split = 21,
    min_samples_leaf = 19, 
    max_features = 0.9,
    loss = 'huber'
)

把它放到管道里

一旦选择了模型,设置了全局变量,并且所有函数都已转换并与管道兼容,就该将这些部分组合在一起了:

pl = Pipeline(memory=None,
    steps=[
        ('reset_index', get_reset_index),
        ('year', get_year),
        ('word_count', get_word_count),
        ('encode', get_encoded_text),
        ('selector', get_numeric_data),
        ('model', model)
    ], verbose=True)

注意,我设置了 Verbose = True。这样打印步骤就完成了。这使得调试过程更加透明。

Verbose = True output

把所有的放在一起

要测试管道,使用列车测试分割来分割数据,并通过管道运行:

features = df.drop(['rating'], axis=1)X = features
y = df['rating']
X_train, X_test, y_train, y_test = train_test_split(X, y
                                                   , test_size = .3
                                                   #, stratify=y
                                                   )
pl.fit(X_train, y_train)
pl.score(X_test, y_test)

Score

完整的代码

import numpy as np
import pandas as pd
import sqlite3
import category_encoders as ce
import refrom sklearn.feature_selection import chi2, SelectKBest
from sklearn.model_selection import train_test_split
from sklearn.feature_extraction.text import HashingVectorizerfrom sklearn.pipeline import Pipeline, FeatureUnion
from sklearn.impute import SimpleImputerfrom sklearn.linear_model import LogisticRegressionfrom sklearn.preprocessing import MaxAbsScaler
from sklearn.preprocessing import FunctionTransformerconn = sqlite3.connect('db/wine_data.sqlite')
c = conn.cursor#create Dataframe
df = pd.read_sql("select country  \
                 ,description     \
                 ,rating          \
                 ,price           \
                 ,province        \
                 ,title           \
                 ,winery from wine_data where variety = 'Chardonnay'", conn)
#df.head(2)def extract_year(dataframe):
    global year_column
    years = dataframe[year_column]
    #years.reset_index(inplace=False)
    #years.fillna("", inplace=True)
    l = []
    i = 0 
    for year in range(len(dataframe)):
        temp = re.findall(r'\d+', years[i]) 
        res = list(map(int, temp)) 
        try: 
            if len(str(res[0])) == 4:
                l.append(res[0])
            elif len(str(res[0])) != 4:
                l.append(0)
        except:
            l.append(0)
        #print(res[0])
        i+=1
    dataframe['year'] = lreturn dataframe
#df = extract_year(df)def word_count(dataframe):
    global word_count_column
    dataframe['word_count'] = dataframe[word_count_column].apply(lambda word: len(str(word).split(" ")))
    return dataframe
# df = word_count(df)
# df.head(3)# encoder = ce.JamesSteinEncoder(cols=[...]) --maybe (best score)
# encoder = ce.LeaveOneOutEncoder(cols=[...]) --maybe
# encoder = ce.MEstimateEncoder(cols=[...]) --maybe (good)
# encoder = ce.OrdinalEncoder(cols=[...]) --maybe
# encoder = ce.TargetEncoder(cols=[...]) --maybeyear_column = 'title'
word_count_column = 'description'
category_columns = ['country','province','title','winery']
target = 'price'
combine_text = ['country','province','title','winery', 'description']
numeric= ['price', 'year', 'word_count','country','province','title','winery']def category_encode(dataframe):
    global category_columns
    global category_target
    x = dataframe[category_columns]
    y = dataframe[target]
    ce_ord = ce.OrdinalEncoder(cols=category_columns)
    dataframe[category_columns] = ce_ord.fit_transform(x, y)
    return dataframe# df = category_encode(df)
# df.head()get_year = FunctionTransformer(extract_year, validate=False)get_word_count = FunctionTransformer(word_count, validate=False)get_encoded_text = FunctionTransformer(category_encode, validate=False)get_numeric_data = FunctionTransformer(lambda x: x[numeric], validate=False)def reset_index(dataframe):
    dataframe = dataframe.reset_index(inplace = False)
    return dataframeget_reset_index = FunctionTransformer(reset_index, validate=False)from sklearn import ensemble 
model = ensemble.GradientBoostingRegressor(
    n_estimators = 100, #how many decision trees to build
    learning_rate = 0.5, #controls rate at which additional decision trees influes overall prediction
    max_depth = 6, 
    min_samples_split = 21,
    min_samples_leaf = 19, 
    max_features = 0.9,
    loss = 'huber'
)pl = Pipeline(memory=None,
    steps=[
        ('reset_index', get_reset_index),
        ('year', get_year),
        ('word_count', get_word_count),
        ('encode', get_encoded_text),
        ('selector', get_numeric_data),
        ('model', model)
    ], verbose=False)features = df.drop(['rating'], axis=1)X = features
y = df['rating']
X_train, X_test, y_train, y_test = train_test_split(X, y
                                                   , test_size = .3
                                                   #, stratify=y
                                                   )
pl.fit(X_train, y_train)pl.score(X_test, y_test)

开源代码库

[## bend game/wine _ rating _ 预测

此时您不能执行该操作。您已使用另一个标签页或窗口登录。您已在另一个选项卡中注销,或者…

github.com](https://github.com/bendgame/wine_rating_predictions)

谢谢大家!

—埃里克·克莱本

在数据科学中使用 Git:独唱大师

原文:https://towardsdatascience.com/using-git-in-data-science-the-solo-master-954577bc9f9a?source=collection_archive---------42-----------------------

The solo tree in Tongva Park, Santa Monica, CA (I took the photo during a lunch break back in 2014)

Git 是一个非常流行的版本控制系统,用于跟踪计算机文件中的变化,并协调多人对这些文件的工作。它在数据科学项目中被很好地用于跟踪代码和维护并行开发。Git 可以以非常复杂的方式使用,但是,对于数据科学家来说,我们可以保持简单。在这篇文章中,如果你是一个“独行侠”,我将介绍主要的用例。

什么是“Solo Master”?

当你使用 GIT 只是为了保护你的代码安全,避免在你的笔记本电脑坏了/被偷了之后变得疯狂,所有的改变都只在“主”分支上。现在你处于“独唱大师”模式。在这种模式下,事情相对容易,主要有六种可能的情况:

Credit. https://vignette.wikia.nocookie.net/character-stats-and-profiles/images/a/a9/Neo_%28BOS%29.png

  1. 一个工作空间,没有出错
  2. 一个工作空间,在“git add”前出错
  3. 一个工作空间,在“git commit”之前出错
  4. 一个工作空间,在“git push”之前出错
  5. 一个工作空间,在“git push”后出错
  6. 多个工作空间

注意。有很多很棒的资源在谈论“什么是 Git”和“Git 的基本概念”,我会参考 Git 官方网站上的“入门— Git 基础

现在我们可以开始一些很酷的项目了!首先,让我们去 Github 创建一个空项目,然后开始在本地笔记本电脑上正确配置它。

Create the Git repository in GitHub

git clone git@github.com:PanWu/git-solo-master.gitcd git-solo-master/git config user.name "Your Name"git config user.email yourname@gmail.com

案例一。一个工作空间,一切正常

这是最理想也是最简单的情况,您需要做的只是在一次提交中添加更多的文件,提交代码,然后推送到远程主分支。在这样的情况下,生活是如此轻松。

echo 'GOOD CODE' > feature_1.pygit add feature_1.pygit commit -m 'add feature'git commit --amend -m 'add one feature'git push origin master# after this, your Git structure will look like following

案例二。一个工作空间,在“git add”前出错

这总是会发生…你开始玩弄你的想法,并在文件中添加了一些草稿代码,然后很快发现这个想法不可行,现在你想重新开始。怎么做呢?幸运的是,如果您没有在新文件上运行任何“git add ”,这是非常容易的。

更多详情请参考“ Git checkout ”。

echo 'BAD CODE' > feature_1.pygit checkout -- feature_1.py# Now, feature_1.py file will contain only "GOOD CODE"

案例三。一个工作空间,在“git commit”之前出错

您认为这个想法可行,添加了一些文件,做了一些更改,做了一些“git add ”,最后,您发现结果不对。现在你想摆脱混乱,回到美好的,正确的,旧的代码。

更多详情,请参见“ Git 复位”。

echo 'BAD CODE' >> feature_1.pyecho 'BAD CODE' > feature_2.pygit add feature_1.py feature_2.pygit resetgit checkout -- feature_1.py# Now, feature_1.py file will contain only "GOOD CODE"# and feature_2.py will be considered as "Untracked files" in the folder

案例四。一个工作空间,在“git push”之前出错

这次你更进一步,不仅你做了“git add ”,而且这个修改花了几个小时,你还做了几个“git commit ”!啊,又一个巨大的错误,怎么办?!

更多详情请参考“ Git 复位”。

# if there is only 1 incorrect "git commit"echo 'BAD CODE' > feature_1.pygit add feature_1.pygit commit -m 'add an unnecessary feature'git reset HEAD~git checkout -- feature_1.py# if there is more than 1 incorrect "git commit"echo 'BAD CODE' >> feature_1.pyecho 'BAD CODE' > feature_2.pygit add feature_1.pygit commit -m 'add first unnecessary feature'git add feature_2.pygit commit -m 'add second unnecessary feature'# now you need to run "git log", find out where the "origin/master"# and "origin/HEAD" points to d317a62a12481a850be4c3cf5bc9a7bf45c094b7# now the "HEAD -> master" is 2 commits ahead of the "origin/HEAD"git loggit reset d317a62a12481a850be4c3cf5bc9a7bf45c094b7git checkout -- feature_1.py# if you run "git log" again, you will see now "HEAD -> master" is the same# as "origin/master"

Git commits history: when you made a mistake and commit into the branch

Git commits history: after you reset the HEAD to the previous “good” commit

案例五。一个工作空间,在“git push”后出错

您将代码推向生产,而其他成员发现这是一个大错误。现在您需要将代码恢复到原来的位置。

更多详情请参见“ Git revert ”。

echo 'BAD CODE' >> feature_1.pyecho 'BAD CODE' > feature_2.pygit add feature_1.py feature_2.pygit commit -m 'add unnecessary features'git push origin mastergit revert HEAD# or first use "git log" to find current head# then run "git revert 66cda7e93661df0c81c8b51fec6eec50cf1e5477"# either way, you need to edit and save the revert messagegit push origin master# now although the master/HEAD gets to where it was, your mistake is forever# recorded in Git system :( so pay attention to your push!

Git commits history: it is recorded on the GitHub server!

Git commits history: after revert, the mistake is no longer there. However, you leave a permanent log in the server.

案例六。多个工作空间

你有两个工作空间,一个在你的笔记本电脑上,一个在你的桌面工作站上。您在一个工作空间开发特征 2,在另一个工作空间开发特征 3。

# SPACE 1git clone git@github.com:PanWu/git-solo-master.gitcd git-solo-master/git config user.name "Your Name"git config user.email yourname@gmail.comecho 'NEW CODE 2' > feature_2.pygit add feature_2.pygit commit -m 'add feature 2'# SPACE 2git clone git@github.com:PanWu/git-solo-master.gitcd git-solo-master/git config user.name "Your Name"git config user.email yourname@gmail.comecho 'NEW CODE 3' > feature_3.pygit add feature_3.pygit commit -m 'add feature 3'# In SPACE 1: we pushed successfullygit push origin master# In SPACE 2: the same cod will failgit push origin master# error: failed to push some refs to 'git@github.com:PanWu/git-solo-master.git'# hint: Updates were rejected because the remote contains work that you do# hint: not have locally. This is usually caused by another repository pushing# hint: to the same ref. You may want to first integrate the remote changes# hint: (e.g., 'git pull ...') before pushing again.# hint: See the 'Note about fast-forwards' in 'git push --help' for details.

现在你看到问题了,解决方法是先用“git pull”。
“Git pull”=“Git fetch”+“Git merge”或“Git fetch”+“Git rebase”
具体参见“ Git pull ”。记住,现在远程分支如下所示

# In SPACE 2# first, pull the current most up-to-date HEADgit pull# this equals "git fetch" + "git merge"# then, edit and save the merge message# you may also try 'git pull --rebase", see what's the differencegit push origin master

现在,只要你在每一个工作空间开发每一个单独的功能,这个过程就不会有问题。这被认为是比在不同的工作空间中处理同一特征更好的做法。因为如果同一个文件在不同的空间被修改,“合并”过程将会有许多冲突,解决这些冲突对“单飞大师”来说是一件大事。

很好,现在在这些简单的案例研究之后,您成为了在数据科学中使用 Git 的真正的“独行侠”。你永远不会丢失任何代码(它会一直被推到云端)或者担心多个工作空间的代码不一致(只要正确使用“git pull”)。

享受使用 Git 吧!

注意。这篇文章最初发布在我的个人博客上,并在 Medium 上转载。

使用 Gitlab 的 CI 进行周期性数据挖掘

原文:https://towardsdatascience.com/using-gitlabs-ci-for-periodic-data-mining-b3cc314ecd85?source=collection_archive---------11-----------------------

用最少的代码和努力无服务器地周期性挖掘新闻门户 RSS 提要

Photo by Patrick Lindenberg on Unsplash

标准数据科学开发流程中最耗时、最困难的阶段之一是创建数据集。在这种情况下,你已经提供了一个数据集 kudos 给你!你刚刚为自己节省了大量的时间和精力。尽管如此,在许多情况下,情况并非如此。事实上,数据挖掘阶段可能是项目时间表中最没有动力的阶段之一。因此,当有简单和容易的技术来挖掘所需的数据时,它总是有利的。

也就是说,在这篇文章中,我将描述 GitLab 的 CI 管道如何用于周期性的数据挖掘工作,而不需要存储桶、VPSes、外部服务器等等。所以,事不宜迟,让我们在教程潜水。

用例

为了实现本教程的价值,我将把这项技术放在一个用例中,这是我正在做的一个附带项目的一部分。更具体地说,我一直在尝试对一个希腊新闻数据集应用一些自然语言处理。因此,我们将使用塞浦路斯新闻门户(【http://www.sigmalive.com】T2)的 RSS 提要来定期获取和存储发布在门户中的新闻文章。

在对该网站的全球 RSS 提要进行了一些初步检查后,发现它返回了最近发表的 25 篇文章。考虑到帖子的频率,每小时拉一次 RSS 提要应该不会错过任何东西。但是即使我们错过了一些,这也不是什么大事。

因此,我需要写一个脚本,让下载并存储来自 RSS feed 的文章,但是一直在后台运行并且每小时触发一次。这些是我的主要要求。

实施前的一些想法

直觉上,当谈到重复的周期性任务时,cron 作业是最常见的事情。一种选择是编写一个 python 脚本,作为 cron 作业每小时下载、存储并执行一次。嗯……看起来很简单,但是我需要确保我的电脑 24/7 都可以上网。不太方便。

或者,我可以从云提供商那里获得一个 VPS,并在那里运行我的 cron 作业。听起来似乎可行,但这需要设置 VPS,在远程文件系统中存储新闻文件,并随着时间的推移维护这一切。另外,我需要支付服务器的费用。

我的懒惰本能坚持认为应该有更简单的方法…

就在那时,我突然想到了!从 DevOps 的角度来看,我可以创建定期运行的 CI 管道!因为我不想托管任何东西,所以我可以免费使用 Gitlab 的托管 CI 平台。此外,在存储新闻方面,我可以将它们作为 CI 作业的工件公开,然后将它们下载到一起进行聚合。鉴于 Gitlab 每月提供 2000 个免费管道小时,它们应该绰绰有余。

使用 GitLab 的 CI 完成这项任务的另一个额外好处是内置的监控和报告。如果任何管道作业失败,将向您的收件箱发送一封电子邮件。多方便啊?

没有云桶,没有 google drive,没有外部服务器。听起来是个不错的计划。让我们继续讨论实现。

但是在开始之前,我假设你已经有一个 GitLab 帐户,并且知道如何使用 Git。你也可以从这里的克隆我的库,直接跳到完整的代码。

履行

为了透明起见,我将使用 Python 3.6.5,但它应该可以在任何 Python 3 版本中工作。

为了获取新闻,我编写了一个 python 脚本,它执行一个普通的 HTTP 请求,解析 XML 并将其保存在一个 JSON 文件中。

事实上,我正在使用 tiny DB(【https://tinydb.readthedocs.io/en/latest/】)一个非常轻量级的 python 包,它在存储中间件之上提供了一个简单而干净的 DB API。(默认情况下,它只是将它们存储在一个 JSON 文件中,这样就可以了)。

以下是脚本源代码:

您可以随意测试代码,但是要确保通过运行以下命令安装了所有附加的依赖项:

pip install requests
pip install tinydb
pip install xmltodict

太好了,现在是时候做些开发工作了。

首先,我们应该将 python 依赖项导出到 Gitlab 作业的 requirements.tx t 文件中:

pip freeze > requirements.txt

任务列表上的下一件事是通过配置 CI 管道。 gitlab-ci.yml 文件:

如果您以前从未见过这些文件,它只是 Gitlab 的一个配置文件,用于了解在每个 CI 管道中执行什么。在上面的配置中,我定义了一个名为“scrape”的阶段(这可以是您喜欢的任何东西),我在执行脚本之前安装 python 需求,最后在“scrape”作业中运行脚本,目录中的所有 JSON 文件都作为工件公开。

让我们把它付诸实践。创建一个新的 GitLab 存储库,并推送我们刚刚创建的文件。这些应该是:

- feed_miner.py
- .gitlab-ci.yml
- requirements.txt

如果您导航回 GitLab 项目页面,CI 作业应该已经开始运行。

更重要的是,在 GitLab 中导航到 CI/CD- > Pipelines 以获得所有作业状态的概述并下载工件:

下载工件并提取内容证实了我们的脚本在 Gitlab 的 runners 上运行得非常好。但是等一下,我们希望它每小时运行一次!为此,我们将使用 GitLab 的 CI 计划。

导航至 CI / CD - >日程并点击新日程

填写描述以及希望作业运行的频率。频率应该是 cron 格式(http://www.nncron.ru/help/EN/working/cron-format.htm)。最后,点击保存管道进度表。

你都准备好了!此时,我们有一个脚本,它下载并存储我们需要的新闻,并且每小时运行一次。

然而,工件在每次作业运行时都会被分割,因此我们需要编写另一个脚本来下载我们所有的 JSON 工件,并将它们聚集在一个数据集中。

聚集工件

因为我们将使用 GitLab 的 API 来下载工件,所以我们需要获得一些初始信息,比如项目的 ID 和 HTTP 请求的访问令牌。

要查找项目 id,只需导航到项目的 GitLab 页面:

要创建新的访问令牌,请从右上角转到您的配置文件设置:

点击访问令牌选项卡,填写令牌名称,点击创建个人访问令牌:

令牌应该显示在页面的顶部。把它保存在某个地方,因为我们在接下来的步骤中会用到它。

有了这些,您可以使用下面的脚本来下载所有工件,将它们提取到一个目录中,并加载到内存中:

确保在运行之前已经替换了 CONFIG 类中的 project-idaccess-token 值。此外,还需要一个额外的进程依赖项,因此您可以继续安装它:

pip install progress

这是本教程最后需要的部分。在等待了几天之后,我运行了我的聚合脚本,我的数据集中已经有 340 个不同的新闻条目了!整洁!

概述

如果您遵循了前几节中的所有步骤,您应该会得到以下文件:

- feed_miner.py
- requirements.txt
- aggregate.py
- .gitlab-ci.yml

其中包括:

  1. 一个将 RSS 提要下载并存储到 json 文件的脚本。
  2. Gitlab CI 配置文件,定义了安装 python 依赖项和运行 miner 脚本的管道。(计划每小时运行一次)
  3. 一个聚合脚本,从成功的作业中下载所有工件,提取它们并读取内存中的所有新闻记录,同时删除重复项。

有了这些,您就可以高枕无忧了,因为数据正在被挖掘并存储在您的 Gitlab 存储库中。一个潜在的改进是创建另一个管道,大约每周运行一次聚合脚本,并创建一个 csv 文件,但是进一步的数据处理完全取决于您。

我希望你喜欢这个教程!你可以在我的 github 库这里找到完整的代码。

使用谷歌趋势数据来利用你的预测模型

原文:https://towardsdatascience.com/using-google-trends-data-to-leverage-your-predictive-model-a56635355e3d?source=collection_archive---------12-----------------------

在预测模型中使用谷歌趋势数据有一些缺陷。本文描述了一种使 Google 趋势数据可用于模型的方法,通过使用 Google 搜索量预测电影成功的实际例子来提供突破性的结果。

自 2006 年发布以来,谷歌趋势成为人们可能想到的任何主题的搜索量的综合信息来源——从 2019 年 10 月加拿大大选的信息内容到美国哪个州对泰勒·斯威夫特更感兴趣以及哪个州更喜欢搜索金·卡戴珊的不太相关的数据。

Source: Google Trends

当然,如果发现如此丰富的数据源,首先想到的是如何在您的模型中利用它。然而,也有一些陷阱:

  1. 一次只能获得 5 个搜索词的数据
  2. Google Trends 对数据进行了缩放,使其对用户而言具有可比性,但对模型而言则不具可比性
  3. 即使你能够以一种无标度的方式得到每一个搜索词,由于搜索词的模糊性,它仍然可能是有偏见的

尽管如此,在我的研究生课程期间,我从事了一个项目,该项目需要使用谷歌趋势数据来预测电影在首映周末的成功。我们和一名同学一起开发了一种方法,使数据变得可用,并将其输入到模型中。遗憾的是,我一直没有抽出时间来重构代码,放到 github 上。直到现在。该项目的 R 代码可在此处找到,并且将参照该项目描述使 Google Trends 数据可用于任何类型的预测模型的一般方法

我们收到了一个约 900 部电影的数据集,其中包含类型、评级、制片厂等信息,当然还有首映周末的观影人数。受谷歌自己发布的白皮书的启发,我们试图从谷歌趋势收集数据,以将搜索量纳入我们的预测模型。在谷歌搜索上捕捉 900 部电影的流行度是一项艰巨的任务,主要是由于 3 个事实。首先,一次只能提取 5 个搜索词的数据。这个问题可以很容易地通过分块搜索词来解决。然而,这导致了块之间不可比的结果。其次,电影名称并不总是模糊的,这意味着搜索 【被解放的姜戈】 几乎肯定会将你带到与塔伦蒂诺电影相关的结果,而搜索像 希区柯克 这样的传记电影可能会导致关于导演本身的网页。第三,谷歌上的搜索词的搜索量信息不是以可评估的形式公开提供的,这意味着谷歌趋势只提供自然数,从而在观察的时间和地理框架中的最大相对值被缩放到 100,这使得不可能将像 《星球大战——原力觉醒》 这样的电影与像 《头号通缉犯》 这样的独立电影进行比较,因为《头号通缉犯》的量即使不总是被缩放,也大多会被缩放因此,使谷歌趋势数据可用于预测模型的主要任务有三个方面:

  1. 获取所有感兴趣的搜索词的可比数据
  2. 从艺术电影到大片,将数据换算成所有电影的真实值
  3. 确保所提供的请求仅涉及电影

为了获得捕捉人们对电影的兴趣的 KPI,定义了 3 个可能的搜索词的线性组合。这些搜索词分别是电影主标题(如《霍比特人》)、电影主标题+后缀电影(德语为电影)和完整标题(如 《霍比特人:意外之旅》 )。根据谷歌发表的这篇文章,搜索词的绝对搜索量除以给定时间和地理范围内的总搜索量。

对讲故事最有用的是我们的标准化趋势数据。这意味着,当我们查看一段时间内对某个主题的搜索兴趣时,我们会将该兴趣视为在该时间和地点谷歌上对所有主题的所有搜索的比例。当我们查看某个主题的区域搜索兴趣时,我们是在查看某个给定区域中该主题的搜索兴趣占同一时间同一地点谷歌上所有主题的所有搜索的比例。

在此之后,数据被归一化到从 0 到 100 的自然数范围,由此五个转换的查询结果的相对最大值被缩放到 100。

我们的数据背景也很重要。我们将数据索引为 100,其中 100 是所选时间和地点的最大搜索兴趣。

这导致不可比的值,使得预测不可行。

Google Trends data for the search terms Django Unchained, A most wanted Man, Mama and Star Wars. Vertical lines mark the premiere date of each movie.

上面的图显示了电影星球大战——原力觉醒被解放的姜戈、 妈妈通缉犯 的谷歌趋势数据。垂直线标志着这些电影的首映日期。显而易见,《星球大战》甚至远远超过了像《被解放的姜戈》这样的大片。相比之下,Mama(德语中妈妈的意思)的得分稳定在 5 分左右,仅在所谓的电影首映前几周略有上升。《头号通缉犯》即使在首映周也是定值 0,因此根本没有可比性。首映前 6 周的搜索词的确切数据如下:

Search volume for the movies 6 weeks prior premiere date t

表格中的最后一行显示了首映周末在时间 t. 的搜索量和实际访客数量之间的相关性。相关性本身已经非常高了,但是特别是和头号通缉犯的数量根本不能用于预测,而的数量似乎有很大偏差。

好吧,但是如何克服这些问题呢?让我们解决一个又一个问题。首先,让我们将数据相互比较,得到真实值而不是自然数,以便得到可用的数据,即使是对一个头号通缉犯。我们可以通过引入锚定条款计划来实现这一点。这背后的想法是为每个搜索词的创建一个到单个值的关系。为此,我们需要定义一个锚项列表,其搜索量尽可能随时间保持不变,以防止扰乱搜索项的标准化。城市或报纸是这类术语的一个好选择;从大城市开始,继续到地方报纸。第一个锚点由其自己的中值标准化,以获得第一个缩放因子:

为了将每个搜索项链接到第一个锚点的中间值,有必要自上而下地链接锚点。为此,计算 s 缩放因子作为一个锚和下一个较低锚项的搜索量的分数。比例因子的一般公式由下式给出:

为了制作类似《星球大战——原力觉醒》和《头号通缉犯》的电影,搜索词被从上到下提取并链接到锚词。因此,在第一步中,使用第一锚点绘制搜索项,并使用其缩放因子进行缩放。级别 i 的缩放搜索量现在给出为

如果感兴趣的时间窗口内的搜索词的最大缩放搜索量低于缩放锚的给定百分比(在我们的项目中我们使用 25%),则必须用下一个较低的锚词来重新绘制。链接的锚项的结果(以及每个级别 i 的缩放因子)如下所示,其中右边的图只是放大了低级锚项。

Scaling factors used in the project

特别是在右侧,可以看到缩放搜索项的效果。未缩放的粉红色搜索词的数量大多在 5 到 6 之间,而缩放版本的数量介于两者之间。将这种缩放方法应用于我们感兴趣的 4 部电影的搜索词,会产生下面的图。

Scaled Google Trends data for the search terms Django Unchained, A most wanted Man, Mama and Star Wars. Vertical lines mark the premiere date of each movie.

仅通过观察该图,人们可能看不出与第一个图相比有如此大的差异,除了 y 轴现在在 0 和 1 之间缩放,而不是在 0 和 100 之间。这是因为我们现在看到的数字是相对于第一个锚项的中值进行缩放的。换句话说,《星球大战》现在在首映周末的搜索量是第一个主播词中值的 65%。四舍五入后的数字如下。

Scaled search volume for the movies 6 weeks prior premiere date t

相关性的微小改善并不值得,但看看一个头号通缉犯的数字,你会注意到它们现在是实值的,这意味着我们解决了第一个问题:数据现在是可比较的,因为我们根据固定的绝对值对其进行了缩放,这样做甚至变得实值化和更具信息性。然而,妈妈的数字似乎还是太高了。为了解决这个问题,我们简单地减去我们感兴趣的时间范围之前的时间序列的中值。

下图显示了 4 部电影在减去预测范围第一天前 52 周(即首映前 58 周)每个时间序列的中值后的谷歌趋势数据。

Scaled Google Trends data for the search terms Django Unchained, A most wanted Man, Mama and Star Wars after median substraction. Vertical lines mark the premiere date of each movie.

这张图说明了中位数减法的用处。每个搜索项在其首播日支配所有其他搜索项。甚至在 2014 年 8 月首播的《头号通缉犯T5》中,蓝线也占据了其他所有搜索词的首位。请注意,这并不意味着一个头号通缉犯在那段时间里比星球大战被谷歌搜索的次数更多,而是一个头号通缉犯的搜索量比前 52 周的中位数高 1 个百分点,而星球大战的搜索量比相应的中位数低 5 个百分点。所有的数据点仍然是相对于上锚位进行缩放的。

Scaled search volume for the movies 6 weeks prior premiere date t after median substraction Multiplied by factor 100.

下表显示了减去中位数后每个搜索项的数字。看看《妈妈》的数字,我们发现我们能够解决我们的模糊问题,因为它们不再像《被解放的姜戈》的数字那么高了——如果你看看访问者的数量,这就说得通了。与未缩放的数据相比,这导致了更高的相关性,并允许我们在我们的模型中使用它的无偏版本来预测首映周末的电影观众数量。

如上所述,该项目的代码,也包括预测模型和进一步的描述性分析,在 github 上,可以适应任何用例。记住锚词的重要之处:它们必须尽可能的稳定,并且应该与你所在的地区相关。使用我们的美国或印度谷歌趋势数据的锚词列表根本行不通,因为(我假设)在洛杉矶或钦奈没有人会对在阿尔高出版的本地报纸感兴趣。

使用 GPT-2 生成神奇宝贝动画集

原文:https://towardsdatascience.com/using-gpt-2-to-generate-pokémon-anime-episodes-113c0f15859c?source=collection_archive---------30-----------------------

从数据采集到为真正愚蠢的东西提供网络服务的旅程。

乐天河童是萨尔萨舞大师,他会教亚什如何像神一样移动。他会取笑亚什不能快速移动,甚至会攻击他身体虚弱。

接下来的故事讲述了某人利用一项极其复杂的技术做出了一件愚蠢的事情。OpenAI 展示的 GPT-2 模型是人工智能生成文本的游戏改变者。以至于开发该模型的团队推迟了它的公开发布,以便人们可以准备好迎接一个像假新闻这样的事情可以毫不费力地产生而无需太多人工干预的世界。是的,今天我将展示如何使用这种危险的神器来制作神奇宝贝剧集。

你可以在这里查看最终结果:所有代码都可以在我的Github资源库找到。如果你只是想看一些例子,可以跳到文章的末尾。

我不能保证网站会在任何时候回答所有的请求,因为服务器不能同时处理 3 个以上的请求(我将很快解释为什么),而且我已经脱离了在 AWS 上托管它的自由层。但是,如果网站产生一个错误,只需等待几秒钟,再试一次:)

在本文中,我将尽力解释端到端机器学习项目的主要挑战,每一步都是如此。

数据

****机器学习方法用于从数据中提取信息和推断模式。传统的统计方法在建模阶段会有统计人员选择的许多参数和假设,而机器学习方法会让数据自己说话。这是一个众所周知的可解释(经典)模型和精确(机器学习)模型之间的权衡。机器学习的预测能力基本上来自于拥有大量数据和足够复杂的模型,以从中捕捉高度微妙的模式。有一个“平滑度”假设,即模型正在一个足够大的现实样本上进行训练,以推断(概括)它没有直接看到的东西,假设它接近它确实已经训练过的某个例子(因此是平滑度)。

最近的 NLP(自然语言处理)模型没有什么不同,它们需要大量的文本和计算能力来训练。这些新模型从零语言知识开始,到最后,它们变得非常擅长从单词序列中测量上下文信息。就理解完全相同的单词在句子的不同位置具有不同的含义而言,这是经典的 NLP 模型不太擅长实现的。

GPT-2 模型是在维基百科、Reddit 和许多其他地方预先训练好的。我所做的是在来自互联网的一组更具体的文本上对模型进行微调。这是互联网的子集,由神奇宝贝动画剧集的摘要组成(并且在 Bulbapedia 上)。向 Bulbapedia 大喊,因为它是一个优秀的社区驱动的神奇宝贝网站!

我写的爬虫下载了社区写的大约 400 个剧集摘要。以下是其中一集的样本:

亚什向自己和全世界的神奇宝贝宣布,他将成为一名神奇宝贝大师。然而,他的演讲被他的妈妈打断了,妈妈告诉他去睡觉,因为明天是他的大日子。阿什抗议说,他太兴奋了,睡不着,所以他的妈妈告诉他,如果他不睡觉,那么至少要为第二天做好准备,因为她打开了由镇上的神奇宝贝专家奥克教授主持的一个节目。Ash 看着 Oak 解释新的训练者从三个神奇宝贝中选择一个开始他们的旅程;草型妙蛙种子,火型小火龙或水型杰尼龟。

我的 crawler 在文件 crawler_bulbapedia.py 上,运行时会创建一个名为 data/pokeCorpusBulba 的文件夹,它会将每一集存储在一个单独的文本文件中。

数据尚未准备好提供给模型。另一个名为 prepare_corpus.py 的脚本将清理文本,并将它们合并到一个名为 train.txt 的文件中,准备用于 GPT-2。

模型

GPT-2 是一种基于变压器的模型,它使用一种称为自我关注的技术,以一种令人惊讶的自然方式学习单词如何完成或继续句子。我不认为我能比这些倍数 优秀 来源更好地解释这个模型的数学和内部运作。但是我可以从纯编程的角度,就如何使用这个预先训练好的模型提供一些见解,就像它是一个文本生成 API 一样。为此,我找到了一个很好的资源, gpt-2-simple python 库,它使所有 Tensorflow 的复杂性基本上不可见,并提供了一些非常简单的函数,可以从 gpt-2 模型中下载、微调和采样。

基本上,语言模型试图从一个句子中预测下一个单词,我们可以不断从模型中获得预测以生成新的文本,将最后的预测作为新的输入,以获得越来越多的单词。因此,作为一个例子,我们可以为我们的模型提供前缀输入“Ash 和 Pikachu were”:

GPT-2 使用注意力机制,动态评估最后一个单词对预测下一个单词的重要性。在这个模型中有一个叫做“transformer cell”的东西,它计算输入序列中每个单词相对于其他每个单词的关注值。这些都被传递以生成输出,即预测句子中的下一个单词。

作为一个稍微简化的例子,我们可以通过注意力值的强度(紫色-er 越多的注意力)看到,显然“Ash”和“Pikachu”与确定“was”之后的内容相关。这是这个模型的一个非常好的地方,经典的“计算单词”方法,比如朴素贝叶斯方法不能做到。

通过从语料库中删除句子上的单词并微调模型以正确预测它们来进行训练。 最后,我们有一个检查点文件夹,这是我们从这个模型生成文本唯一需要的东西。tensorflow 创建的这个文件夹包含了用我的神奇宝贝语料库微调后模型的整个状态,gpt-2-simple 库在生成新文本时会寻找它。

服务器

这是迄今为止最具挑战性的部分。在互联网上为这个推理模型提供服务不是一项简单的任务,因为文本生成需要大量的内存。

基本上,服务器结构响应指向端口 5000 的 GET 请求。它有一个函数来响应这个请求,获取参数(用户输入),初始化模型,生成一些固定数量的文本,并返回 JSON 中的所有内容。困难的部分在于,该模型占用了高达 1GB 的内存来进行推理。因此,在做任何事情之前,我必须有一个具有相当大内存的服务器(再见 AWS 免费层!很高兴见到你)。所以我最终选择了 AWS 上的 EC2 t2-medium 实例,并在我的朋友joo的帮助下设置了它。

下面这个 EC2 实例内部的 web 服务器结构完全是从我的另一个朋友 Gabriela,从她受欢迎的媒体的帖子中复制来的。

我选择在这个 EC2 实例上运行的 web 服务器是 nginx,它监听请求,然后将它们转发给 uWSGI web 服务器,后者通过 WSGI 协议与 Flask 应用程序通信。基本上我们有这样的结构:

Diagram by Gabriela Melo

WSGI 协议的目的是为用 Python 编写的 web 应用程序创建一个公共接口。例如,我可以改变应用程序框架(Flask 到 Django)或应用程序服务器(uWSGI 到 Unicorn ),这对于其他部分来说是不可见的。

现在,为什么我不把 uWSGI 服务器提供给网络呢?为什么要用另一层,比如 nginx?嗯,简单的答案是 nginx 抽象出了服务器负载可能带来的一些问题,uWSGI 本身不适合处理这些问题。

当然,我不得不把所有这些软件打包在一个 Docker 容器里,因为这就是现在所有酷孩子做的事情。所有的代码都可以在我的 Github 资源库中找到,但是要阅读关于这种配置的真正深入和完善的解释,我建议访问 Gabriela 的帖子,因为我的设置基本上是相同的,有一些小的调整,因为我的应用程序有点不同。

烧瓶应用程序

Flask 应用程序(模型在服务器上运行的地方)有一个请求的入口点,即生成函数:

经验教训

  • 如果你想用机器学习做出新的东西,数据是非常重要的。体面的清洁也同样重要。
  • GPT-2 模型作为按需文本生成工具是不切实际的,它需要太多的内存和 CPU 来运行。拥有一个需要 1GB 内存来处理每个请求的服务是非常昂贵的。
  • docker 系统修剪是你的朋友。
  • web 服务器的 Python 生态系统并不那么难用,并且有大量的例子。

一些输出示例

模型的输入信息以粗体显示。当然,这涉及到一些樱桃的挑选,但这就是生成模型的方式。

****艾希和米丝蒂恋爱时正在约会。当他们都回忆起各自的第一次经历时,阿什第一次与神奇宝贝擦肩而过是他所记得的一切,因为他还是个孩子。后来,在 ash 做了他的第一个扑克球后,他跳过了午餐,去追一个朋友,并换了运动鞋。这导致他们都坠入爱河,留下道恩和布洛克泪流满面。当他们外出寻找亚什的白头龙时,一只野生的 gyarados 把他们打跑了。(…)

皮卡丘厌倦了这一切,他害怕草地,也害怕驯兽师。杰西和詹姆斯跑出去,跑出去。(…)

亚什想要成为最棒的,为了达到这个目标,他训练了所有的神奇宝贝。他告诉他的教练整个故事,并承诺成为一名伟大的教练。他告诉他的父母和朋友,他会尽最大努力训练他们。他们很惊讶,正准备放弃他时,他的父母开始哭了。他的母亲告诉他回家找他的朋友。他们别无选择,只能跟他走。

****皮卡丘因逃税被捕。三人组一走出橄榄石城神奇宝贝中心,就立刻遭到一名前警官、一名警探、一名护士 joy 和一名护士 joy 的 glameow 的攻击。

对时间序列预测任务使用梯度增强

原文:https://towardsdatascience.com/using-gradient-boosting-for-time-series-prediction-tasks-600fac66a5fc?source=collection_archive---------3-----------------------

Pixabay

简单的时间序列建模

时间序列预测问题在零售领域相当常见。

像沃尔玛和塔吉特这样的公司需要记录有多少产品应该从配送中心运送到商店。在劳动力管理、库存成本和缺货损失方面,即使对这种需求预测系统进行很小的改进也可以帮助节省大量的美元。

虽然有许多技术来解决这个特殊的问题,如 ARIMA,先知和 LSTMs,我们也可以把这样的问题作为一个回归问题,并使用树来解决它。

在本帖中,我们将尝试使用 XGBoost 解决时间序列问题。

我要关注的主要事情是这样一个设置需要什么样的功能,以及如何创建这样的功能。

资料组

Kaggle 大师 Kazanova 和他的一些朋友一起发布了一个“如何赢得数据科学竞赛” Coursera 课程。这门课程包括一个期末专题,它本身是一个时间序列预测问题。

在这场比赛中,我们得到了一个由日常销售数据组成的具有挑战性的时间序列数据集,该数据集由俄罗斯最大的软件公司之一 1C 公司提供。

我们必须预测下个月每个产品和商店的总销售额。

数据如下所示:

我们得到了每天的数据,我们希望建立一个模型来预测下个月每个产品和商店的总销售额。

变量 date_block_num 是一个连续的月数,为方便起见而使用。2013 年 1 月为 0,2015 年 10 月为 33。你可以把它看作月变量的代理。我认为所有其他变量都是不言自明的。

那么我们如何处理这类问题呢?

数据准备

我注意到的主要事情是,当我们试图使用回归来解决时间序列问题时,数据准备和特征生成方面是最重要的事情。

1.进行基本的 EDA 并去除异常值

sales = sales[sales['item_price']<100000]
sales = sales[sales['item_cnt_day']<=1000]

2.按照您希望的预测级别对数据进行分组:

我们首先创建一个不同的日期块数量、商店和商品组合的数据框架。

这一点很重要,因为在我们没有商品商店组合数据的几个月里,机器学习算法需要被明确告知销售额为零。

网格数据框架包含所有商店、商品和月份的组合。

然后,我们将网格与销售额合并,得到月销售额数据框架。对于没有任何销售的月份,我们也用零替换所有的 NA。

3.创建目标编码

为了创建目标编码,我们按特定的列分组,并取平均值/最小值/总和等。目标列的名称。这些特征是我们在模型中创建的第一个特征。

请注意,这些特性可能会在我们的系统中引起大量泄漏/过拟合,因此我们不会在模型中直接使用它们。我们将在接下来创建的模型中使用这些特性的基于滞后的版本。

我们按item_idshop_iditem_category_id分组,并在item_priceitem_cnt_day列上聚合,以创建以下新特性:

We create the highlighted target encodings

我们也可以为此使用特征工具特征工具是一个执行自动化特征工程的框架。它擅长将时态和关系数据集转换为机器学习的特征矩阵。

4.创建滞后要素

我们的模型需要的下一组特征是基于滞后的特征。

当我们创建常规分类模型时,我们将训练示例视为彼此完全独立。但在时间序列问题的情况下,在任何时间点,模型都需要过去发生的信息。

我们不能对过去的所有日子都这样做,但是我们可以使用我们的目标编码特征为模型提供最新的信息。

因此,我们的目标是在数据中添加一些特征的过去信息。我们为我们创建的所有新功能和item_cnt_day功能都这样做。

一旦有了滞后特性,我们就用零填充 NA。

我们最终创建了许多具有不同滞后的滞后特征:

'item_id_avg_item_price_lag_1','item_id_sum_item_cnt_day_lag_1', 'item_id_avg_item_cnt_day_lag_1','shop_id_avg_item_price_lag_1', 'shop_id_sum_item_cnt_day_lag_1','shop_id_avg_item_cnt_day_lag_1','item_category_id_avg_item_price_lag_1','item_category_id_sum_item_cnt_day_lag_1','item_category_id_avg_item_cnt_day_lag_1', 'item_cnt_day_lag_1','item_id_avg_item_price_lag_2', 'item_id_sum_item_cnt_day_lag_2','item_id_avg_item_cnt_day_lag_2', 'shop_id_avg_item_price_lag_2','shop_id_sum_item_cnt_day_lag_2', 'shop_id_avg_item_cnt_day_lag_2','item_category_id_avg_item_price_lag_2','item_category_id_sum_item_cnt_day_lag_2','item_category_id_avg_item_cnt_day_lag_2', 'item_cnt_day_lag_2',...

系统模型化

1.删除不需要的列

如前所述,我们将删除目标编码特征,因为它们可能会导致模型中的大量过度拟合。我们还失去了项目名称和项目价格功能。

2.只取最近的一点数据

当我们创建滞后变量时,我们在系统中引入了很多零。我们使用的最大滞后为 12。为了应对这种情况,我们删除了前 12 个月的指数。

sales_means = sales_means[sales_means['date_block_num']>11]

3.训练和 CV 分割

当我们进行时间序列分割时,我们通常不进行横截面分割,因为数据是与时间相关的。我们想创建一个模型,看到现在,并能很好地预测下个月。

X_train = sales_means[sales_means['date_block_num']<33]
X_cv =  sales_means[sales_means['date_block_num']==33]Y_train = X_train['item_cnt_day']
Y_cv = X_cv['item_cnt_day']del X_train['item_cnt_day']
del X_cv['item_cnt_day']

4.创建基线

在我们继续建模步骤之前,让我们检查一个简单模型的 RMSE,因为我们想让有一个与比较的 RMSE。我们假设我们将预测上个月的销售额作为基线模型的本月销售额。我们可以使用这个基线 RMSE 来量化我们模型的性能。

1.1358170090812756

5.列车 XGB

我们使用来自xgboost scikit API 的 XGBRegressor 对象来构建我们的模型。参数取自这个 kaggle 内核。有时间的话可以用 hyperopt 来自动自己找出超参数

from xgboost import XGBRegressormodel = XGBRegressor(
    max_depth=8,
    n_estimators=1000,
    min_child_weight=300, 
    colsample_bytree=0.8, 
    subsample=0.8, 
    eta=0.3,    
    seed=42)model.fit(
    X_train, 
    Y_train, 
    eval_metric="rmse", 
    eval_set=[(X_train, Y_train), (X_cv, Y_cv)], 
    verbose=True, 
    early_stopping_rounds = 10)

运行这个之后,我们可以在 CV 集上看到 RMSE 在 0.93 的范围内。基于我们对 1.13 的基线验证 RMSE,这是非常令人印象深刻的。因此,我们致力于部署这个模型,作为我们持续集成工作的一部分。

5.地块特征重要性

我们还可以看到来自 XGB 的重要特性。

Feature importances

结论

在这篇文章中,我们讨论了如何使用树进行时间序列建模。目的不是在 kaggle 排行榜上获得满分,而是了解这些模型是如何工作的。

几年前,当我作为课程的一部分参加这个比赛时,通过使用树木,我接近了排行榜的顶端。

随着时间的推移,人们在调整模型、超参数调整和创建更多信息功能方面做了大量工作。但是基本方法保持不变。

你可以在 GitHub 上找到完整的运行代码。

看看 Google Cloud Specialization 上的高级机器学习。本课程将讨论模型的部署和生产。绝对推荐。

将来我也会写更多初学者友好的帖子。让我知道你对这个系列的看法。在关注我或者订阅我的 博客 了解他们。一如既往,我欢迎反馈和建设性的批评,可以通过 Twitter @mlwhiz 联系。

此外,一个小小的免责声明——这篇文章中可能会有一些相关资源的附属链接,因为分享知识从来都不是一个坏主意。

使用 GraphSAGE 学习 CORA 中的论文嵌入

原文:https://towardsdatascience.com/using-graphsage-to-learn-paper-embeddings-in-cora-a94bb1e9dc9d?source=collection_archive---------12-----------------------

这里我们使用 stellargraph 库通过 GraphSAGE 算法学习 CORA 上的论文嵌入。

简介

CORA[1]是七个不同班级的学术论文的数据集。它包含论文之间的引用关系,以及每篇论文的二进制向量,该向量指定某个单词是否出现在论文中。因此,CORA 包含每篇论文的基于内容的特征和论文之间的关系特征。我们可以用一个网络来模拟这些特征,在这个网络中,每篇论文用一个节点来表示,这个节点带有基于内容的特征,引用用边来表示。

利用图模型,我们可以使用几何深度学习方法来学习每篇论文的嵌入。在这个故事中,我们使用 GraphSAGE。

GraphSAGE 是一种无监督的节点嵌入算法,因其在大型图上的成功而闻名。它可以利用节点特征和节点关系来学习表示图中邻域结构的每个节点的向量。要阅读更多关于 GraphSAGE 的内容,你可以参考链接中的故事。

[## GraphSAGE 的直观解释

归纳学习在动态数据集中很有用。这里我们讨论一个关于图的归纳学习算法。

towardsdatascience.com](/an-intuitive-explanation-of-graphsage-6df9437ee64f)

为了实现 GraphSAGE,我们使用了一个 Python 库 stellargraph ,其中包含了几种流行的几何深度学习方法的现成实现,包括 GraphSAGE。stellargraph 的安装指南和文档可以在这里找到。此外, 本文中使用的代码基于该库的 GitHub 库[2]中的示例。

图形创建

stellargraph 库使用 StellarGraph 对象来表示图形。幸运的是,我们可以很容易地从 networkx 图中初始化 StellarGraph 对象。因此,我们通过将 CORA 中的链接视为一个边列表来创建一个 networkx 图。请注意,这将自动创建必要的节点。然后,我们通过解析 cora.content 文件并从 1 到唯一单词数(1433)索引每个唯一单词,向每个节点添加基于内容的特性。我们还将这些特性分别存储在一个名为 node_features 的变量中。我们使用这些特性来创建一个 StellarGraph 对象。

**cora_dir = './cora/'
edgelist = pd.read_csv(cora_dir+'cora.cites, sep='\t', header=None, names=['target', 'source'])
edgelist['label'] = 'cites'** # set the edge type**Gnx = nx.from_pandas_edgelist(edgelist, edge_attr='label')
nx.set_node_attributes(Gnx, 'paper', 'label')**# Add content features **feature_names = ["w_{}".format(ii) for ii in range(1433)]
column_names =  feature_names + ['subject']
node_data = pd.read_csv(data_dir+'cora.content), sep='\t', header=None, names=column_names)
node_features = node_data[feature_names]**# Create StellarGraph object
**G = sg.StellarGraph(Gnx, node_features=node_features)**

多亏了 networkx 和 pandas,我们将 CORA 加载到 networkx 图中,然后只用几行代码就创建了一个 StellarGraph 对象。我们现在可以使用创建的对象来实现 GraphSAGE。

模特培训

为了实现 GraphSAGE,我们将使用 stellargraph 中的模块。stellargraph 包含一个 UnsupervisedSampler 类,用于从图中对给定长度的多个行走进行采样。我们还使用 GraphSAGELinkGenerator 来生成损失函数中需要的边。注意,GraphSAGE 利用链路预测任务为相邻节点创建类似的嵌入。生成器根据采样的行走创建边。

# Specify model and training parameters **nodes = list(G.nodes())
number_of_walks = 1
length = 5
batch_size = 50
epochs = 4
num_samples = [10, 5]****unsupervised_samples = UnsupervisedSampler(G, nodes=nodes, length=length, number_of_walks=number_of_walks)****train_gen = GraphSAGELinkGenerator(G, batch_size, num_samples)
                                   .flow(unsupervised_samples)**

生成了遍历和链接生成器之后,我们现在定义并构建 GraphSAGE 模型。构建的对象返回输入/输出占位符,供我们稍后填充。基于输出占位符,我们添加一个具有 sigmoid 激活的预测层,因为链接预测是一个二元分类问题。

**layer_sizes = [50, 50]
graphsage = GraphSAGE(layer_sizes=layer_sizes, generator=train_gen, bias=True, dropout=0.0, normalize='l2')**# Build the model and expose input and output sockets of graphsage, # for node pair inputs **x_inp, x_out = graphsage.build()****prediction = link_classification(output_dim=1, output_act='sigmoid', edge_embedding_method='ip')(x_out)**

最酷的部分来了!我们可以使用预测层和输入占位符来创建一个 keras 模型,并训练它学习嵌入!由于 stellargraph 在其代码中使用了 keras 的层,每个实现的图算法都与 keras 兼容。因此,我们可以以本机方式使用 keras 的实用程序,如损失跟踪和超参数调整。

**model = keras.Model(inputs=x_inp, outputs=prediction)****model.compile(
    optimizer=keras.optimizers.Adam(lr=1e-3),
    loss=keras.losses.binary_crossentropy,
    metrics=[keras.metrics.binary_accuracy],
)****history = model.fit_generator(
    train_gen,
    epochs=epochs,
    verbose=1,
    use_multiprocessing=False,
    workers=4,
    shuffle=True,
)**

我们已经训练了边缘预测模型来学习纸张嵌入。给定一个节点,我们可以使用这个模型创建一个嵌入生成器。为此,我们创建另一个名为 embedding_model 的 keras 模型,并创建一个 GraphSAGENodeGenerator 对象。结合这两个,我们可以获得每篇论文在 CORA 中的嵌入情况!

**x_inp_src = x_inp[0::2]
x_out_src = x_out[0]
embedding_model = keras.Model(inputs=x_inp_src, outputs=x_out_src)****node_ids = node_data.index
node_gen = GraphSAGENodeGenerator(G, batch_size,num_samples) 
                                             .flow(node_ids)****node_embeddings = embedding_model.predict_generator(node_gen, workers=4, verbose=1)**

为了验证这些嵌入是有意义的,我们使用 TSNE 在 2D 上绘制了结果嵌入。我们根据数据集中的类别对每篇论文进行着色,并观察到该类别的论文在图中被分组在一起。鉴于我们在训练中没有利用职业标签,这是一个惊人的结果!

2D visualization of paper embeddings learned by GraphSAGE [2].

结论

在这个故事中,我们在 CORA 数据集上运行 GraphSAGE,并学习了论文嵌入。我们使用了 stellargraph 库,因为它提供了一个易于使用的接口,并且与 networkx 和 keras 库兼容。多亏了 stellargraph,我们可以快速尝试不同的几何不同学习方法,并比较它们的结果。这使得 stellargraph 成为创建基线和尝试基于网络的方法来解决手头问题的理想起点。

参考

[1] 科拉

[2] s tellargraph GitHub

使用图像数据确定文本结构

原文:https://towardsdatascience.com/using-image-data-to-determine-text-structure-5c361e76aae?source=collection_archive---------8-----------------------

Painting by Patrick Henry Bruce

点点滴滴,循线而行

在我之前的文章中,我讨论了如何实现相当简单的图像处理技术来检测图像中的文本斑点。实际上,该算法只不过是在图像中找到高对比度的像素区域。然而,这个简单的过程仍然为基本的光学字符识别(OCR) Python 脚本奠定了基础。

在这篇文章中,我将讨论对前面的代码所做的添加。具体来说,我感兴趣的是通过将字母分配到它们所属的行来检测文本的结构。为了使算法更加稳健,我将结合字母“I”和“j”上面的点。阅读本系列文章的读者会记得,在前面的过程中,字母上面的点被认为是独立的对象。正如后面将要说明的,这些点会干扰图像中的检测线。

观察差距

说实话,在解决点问题之前,我已经开始探索线检测。由于我对如何实现线检测有一个模糊的理解,清理点和它们的父符号之间的间隙是一个相当大的设计决策。一种想法是使用图像中的数据,我最终需要这些数据来进行线条检测。但是这种方法感觉太不稳定了。或者,使用点的几何属性及其与周围字母的关系的解决方案似乎是更具体的解决方案。

我还是做了一些假设。首先,我认为圆点并不常见。此外,我假设一个点将有一个小面积的手写和打字文本。这个点应该是圆形的。为了将异常点与其他笔画和破折号区分开,这是必要的。有一些方法被避免了。一个想法是定位圆点,然后沿着 y 轴找到它下面的第一段文本。虽然实现的解决方案与这个想法相差不远,但是这种简单的方法对于倾斜的文本可能会失败。

That dot is not above the “i”

这些假设影响了接下来的设计。首先收集每个字母的边界框的面积。计算这些区域的平均值和标准偏差,并用于找出异常值。这种寻找点的方法基于我们的假设,即点的出现和面积是异常值。然后循环通过每个异常值,并使用 OpenCV 工具在每个异常值周围找到一个紧密的边界框。minAreaRect()"。这个函数用来计算物体的宽高比,也就是它的圆度。这个比率越接近 1,形状就越像一个圆。误差幅度包括在内。最初,我试验了一个‘+-0.4’的误差。我使用的字体似乎特别加宽了几个像素,如果某些字母在它旁边的话。因此,误差幅度增加到了“+-1”。

Success (Left) and failure (Right)

一旦这些点被识别出来,寻找它们父母的行动就开始了。目前使用一个基本策略。对于每个点,每个潜在的字母都被扫描。首先,字母在图像中必须较低(在 y 轴上较高)。其次,选择与点最接近的字符作为最佳选项。这是否总是给出正确的结果?不,还有很多可以改进的地方。

我想利用第二个字符的圆形,或者考虑被比较字符的两个中心之间的斜率。这两个想法都需要更多的硬编码数字,这些数字对于其他字体和风格来说不太可能是可靠的。我想将来识别一个字母有一个随机的点可能会更容易。虽然连接点并不总是产生完美的解决方案,但它大大有助于清理线条检测的图像。

一往无前

有两种方法可以找到属于同一行的所有字母。这两个想法都是基于处理从图像中提取的数据。一行文本的特征是一系列单词在页面上处于相同的高度。简单地说,属于特定行的每个字母应该有一个相似的 y 轴值。该方法受主成分分析的启发,主成分分析是一种简化数据集维数的手段。

Number of overlapping letters (Right) the projection of the constitution on the Y-axis (Left)

此时,将坐标投影到 y 轴上的想法似乎很巧妙。然而,如何从这一步开始还不清楚。最初,我想把它框架为一个聚类问题,并应用均值漂移算法来寻找潜在的聚类。我担心均值漂移需要引入额外的硬编码参数。我不想建立一个只能读取宪法文本的 OCR。

对于第一种方法,我从著名的图像处理技术 Otsu's threshold 中获得灵感。Otsu 阈值传统上用于寻找图像的全局阈值。当直方图中有双峰分布时,效果最好。我在许多其他的项目中使用过这种方法。

阈值方法的核心是一种数学技术,可以应用于组织成直方图的任何集合。寻找阈值是基于最小化直方图数据的类内方差的技术。在 OpenCV 文档中展示了用 Python 实现该算法的有力解释。

我没有直接使用投影坐标,而是从这些点推断出更远的日期。在每一对相邻的投影点之间,我找到了位置的差异(分开的距离)。我认为 y 轴上每个点之间的距离可以区分一条新的线是否已经开始。这些距离被放入直方图中。

Histogram of typed (Left) and handwritten (Right) text

一旦确定了阈值,就依次检查每个字母。找到了字母和它所引导的字母之间的距离。如果差异大于阈值,则认为这两个字母在不同的行上。否则,字母在同一行。

这种方法对键入的文本相当有效。虽然 Otsu 法有时很难拾取线条,但当线条间距一致时,它工作得很好。手写文本没有产生成功的结果,这是一个慷慨的批评。该方法确实找到了行。然而,从测试图像来看,只找到了一半的线条。此外,由逗号、括号和下标引起的不规则性会产生假阳性。

另一种方法是将每个像素之间的距离视为一个函数。这样的函数创建一个图,其中出现新线条的区域包含一个大尖峰。同一行上的字母将产生低值区域,理想情况下为零。

这种方法仍然使用一个阈值来确定一个字母是否在下一行。取距离的平均值和标准偏差。平均值和标准偏差之和作为阈值。沿着函数的每个点都被循环通过。两个阈值通过尖峰之间的区域被认为是单线。找到这些区域的中心点就给出了那条线上的一个字母的索引。字母的底部尺寸用于确定 y 轴上线条的位置。

第二种方法产生了令人印象深刻的好结果。使用基本示例完全确定了键入的文本。一个更复杂的例子(显示在最后)确实遇到了超级脚本的问题,比如引号。手写笔迹能够找到线条,尽管结果确实更杂乱。在下面的例子中,每行字母的上方和下方都有一个红色条。上面的红线实际上是检测悬挂的上标。在打印的文本中,这通过组合我们的点而减轻。手写的文本取自线性代数讲座,并且充满了被检测为单独行的指数。

总的来说,我对我的定制方法的结果相当满意。在这种情况下,最好检测无关的线,而不是没有线。可以执行进一步的数据分析来识别哪些行属于上标。一旦确定了这一点,就可以将该线与其较低的相邻线合并。

既然我们知道了哪些字母属于哪一行,我们就可以确定哪些字母属于哪个单词。为了找到这些线,y 轴坐标被投影。为了找到单词,应该投影每行的 x 轴坐标。类似的距离算法将能够检测出哪个字母是同一个单词的一部分。

后来添加的东西

虽然我喜欢从零开始构建 OCR 的绝对起点,但对于这个项目的剩余部分,我计划切换到使用 Tesseract 。Tesseract 是 Google 支持的开源 OCR。我可能会花更多的文章来编写我自己的复杂的神经网络来解释文本。然而,我确实希望这个项目最终是强大的,我相信谷歌的好人们会在这方面帮助我。

开源代码库

快速免责声明。这个 Github 中的脚本目前非常混乱,并不代表最终代码。我计划以后花些时间清理代码。

[## TimChinenov/PictureText

一个基本的图像处理代码,用于检测高对比度图像上的文本

github.com](https://github.com/TimChinenov/PictureText)

Notice the error caused by the quotations between 400 and 500

使用图像分割来处理 Photoshop 图像

原文:https://towardsdatascience.com/using-image-segmentation-to-photoshop-images-db8c04942747?source=collection_archive---------30-----------------------

在这一集用 Colab 和 Python 做有趣的事情中,我们将使用深度学习从一幅图像中裁剪出对象,并将其粘贴到另一幅图像中。

深度学习部分是图像分割,也就是识别图像中的对象,我们可以随后屏蔽并最终剔除这些对象。

当作者对 Opencv 的有限知识变得太明显时,我们使用令人敬畏的 Opencv 库进行所有的剪切和粘贴。

为了好玩,让我们把一只北极熊放在杰夫·高布伦旁边。

你可以从这里开始:

[## 谷歌联合实验室

编辑描述

colab.research.google.com](https://colab.research.google.com/drive/19-lKjG_8xhaniXfuANfoOPdhvPtHvkXy)

我们从下载所需的图像开始。为此,我们需要一个前景图像(裁剪对象的图像)和背景图像(粘贴对象的图像)。

我们可以观看图像。

Foreground Image Credit: https://live.staticflickr.com/1399/1118093174_8b723e1ee5_o.jpg & Background Image Credit: https://live.staticflickr.com/7860/46618564664_be235e82e8_b.jpg

为了裁剪出熊,我们需要生成一个遮罩。接下来的几个细胞这样做,我们得到:

现在我们有了蒙版,我们可以将前景图像粘贴到背景图像上。通过传入遮罩,我们可以确保只粘贴前景图像的一部分,而忽略其余部分。

耶!有用!但是我们看到熊被贴在一个尴尬的地方。让我们使用 x 和 y 滑块来调整它的位置。对于这个例子,我们只需要将熊一直移动到右边。

成功!我们在杰夫·高布伦旁边放了一只北极熊!

我相信你可以想出更多有创意的例子,所以试一试,请分享结果。😃

Colab 链接:

[## 谷歌联合实验室

编辑描述

colab.research.google.com](https://colab.research.google.com/drive/19-lKjG_8xhaniXfuANfoOPdhvPtHvkXy)

这是完整的代码:

利用信息增益对兴奋性神经元进行无监督训练

原文:https://towardsdatascience.com/using-information-gain-for-the-unsupervised-training-of-excitatory-neurons-e069eb90245b?source=collection_archive---------21-----------------------

寻找一种生物学上更合理的方法来训练神经网络。

传统上,人工神经网络是使用 Delta 规则和反向传播来训练的。但这与神经科学对大脑功能的发现相矛盾。不存在通过生物神经元向后传播的梯度误差信号(见这里的和这里的)。此外,人脑可以在自己的视听训练数据中找到模式,而不需要训练标签。当父母向孩子展示一只猫时,孩子并没有利用这些信息去学习构成猫的每一个细节,而只是将一个名字与猫的概念联系起来。另一方面,深度神经网络需要数以千计的有猫和没有猫的图像,以及这些图像的精确训练标签。深度神经网络将试图在其输出层学习猫的概念。但它也会尝试学习中间层中较低级别的功能。例如,该网络可以尝试学习像猫耳朵、胡须、爪子、猫眼等概念,以帮助识别整只猫。然而,问题是,这些低级概念是以一种非常间接和模糊的方式从标签中学来的,这些标签告诉我们哪些图像显示了猫,哪些没有。在我看来,这不是学习这些概念的好方法。或许更好的方法是直接从数据中学习这些概念,而不依赖于输出标签。如果我们仔细观察猫眼,我们会发现有许多低级特征,如瞳孔的形状、眼睑的形状、眼睛出现的环境等等,这些特征同时出现,构成了眼睛的模式。那么我们为什么不利用这种特征的共现来学习构成眼睛的模式呢?

如果我们回到人工神经网络研究的最开始,我们会偶然发现唐纳德 o 赫布的一些非常有趣的想法。在他的书《行为的组织》中,Hebb 认为现实世界物体的内部表征由外部刺激激活的皮层细胞组成。他称这组同时激活的神经元为细胞集合体。赫布认为所有这些细胞都是相互联系的。只要活动在神经元细胞集合的回路中循环,物体的内部表征就会保留在短期记忆中。此外,他假设,如果神经元细胞组合的激活持续足够长的时间,它将通过“生长过程”导致巩固,通过这一过程,相互回路变得更有效;一起放电的神经元也会连接在一起。因此,如果组件中只有一小部分细胞被后来的刺激激活,现在放大的互易电路将使整个细胞组件再次激活,回忆起外部刺激的整个内部表征。他的理论被称为“赫布边理论”,遵循这一理论的模型被认为表现出“赫布边学习”。Hebb 规则的等式如下,其中 wi 是突触权重, α 是学习速率, y 是神经元的输出激活,x i 是突触 i 的输入激活:

正如我们很容易看到的那样,这个等式过于简单,并且不会导致稳定的训练模型,因为权重只是增加了。

兴奋性和抑制性神经元

那么,我们怎样才能找到一种避免这个问题的希伯来人学习模式呢?首先,我们需要认识到,Hebbian 学习只描述了某一类神经元(即兴奋性神经元)的学习机制。赫比学习适用于共现特征的学习,但不适用于类别的学习。兴奋性神经元本质上是连接的。它们允许表示由许多单独特征组成的模式。另一方面,抑制性神经元本质上是分离的,并且可以将兴奋性神经元分组。它们被称为抑制性神经元,因为它们可以形成负反馈环路,抑制兴奋性神经元。兴奋性和抑制性神经元的生物学角色模型是大脑皮层的棘状锥体细胞和棘状星状细胞。锥体细胞通常表现出兴奋性特征,有些具有连接大脑其他部分的长距离轴突。另一方面,星状细胞通常是具有短轴突的抑制性中间神经元,与附近的神经元形成回路。

信息增益

由于我们只是试图训练兴奋性神经元,让我们退一步,从信息论的角度来看这个问题。如果我们将神经元视为数据源,将神经元激活视为事件,我们可以使用香农熵来测量神经元产生信息的平均速率。(在我们的例子中, k 只迭代活动和非活动两个选项。)

作为一个例子,考虑一组神经元,每个代表一个字母,其中每个神经元都有自己的熵值。如果我们认为这些神经元是独立的,我们可以简单地将熵值相加。但是这些神经元真的是独立的吗?当然不是。在一些单词中,这些字母神经元的子集经常一起被激活。因此,我们或许可以通过引入代表单词或其他类型模式的兴奋性神经元来降低网络的整体熵。这些兴奋性神经元然后压缩包含在字母神经元激活中的信息。换句话说,在一个单词神经元中,我们需要比用单个字母神经元更少的信息来表示一个单词。如果我们遵循降低网络总熵的目标,我们可能可以使用这个信息论框架来为我们的兴奋性神经元提出一个训练规则。为了调整我们兴奋性神经元的突触权重,以降低总熵,我们首先需要为我们的兴奋性神经元定义一个成本函数,我们可以在优化过程中使用它。让我们通过查看通过兴奋性神经元的单个突触 i 获得的相对熵来开始制定这样的成本函数。这种相对熵也被称为库尔贝克-莱布勒散度,可以表述如下:

其中 Xi 是输入神经元的离散随机变量,而 Y 是输出神经元的离散随机变量。对于分布 Q ,假设 XiY 的联合概率分布为独立。这是计算相对熵的参考分布。所以,如果分布 P(Xi,Y) 也是独立的,那么信息增益为 0。

因此,我们为神经元获得的总信息增益看起来像这样:

由于我们已经向网络添加了一个新的兴奋性神经元来降低总熵,因此我们也需要考虑这个新神经元的熵:

我们需要注意的另一件事是,只考虑那些实际上参与压缩的突触。如果兴奋性神经元的输入突触的权重为 0,它也应该对成本函数没有影响。为了实现这一点,我们使用覆盖项 covi 来确定突触 i 对输出神经元的影响有多强。稍后我们将更详细地讨论如何计算 covi 。现在我们最终的成本函数看起来像这样:

兴奋性神经元模型

在我们展示如何使用成本函数来优化突触权重之前,让我们更仔细地看看兴奋性神经元的模型。该模型实际上非常简单,因为它计算所有输入突触的加权和,并使用偏差值来设置阈值。

然后通过激活函数 φ 发送结果,以计算输出激活值 y

兴奋性神经元和普通神经元之间的唯一区别是前者的偏置值可以拆分如下:

因此,如果兴奋性神经元的所有输入都是完全活跃的,那么 net 将等于 b 。我们使用的激活函数 φ 是双曲正切函数的正半部分。

它的导数,我们稍后会用到,由下式给出:

最后,我们已经提到的覆盖项 covi 计算如下:

这表明突触 i 能够多好地抑制兴奋性神经元的激活。如果突触权重 wi 等于或大于偏差 b ,那么 covi 值将为 1。

计数频率

由于熵的计算依赖于概率分布,我们应该简短地介绍一下这些是如何计算的。首先,通过对所有训练实例 d 上的输入激活 xd 和输出激活 yd 求和来计算频率。

然后通过将频率除以训练实例的数量 N 来计算概率分布。

然而,这种简单形式的频率计数有两个问题。首先,样本可能太小,不可靠。在这种情况下,狄利克雷分布可能有助于估计分布的可靠性,但这变得相当复杂。第二个问题是分布是一个移动的目标。由于我们不断调整兴奋性神经元的权重,这意味着概率分布也在变化。这个问题可以通过使用移动平均线来计算概率来解决。

成本函数的导数

为了得到可以调整突触权重的训练规则,现在必须计算成本函数的导数。首先,我们移除等式中的信息内容部分,并在以下步骤中将它们视为常数:

假设 covi 对于除当前训练实例 d 之外的所有实例都是常数,我们可以导出以下外部推导:

当涉及到神经元输出值的导数y’l时,我们可能需要调整几个变量。存在所有输入突触 j 的突触权重 wj 并且存在偏差。当调整突触权重 wj 时,我们需要将 b 视为常数,或者将 bc 视为常数,这取决于我们看到的是活动输入突触还是非活动输入突触。当然,如果假设一个偏置值不变,另一个也必须改变。主动输入突触的情况如下:

不活跃输入突触的情况是这样的:

偏置值的推导由下式给出:

当考虑主动输入突触的情况时,我们需要引入不对称性。如果兴奋性神经元的代价函数想要增加神经元的活性,只有增加突触的权重。这就是“什么一起点燃电线”的情况。但是如果成本函数想要降低神经元的活动,则仅降低偏差值。当输入字母出现在由兴奋性神经元表示的单词之外时,就是这种情况。在这种情况下,我们只想降低神经元的活性,而不降低突触的强度。

最终的训练规则将是这样的,其中 α 是学习率:

因此,为了训练突触 j ,兴奋性神经元的所有其他输入突触 i 被用于计算调整突触 j 的权重的目标方向。等式G′cov′I部分充当一种用于弱突触的自举机制。等式的这一部分也防止了偏差变得太大,因为如果发生这种情况,许多突触突然变成弱突触,covi 再次变得活跃。推导G′也很好地抓住了直觉,即频繁激活的输入突触应该被认为是不太相关的。甚至有可能通过连接负反馈突触作为输入,以受监督的方式训练兴奋性神经元。

开放式问题

迄今尚未回答的一些问题是:

  • 如何诱导新的兴奋性神经元?为了解决这个问题,我们可以从一个成熟的输入神经元开始,并开始观察是否有其他神经元同时放电。
  • 如何防止重复?
    对于这个问题,我们可能需要抑制神经元来形成一个反馈回路,可以抑制潜在的重复。
  • 抑制性神经元的训练是什么样的?
    本文描述的更新规则仅涵盖基于共现特征的训练。但是基于类别的抑制神经元的训练需要完全不同的训练方法。一种可能性是根据共有的属性将兴奋性神经元聚集在一起。

实施和相关工作

这个训练规则的实现可以在【GitHUB】上的 【爱歌】 项目的 兴奋性神经元 类中找到。 本文 给出了一些可以使用兴奋性神经元的上下文。最后, 这篇文章 描述了兴奋性神经元是如何嵌入反馈回路的。

利用 K-Means 聚类算法重新定义 NBA 位置并探索花名册的构建

原文:https://towardsdatascience.com/using-k-means-clustering-algorithm-to-redefine-nba-positions-and-explore-roster-construction-8cd0f9a96dbb?source=collection_archive---------18-----------------------

项目描述和动机

NBA 中的传统位置并不能准确反映球员为球队提供的比赛风格或功能角色。打球的整体风格已经发生了巨大的变化,NBA 各个时代都表明了这一点。同样,球员的比赛风格也反映了这种变化。目前联盟的节奏很快,场地空间也越来越大。证明这一点的一个例子是中锋们投三分球并为他们的球队拓展场地。这些中心是多方面的,但仍然与传统中心归为一类,没有方法区分两者。这个项目的目的是找到一个更好的方法来定义这些球员的角色,基于他们给他们的团队带来的价值。

数据源

从篮球参考中收集信息,并收集 2011 年至 2018 年每个球员的统计数据。2011 年被用作最初的开始年,因为它反映了无位置篮球开始形成的时间(勒布朗是迈阿密的主要推动者,也是金州王朝的开始)。最终的数据集中包含了大约 3000 个观察值。总共有 30 个特征描述每个球员。功能包括方块得分指标,如分,篮板,盖帽,抢断。还使用了高级指标,如:USG%、PER 和正负分数。所有的特征都是由每 100 人拥有量来定义的。这样做是为了确保球员的统计数据是可比的,不管他们打了多少分钟或多少场比赛。游戏时间不超过 400 分钟的玩家被排除在数据集之外,因为他们对游戏没有显著影响。

初步探索性数据分析

为了更好地理解我的数据集,我开发了一些初步的视觉效果。

散点图显示一段时间内联盟平均 3 个百分点

League Average for 3 pt % over time

显示一段时间内各种特征(Ortg,Drtg,3P%)的联赛平均水平的图表

League Average for various features over time

这两个图是集中于某些特征的例子,并表明随着时间的推移呈上升趋势。这些图表的特点包括三个指针,以及展示效率和整体进攻的其他指标。从联盟的角度来看,这种变化表明球员的角色/风格也随着赛季的发展而变化。

说明常规头寸平均统计数据的图表。

Average stats by conventional NBA positions

这个图表不能告诉我们那些不符合他们传统角色的球员。举个例子,大前锋也是促进者吗?还是扮演多维角色的警卫?

显示常规头寸平均分布的饼图

Distribution of conventional positions

常规位置的聚类可视化

Clusters representing conventional NBA positosn which take all 30 features into consideration

每个点代表一个玩家。分配到相同常规位置的玩家分散在整个图形中。表明它们没有相似的演奏风格。(主成分分析用于将 30 个特征的维度减少为 3 个成分)。

聚类后…

Results After Clustering…

使用的数据科学方法

  • 主成分分析(PCA)用于降低视觉效果的维数。因为有超过 30 个特征描述每个球员,所以不可能用这么多特征创建视觉集群。使用主成分分析后,所有特征中 90 %的变异仍然保留。它们被简化为 3 个组件,因此是一个 3D 模型。PCA 用于常规职位聚类的可视化,以及在实施 k 均值聚类算法后的新角色的可视化。
  • K-means 聚类是一种无监督的算法,其中没有给定标签。基本思想是指定质心(n ),然后根据观察(玩家)与质心的接近程度开始聚类(分组)。
  • 肘法和剪影评分。为了计算出有多少集群(新角色)是理想的,使用了 silhoutte 分数。轮廓分数解释了每个簇的密度和簇与簇之间的分离。肘方法显示随着聚类数的增加,侧影分数变化的程度。一旦速率明显下降,选择一个更高的“n”个簇的数量就没什么用了。对于这个项目,我最终总共有 9 个集群。
  • 缩放功能。由于 k-means 使用距离度量来评估和分配每个观察值所属的聚类,因此缩放所有特征非常重要。比如 40 分和 2 块是没有可比性的,它们本质上是不同的单位。我还为各种特征分配了权重,以突出某些风格。例如,助攻和失误可以说代表了控球,所以与其他特征相比,它被赋予了不同的权重。

K-均值聚类后的结果

新角色饼图

分配了新角色的群集可视化

通过查看每个集群的平均统计数据,然后查看每个集群中的球员列表,标签被分配给新的 9 个集群。通过使用领域知识和聚类中揭示的内容,生成一个标签来描述该聚类。

与为传统角色生成的集群相比,现在的集群更加精简和有序。这表明集群代表了他们的比赛风格/角色,并为球队和球迷提供了更多的洞察力。

Lets take a look at how labels were assigned to each cluster

深入了解每个集群,以及如何为新角色分配新标签

值得注意的是,虽然 5-6 名玩家被列在“著名玩家”下,但实际上每个集群都有超过 250 名玩家。

集群 1 : 外围边锋/得分手

著名球员:

  • 威尔森·钱德勒
  • 杰伦·亚当斯
  • 凯文·诺克斯(尼克斯球迷)
  • 康特尼·李
  • 斯坦利·约翰逊

群组 2:“三个& D”

值得注意的玩家:

  • 特雷沃·阿里扎
  • 肯特·巴兹摩尔
  • 威尔·巴顿
  • OG Anounoby
  • 托里恩·普林斯
  • 罗伯特·卡温顿

群组 3:“全部完成”

值得注意的玩家:

  • 凯尔·安德森
  • 布兰登·英格拉姆
  • 达尼罗·加里纳利
  • 凯文·乐福
  • 凯利·乌布雷
  • 扎克·拉文

集群 4:精英之翼

值得注意的玩家:

哈里森·巴恩斯

杰伦·布朗

德马雷·卡罗尔

阿隆·戈登

丹尼·格伦

埃里克·戈登

集群 5:备份 big(内部)

值得注意的玩家:

乔丹·贝尔

泰森·钱德勒

-内内·希拉里奥

科斯塔·库佛斯

阿隆·贝恩斯

集群 6:精英大佬(内部)

值得注意的玩家:

  • 艾德·戴维斯
  • 特里斯坦·汤普森
  • 梅森·普拉姆利
  • 格雷格·门罗
  • 扎扎·帕楚里亚
  • 马辛·戈塔特

星团 7:大恒星(内部)

值得注意的玩家:

  • 史蒂芬·亚当斯
  • 拉马库斯·阿尔德里奇
  • 安德烈·德拉蒙德
  • 尤素夫·努尔基奇
  • 德里克·费沃斯

第八组:所有的星星

值得注意的球员:

  • 布拉德利·比尔
  • 德文·布克
  • 吉米·巴特勒
  • 布雷克·格里芬
  • 托拜厄斯·哈里斯
  • 克莱·汤普森
  • 拉塞尔·维斯特布鲁克

集群 9:超级明星

值得注意的玩家:

  • 扬尼斯·阿德托昆博
  • 斯蒂芬·库里
  • 安东尼·戴维斯
  • 凯文·杜兰特
  • 詹姆斯·哈登
  • 勒布朗·詹姆斯

然后,我想发展更实际的洞察力,并创造了一些问题,探索名册的多样性。

商业洞察力问题

  • 精英队伍&一般队伍在球员角色/风格上有什么区别?
  • 获胜的球队有更多或更少的球员有特定的角色/风格吗?花名册的多样性对获胜有影响吗?

为了回答这些问题,我比较了过去 4 年中被认为“一般”(几乎没有进入季后赛或者是第 8 种子)的球队和过去 4 年中进入总决赛的球队的阵容结构。两个小组都有同等数量的来自西部和东部联盟的球队。

过去 4 年进入 NBA 总决赛的球队名单。

回答:

总的来说,NBA 决赛球队拥有更多的明星力量,他们的内线球员有一个保留/确定的角色。相比之下,“普通”NBA 球队的明星影响力更小,他们依赖明星内线作为焦点。想要赢的球队应该让他们的名单更能反映 NBA 决赛球队的饼状图。

希望你们喜欢我的项目!这里有一个链接到我的 GitHub 账户,它进一步解释了我为这个项目采取的步骤。最后,如果你想讨论我的项目或者只是谈论篮球,你可以在 LinkedIn 上找到我。

将 Kaggle 用于您的数据科学工作。

原文:https://towardsdatascience.com/using-kaggle-for-your-data-science-work-a2e78d692395?source=collection_archive---------14-----------------------

停止在你的小笔记本电脑上运行神经网络!

作为数据科学家,我们都喜欢 Jupyter 笔记本。但是,当你在处理一个非常大的数据集和/或一个复杂的模型时,你的计算机就不能胜任了。好消息是,您可以将 Jupyter 笔记本文件导入 Kaggle。如果你是数据科学的新手,Kaggle 是一个举办数据科学竞赛并提供现金奖励的网站。Kaggle 还拥有丰富的信息和一个非常愿意帮助您发展数据科学教育的社区。

Kaggle 的另一个特点是他们有免费的在线云计算(有一些限制)。因此,如果您的计算机变得太热,运行时间太长,或者没有足够的处理能力或内存来运行您的模型,您可以使用 Kaggle 的内核来运行您的代码!报名就好!

使用 Kaggle 的好处

  • 免费的!有了 Kaggle 账户,你可以免费使用他们的服务器。
  • 云计算。您可以运行一个模型,提交更改,去市中心,然后在另一台计算机上调出您的模型。只要你能上网,你的作品就能跟着你(不用 Git)!
  • GPU。对于计算密集型机型,您可以使用多达 2 个内核和 13 GB 的 GPU RAM。对于那些买不起昂贵 GPU 的人来说,为什么不用 Kaggle 的呢?
  • 笔记本或脚本。以你喜欢的方式导入你的代码!
  • 没必要pip install。Kaggle 已经预装了大多数 python 包(你甚至可以pip install打包 Kaggle 不支持的包)。
  • 黑暗模式。因为这样更好。

缺点和局限性

不全是神经网阳光和内核彩虹。首先,Kaggle 归谷歌所有。因此,如果你对 Alphabet 在其服务器上安装面部识别模型感到不安,那么 Kaggle 的内核可能不适合你。

还有,你网页上运行的内核,没有用户输入只能运行一个小时。所以如果你运行你的模型,离开超过一个小时,你的内核就会停止。您将丢失所有的输出,并且必须重启您的内核。您可以通过提交代码来克服这个问题。代码将在一个独立的内核中运行,而不是你在网页上看到的那个。但是提交的一个警告是,提交的内核的输出只有在内核完全运行后才能看到。因此,如果您的总运行时间是 5 个小时,那么您不能在 5 个小时内检查您提交的内核。如果你的代码有一个致命的错误,你要到 5 个小时后才能知道🙃

以下是使用 Kaggle 时的硬件时间限制:

  • 9 小时执行时间
  • 5gb 自动节省的磁盘空间(/kaggle/working)
  • 16gb 的临时暂存磁盘空间(外部/ka ggle/工作)

CPU 规格

  • 4 个 CPU 内核
  • 16 千兆字节的内存

GPU 规格

  • 2 个 CPU 内核
  • 13 千兆字节的内存

如果你要用这些规格制造一台计算机,你很容易就能花掉 1000 多美元。只要确保您的数据少于 16GB 的磁盘空间(除非您使用 Kaggle 数据集),并且运行速度可以超过 9 小时。如果您的模型可以在这些限制下运行,那么上传您的数据并开始工作吧!

Kaggle 入门

  • 登录您的 Kaggle 帐户
  • 在顶部栏中,点击笔记本
  • 然后选择新笔记本

  • 选择 PythonR
  • 选择编码风格
  • 如果要使用 GPU,点击显示高级设置,然后在上选择 GPU
  • 然后点击创建

ka ggle 内核

Your new online Jupyter Notebook.

如果你选择了笔记本风格,你会有宾至如归的感觉。要上传您的数据,点击右上方的**+ Add Data** 您可以选择预先存在的 Kaggle 数据集或上传您自己的数据集。请记住,您只能使用 16GBs 的数据。

在右边栏,你可以跟踪你的在线内核。“会话”选项卡会记录您有多少可用的计算能力。将您的工作区选项卡想象成一个 GUI 文件结构。如果您使用 Kaggle 数据集,您的文件将位于/kaggle/input/your-kaggle-dataset中。如果你上传了一个数据集,你的文件将会在/kaggle/input/your-uploaded-data中。在“设置”选项卡上,您可以更改之前设置的设置。

现在你都准备好了!编码并享受您的免费在线笔记本。当您完成或准备提交时,点击右上角的提交按钮。您的代码将在一个单独的内核中运行。一旦你所有的代码都运行了,它就变成了一个版本。您可以返回到任何版本或您提交的代码,并查看输出(如果它运行正常)。

如果你正在提交一个 kaggle 竞赛,你将进入你的内核版本。在左侧点击输出。如果您有一个. csv 输出,您将能够在这里看到它。选择您的。cvs 文件,点击提交参赛

Kaggle 是数据科学家的强大工具。他们甚至有关于 python 的课程,使用熊猫和神经网络,都使用它们的内核。另一个免费的在线云服务,请查看 Google Colab。

使用 Keras 和 TensorFlow 预测登革热暴发

原文:https://towardsdatascience.com/using-keras-and-tensorflow-to-predict-dengue-fever-outbreaks-99392202bd5c?source=collection_archive---------17-----------------------

使用时间序列天气数据的机器学习预测模型。

Image licensed from Adobe Stock

什么是登革热?

登革热通常被称为登革热,是一种蚊媒疾病,发生在世界的热带和亚热带地区。在轻度病例中,症状与流感相似:发热、皮疹、肌肉和关节痛。在严重的情况下,登革热会导致严重出血、低血压,甚至死亡。

因为登革热是由蚊子传播的,所以登革热的传播动态与温度和降水等气候变量有关。尽管与气候的关系很复杂,但越来越多的科学家认为,气候变化可能会产生分布变化,这将对全世界的公共卫生产生重大影响。

近年来,登革热一直在蔓延。历史上,这种疾病在东南亚和太平洋群岛最为流行。如今,每年近 5 亿例病例中的许多发生在拉丁美洲(邓艾:预测疾病传播,挑战总结)。

准确预测给定地区将感染登革热的人数的能力对于公共卫生官员、医生以及最终处于感染风险中的任何人都具有重大价值。使用来自美国国家海洋和大气管理局 (NOAA)和黑暗天空的历史数据,我的目标是创建一个机器学习模型,能够准确预测两个地方每周将发生的登革热病例数:波多黎各的圣胡安和秘鲁的伊基托斯。

该图显示了从 1990 年中期到 2008 年初波多黎各圣胡安每周报告的登革热病例。

在圣胡安,报告的登革热病例通常在一年的后半段达到高峰,显然有些年份感染人数会显著增加。据了解,这与蚊子数量的增加有关。蚊子在温暖潮湿的条件下和雨量充足的时候更容易繁殖。这些条件创造了更多的静水区域,因此有更多适合产卵的地方。

埃及伊蚊与“领域知识”

Image licensed from Adobe Stock

一只雌性埃及伊蚊吸血后,平均会产下 100 到 200 个卵,一生中最多能产五次。卵产在可能暂时被洪水淹没的潮湿表面,如树洞和人造容器,如桶、鼓、罐、盆、桶、花瓶、花盆托盘、罐、废弃的瓶子、罐、轮胎、水冷却器等。以及更多收集或储存雨水的地方。她分开产卵,不像大多数物种。并非所有的卵都是一次产下的,但它们可以分散几个小时或几天,这取决于是否有合适的基质。鸡蛋通常被放置在吃水线以上不同的距离。此外,她不会在一个地方产卵,而是将卵分散在几个地方。卵可以在干燥的环境中存活一年以上,但是当它们在潮湿的环境中时,它们可以在短短两天内孵化。剩下的成长阶段到成年可能在短短六天内发生(【denguevirusnet.com】T2)。

当训练机器学习模型时,了解这种生命周期是有用的,因为天气事件和/或条件之间可能存在关系,从而产生持续足够长时间的静止水,以使蛋达到成熟。在数据科学领域,这种类型的信息被称为“领域知识”。拥有广泛领域知识的数据科学家在其专业领域内开发机器学习模型方面具有优势。

获取数据

如上所述,数据是从两个来源获得的。NOAA 的每周数据已经准备好了 CSV 文件供下载。更详细和日常的黑暗天空数据必须使用 API(应用程序编程接口)获得。大约有 15,000 个 API 调用了 Dark Sky 来获取这两个城市的每日天气数据。数据被保存到文本文件中,随后被处理以创建 CSV 文件供重复使用。

这个项目的数据类型被称为时间序列。时间序列数据需要独特的模型、考虑因素和机器学习的预处理。尤其是缺失值,必须在训练任何模型之前解决。以下是这两个地方每天可用的天气变量的示例,包括圣胡安的 6,073 条记录中每个变量的缺失值计数:

date                             16
latitude                          0
longitude                         0
timezone                          0
offset                            0
apparentTemperatureHigh          18
apparentTemperatureHighTime      18
apparentTemperatureLow           17
apparentTemperatureLowTime       17
apparentTemperatureMax           18
apparentTemperatureMaxTime       18
apparentTemperatureMin           18
apparentTemperatureMinTime       18
cloudCover                      175
dewPoint                         18
humidity                         18
icon                             16
moonPhase                        16
precipIntensity                3695
precipIntensityMax             3695
precipIntensityMaxTime         5041
precipProbability              3695
precipType                     1561
pressure                         18
summary                          16
sunriseTime                      16
sunsetTime                       16
temperatureHigh                  18
temperatureHighTime              18
temperatureLow                   17
temperatureLowTime               17
temperatureMax                   18
temperatureMaxTime               18
temperatureMin                   18
temperatureMinTime               18
time                             16
uvIndex                          16
uvIndexTime                      16
visibility                     3918
windBearing                      18
windGust                       4854
windGustTime                   4854
windSpeed                        18

几乎所有的变量都有缺失值,有些接近 80%。我如何处理这些缺失数据的细节可以在 GitHub 的 Jupyter 笔记本上查看。如果你想了解更多关于处理缺失数据的内容,我在这里写了一篇关于这个主题的简短文章:走向数据科学

在所有的数据被获取、清理和评估之后,它就可以用于一些机器学习模型了。

构建序列模型

我使用 Keras 和 Tensorflow 库来构建我的模型。如果使用 LSTM 的递归神经网络的细节听起来很无聊,就跳过这一节。

当我写这篇文章时,LSTM(长短期记忆)是 Keras 库中处理时序数据最强大的层,但它也是计算开销最大的层。如果您的硬件平台对于给定的时间序列项目足够强大,我推荐尝试 LSTM。

我开始使用的基本模型如下:

model = models.Sequential() 
model.add(LSTM(103, input_shape=(train_X.shape[1],
               train_X.shape[2])))
model.add(Dense(50, activation='relu'))
model.add(Dense(1))model.compile(loss='mae', optimizer='adam')

然后,我尝试添加不同比例的脱落层:

model = models.Sequential() 
model.add(LSTM(103, input_shape=(train_X.shape[1],
               train_X.shape[2])))
**model.add(Dropout(0.3)) # 0.3, 0.4, and 0.5 were tested**
model.add(Dense(50, activation='relu'))
model.add(Dense(1))model.compile(loss='mae', optimizer='adam')

添加下降图层显著提高了模型的性能。丢弃层可以是防止模型过度拟合的有效工具,这是机器学习中的一个常见问题,我计划很快写更多关于使用丢弃层的内容。

该模型使用平均绝对误差来评估其性能。

做预测

处理时序数据的另一个挑战是无法使用复杂的数据分割方法,如交叉验证。对于时态数据,训练/验证/测试分割的可用方法是有限的,超出了本文的范围。关于这个主题的更多信息,请看杰森·布朗利博士的这篇优秀文章

我希望训练和测试数据都包括登革热感染低和高的年份。我发现下面的分割很适合这个项目:

以下是我用来评估模型的输出示例:

在本例中,该模型使用四周的天气数据来预测下一周的登革热病例数。蓝线表示模型在训练数据上的表现,越低越好,橙线表示模型从未“见过”的数据上的表现。从左到右代表模型的每次连续迭代(在机器学习术语中称为“时期”)。上面的例子代表了我测试的模型参数的最佳组合:

  • 回顾期(模型用于预测的前期周数)
  • 丢弃比例(在一个时期内随机“关闭”的节点的比例。
  • 要运行的时期数

我用这些参数的几种组合进行了测试。

下面的图表显示了最佳模型预测的案例数与实际案例数的对比:

7.68 天的平均绝对误差(实际病例和预测的登革热病例之间的平均差异)表明还有改进的空间,但该模型确实准确预测了第 95 周左右超过 150 例的巨大高峰。正如本文开头所提到的,这样的信息对于一个地区的决策者来说具有巨大的价值。

展望未来,我将尝试几种方法来改进这一模式:

  • 尝试用不同的方法从每天的黑暗天空数据中计算出一周的数值。
  • 通过获取每周的值并从上周的值中减去它们来区分数据。
  • 测试其他一些为时序数据设计的机器学习模型。

感谢您阅读我的项目——我对数据科学让世界变得更美好的潜力充满热情!

简单介绍一下我:
在毛伊岛拥有/管理了一家旅馆 15 年后,我搬到了旧金山,开始了自己的科技职业生涯。我将于 2019 年 9 月完成 Flatiron School 数据科学项目,并于 2022 年获得约翰霍普金斯大学的数据科学硕士学位。

使用 LinkedIn 个人资料图片进行面部识别

原文:https://towardsdatascience.com/using-linkedin-profile-pictures-for-facial-recognition-8be709e8fac?source=collection_archive---------25-----------------------

Photo by Kyle Glenn on Unsplash

您可能听说过《华盛顿邮报》上的一则报道,政府机构正在使用机动车管理局(DMV)的数据进行面部识别。你可以在这里找到那篇文章,但是当你看完之后,请回到这里。

虽然我知道这是非常令人担忧的,但我们作为一个社交媒体社会泄漏(消防水管?)几乎公开的个人信息。

我将向你们展示我是如何使用一张 LinkedIn 个人资料图片来创建一个面部识别系统的,这些图片来自许多同事的 LinkedIn 个人资料,全部使用免费的开源工具。政府不需要翻遍车管所的记录——他们只需要登录 LinkedIn 或脸书或任何其他社交媒体网站。我们每天都在多次放弃我们最容易识别的属性——我们的脸。

题外话:由于我没有权限展示或使用我在本文中实际使用的同事的 LinkedIn 个人资料照片,我将保持它的抽象性。但是你要做的就是收集一些图片。

背景材料

我通常参考的技术站点是 PyImageSearch.com 的和 MachineLearningIsFun.com 的和。在这种情况下,我结合了以下帖子中的信息:

如果你对我的 Github 回购感兴趣,你可以在这里找到。然而,你不会发现我使用的任何个人资料图片。此外,我只在 Mac 上运行过,我不确定对于 Windows 用户来说这些指令会有什么变化。

灵感

几个月前,我使用上面的第一个链接在我的电脑上进行面部识别,我用电脑摄像头拍了大约 30 张自己和其他几个人的照片。PyImageSearch 文章使用了一个名为 face_recognition 的库,它是由 MachineLearningIsFun 网站的所有者编写的。让我印象深刻的是,要获得良好的面部识别结果,一个人的不同照片是如此之少。

在阅读了 ImageDataGenerator 上的 PyImageSearch 文章和《华盛顿邮报》的文章后,我想知道我是否可以用单张照片训练一个面部识别模型,并生成同一张照片的 30 张新的增强图像。

对于单张照片,我选择 LinkedIn 作为我的来源,因为大多数人都有正面的干净照片。

训练一个模特的流程是怎样的?

第一步——下载一些 LinkedIn 个人资料图片

我下载了大约 8 张同事的个人资料照片,这样我可以很快试验出结果。LinkedIn 个人资料图片的好处是它不是很大,并且创建面部编码相对较快。

技术细节

在“original_images”文件夹中创建一个格式为“firstname_lastname”的文件夹,并将图片放入该文件夹中。

第 2 步—扩充个人资料图片

要了解图像增强,请参见我上面提到的这篇文章。PyImageSearch, Keras ImageDataGenerator 和数据扩充

在那篇文章中,作者向您展示了如何创建一个 Python 脚本来使用 Keras 从原始图像创建 30 个增强图像。增强后的图片是同一个 LinkedIn 个人资料图片——但在增强后,图片可能会稍微旋转,或垂直翻转,或稍微剪切。

当你完成所有的个人资料图片后,你应该有一个数据集文件夹,子文件夹中有人名,每个人名文件夹将有 30 张(或你选择的数量)LinkedIn 个人资料图片。

技术细节

要从一个图像生成多个图像,您可以在终端执行:

python pr_generate_images.py --image original_images/john_public/john_public.jpg --output generated_images/john_public --total 30 --prefix jp

在 generated_images 文件夹中,将人名作为文件夹名是很重要的。编码过程使用文件夹名称作为目标或标签值。

对您下载的每张 LinkedIn 个人资料图片运行以上命令

完成后,检查 generated_images 目录中的图像。你会看到 30 张图片,每一张都略有不同

步骤 3-从数据集创建面部编码

使用这些文章中的材料:

你会明白面部识别软件在照片中定位一张脸,然后识别 68 个兴趣点。从那里,它创建一个 128 维值向量。对于每个扩充的 LinkedIn 个人资料图片,收集 128 个值的向量,以及与该向量相关联的人的姓名。

这些信息最终被收集到一个表格中,表格中的每一行都代表一张个人资料图片,并带有一个人名标签列。这个集合被腌制并被称为编码。

技术细节

现在是时候创建一个单独的编码文件了。您可以通过以下方式实现这一点:

python encode_faces.py --dataset generated_images --encodings-file encodings/linkedin_encodings.pkl

这将对“generated_images”父目录中的所有目录进行编码,并将编码文件写入编码目录。这个编码文件包含每张图片的 128 维编码,以及标签,在本例中是人名。

第 4 步—启动笔记本电脑网络摄像头并预测

使用本文、PyImageSearch、 Face Recognition with OpenCV、Python 和 deep learnin g 中的信息,您将了解如何创建一个脚本来读取网络摄像头,逐帧捕获输入帧,并运行 face_recognition 包来预测视频帧与步骤 1–3 中的编码人脸的最接近匹配。

技术细节

现在,您可以打开计算机的摄像头,查看面部识别功能是否正常工作。执行以下操作:

python recognize_faces_video.py --encodings-file encodings/linkedin_encodings.pkl --input camera

如果一切顺利,你下载了你的个人资料图片,你应该看看是否预测自己。

结果

在我按照本文描述准备的 8 张 LinkedIn 个人资料照片中,所有照片都正确地识别了我的同事。

如果你有兴趣亲自尝试一下,我强烈推荐背景材料中的链接。他们将为您提供所有必要的技术背景和示例实现。

来自我的 LinkedIn 个人资料图片:

LinkedIn Profile Picture

并生成 30 张新图片:

30 Auto Generated and Augmented pictures

我可以训练一个面部识别模型来识别我。

离别的思绪

人们对面部识别的使用有很大的担忧,这种担忧是有充分理由的。然而,我们不能把这个技术精灵放回瓶子里——所以我们最好理解它是如何工作的,以及用一张照片创建一个面部识别系统是多么容易。政府不需要搜索车管所,只需点击任何一个社交媒体网站,拉一张照片。

使用机器学习算法

原文:https://towardsdatascience.com/using-machine-learning-algorithms-d47711ff4732?source=collection_archive---------38-----------------------

如何评估和改进机器学习模型的指南。

此时,您必须对线性回归、逻辑回归和神经网络等最常用的机器学习算法有一个基本的了解。但是,为了有效地应用这些算法,您可能需要阅读一些要点。

A note on the notation. x_{i} means x subscript i and x_{^th} means x superscript th.

特征工程

很明显,一个好的数据集可以产生一个好的模型。然而,考虑这样一个场景,你在一家计算机公司工作,你的新任务是预测服务器多久崩溃一次。为了构建模型,该公司向您提供了如下所示的服务器日志。

- - [30/Apr/2019:14:57:29 +0530] "GET /launched-version/scripts/vendor/angular-animate.min.js.map HTTP/1.1" 404 547 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.108 Safari/537.36"

您不能立即使用日志文件来开始预测服务器的健康状况。将原始数据转换成计算机可以操作的数据集的任务被称为特征工程。诸如服务器的运行时间、服务器的停机时间、客户端经历的等待时间、服务器抛出的错误类型或任何可测量的事物都可以被认为是特征。目标是创建有助于学习算法做出正确预测的特征。

现在,让我们来看几个用于特征工程的方案。

一键编码

大多数学习算法都适用于数值。但是,特征向量有可能是分类的。在这种情况下,我们需要将分类变量转换成数字变量。假设分类变量“血型”有四个可能的值——A、B、AB 和 o。我们可以使用以下映射将“血型”特征转换为数值。

A  = [1,0,0,0]
B  = [0,1,0,0]
AB = [0,0,1,0]
O  = [0,0,0,1]

请注意,转换增加了特征的维度。人们可能会争论执行编码,其中 1 对应于 A,2 对应于 B,3 对应于 AB,4 对应于 o。但是,这应该避免,因为它意味着值之间的排序。它可能会混淆学习算法,因为算法会试图在没有订单时找到订单。这也可能导致过度拟合。

扔掉

可能会出现将数值转换为分类值的罕见情况。宁滨允许进行这样的转换。例如,不是将“标记”表示为单个连续的特征,而是可以将它分成箱:100-90 之间的标记放入一个箱,89-80 之间的标记放入第二个箱,依此类推。

Example of Binning

宁滨告诉学习算法,重要的不是特定的数值(比如 85 分),而是数值的范围(比如 89-80 分)。它有助于更好地概括学习算法。

分割数据集

假设约翰被分配了训练机器学习模型的任务。他决定训练一个线性回归模型。

A linear regression model *f(x)*,is a linear combination of the features of the input examples *x*, and is represented by *f(x) = wx+b*.Transforming the original features (consider a 1-dimensional feature vector *x*) by changing their degree such as squaring or cubing them results in polynomial models (such as *f(x) = wx²+b* or *f(x) = wx³+b*).

然而,他在为他的线性回归模型选择 d 时遇到了麻烦。变量,如定义模型本身的被称为超参数。超参数甚至在训练开始前就已经设置好了。

一个解决方案是将数据集分成三个子集—

  • 训练集— 70%
  • 验证集— 15%
  • 测试集— 15%

在分割数据集之前,将数据集随机化是很重要的。此外,分割应该代表原始数据集。

The idea behind splitting the dataset so that the split is a good representation of the original data set.

分割完成后,训练集被用于训练,这为我们提供了一个模型。然后根据验证集评估获得的模型。

数据分析师可能会调整 hyper 参数,在训练集上训练模型,在验证集上评估模型,最后选择在验证集上表现最佳的模型。一旦选择了最佳模型,就要在测试集上再次评估它的性能和通用性。

拥有测试集的想法是,持续使用训练集和验证集来调整超参数可能会“磨损它们”,并导致过度拟合的模型,而不是一般化的模型。

Using the three sets.

欠配合与过配合

如果算法欠拟合,则称其具有高偏差。也就是说,算法对数据有很强的先入之见,不想去适应数据集。另一方面,过拟合算法被认为具有高方差。

Over fitting and Under fitting

一个模型很可能不适合——

  • 模型对于数据来说过于简单(例如,线性模型可能不适合);
  • 这些特征的信息量不足(假设您想要预测某个学生是否会通过某项考试,但是用于解决问题的特征是该学生的身高和体重。显然,功能的选择是有问题的。它们与手头的问题不相关)。

一个模型可能会过度拟合,以防—

  • 模型对于数据太复杂(考虑包括所有二次和三次项来训练简单的线性回归模型);
  • 您有太多的特征,但训练示例的数量较少(只有 50 个示例的数据集,其中每个示例有 100 个特征,这可能会过度拟合,因为算法没有足够的信息来观察数据集所有特征的模式)。

防止过度配合最常用的方法之一是调整

规范化

正则化有助于降低学习算法的复杂性。观察下面的等式—

Regularisation

这里的 J 是未调整的成本函数。我们的目标是找到假设函数 f(x) 的参数 wb 的值,使得非正则成本函数值最小。

现在观察正则化项,它只是我们假设函数 f(x) 所有参数的平均值。

正则化成本函数 J_{reg} 是这两项的简单总和。现在的目标是最小化正则化成本函数由于 J_{reg} 是两项之和,因此最小化其中任何一项都会导致其最小化。正则项给新的成本函数增加了额外的负担。成本函数上的每次迭代都受到正则化项的惩罚,因此,参数值随着每次后续迭代而被简化,从而防止过拟合。

λ 是一个超参数,用于控制惩罚成本函数的强度。如果 λ=0 ,则成本函数完全不被惩罚,导致高方差模型。在 λ 被设置为非常大的值的情况下,通过将大多数参数 w_{i} 设置为零来最小化成本函数,这导致高偏差模型。通常会测试一系列的 λ 值,并为模型选择在验证集上表现最佳的值。

学习曲线

学习曲线也有助于解决高偏差和高方差的问题。针对训练示例的数量绘制了由验证集和训练集生成的误差的图表。有目的地限制训练样本的数量,并绘制误差图。诸如均方误差函数的任何标准误差函数可用于计算验证集和训练集的误差。

Learning Curve

训练误差最初很小,因为训练样本的数量较少,或者我们可以说要处理的数据中的变化较少。然而,随着训练样本数量的增加,数据内的变化也增加,因此训练误差也增加。

最初,使用少量训练示例来训练模型,因此它不能很好地概括,从而在验证集上给出较高的误差。但是,随着训练样本数量的增加,模型开始泛化,验证集上的错误减少。

在过拟合模型的情况下,训练集和验证集的误差之间的差距很小,并且两个误差都取大值。因此,如果一个算法显示了这种行为,那么获得更多的训练数据将没有任何帮助。

另一方面,在欠拟合模型的情况下,训练集和验证集的误差之间的差距相对较大,验证误差也保持较高,因为模型不能很好地概括。这种行为可以通过收集更多的训练样本来改进。

模型性能指标

一旦我们有了模型,我们就使用测试集来评估模型的性能,并决定模型的泛化程度。有一些评估指标可以帮助我们分析模型的性能—

混淆矩阵

混淆矩阵总结了分类问题的预测结果。考虑下面的混淆矩阵—

Confusion Matrix

从该表中可以得出结论,在总共 25 封实际垃圾邮件中,该模型正确地预测了 20 封是垃圾邮件(真阳性),然而将 5 封电子邮件误分类为非垃圾邮件(假阴性)。类似地,在总共 510 封非垃圾邮件中,该模型正确地将 500 封电子邮件标记为非垃圾邮件(真阴性),但是将 10 封非垃圾邮件误分类为垃圾邮件(假阳性)。

混淆矩阵让我们了解学习算法所产生的错误模式。假设一个模型具有较高的假阴性率,这意味着该模型经常将垃圾邮件预测为非垃圾邮件。在这种情况下,用更多的垃圾邮件例子训练模型听起来是一个合理的选择。

在多类分类的情况下,使用一个对所有的方法,其中除了感兴趣的类之外的所有类被分组为单个类,从而将我们的问题转换为二元分类问题。一个 n 类多分类器给了我们 n 个混淆矩阵。

A classifier predicting three classes High, Moderate and Low is evaluated for the High class using a confusion matrix.

精确

精度是模型错误警报率的量度。

Calculating Precision of a Model

考虑到上面的混淆矩阵——在被模型分类为垃圾邮件的 30 封电子邮件中,20 封实际上是电子邮件,而剩余的 10 封被错误地标记为垃圾邮件,因此我们的准确率为 66%,误报率为 33%。

回忆/敏感度

Recall also known as Sensitivity.

召回反映了该车型的敏感度。它显示了真实阳性率。对于上述混淆矩阵,在总共 25 封实际垃圾邮件中,该模型正确地标记了 20 封电子邮件,但是将 5 封电子邮件错误地分类为非垃圾邮件,从而使得该模型对将电子邮件标记为垃圾邮件 80%敏感。

特征

特异性是一个相关的衡量标准,它告诉我们有多少被归类为非垃圾邮件的电子邮件实际上不是垃圾邮件。它测量真实负利率。上述混淆矩阵具有 98%的特异性。

Specificity.

作为一名分析师,我们希望控制精确度和召回率之间的平衡。大多数情况下,这取决于手头的问题——考虑一个试图将患者分类为癌症或非癌症的模型的情况。在这种情况下,人们可能希望有更高的回忆,也就是说,你不希望将实际的癌症患者错误地分类为健康的(避免假阴性)。无论如何,较低的准确率是可以接受的,这意味着,将一个健康的人归类为癌症患者并对他进行疾病测试(愿意接受假阳性)不会有什么坏处。然而,如果我们能以某种方式将精确度和召回率合并成一个术语,那将会非常有帮助。这将为我们提供一种更简单的方法来使用单一指标评估和比较模型,而 F-measure 正是这样做的。

f-测度

The F-Measure value.

数学上,F-measure 是精度召回的调和平均值。对较低的值赋予较高的权重。如果精度或召回率达到一个较低的值,那么 F-measure 就会下降,迫使我们调整我们的模型以给出更好的 F-measure 值。

使用机器学习将来自大脑的 EEG 信号分类为单词

原文:https://towardsdatascience.com/using-machine-learning-to-categorise-eeg-signals-from-the-brain-to-words-728aba93b2b3?source=collection_archive---------4-----------------------

这篇文章最初发表在我 2017 年的旧博客上,我现在再次拾起它,并将在不久的将来研究扩展这项技术,特别是智能手机和物联网设备的内置 AI/ML 功能…

这篇博文的标题差不多就是 TL;我已经尝试过(并取得了一些成功)的博士,尽管我可能一开始就不够资格去尝试。我的想法是在受试者思考说某些单词时从大脑中收集数据。在那里,我会用收集到的数据训练一个机器学习分类算法,然后使用得到的模型实时读取受试者的脑电波,并将它们分类为他们可能试图说的话。预期的结果将是一个应用程序,它可以读取试图说话的人的想法,并将这些话输出给他们试图与之交流的人。

这是在我祖母被诊断出患有一种叫做延髓麻痹的运动神经元疾病之后发生的,这种疾病开始影响她说话的方式。随着病情恶化,我开始想办法让她能够交流。她去看的医生给她提供了一个不合适的 iPad,而且对她不起作用。意大利语是她的第一语言,当她试图拼写英语单词时,使用苹果的文本到语音引擎就不会正确地拼写出来。我设法将安卓手机的文本到语音引擎切换到谷歌的文本到语音引擎,这允许她使用带有意大利口音的扬声器,据说这是用来将意大利文本转换成意大利语音的。有趣的是,当她用被认为是说意大利语的引擎用英语写作时,你能理解她想说什么。

下一个要考虑的问题是,如果她失去了双手的功能,或者有人试图使用这种方法,但他不会拼写,就像我祖母这个年龄的许多人一样。这是我想到用机器学习把脑电波转换成文字的时候。我对脑电波知之甚少,而且当时我只是狂热地阅读和宣传机器学习,并没有真正将其付诸实践。

读取脑电波

我在某处看到了脑电图(EEG)读数,意识到这些读数一定是由来自大脑的原始数字组成的,所以用某种软件解析它们会有多难。当我看到另一个关于 NeuroSky MindWave 移动耳机的视频时,我正在看一个 YouTube 视频,视频中有一个人把湿海绵绑在他的头上。你可以在这里阅读《科学美国人》的一篇文章,但它本质上是一个用来制作游戏和冥想应用的设备,符合我的两个需求:

1)它能读取脑电波,而
2) 它有一个 API ,我可以用它来读取原始数字格式的脑电波。

我不希望任何内部软件处理我的数据,尽管 MindWave 有一个内部处理器来确定你有多放松或专注,但它也允许你获得一个原始的脑电图读数,可以很容易地分成正确类型的脑波类别

我从阅读 Neurosky 的文档中了解到,SDK 会解析来自大脑的数据,并将其放在以下频带中:

这些值与我的想法之间的联系是,这些类别的脑电波用于解释大脑的不同状态,如上表右栏所述。更重要的是,我可以将这些值传递给机器学习算法,让它在识别这些值中的特定模式时预测一个人在想什么。我想依靠机器学习算法进行分类的原因是,我知道数据中会有噪声和差异,我无法可靠地用代码中的基本条件过滤掉自己。

Python 原型

在我花 150 美元买耳机之前,我决定做一个软件原型来测试我的想法是否真的可行。我首先完成了微软机器学习工作室的课程,然后进行了一些涉及住房数据的测试实验;预测房价等。一旦我很高兴四处导航并熟悉了不同算法的能力,我就开始用 Python 模拟一些脑电图数据。在 Python 中,我使用了下面的脚本,我已经将它上传到 GitHub 来将我的测试数据生成到一个 csv 文件中,然后我可以将它上传到我在 Azure 中的机器学习实验中。我让数据重叠,试图模拟真实数据中会出现的一些差异和噪声。我拼凑了一个机器学习实验来测试我的模拟数据,在我对结果感到满意后,我从 Neurosky 订购了耳机。

该系统

然后,我继续设计一个整体系统,这样我就能够朝着某个目标努力,而不会忘记我在做什么。我将我的项目命名为 Cerasermo,并提出了以下粗略的系统图…

该系统包括各种子系统,例如保存用户数据和潜在的大量 EEG 数据的数据库。我也有一些小的子程序计划去做一些我认为在解析大脑数据时可能需要做的事情。一个这样的子程序将处理这样一个事实,即我需要根据受试者的性别和可能的其他我还不知道的因素对数据进行归一化。这个想法是我从英格丽德·尼乌文胡伊斯和弗雷德里克·鲁在 T2 的交流中得到的,他们讨论了男性和女性的脑电图数据可能不同。我计划采用的跨主题数据标准化的实际实现是在 R-Bloggers 上发布的。然而,就目前而言,实施将针对单一主题;我自己,最终还有我的祖母。

安卓应用

我开始编写一个 Xamarin 应用程序,因为我熟悉这个框架,并且以前有过将 C# Xamarin Android 应用程序发送到 Google Play 商店的经验。当我将蓝牙添加到实现中时,我遇到了问题,因为 Xamarin 当时不支持常规的蓝牙(只有低功耗的蓝牙实现)。这迫使我切换到 Android Studio,并因此将我的应用程序语言从 C#翻译成 Java。我最终得到了计划中的 Cerasermo 系统的一个极其简化的版本;我让我的应用程序从耳机中读取 EEG 数据并导出到文件中。这整个过程,包括上传到我的 Azure 机器学习实验,非常慢,最终如果要按照我的计划在日常对话中使用,系统将需要完成。

Azure 机器学习

我使用了下面的机器学习实验,其中我将我的数据一分为二,以便我可以并排训练和测试我的两个入围算法…

我这里的两个分类算法是多类决策森林多类神经网络。我使用了微软的调谐模型超参数模块与整个网格扫描,以便自动选择两个模型的最佳参数。在这个神奇的备忘单的帮助下,我决定使用多类决策森林算法,因为我知道很难获得大量数据,我需要一个易于在短时间内用有限数据训练的模型。此外,根据我对算法本身的理解,该模型基于建立非线性决策边界,我认为这将作为分类模型很好地工作。出于好奇,我选择了多类神经网络算法来测试更多。

我最初选择了“是”和“不是”这两个词来检测,因为我觉得它们是彼此情绪上的对立面。在两个模型都达到接近 100%的预测准确率后,我决定添加单词“水”、“食物”、“快乐”和“悲伤”。我觉得我试图检测的单词类型在情感意义上是彼此对立的,因此会有很大不同的脑电波模式,使它们更容易分类。我将来自耳机的大部分数据输入算法,包括 EEG 信号的原始值、分类信号值以及注意力、冥想和眨眼值。我为每个单词记录了 5 个 30 秒间隔的数据。

两种算法的结果如下,左边是多类决策森林,右边是多类神经网络…

值得注意的是,除了比多类神经网络更准确之外,多类决策森林的训练速度也快得多。我不确定为什么多类神经网络没有更好地对脑电图数据进行分类,但我认为这与我输入模型的数据量有关。我可能需要记录更多的数据以供算法使用。对我的数据集中的字段应用权重也可能有所帮助。

我从实验中移除了多类神经网络,并在用实际数据测试之前重新训练了模型。测试时,我发现得到的模型极其准确;大约 95%的人在一系列 20 次测试中有一次错误地预测了水。当你看上面的混淆矩阵时,这是完全可以预料的。

对结果的反思

有趣的是,当我第二天早上再次测试该模型时,我的结果不太准确,我认为这与大脑在一段时间后和一天中不同时间的状态不同有关。大脑在处理单词时可能会发出不同的信号,这取决于情绪、饥饿、口渴和周围环境等因素。为了减轻这一点,我已经考虑过包括某种预训练,几乎是冥想,例行公事,以便集中精神提供一个更标准化的阅读。我可以通过潜在地向受试者展示某种模式或物体以及声音来实现这一点(万一他们失去了视力,他们仍然有一个可以依靠的基石)

尽管我的祖母可能无法从这项努力中受益,但我认为继续这项实验是值得的,因为它可能会帮助其他处于类似或更糟糕情况的人。我目前正在从我的祖母那里收集一天中不同时间的数据,以抵消我在训练后的早晨所经历的不准确性。我预计有了这些新数据,我可能需要重新配置算法。

虽然这个实验是一个成熟的实验,但我想象像这样的东西可以用于许多不同的目的,例如固定不动的人,或者它甚至可以用作一种安全形式或一种类似心灵感应的通信方法。另一种训练模型的方法是让它一直听并记录你的声音。和你呆了一天,听你说话后,它会知道当你想说某些单词时会发生什么,从而增加你的潜在词汇量。

在未来的博客文章中,我计划更深入地研究这个解决方案的数学原理,因为我希望有一天为了成本和速度的利益,使用我自己的算法而不是微软的算法。

欢迎在此评论或联系。有人对我的工作进行评估并提供反馈是非常好的,也是非常受欢迎的。我在业余时间做这个,和这个领域的其他人有些脱节,希望得到反馈和/或建议。

感谢阅读!

Cerasermo is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.

使用机器学习来了解你的胸痛是否是心脏病的征兆

原文:https://towardsdatascience.com/using-machine-learning-to-know-if-your-chest-pain-is-the-sign-of-heart-disease-or-not-f7bcf73be71b?source=collection_archive---------18-----------------------

医学机器学习

开发机器学习模型,以通过给定的胸痛和其他属性来分类该人是否患有心脏病

Photo by Marcelo Leal on Unsplash

先决条件

在开始项目之前,您应该具备以下基本知识:

  1. 计算机编程语言
  2. 熊猫(数据分析库)
  3. 科学计算库
  4. Scikit 学习(用于数据预处理和模型选择)

资料组

我们将使用加州大学 机器学习库提供的 心脏病数据集

UCI 页面提到以下人员是负责数据收集的主要研究者:
1。匈牙利心脏病研究所。布达佩斯:医学博士安朵斯·雅诺西。瑞士苏黎世大学医院:医学博士威廉·斯坦布伦。瑞士巴塞尔大学医院:医学博士马蒂亚斯·普菲斯特勒。弗吉尼亚医疗中心,长滩和克利夫兰诊所基金会:罗伯特·德特拉诺,医学博士,哲学博士。

介绍

在这个项目中,我们将通过使用患者的年龄、性别、胸痛类型、血压、胆固醇水平及其心脏病状况数据来对胸痛是否是心脏病的指征进行分类。

代码部分

2.1 准备数据

首先让我们看看我们的数据字典:

这里我们总共有 14 列,13 列是我们的特性,1 列是标签。

import **pandas** as **pd**df = pd.read_csv('data.csv')

我们正在用熊猫进行数据处理。

df.head()

在我们的数据集中,我们没有列的名称,现在我们的任务是根据数据字典为相应的列添加名称。

同样,我们将使用 pandas 读取 csv 文件,但这次我们也将向列中添加名称。

df = pd.read_csv('data.csv', sep=",", names=["Age", "Sex", "CP", "Trestbps", "Chol", "Fbs", "Restecg", "Thalach", "Exang", "Oldpeak", "Slope", "CA", "Thal", "Label"])df.head()

现在看起来不错。

2.2 探索数据

让我们检查信息,看看数据集中是否有空值。

df.info()

如您所见,每列有 303 个条目,没有任何空值。这对我们来说是个好兆头。

现在,让我们立即开始特征工程。

2.3 特征工程

众所周知,特征工程是数据科学中最关键的部分。从这里,我们应该能够深入了解我们的数据,并设计出对我们的分类贡献更大的最佳特征。

2.3.1 固定数据

通过观察数据,我们可以看到标签栏中的值偏差很小。因为这是一个二元分类问题,应该有 0 或 1 个值,但这里我们有 5 个不同的值。

如果我们查看由 UCI 提供的 数据描述 我们可以看到 label(num)列值分为两类:

  1. 值 0:表示没有心脏病
  2. 价值 1:意味着有心脏病

由此我们假设大于 1 的值也属于有心脏病一类。

让我们编写一个函数来映射这些值:

def **mapLabels**(value):
    if value > 0:
        return 1
    else:
        return 0

上面的函数获取值,如果值大于 0 则返回 1,否则返回 0。

让我们将其映射到我们的标签:

df['Label'] = df['Label'].map(mapLabels)
df['Label'].value_counts()

我们数据中的另一个问题是:

在我们的 CA 和 Thal 列中,我们将它作为对象数据类型,但是值是浮动的。

import **numpy** as **np**df.select_dtypes([np.object]).head()

这里我们使用 numpy 从数据集中选择对象数据类型。

经过一点挖掘,我发现,CA 和 Thal 列有一些空值设置为“?”。

让我们也修复这些数据:

def **caToFloat**(value):
    if not value == '?':
       return float(value)
    else:
        return 0df['CA'] = df['CA'].map(**caToFloat**)

这里,我们将 CA 列的值映射到 float 值和任何带“?”的值到 0。因为只有几个人?数据,我们的数据最初属于[0–3]类;可以将它们映射到 0。

对于 Thal 数据:

df['Thal'].value_counts()

如我们所见,我们的大多数数据都是 3.0 值,因此我们可以映射出'?'值到 3.0 ,因为它们只有 2 个数字。

df['Thal'] = df['Thal'].map(lambda x : 3.0 if x == '?' else float(x))df['Thal'].value_counts()

现在让我们检查我们的数据信息:

df.info()

我们所有的值都是数字。

让我们将连续年龄数据转化为类数据:

df.loc[df['Age'] <= 16, 'Age']  = 0,
df.loc[(df['Age'] > 16) & (df['Age'] <= 26), 'Age']  = 1,
df.loc[(df['Age'] > 26) & (df['Age'] <= 36), 'Age']  = 2,
df.loc[(df['Age'] > 36) & (df['Age'] <= 62), 'Age']  = 3,
df.loc[df['Age'] > 16, 'Age']  = 4

这里,我们将年龄数据分为[0,1,2,3,4]类,其中:

儿童:0 青少年:1 成人:2 中年:3 老年人:4

df['Age'].value_counts()

如你所见,我们的数据中没有孩子或年轻人。

这有助于更好的分类。你也可以寻找其他的特性并设计它们。

2.4 数据预处理

现在是准备分类数据的时候了。

labels = df['Label']
features = df.drop(['Label], axis=1)

这里,我们将特征和标签从数据帧中分离出来。

现在,我们将使用 scikitlearn 将我们的数据分成训练和测试数据。

from sklearn.model_selection import train_test_splittran_x, test_x, train_y, test_y = train_test_split(features,labels, shuffle=True)

2.5 型号选择

现在我们准备好训练我们的数据。

为了选择我们的最佳模型并在此基础上训练我们的数据,我们将使用 sklearn。

from sklearn.svm import SVC
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.naive_bayes import GaussianNB
from sklearn.model_selection import KFold, cross_val_score
from sklearn.ensemble import GradientBoostingClassifierk_fold = KFold(n_splits=12, shuffle=True, random_state=0)

在这里,我们将使用 KFold 交叉验证我们的数据,并从这些不同的分类模型中选择我们的最佳模型。

KFold 允许我们验证所有的训练数据,并帮助找到我们的最佳模型。

KFold

这里我们将使用 12 个折叠拆分。

现在,让我们训练我们的第一个模型是 SVC 或 SVM(支持向量机)

clf = SVC(gamma='auto')
scoring = 'accuracy'
score = cross_val_score(clf, train_x, train_y, cv=k_fold, n_jobs=1, scoring=scoring)
print(score)
## OUTPUT: 61.38

从 SVC 我们只能得到 61.38%的准确率。

让我们看看其他模型:

梯度推进分类器

clf = GradientBoostingClassifier()
scoring = 'accuracy'
score = cross_val_score(clf, train_x, train_y, cv=k_fold, n_jobs=1, scoring=scoring)
round(np.mean(score)*100, 2)## OUTPUT: 77.35

决策树分类器

clf = DecisionTreeClassifier()
scoring = 'accuracy'
score = cross_val_score(clf, train_x, train_y, cv=k_fold, n_jobs=1, scoring=scoring)
round(np.mean(score)*100, 2)## OUTPUT: 75.91

随机森林

clf = RandomForestClassifier(n_estimators=10)
scoring = 'accuracy'
score = cross_val_score(clf, train_x, train_y, cv=k_fold, n_jobs=1, scoring=scoring)
round(np.mean(score)*100, 2)## OUTPUT: 83.28

朴素贝叶斯

clf = GaussianNB()
scoring = 'accuracy'
score = cross_val_score(clf, train_x, train_y, cv=k_fold, n_jobs=1, scoring=scoring)
round(np.mean(score)*100, 2)## OUTPUT : 85.95

正如我们可以看到的,我们在朴素贝叶斯上得到了高分,所以我们将使用这个分类器进行分类。

我们的分数很低,因为我们没有正确设计我们的数据。你可以通过更多的数据清理和特征选择来获得更多的分数。

您还可以调整 hyper 参数以获得更好的效果。

2.6 培训模式

让我们使用朴素贝叶斯分类器算法来训练我们的模型:

clf = GaussianNB()
clf.fit(train_x, train_y)

现在让我们看看我们的预测:

predictions = clf.predict(test_x)
values = list(zip(predictions, test_y.values))status = []
for x, y in list_of_values:
    status.append(x == y)
list_of_values = list(zip(predictions, test_y.values, status))final_df = pd.DataFrame(list_of_values, columns=['Predicted', 'Actual', "Status"])

这里我们可以看到我们也有一些错误的分类,您可以通过改进我们的特征选择来改善这些。

结论

现在,我们的模型能够通过给定的各种特征来预测心脏病的迹象😀。

分类问题有时容易,有时非常困难,这完全取决于您使用哪种数据以及您在特征选择+模型超参数选择上付出了多少努力。

对于像我们这样的初学者来说,了解 ML 如何工作,探索数据集和解决问题是最好的学习方式。

暂时就这样了。希望你喜欢这个项目,并学到了一些东西。

使用机器学习来预测房价

原文:https://towardsdatascience.com/using-machine-learning-to-predict-home-prices-d5d534e42d38?source=collection_archive---------14-----------------------

LassoCV、RidgeCV 和线性回归机器学习算法。

Photo by Gus Ruballo on Unsplash

在这篇文章中,我将向你展示我使用机器学习来预测房价的数据科学过程。在开始之前,我想概述一下数据科学流程:

  • 定义问题
  • 收集数据
  • 清理和探索数据
  • 对数据建模
  • 评估模型
  • 回答问题

定义问题

我的任务是创建一个机器学习模型,使用 Kaggle 的 Ames 住房数据集预测房价。为了使数据科学问题更加现实,我添加了提高 Zillow 的 Zestimate 准确性(星级)的需求,用于像 Ames 这样有 3 颗星的地区(良好的 Zestimate)。这可能是由于假设的三星级酒店的用户网络流量增加。

收集数据

该数据集包含来自评估人办公室的信息,用于计算 2006 年至 2010 年在爱荷华州埃姆斯出售的个人住宅物业的评估价值。数据集包含 2051 行和 81 列(特征)信息。这些数据由 Kaggle 收集和提供。如果没有提供数据,我收集数据的方法是做研究,看看它是否公开,或者通过 Zillow 的 API 下载。

清理和探索数据

接下来,我执行了数据清理和探索性分析。对于前者,我检查空值和数据输入错误并做出决定。对于后者,我将数据可视化,以便更好地查看和理解关系和分布。

下面是我的目标变量——销售价格的两个可视化视图。我想了解它的分布。

the distribution of Sale Price, the target, which we can see is right-skewed

the distribution of Sale Price, the target, after taking the log — now it’s more normally distributed

我把目标的日志输入到模型中。我这样做是因为该模型将试图找到我们目标的满意中值,但如果不加处理,它会一直低估离群值,这会对 R 平方得分产生负面影响。根据 R 平方公式,我们的模型越错误,它将受到越多的惩罚,因为分子中的残差(误差)被平方。因此,对我们记录的目标进行预测将允许模型具有与欠猜一样多的过猜或更正态分布的预测。

接下来,我想了解我的特征与我的目标变量之间的关系,所以我绘制了我的特征与售价 0.50 或更高的相关性的热图。没有一个与销售价格呈负相关,相关系数为-0.50 或更低。

我想进一步研究这些关系,所以我从上面的关联热图中绘制了六个特征的散点图。

如您所见,与 0.80 的销售价格具有最强相关性的total _ qual在所选的六个中显示了最强的线性关系。

对数据建模

在这一步中,我将我的数据分为训练集和测试集,选择我的特征以馈入模型、特征工程方法和模型。我最初从一个向前选择的过程开始——选择一个特性,运行我的模型,检查性能,然后重复这些步骤。我还手动创建了一些交互术语,dummied(将分类特征转换为布尔矩阵),并映射(评分/加权分类特征)了一些我的分类特征。我选择的每一个功能都是有意为之的,无论是原样还是手工设计的。我主要依赖于该功能与销售价格的强相关性,以及我对某个功能是否会影响销售价格所做的直觉假设。使用这种方法,我得到了很好的结果,但后来我变得急切,并做出了(不正确的)假设,即如果我模拟或映射每个分类特征,然后在它们是数字后对所有特征应用多项式特征(整体相互作用项),那么我的所有特征对我的模型都将发挥最佳作用。

我检查了我新设计的功能与我的目标变量销售价格的相关性。你可以看到下面几个的结果。

correlations of the new dummied features to Sale Price

correlations of the new mapped features to Sale Price

正如你所看到的,我绘制的特征(第二张图)比我模拟的特征与销售价格有更强的相关性。我仍然坚持我的假设,继续给我的模型添加我所有的特征(当然除了售价)。

我选择了三种机器学习算法,分别是线性回归、RidgeCV 和 LassoCV。我知道有了大量的特征,我会提高我的过度拟合的潜力,所以我想包括后面的模型,因为它们有严格的正则化方法。我还假设多项式要素会处理我的要素之间的任何多重共线性。

评估模型

我的模特是拉索夫。它在我的训练数据上达到了 94%的 R 平方,在看不见的数据上达到了 86%。我的测试数据的 RMSE 是 37,334。这意味着两件事:1)模型解释了数据中 86%的可变性,2)模型过度拟合。

下面你可以看到我的预测(yhat)的分布覆盖在目标变量(y)上。

最终的模型不是我最好的模型。不幸的是,我重写了我的最佳模型中的特征——在我的特征选择和工程过程中我是故意的——因为做出了错误的假设,即把所有特征转换为数值并使用多项式特征会产生更好的结果。

回答问题

LassoCV 模型很好地处理了看不见的数据,所以我会用它来预测房价。

建议

我的一个建议是,通过以下方式继续测试/学习改进模型:

  • 重新审视我最初的正向选择流程
  • 选择与销售价格高度相关的功能
  • 创建新的并检查它们的相关性
  • 输入模型并检查结果
  • 跟踪改进模型的特性,并丢弃(但也跟踪)不改进模型的特性

查看 我的代码我的演示 。请评论任何问题。感谢阅读!

使用机器学习预测 Kickstarter 的成功

原文:https://towardsdatascience.com/using-machine-learning-to-predict-kickstarter-success-e371ab56a743?source=collection_archive---------4-----------------------

Kickstarter 适合你的项目吗?你如何优化以获得成功?

项目目标

近年来,个人和小公司创建的项目的融资选择范围大大扩大。除了储蓄、银行贷款、朋友和家人的资助以及其他传统选择,众筹已经成为一种流行且容易获得的替代方式。 Kickstarter ,成立于 2009 年,是一个特别知名和受欢迎的众筹平台。它有一个全有或全无的资助模式,即一个项目只有在达到其目标金额时才能获得资助;否则,资助者不会给项目提供资金。

一个项目的成败取决于各种各样的因素——一般来说,Kickstarter 也是如此。其中一些能够被量化或分类,这允许构建一个模型来尝试预测一个项目是否会成功。这个项目的目的是构建这样一个模型,并更广泛地分析 Kickstarter 项目数据,以帮助潜在的项目创建者评估 Kickstarter 对他们来说是否是一个好的融资选择,以及他们成功的机会有多大。

数据源

本项目中使用的数据集下载于。csv 格式,来自一个名为 Web Robots 的网络抓取网站。该数据集包含 Kickstarter 上托管的所有项目的数据,这些项目是从该公司 2009 年 4 月启动到 2019 年 3 月 14 日的网络搜集之日。该数据集包含 209,222 个项目,尽管其中一些是重复的。

清洁和预处理

为了将数据集转换成适合应用机器学习模型的格式,需要进行大量的清理工作。如果你对df.isna()df.drop()还不够,你可以在我的 GitHub 库中查看完整的 Jupyter 笔记本代码。

在删除了重复的和不相关的行(例如,在活动中期取消的项目,或者仍然有效的项目)之后,我得到了一个相当大的数据集,包含 168,979 个项目。

保留或计算的列有:

  • 项目目标(美元)
  • 活动持续时间——从发布到截止日期的天数
  • 从页面创建到项目启动的天数
  • 广告词长度
  • 名字字长
  • 项目是否突出显示为员工选择(一键编码)
  • 类别(一键编码)
  • 国家(一键编码)
  • 项目启动的月份(一键编码)
  • 项目截止日期的月份(一次性编码)
  • 项目启动的星期几(一键编码)
  • 项目截止日期的星期几(一键编码)
  • 项目启动的两小时时间窗口(一键编码)
  • 项目期限的两小时时间窗口(一键编码)

一些功能最初是为了探索性数据分析(EDA)的目的而保留的,但后来为了使用机器学习模型而被放弃了。这些包括与结果相关的特征(例如承诺的金额和支持者的数量),而不是与项目本身的属性相关的特征(例如类别、目标、活动的长度)。

探索性数据分析

现在是精彩的部分。

自 2009 年推出以来,Kickstarter 已经大幅增长,特别是在 2014 年,扩张真正开始加速。然而,在这一点上,成功的项目的比例大大降低了,因为站点被大量的项目淹没了。尽管近年来成功率一直在上升,但还是有希望的。

总体而言,56%的已完成项目(即那些已经完成且未被取消或暂停的项目)是成功的。

Changes over time in the number of projects launched on Kickstarter

Changes over time in project successes and failures

下图显示了成功项目和失败项目在某些特征上的差异。这里的关键要点是:

  • 不出所料,成功的项目往往有更小(因此更现实)的目标 —成功项目寻求的金额中位数是失败项目的一半左右(使用中位数是因为资金和目标金额的正偏高)。
  • 每个项目的承诺金额中位数的差异更令人惊讶。每个成功项目的承诺金额中值明显高于申请金额中值,这表明达到目标的项目往往会获得更多资金,并变得“资金过剩”
  • 与此相关的是,与目标金额相比,失败的公司和成功的公司在承诺金额和支持者数量方面的差异要大得多。可能一旦潜在的资助者看到一个项目看起来会成功,他们就更有可能加入并资助它。
  • 成功的项目活动时间稍短,但启动时间稍长(从项目首次在网站上创建时算起)。
  • 大约 20%的成功项目在网站上以员工选择的方式突出显示。在这里提出一种因果关系似乎是合理的,也就是说,被选作员工选择的项目更有可能继续成功,只有少数员工选择继续失败。

Comparison of features between successful and failed projects

在项目数量、目标和资金数额、支持者和成功率方面,探讨了各种其他特征。例如,下图显示了不同项目类别之间的差异(也提供了代码)。这里的关键要点是:

  • 在 Kickstarter 上推出的最佳项目类型是漫画(根据成功率、支持人数和承诺金额)、舞蹈(成功率和承诺金额)和游戏(承诺金额和支持人数)。这可能至少部分是由于它们相对较小的筹资目标——如上所述,目标较小的项目往往更成功。
  • 虽然漫画游戏往往吸引最多的支持者,但每个支持者往往认捐相对较少。舞蹈电影&视频往往吸引最慷慨的资助者。
  • 技术项目到目前为止拥有最高的中值目标规模。然而,就实际承诺的中值金额而言,他们在排行榜上垫底。
  • 表现最差的类别是食品新闻科技。
# Code used to create the graphs below# Importing the required libraries
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib import cm
import numpy as np# Creating a dataframe grouped by category with columns for failed and successful
cat_df = pd.get_dummies(df.set_index('category').state).groupby('category').sum()# Plotting
fig, ((ax1, ax2), (ax3, ax4), (ax5, ax6)) = plt.subplots(3, 2, figsize=(12,12))color = cm.CMRmap(np.linspace(0.1,0.8,df.category.nunique()))df.groupby('category').category.count().plot(kind='bar', ax=ax1, color=color)
ax1.set_title('Number of projects')
ax1.set_xlabel('')df.groupby('category').usd_goal.median().plot(kind='bar', ax=ax2, color=color)
ax2.set_title('Median project goal ($)')
ax2.set_xlabel('')df.groupby('category').usd_pledged.median().plot(kind='bar', ax=ax3, color=color)
ax3.set_title('Median pledged per project ($)')
ax3.set_xlabel('')cat_df.div(cat_df.sum(axis=1), axis=0).successful.plot(kind='bar', ax=ax4, color=color) # Normalizes counts across rows
ax4.set_title('Proportion of successful projects')
ax4.set_xlabel('')df.groupby('category').backers_count.median().plot(kind='bar', ax=ax5, color=color)
ax5.set_title('Median backers per project')
ax5.set_xlabel('')df.groupby('category').pledge_per_backer.median().plot(kind='bar', ax=ax6, color=color)
ax6.set_title('Median pledged per backer ($)')
ax6.set_xlabel('')fig.subplots_adjust(hspace=0.6)
plt.show()

Exploring the ‘category’ feature

为了空间和视网膜的利益,只有“成功比例”图表将显示在下面的额外功能。同样,要了解更多细节,请随时查看我的 GitHub 库。这里的关键要点是:

  • 香港的成功项目比例更高(它们的支持者人数和资助金额的中位数也更高)。
  • 周二是启动一个项目的最佳日子,周末最糟糕(筹集的金额和支持者的数量也是如此)。
  • 世界标准时间下午 12 点到下午 2 点是启动项目的最佳时间——这也是支持者人数和资金数额最多的时候。世界协调时下午 6 点到凌晨 4 点是最差的发射时间。
  • 十月是启动一个项目的最佳月份——它也拥有最多的支持者和资金。七月和十二月是最糟糕的月份。

Top left: success rates by country. Top right: success rates by the day of the week on which projects were launched. Bottom left: success rates by the time of day at which projects were launched (in UTC/GMT). Bottom right: success rates by the month in which projects were launched.

为机器学习准备数据

这个项目的最终目标是创建一个模型,该模型能够以较高的准确度预测一个项目是成功还是失败。

为了准备机器学习的数据,采取了以下步骤(代码如下):

  1. 一次性编码分类变量。
  2. 将数据分为从属目标变量“y”(在本例中为“状态”,即项目成功或失败)和独立特征“X”。
  3. 变换 X 轴上的要素,使其比例相同。对于这个项目,使用 Scikit-learn 的 StandardScaler 将每个特征转换为平均值 0 和标准差 1。
  4. 数据被分成训练集和测试集,用于模型的稳健评估。
# Importing the required libraries
import pandas as pd
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import train_test_split# 1) Creating dummy variables
df_transformed = pd.get_dummies(df_transformed)# 2) Separating into X and y
X_unscaled = df_transformed.drop('state', axis=1)
y = df_transformed.state# 3) Transforming the data
scaler = StandardScaler()
X = pd.DataFrame(scaler.fit_transform(X_unscaled), columns=list(X_unscaled.columns))# 4) Splitting into train and test sets
X_train, X_test, y_train, y_test = train_test_split(X,y, test_size=0.3, random_state=123)

在运行机器学习模型之前,而不是之后,选择一种评估方法是一种很好的做法。选择加权平均 F1 分数。F1 分数计算精确度和召回率之间的调和平均值,并且是一个合适的度量,因为在这种情况下没有对假阳性或假阴性的偏好(两者都同样不好)。将使用加权平均值,因为这些类的大小略有不同,并且我们希望能够预测成功和失败。

在运行机器学习模型之前,而不是之后,选择一种评估方法是一种很好的做法。

模型 1:标准逻辑回归

逻辑回归可用作二元分类器,以预测数据点属于两个类别中的哪一个。

为了创建一个基线模型进行改进,使用默认参数将逻辑回归模型拟合到数据中。

# Importing the required libraries
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import classification_report# Fitting a logistic regression model with default parameters
logreg = LogisticRegression()
logreg.fit(X_train,y_train)# Making predictions
y_hat_train = logreg.predict(X_train)
y_hat_test = logreg.predict(X_test)# Logistic regression scores
print("Logistic regression score for training set:", round(logreg.score(X_train, y_train),5))
print("Logistic regression score for test set:", round(logreg.score(X_test, y_test),5))
print("\nClassification report:")
print(classification_report(y_test, y_hat_test))

Results of the vanilla linear regression model

还不错。该模型的加权平均 F1 分数为 0.70。现在的目标是提高这个分数。

主成分分析

用于初始逻辑回归模型的数据集中有大量的要素(106)。PCA(主成分分析)被用于将其减少到更少数量的成分,这些成分仍然可以解释尽可能多的数据变化。这有助于提高模型拟合度和精确度。

下图(由下面的代码生成)显示 PCA 中使用的组件数量没有明显的界限。

# Importing the required libraries
import matplotlib.pyplot as plt
from sklearn.decomposition import PCA# Fitting PCA
pca = PCA()
pca.fit_transform(X)
explained_var = np.cumsum(pca.explained_variance_ratio_)# Plotting the amount of variation explained by PCA with different numbers of components
plt.plot(list(range(1, len(explained_var)+1)), explained_var)
plt.title('Amount of variation explained by PCA', fontsize=14)
plt.xlabel('Number of components')
plt.ylabel('Explained variance');

Plotting the amount of variation in the data explained by PCA using various numbers of components

发现了以下结果:

Number of components explaining 80% of variance: 58
Number of components explaining 90% of variance: 70
Number of components explaining 99% of variance: 90

为了选择在机器学习模型中使用的组件数量,使用默认参数将这些值中的每一个插入到逻辑回归模型的管道中:

# Running a for loop to test different values of n_components
n_comps = [58,70,90]
for n in n_comps:
 pipe = Pipeline([(‘pca’, PCA(n_components=n)), (‘clf’, LogisticRegression())])
 pipe.fit(X_train, y_train)
 print(“\nNumber of components:”, n)
 print(“Score:”, round(pipe.score(X_test, y_test),5))

结果显示,90 个组件的得分最高,尽管差异很小(从 58 个组件改进了约 3%):

Number of components: 58
Score: 0.67831Number of components: 70
Score: 0.6858Number of components: 90
Score: 0.70799

模型 2:具有 PCA 和参数优化的逻辑回归

逻辑回归模型可以通过优化其参数来进一步改进。GridSearchCV 用于测试多个不同的正则化参数(C 值)、惩罚(l1 或 l2)以及有截距和无截距的模型。

# Importing the required libraries
from sklearn.model_selection import GridSearchCV# Timing how long the model takes to run
logreg_start = time.time()# Building the pipeline
pipe_logreg = Pipeline([('pca', PCA(n_components=90)),
                    ('clf', LogisticRegression())])# Creating the parameters to test
params_logreg = [
    {'clf__penalty': ['l1', 'l2'],
     'clf__fit_intercept': [True, False],
        'clf__C': [0.001, 0.01, 1, 10]
    }
]# Using GridSearchCV to test multiple different parameters
grid_logreg = GridSearchCV(estimator=pipe_logreg,
                  param_grid=params_logreg,
                  cv=5)grid_logreg.fit(X_train, y_train)logreg_end = time.time()logreg_best_score = grid_logreg.best_score_
logreg_best_params = grid_logreg.best_params_# Printing the results
print(f"Time taken to run: {round((logreg_end - logreg_start)/60,1)} minutes")
print("Best accuracy:", round(logreg_best_score,2))
print("Best parameters:", logreg_best_params)

结果:

Time taken to run: 48.56 minutes
Best accuracy: 0.71
Best parameters: {‘clf__C’: 10, ‘clf__fit_intercept’: True, ‘clf__penalty’: ‘l2’}

然后使用最佳参数(根据准确度得分)为逻辑回归模型生成分类报告和混淆矩阵。

使用以下函数生成混淆矩阵:

def plot_cf(y_true, y_pred, class_names=None, model_name=None):
    """Plots a confusion matrix"""
    cf = confusion_matrix(y_true, y_pred)
    plt.imshow(cf, cmap=plt.cm.Blues)
    plt.grid(b=None)
    if model_name:
        plt.title("Confusion Matrix: {}".format(model_name))
    else:
        plt.title("Confusion Matrix")
    plt.ylabel('True Label')
    plt.xlabel('Predicted Label')

    class_names = set(y_true)
    tick_marks = np.arange(len(class_names))
    if class_names:
        plt.xticks(tick_marks, class_names)
        plt.yticks(tick_marks, class_names)

    thresh = cf.max() / 2.

    for i, j in itertools.product(range(cf.shape[0]), range(cf.shape[1])):
        plt.text(j, i, cf[i, j], horizontalalignment='center', color='white' if cf[i, j] > thresh else 'black')plt.colorbar()

最佳逻辑回归模型的完整结果如下:

Results of the best logistic regression model

超参数调整后,模型的准确度得分与使用默认参数的逻辑回归模型相同(加权平均 F1 得分为 0.70)。令人失望。

模型 3:随机森林

接下来,使用随机森林分类器。随机森林算法是一种监督学习算法,可用于分类。它通过构建多个不同的决策树来预测数据点属于哪个类别。

同样,GridSearchCV 用于测试多个不同的超参数,以优化模型。

# Importing the required libraries
from sklearn.ensemble import RandomForestClassifier# Using GridSearchCV to test multiple different parameters
rf_start = time.time()pipe_rf = Pipeline([('pca', PCA(n_components=90)),
                    ('clf', RandomForestClassifier())])params_rf = [ 
  {'clf__n_estimators': [100],
   'clf__max_depth': [20, 30, 40],    
   'clf__min_samples_split':[0.001, 0.01]
  }
]grid_rf = GridSearchCV(estimator=pipe_rf,
                  param_grid=params_rf,
                  cv=5)grid_rf.fit(X_train, y_train)rf_end = time.time()rf_best_score = grid_rf.best_score_
rf_best_params = grid_rf.best_params_print(f"Time taken to run: {round((rf_end - rf_start)/60,1)} minutes")
print("Best accuracy:", round(rf_best_score,2))
print("Best parameters:", rf_best_params)

结果:

Time taken to run: 72.2 minutes
Best accuracy: 0.7
Best parameters: {'clf__max_depth': 30, 'clf__min_samples_split': 0.001, 'clf__n_estimators': 100}

最佳随机森林模型的完整结果如下:

Results of the best Random Forest model

在超参数调整之后,模型的加权平均 F1 分数从具有默认设置的模型的 0.65 增加到 0.69。这类似于逻辑回归模型,尽管比它稍差。此外,训练集和测试集的得分之间的差异表明可能存在一些过度拟合。这里可能有更多的超参数调整空间来进一步改进模型,但是时间不允许。

模型 4: XGBoost

啊,卡格尔世界的宠儿。XGBoost 现在非常流行。这是一种梯度推进算法。与随机森林类似,它是一种生成多个决策树以改善数据点分类的集成方法,但它使用梯度下降来改善特别难以分类的数据点的模型性能。

返回用于超参数测试的 good ol' GridSearchCV:

# Importing the required libraries
from sklearn.model_selection import GridSearchCV# Using GridSearchCV to test multiple different parameters
xgb_start = time.time()pipe_xgb = Pipeline([('pca', PCA(n_components=90)),
                    ('clf', xgb.XGBClassifier())])params_xgb = [ 
  {'clf__n_estimators': [100],
   'clf__max_depth': [25, 35],
   'clf__learning_rate': [0.01, 0.1],
   'clf__subsample': [0.7, 1],
   'clf__min_child_weight': [20, 100]
  }
]grid_xgb = GridSearchCV(estimator=pipe_xgb,
                  param_grid=params_xgb,
                  cv=5)grid_xgb.fit(X_train, y_train)xgb_end = time.time()xgb_best_score = grid_xgb.best_score_
xgb_best_params = grid_xgb.best_params_print(f"Time taken to run: {round((xgb_end - xgb_start)/60,1)} minutes")
print("Best accuracy:", round(xgb_best_score,2))
print("Best parameters:", xgb_best_params)

结果:

Time taken to run: 865.4 minutes
Best accuracy: 0.7
Best parameters: {'clf__learning_rate': 0.1, 'clf__max_depth': 35, 'clf__min_child_weight': 100, 'clf__n_estimators': 100, 'clf__subsample': 0.7}

呀。14 个半小时,它仍然只能达到与初始回归模型相同的精度(这也仅比使用默认参数运行的 XGBoost 模型提高了 0.01 个精度)。

最佳 XGBoost 模型的完整结果如下:

Results of the best XGBoost model

与随机森林模型一样,训练集和测试集的准确性得分之间的差异表明可能存在一些过度拟合。同样,这里可能有更多的超参数调整空间来进一步改进模型——但是我没有另外 14 个半小时的空闲时间。

模型评估

在参数调整之后,每个模型能够实现大约 70% 的精度。虽然达到这一精度水平相对容易,但参数调整只能少量提高精度水平。可能只有两类中的每一类都有相当大的数据量,这意味着即使是相对简单的模型(如具有默认设置的逻辑回归)也有足够的数据来达到良好的验证准确度。

创建的最佳随机森林和 XGBoost 模型仍然表现出一定程度的过度拟合。需要进一步调整参数来减少这种情况。

最终选择的模型是调整后的逻辑回归模型。这是因为,尽管每个模型都能够为测试集达到相似的精度水平,但这是唯一没有表现出过度拟合的模型。

有趣的是,与成功相比,每个模型在预测失败方面表现更差,真实的否定率低于真实的肯定率。也就是说,它将相当多的失败项目归类为成功,而将相对较少的成功项目归类为失败。可能导致项目失败的因素更有可能超出数据的范围,例如营销不善、更新不足或没有回复潜在支持者的消息。

假阳性和假阴性率意味着,如果一个新项目的数据通过模型来预测其成功或失败:

  • 如果这个项目最终会成功,这个模型将会在大约 80%的情况下正确地预测它会成功
  • 如果项目以失败告终,模型只会在大约 60%的时间里正确地将其预测为失败(而其余的时间会错误地将其预测为成功)

对考虑 Kickstarter 的项目创建者的建议

对成功率和/或收到的资金数量产生积极影响的一些因素有:

最重要的是:

  • 较小的项目目标
  • 被选为员工选择(质量的衡量标准)
  • 漫画、舞蹈和游戏项目
  • 来自香港的项目

不太重要:

  • 较短的活动
  • 从创建到发布需要更长时间
  • 电影、视频和音乐项目(网站上的热门类别,相当成功)
  • 周二发布(尽管这也是最常见的项目发布日,所以要小心竞争)
  • 10 月发布
  • 在 UTC 时间下午 12 点到下午 2 点之间发布(这当然与项目发布的国家有关,但请记住,支持者可能来自世界各地)

对成功率和/或收到的金额有负面影响的因素有:

最负面:

  • 大目标
  • 食品和新闻项目
  • 来自意大利的项目

负面影响较小:

  • 长期活动
  • 在周末发布
  • 7 月或 12 月发布
  • 在世界协调时下午 6 点到凌晨 4 点之间发布

总体而言,Kickstarter 非常适合小型、高质量的项目,尤其是漫画、舞蹈和游戏。它不太适合大型项目,尤其是食品(如餐馆)和新闻项目。

感谢您读到这里!如果您有任何想法、意见或建议,请在下面添加。

使用机器学习预测体育比分——以橄榄球世界杯为例

原文:https://towardsdatascience.com/using-machine-learning-to-predict-sport-scores-a-rugby-world-cup-example-f699fd552673?source=collection_archive---------17-----------------------

Photo by Thomas Serer on Unsplash

扩展你的编码技能的最好方法之一是坚持做一个你感兴趣的项目。就在 9 月份 2019 年橄榄球世界杯开始之前,我决定尝试预测锦标赛的结果。

下面,我将介绍我尝试预测橄榄球世界杯小组赛的获胜者和分数的高级流程。希望它能鼓励你在你最喜欢的运动中尝试一下!

为了这个项目,我使用了 PythonJupyter 笔记本PyCharmPower BI (用于快速数据识别)。

第一步:获取数据

ESPN Scrum 有一个庞大的国际橄榄球比赛数据库。我想从 2003 年开始参加所有的国际橄榄球比赛。我选择这个日期是因为世界橄榄球排名是在 2003 年世界杯之前推出的(更多信息请见专题部分)。

ESPN Scrum match result database

但是这些数据被分割成 175 页——复制/粘贴不是一个实用的解决方案。美丽之声来救援。BeautifulSoup 是一个从 HTML 和 XML 文件中提取数据的库。下面你可以看到包含 2019 年 9 月 7 日威尔士比赛信息的原始数据:

Result of BeautifulSoup scraping for match results

我注意到 ESPN 的 URL 引用了页面和页面,所以我遍历了每个页面并存储了结果。

DataFrame of match results

我还添加了世界橄榄球排名作为一个特色。

World Rugby Rankings

第二步:数据准备

显然,收集到的数据并没有达到机器学习的完美状态,所以我需要清理一些小问题,例如删除反对派名称字段中的‘v’,并确保团队和反对派字段中的国家名称相同(我注意到一个字段中的美国是美国,另一个字段中的美国是美国。Pandas 让这变得相对简单——例如,参见 应用贴图 。我执行了一些其他的准备步骤,比如计算原始数据中的错误/空白,以及正确地格式化日期。

第三步:特征

世界橄榄球排名被合并到主数据集上,以便对每支球队应用最接近每场比赛日期的排名。

虽然我有世界橄榄球排名,但我仍然想为每支球队计算一个单独的、更简单的技能得分。我使用 Elo 评级系统的概括来计算相对技能。在这个系统中,玩家的等级根据比赛结果和两个队之间的相对等级差异而变化。在一个简单的例子中,如果排名第 10 的球队击败排名第 2 的球队,排名第 10 的球队将比排名第 15(较弱)的球队获得更多的评分。类似地,输了的排名第二的队伍会因为输给一个弱对手而比输给排名第一的队伍失去更多的评分。因此,该算法可以自我修正,并随着时间的推移“学习”每个团队的技能。

世界橄榄球排名考虑了各种比赛特征,如比赛状态(世界杯决赛得分更多)、主场优势和比赛得分。计算出的技能分数忽略了所有这些,而只是简单地看比赛结果和比赛时两队之间的相对技能。

让我们来看看这些排名在一段时间内的对比情况:

Official World Rugby rankings (23rd September) versus the calculated rankings

这里有一些有趣的结果——澳大利亚的排名高于预期,而爱尔兰和威尔士低于真实排名。我怀疑澳大利亚的高排名很大程度上受到他们最初高起点的影响(他们在 2003 年是世界排名第三的球队)。下面你可以看到随着算法的学习,一些团队的技能分数是如何随着时间而变化的。请注意,大约从 2014 年开始,英格兰、爱尔兰和威尔士的排名稳步上升。

Relative team skill score over time

总之,每场历史比赛的数据包括:比赛日期、比赛结果、得分、比分、两队的世界橄榄球排名以及两队的相对技能得分。

第四步:培训和测试

对于分数预测,我使用了 Keras,一个高级神经网络 API。Keras 中最简单的模型是顺序模型。

我进行了超参数调整(点击这里查看杰森·布朗利的伟大教程,并对宽(一层有很多神经元)和深(更多层,但每层神经元更少)网络进行了实验。我最终使用了第一层的 15 个神经元和第二层的 8 个神经元,都带有整流线性激活单元(ReLU)。我们没有为输出层使用激活函数,因为我们不想转换输出值。

Neural network topology

下面你可以看到一个损失(均方误差)的曲线图。

Neural network model loss against number of epochs

我也尝试了粉丝最喜欢的 XGBoost,,但是用神经网络得到了稍微好一点的结果,代价是训练时间更长。

第五步:预测!

作为模型输入,我创建了一个即将到来的世界杯小组赛的数据集,并给每支球队分配了他们最新的技能得分和排名。

那么预测的表现如何呢?比我预想的好多了(至少前 15 场)!在它预测的 30 场比赛中,它正确预测了其中 27 场比赛的冠军(预测日本对爱尔兰的比赛会令人震惊)。

该模型在前 15 场比赛中表现特别好,其中 10 场比赛的实际得分差异不到 5 分。

Model prediction results versus actual results

请注意,我没有在小组赛阶段重新训练模型,上面的结果是在世界杯开始时获得的。有趣的是,一旦大多数球队至少打了一场比赛,预测似乎会变得更糟。这是有意义的,因为相对排名和技能分数会发生变化,所以人们可以假设,如果我在第一轮游戏后更新这些功能并重新训练模型,预测会有所改善(我没有这样做,因为我太专注于观看实际的游戏了!).

无论哪种方式,对于几个晚上的工作来说都是不错的结果!机器学习是一个迷人的领域,如果你决定亲自尝试,请告诉我,还有很多需要改进的地方和可以添加的有趣功能。希望你喜欢这个演示!

这里有一些有用的资源可以帮助你开始:

用 BeautifulSoup 刮网

[## 网刮 MLB 统计与 Python 和美丽的汤

Codecademy 练习已经很好地打包了数据供我们使用。然而,会有很多场合当我们…

news.codecademy.com](https://news.codecademy.com/web-scraping-python-beautiful-soup-mlb-stats/) [## 如何用 Python 和 BeautifulSoup 刮网站

如何用 Python 和 BeautifulSoup 抓取网站互联网上的信息比任何…

www.freecodecamp.org](https://www.freecodecamp.org/news/how-to-scrape-websites-with-python-and-beautifulsoup-5946935d93fe/)

用熊猫操纵数据

[## 熊猫教程:Python 中的数据帧

使用 Python 探索数据分析。熊猫数据框使你的数据操作简单,从选择或替换…

www.datacamp.com](https://www.datacamp.com/community/tutorials/pandas-tutorial-dataframe-python)

数据科学

我强烈推荐 Jake VanderPlas 的优秀 Python 数据科学手册(包括示例笔记本)

[## Python 数据科学手册

该网站包含 Jake VanderPlas 的 Python 数据科学手册的全文;该内容可在…上获得

jakevdp.github.io](https://jakevdp.github.io/PythonDataScienceHandbook/)

【Keras 和神经网络入门

[## 你的第一个深度学习项目是用 Python 和 Keras 一步一步完成的

Keras 上一次更新是一个强大且易于使用的免费开源 Python 库,用于开发和评估深度…

machinelearningmastery.com](https://machinelearningmastery.com/tutorial-first-neural-network-python-keras/)

使用机器学习来理解客户行为

原文:https://towardsdatascience.com/using-machine-learning-to-understand-customers-behavior-f41b567d3a50?source=collection_archive---------2-----------------------

Photo by Amy Shamblen on Unsplash

并非所有的客户都一样

请把我的毛衣给我。我快冻僵了”——我的一个朋友 Lara 说。

“哇,那看起来像一件昂贵的毛衣” —玛利亚惊叫道

“是的,它花了我一大笔钱”——劳拉回答

我永远不会买这么贵的东西” — Maria 坚定地说— “我是说……我买得起,但是……真的不值得”

在我们的朋友群中,劳拉因为在衣服上过度消费而出名,仅仅因为这些衣服是由某个特定的品牌出售的。

另一个极端是玛丽亚。她赚了很多钱,但她不愿意在每件物品上花很多钱。

我们其余的人正好落在中间。

我喜欢买手表,我想一周的每一天都有一只。我愿意为它们付钱,但不是一个疯狂的数目。

我的一些朋友过去常常买许多便宜的东西。其他人只是喜欢把薪水花在外出就餐或美食活动上。

我有一个喜欢在网上订购东西的朋友。她讨厌去购物中心。所以每个月她都会少一百块钱,因为她点的东西太多了。

“不适合我” —我的另一个朋友过去常常自豪地说— “我需要试穿这双鞋,或者感受一下它的质量,才能买下它。我喜欢以旧的时尚方式购买。”

每个人都是不同的,他们作为顾客的行为也是不同的。

假设你是一家商店的老板。不管你是开电商还是开超市。不管是一家小商店还是亚马逊或网飞这样的大公司,了解你的客户更好

机器学习对于这项任务来说很方便。特别地,聚类,最重要的无监督学习问题,能够创建将相似个体分组的类别。

这些类别被称为集群。聚类是数据集中的点的集合。这些点在它们之间比它们与属于其他聚类的点更相似。

基于距离的聚类将点分组为一些簇,使得簇内的距离应该小,而簇之间的距离应该大。

Clustering example: A cluster is a collection of points which are more similar to each other that they are to points in another cluster.

有几种方法可以计算这些距离。你可以阅读我的帖子了解更多详情。

假设现在您能够收集持有会员卡的客户的基本数据。

您设法获得了客户 ID、年龄、性别、年收入和支出分数。最后一个是基于客户行为和购买数据的分数。

市场上有一些你有兴趣销售的新产品。但是您希望针对每种产品的特定类型的客户。所以,你需要在你的顾客中找到模式。

嗯……我们可以开始了吗?我们将使用 Python 的几个库来完成整个过程。

在所有的聚类算法中,我们将选择 K-means。

在将收集的数据读入pandas数据帧后,任何涉及数据科学的项目的下一步都是探索数据。

A quick overview of the first rows of the dataset.

这意味着探索数据的质量和变量的分布。有必要确定您是否有丢失的值。

K-means 算法不能够处理 缺失值 。处理缺失值总是很困难。如果只有少数观察值缺失,则可以将其从聚类中排除。

如果有大量的缺失值,有几个选项可用。

其中之一就是输入这些值。由于使用 K-means 进行聚类是基于距离计算的,因此应该仔细考虑输入它们的技术。

Missing values present in our dataset.

幸运的是,数据集不包含缺失值。

另一方面,我们还应该探索数据集中存在的变量类型。 分类变量 不能直接处理。

同样,K 均值是基于距离的。转换这些变量的方法取决于分类变量的类型。

Type of variables in the dataset.

我们确认(正如我们在数据集概述中已经看到的)变量Gender是分类的。

因为它是一个基数变量(它没有任何固有的顺序)我们可以把它转换成两个二元变量:Male,取值 0 或 1。Female,取值 0 或 1。

此外,您应该获得描述性统计数据,并绘制每个感兴趣变量的分布图。

我们将定义两个函数。第一个返回一些统计数据:平均值、标准差、中值、方差。我们的另一个函数绘制了每个变量的分布(你可以查看我放在文章最后的 GitHub repo 中的代码)。

Descriptive statistics for numerical variables.

Distribution of numerical variables.

此外,我们将分析数字参数之间的相关性。为此,我们将使用pairplot seaborn 函数。

我们想知道性别之间是否存在差异。因此,我们将设置hue参数来为属于女性或客户的点获取不同的颜色。

Pairplot showing the correlation between numerical variables. Also, it can be observed male customers in green and female customers in blue.

为什么在使用 K-means 时研究这些参数很重要?

因为我们需要满足算法假设。k 均值假设:

  • 簇的形状:分布的方差是球形的,意味着簇具有球形形状。为了做到这一点,所有变量都应该是正态分布的,并且具有相同的方差。
  • 聚类的大小:所有的聚类都有相同数量的观察值。
  • 变量之间的关系:变量之间很少或没有相关性。

此外,查看分布和描述性统计数据允许我们确定是否需要执行特征缩放。

k-Means 中的距离计算给每个维度分配相等的权重。如果一个变量的范围与其他变量完全不同,那么绝对变化可能会更大。这可能导致模型更加重视该变量。

在我们的数据集中,变量是正态分布的。方差彼此非常接近。除了年龄比其他变量的方差小。

我们可以找到一个合适的转换来解决这个问题。我们可以应用对数或 Box-Cox 变换。

Box-Cox 是一个变换家族,允许我们修正非正态分布变量或非等方差。它通过为所提供的特定数据选择最佳转换来实现这一点。调节这一点的主要参数由λ表示。

现在,我们将使用 主成分分析 (PCA) 来提取关于数据集的隐藏结构的信息。

PCA 是一种无监督学习算法。它基本上是一种降维算法。

它用于发现哪些维度最大化了数据集中存在的要素的方差。但它也可以用作可视化和特征提取等工具。

“降维”到底是什么意思?

我记得我在大学教数学的时候。最困难的部分是解释 n 维空间。更别说去想象 5 维、6 维或 90 维了。

为什么会这样?因为看二维或至多三维空间总是更容易将事物形象化。

假设我们想找出几个变量之间的关系。如果我们能够在二维空间中绘制这些变量,我们就能够马上描绘出它们之间的联系。

这是 PCA 进入的地方。在 PCA 中,这种关系通过找到数据中的主轴列表来量化。后来,它们被用来描述我们的数据集。

让我们来看看实际情况。我们有 5 个变量(AgeAnnual IncomeSpendingMaleFemale)。所以如果我们想把它们都画出来,我们需要 5 个维度。

相反,我们将应用来自sklearn模块的PCA函数。然后,我们将模型与最终数据集相匹配。并转换数据。

在拟合过程中,模型从数据中学习一些量:componentsexplained variance

Components and explained variance learn during the fitting process.

这些看似抽象的数字定义了矢量。分量定义了向量的方向,而解释的方差定义了向量的平方长度。

向量代表数据的主轴。向量的长度表示该轴在描述数据分布时的重要性。每个数据点在主轴上的投影就是数据的 主成分

我们可以用一种叫做双标图的散点图来表示。每一个点都用它在主成分上的得分来表示。

理解数据的降维是有帮助的。它还帮助我们发现主成分和原始变量之间的关系。

Biplot showing data scores regarding principal components.

我们可以观察到年收入和支出这两个最重要的组成部分。

聚类时间到!

为了对数据进行聚类,我们需要确定如何判断两个数据点是否相似。邻近性度量表征了对象之间存在的相似性或不相似性。

我们可以选择确定两个点是否相似。所以如果值大,点就很相似。

或者选择确定它们是否不同。值小的话,点也差不多。这就是我们所说的“距离”。

聚类算法可以使用各种距离:曼哈顿距离、闵可夫斯基距离、欧几里德距离等等。

还记得你在学校或者大学学的计算两点间的直线距离吗?你用的是欧几里德距离。

它是两个向量的相应元素之间的平方差之和的平方根。欧几里德距离的公式如下:

其中 x 和 y 是两个向量。或者用 Python 编码:

K-means 通常使用欧几里德距离来确定两个点的相似(或不相似)程度。

K-means 的过程简单明了。在开始模型之前,我们需要确定我们想要的集群数量。

不同数量的聚类会导致完全不同的结果。

有几种直接的方法可以实现这一点。其中,我们找到了剪影的方法。

我们将使用肘法。

请记住,聚类的目的是定义这样的聚类,其中的点彼此之间的相似性大于与其他聚类中的点的相似性。

为此,我们将考虑总的类内变异(或总的类内平方和(WSS))。我们会尽量减少。

肘方法关注的是总 WSS 如何随着星团数量的变化而变化。

为此,我们将计算一系列不同 k 值的 k 均值。然后,我们计算总 WSS。我们绘制了 WSS 对集群数量的曲线。

最后,我们定位图的拐点。这个点被认为是适当的集群数量。

为什么?因为如果我们继续增加聚类,WSS 不会提高,但我们将点聚集在一起的能力会下降。

查看该图,我们将选择 5 个集群。

我们忘记说了!K-means 中的 K 是指聚类数。在我们的例子中,是 5。

k-means 聚类是如何工作的?主要思想是选择 k 个中心,每个聚类一个。有几种方法可以初始化这些中心。我们可以随机进行,通过我们认为是中心的某些点,或者以一种巧妙的方式放置它们(例如,彼此尽可能远离)。

第一次放质心的位置很重要吗?是的,非常重要。不同的初始化质心会导致不同的结果。

然后,我们计算每个点和聚类中心之间的欧氏距离。我们将这些点分配到距离最小的聚类中心。

之后,我们重新计算新的聚类中心。我们选择位于每个聚类中间的点作为新的中心。

我们重新开始,计算距离,分配到集群,计算新的中心。我们什么时候停止?当中心不再移动时。

让我们看看 Python 的实现:

现在,让我们看看我们的集群是什么样子的:

回到我们最初的情况。我们想了解我们的顾客。分割它们。所以我们可以为他们提供合适的产品。

每个聚类的中心点与该细分市场的平均客户相匹配。

男性或女性似乎没有任何影响(他们在 0.5 左右。记住这是一个二进制变量)。

最重要的特征似乎是Annual IncomeSpending score

我们有收入较低但支出在同一范围内的人——第 0 部分。收入高且花钱多的人——第一部分。收入中等但消费水平相同的客户——细分市场 2。

然后,我们有收入很高的客户,但他们的支出最多,这就是细分市场 4。最后,收入少但消费高的人——第五部分。

最后一个音符。想象一下,明天我们有了一个新成员。我们想知道那个人属于哪一部分。

没问题!我们可以预测这一点:

现在,您已经准备好开展营销活动了!

→查看我的 GitHub 库 观看完整代码。←

在 Python 中使用魔法方法

原文:https://towardsdatascience.com/using-magic-methods-in-python-48f31685bc18?source=collection_archive---------11-----------------------

魔法方法如何增强我们的 Python 代码

Image Courtesy of Ramón Salinero via Unsplash

什么是魔术方法?

它们是面向对象 Python 中的一切。它们是特殊的方法,你可以定义它们来给你的类增加“魔力”。它们总是被双下划线包围,例如__init__。它们也没有被很好地记录下来。Python 的所有神奇方法都出现在 Python 文档的同一部分,但它们分散在各处,组织松散。那一节几乎找不到例子。

为了纠正缺乏关于魔术方法的文档的感觉,我编写了一些如何使用 Python 魔术方法的简单英语示例。

创建一个只能接受整数和浮点数作为其值的 dict 对象

首先,让我们创建一个虚构的用例。在这个场景中,我想创建一个创建字典对象的类,该类只接受整数或浮点数作为它们的值。

如果任何其他数据类型,例如;字符串、列表、元组作为一个值添加到我们的自定义字典对象中,将引发一个异常,向用户指定这个自定义字典对象只能接受整数和浮点数作为它的值。

为了实现这一点,我们将利用以下神奇的方法:

intsetitem,和 str

首先,我首先创建一个名为 CustomIntFloat 的自定义类,并将 dict 传递到参数继承列表中。这意味着,我们创建的对象将完全像一个字典,除了在我们选择有选择地修改这种行为的地方。

然后我创建一个 init 方法来构造我的 CustomIntFloat dict 对象。这个对象在它的参数列表中接受一个键和值,默认情况下我将它设置为 None 类型。这样做的原因是,如果用户创建一个 CustomIntFloat 类的对象,而没有传递一个键或值,将会创建一个空的 dict。我创建了一个简单的条件语句:如果没有传递键,默认情况下,键参数被赋予参数 None,并且通过引用 CustomIntFloat 对象创建一个空 dict,其类属性为 empty_dict。

接下来,如果用户指定一个长度为 1 的键,以及一个对应的值,该值是 int 或 float 类的一个实例,那么该键和值将在对象中设置。

最后,在 else 语句中,如果用户将多个键和值指定为 iterable,那么这些 iterable 将被 zip 函数压缩,并被赋予 zipped 变量名。我在 zipped 上循环,检查值是 int 类型还是 float 类型。否则,将引发自定义的 CustomIntFloatError 异常。

CustomIntFloatError 异常类和 str magic 方法

当我们引发一个 CustomIntFloatError 异常时,我们实际上是在创建一个 CustomIntFloatError 类的实例并同时打印它。

因此,这个自定义错误类需要 initstr magic 方法。我们创建的实例接受传递的值,并将其设置为 CustomIntFloatError 类中的属性值。

这意味着,当出现错误消息时,传递给 CustomIntFloat 的 init 的值可以设置为 CustomIntFloatError 类中的一个属性( self.value )并易于检查。

当指定无效输入时,将引发 CustomIntFloatError 异常,并且不构造该对象。一条有用的错误消息通知用户,只有整数和浮点数是有效值。

类似地,当您试图实例化具有多个键和值的对象 z(已被注释掉)时,将引发相同的异常,通知用户“三”不是有效的输入。

setitem 魔法方法

setitem 是一个神奇的方法,当我们在字典中设置一个键和值时就会调用它。一旦构造了 CustomIntFloat 对象,如果用户试图添加一个非 int 或 Float 类型的值,将引发相同的 CustomIntFloatError 异常。我在下面提供了一个代码片段,展示了如何根据需要设置一个键和值。

无效输入导致引发 CustomIntFloatError 异常,如下所示。

对于感兴趣的人,可以在我的 GitHub 页面上找到这些代码的源代码:

CustomIntFloat 类的摘要

通过继承像 dict 这样的内置类,我们可以通过魔术方法的重新实现来定制我们的行为。这有很多好处。

重要的是,用户不需要学习任何新的语法。当用户想要向 CustomIntFloat dict 对象添加一个键和值时,他们只需以通常的方式添加即可。唯一的区别是,我们有选择地只允许 int 和 float 类型的值。如果用户指定了任何其他类型,一个定制的错误消息会有效地告诉他们哪里出错了,以及需要什么类型的值。

快速发射魔法方法

使用数学运算符的示例

subadd,和 mul(带有自定义 repr)

我们还可以通过神奇的方法利用 Python 中的数学运算符。让我们看看如何在我们自己创建的自定义对象中使用神奇的方法,比如 addsub、和 mul

运算符,如+、-、/和*是多态方法。正如下面的 Python 提示所示,加号(+)是多态的,可用于连接字符串、对整数求和以及组合列表。这是可能的,因为所有这些类型 str、list 和 int 在它们各自的类中都有一个 add 方法。Python 只是将+号转换为调用它的对象上的 add 方法调用(见下面的例子)。

这意味着如果我们在类中包含 add 方法,我们就可以在自己的对象中利用+号。

我们类中的魔法方法运算符方法

在这里,我们创建了一个名为 NumOperations 的类。此类创建 NumOperations 对象。当该类的用户将列表传递给 init 的参数列表时,该列表被设置为 NumOperations 对象中的一个属性,并命名为。math_list。

当构造了 NumOperations 对象后,我们可以方便地利用这些神奇的方法来处理这些自定义对象,并广播一个数学运算。

举例来说,神奇的方法 sub 采用 2 个 NumOperations 对象,将它们的列表压缩在一起,并迭代它们对应的元组列表。从第一个元素中减去 tuple 中的第二个元素,然后将该值追加到一个名为 minuslst 的新列表中,并作为参数传递给 NumOperations 构造函数。

这会返回一个新的 NumOperations 对象。

此广播正在 sub 方法下执行。这意味着我们可以利用减号(-)操作符。

神奇的方法 repr 已被重新实现,以返回新对象中列表集的字符串表示形式。这一点已经过修改,因此当用户打印两个 NumOperations 对象的输出时,用户将会看到他们可能会看到的内容。

这里是一个列表,其中的元素已经彼此相减;

[90, 81, 72, 63, 54].

addmul 都有类似于 sub 的方法实现,但是使用列表理解来减少所需的代码行数。

The subtraction, addition and multiplication magic methods have been defined in order to work with the custom NumOperation objects.

这种广播行为类似于数据分析包中发现的行为,如 Pandas 和 Numpy。

addmul 方法也可用于两个 NumOperations 对象。这意味着用户可以利用加号运算符+和乘法运算符*。可以看出,在下面的例子中,q 是 x * y 的结果,它返回一个新的 NumOperations 对象。当我们打印 q 时,我们得到了 boradcasting 操作的字符串表示,作为一个列表。

对感兴趣的人来说,可以通过链接到我的 GitHub gist 获得源代码。

摘要

我们可以让定制设计的对象与 Python 操作符一起工作,比如加号、减号和乘号。这是非常强大的功能,部分功能来自于能够非常容易地交流对象所做的事情。用户不需要学习任何新方法,他们可以简单地将 NumOperations 对象加、减或乘在一起,当他们打印结果对象时,他们将看到他们可能期望的输出。

使用元神经元从单个训练示例中学习事实

原文:https://towardsdatascience.com/using-meta-neurons-to-learn-facts-from-a-single-training-example-781ca0b7424d?source=collection_archive---------14-----------------------

当人们看到一种新的动物,遇到一个新的人或参观一个新的地方时,他们不需要重复数千次来记住它——那么为什么计算机必须要这样做呢?

人类的学习有两种形式,一种快,一种慢。慢的需要大量的重复,这似乎是征服一个新的认知领域所必需的,比如学习一门新的语言。但是一旦掌握了一个领域,在这个领域内学习新的事实只需要很少,甚至可能只需要一个例子。似乎参与处理这一领域的大脑区域已经被预先连接到它们所依赖的区域。因此,一旦需要学习一个新的事实,这种预连线就被用来加速参与处理这个新事实的神经元的训练。重要的是,在培训过程中,要区分新知识和现有知识。否则,所有基于已有知识的联系都会因为重复学习已知的东西而丢失。因此,参与处理已知事实的神经元必须能够抑制新知识的形成。

兴奋性神经元、抑制性神经元和元神经元

那么,反映这种学习过程的神经网络会是什么样的呢?它由哪些组件组成呢?首先,我们需要三种不同类型的神经元。兴奋性神经元,本质上是连接的。它们允许表示由许多单独特征组成的模式。另一方面,抑制性神经元本质上是分离的,并且能够将兴奋性神经元分组。从技术上讲,兴奋性神经元和抑制性神经元几乎是相同的。唯一的区别是,对于兴奋性神经元,从神经元偏差值中减去突触权重的总和。最后,元神经元实际上不是真正的神经元。相反,它们是一组兴奋性神经元的集体代表。它们的输入突触不一定与单个神经元相连,而是与神经元群相连。但是我们怎么能提到一组神经元呢?这可以通过使用元突触来实现。元突触是元神经元的输入突触。与常规突触相反,它们能够通过使用抑制性神经元作为网关来连接整组兴奋性输入神经元。因此,元突触可以被视为一种连接整个兴奋性神经元群的神经束。

由这三种类型的神经元组成的示例性网络看起来如下:

在这里,现有的知识由兴奋性神经元来表示。通过抑制性神经元(Inhib-1)的负反馈突触,它们能够相互抑制,或者抑制元神经元(Meta-1)。因为这种反馈回路在网络的激活中引入了几个稳定状态,所以需要优化过程来确定最相关的状态。这篇 文章 包含了这个优化过程更详细的描述。现在,如果在给定的数据集中,没有一个兴奋性神经元被激活得足够强,而是元神经元(Meta-1)通过其输入突触获得足够的支持而被激活,那么元神经元就会产生新的兴奋性。在这个创建过程中,只有那些在训练示例中被激活的输入元突触被复制。通过抑制性神经元(Inhib-2)连接到一组兴奋性神经元的元突触直接与输入兴奋性神经元而不是抑制性神经元建立突触。

关系

在我们继续更详细地举例说明如何应用元神经元之前,需要解释另一个概念。在自然语言文本中,不仅单词本身有意义,而且单词之间的相对位置也有意义。像单词袋这样简单的模型丢弃了这些信息,这大大减少了它们的使用。像 LSTMs(长短期记忆)这样的新模型使用非常复杂的循环网络拓扑来处理这些关系。但是,难道没有更简单的方法来表示这种关系吗?有可能明确描述神经元突触之间的关系吗?单个神经元的激活必须成为可以相互关联的对象。结果,例如,代表一个单词的神经元在文本处理期间,即在该单词在文本中每次出现时,可以被激活几次。我相信,人类大脑通过使用个体激活尖峰的精确相对时间并将它们相互联系起来,做了一些非常相似的事情。

为了给出如何使用这些关系的例子,考虑以下具有两个输入突触的兴奋性神经元(猫),连接输入神经元“the”和“cat”。结束-开始关系确保了兴奋性输出神经元仅在单词‘the’的输入神经元激活的结束位置与单词‘cat’的激活的开始位置匹配时才触发。因此,只有当短语完全匹配时,输出神经元才会激活。开始到开始结束到结束关系在这个例子中被用于将整个短语的开始和结束位置传播到输出兴奋神经元(cat)。

学习人名

为了给出元神经元如何应用的更详细的例子,我们现在将展示一个先前未知的人名是如何被训练并因此被翻译成新的兴奋性神经元的。我们假设,姓名的形式为 <称谓形式> <名> <姓> 。对于任何给定的示例名称,我们都需要考虑几种情况。首先,名字作为一个整体可能是已知的,在这种情况下,它不需要学习,或者是未知的。第二,给定的示例数据集实际上是个人姓名还是有完全不同的含义?第三,已经知道的词是潜在的名还是姓?第四,单词本身是已知的,还是之前从未见过的字母序列?

为了使神经网络模型能够回答所有这些问题,需要在模型中实现三个阶段。第一阶段将单个字母作为输入,并使用它们来表示模型的词汇。因此,如果我们遇到一个完全陌生的单词,并使用元神经元将其识别为一个单词,我们就能够诱导一个新的兴奋性神经元来代表这个确切的单词。

下一阶段代表这些单词的意思。模型的这一部分决定了一个给定的单词是否有名字、姓氏、城市名或其他完全不同的含义。在下图中,两个抑制性神经元I-名字I-姓氏用于对名字和姓氏进行分组,抑制性神经元I-实体用于允许单词的不同含义相互抑制。注意,在这个例子中,一个兴奋性神经元,例如 E-Lisa(名字),可以同时与几个元神经元相关联(M-名字M-实体)。这意味着两个元神经元可能通常用于创建一个单一的兴奋性神经元。

例如,以一个还不知道其含义的词为例,比如一个名字。如果这个单词的上下文使得它很可能实际上是一个名字,那么这个阶段的元神经元可以用于诱导新的兴奋性实体神经元来将这个单词的意思表示为名字。请注意,这些实体神经元可能使用正反馈突触连接到代表完整个人姓名的下一个阶段。这是很有帮助的,因为如果我们知道某个单词被嵌入到一个完整的个人名字的特定位置,那么它更有可能实际上是一个名字。这仅在神经元 I-Personal Name 的激活传播名字和姓氏的开始和结束位置时有效。

最后阶段学习一个人的全名。这一阶段的每个兴奋性神经元指的是一个特定的人名,元神经元用于识别系统尚不知道的人名。

这个图中的黄色虚线箭头用来显示哪些元突触被用来创建哪些兴奋性突触。

这个模型的有趣之处在于,新的神经元在模型的不同阶段同时被诱导,并且仍然被正确地连接起来。因此,如果在未知的个人姓名中存在未知的名字,那么两个兴奋性神经元仍然可以被诱导,并且代表个人姓名的新的兴奋性神经元可以通过输入突触依赖于代表作为名字的单词的神经元。

让我们看看,如果将下面的训练示例输入到网络中,会发生什么。

杰克逊·史密斯先生

在这个例子中,单词“先生”已经被认为是可能的称呼形式,而“史密斯”被认为是可能的姓。到目前为止,“杰克逊”这个词只被认为是一个城市名或一个姓氏,而不是一个可能的名字。因此,元神经元必须诱导两个兴奋性神经元。第一个是实体神经元,表示单词 Jackson 作为名字的含义。这个神经元与单词“Jackson”的神经元相连,并通过一个正循环突触与全名的抑制性神经元相连。

第二个被诱导的兴奋性神经元是代表全名的神经元。这个神经元依赖于地址形式的神经元E-Mr,名字形式的神经元 E-Jackson (First Name) 和姓氏形式的神经元 E-Smith (Surname) 。在诱导过程中,元突触的权重和关系被简单地转移到新的兴奋性神经元的突触。元神经元还使用单独的训练偏差来确定何时应该诱导新的神经元。

开放式问题

爱歌项目 ( GitHub )的目标是为所有三种类型的神经元开发一个完全训练好的模型。此外,该训练过程应该在无人监督的情况下进行,并且应该能够从训练数据中创建网络拓扑。由于每种神经元类型在模型中具有非常不同的行为和目的,因此需要针对每种神经元类型的专门训练方法。在这一探索中出现的一些悬而未决的问题如下:

  • 兴奋性神经元和兴奋性突触如何从零开始诱导?换句话说,如果两个或两个以上的随机神经元持续且频繁地一起放电,如何利用这个观察来创造一个新的兴奋性神经元?
  • 在缓慢学习过程中,如何独立于元神经元训练兴奋性神经元?由于兴奋性神经元本质上是连接的,因此可以使用 Kullback-Leibler 散度(即信息增益)作为调整突触权重的目标函数来训练它们。这种想法是优化兴奋性神经元的突触权重,使其能够压缩表示神经元输入信号所需的信息量。因此,举例来说,如果有五个输入神经元,每个代表一个单词的字母,那么代表整个单词的兴奋性神经元需要明显更少的信息来传递相同的信息。关于突触权重的 KL-Divergence 的推导的一个很好的属性是,它优雅地捕捉了关于学习过程的一些直觉,例如 Hebb 规则:“什么将电线一起点燃”。或者说,如果一个突触不能与其他输入一起触发,它就会被削弱。我会在以后的 博文 中更详细地解释这个想法。
  • 抑制性和元神经元的训练是怎样的?与兴奋性神经元不同,抑制性和元神经元不能直接从数据中训练。由于抑制性神经元代表一类兴奋性神经元,显然在可用于训练的数据中没有发生同现。因此,为了训练抑制性和元神经元,我们需要从单个兴奋性神经元中抽象出来。换句话说,兴奋性神经元需要根据它们输入突触的一些共同特性来聚集。在某些情况下,需要创建新的输入抑制性神经元来分组一组输入神经元,这些输入神经元在分组的兴奋性神经元之间是不同的。
  • 兴奋性突触的变化是如何传播到元突触的?
  • 关系是如何培养的?
  • 目前,将几个元神经元分配给单个兴奋性神经元的能力仍在研究中。

使用混合效应模型进行线性回归

原文:https://towardsdatascience.com/using-mixed-effects-models-for-linear-regression-7b7941d249b?source=collection_archive---------4-----------------------

结合全球和集团层面的影响

当您的数据包含全局和组级别的趋势时,混合效应回归模型是线性回归模型的强大工具。本文通过一个使用虚拟数据将锻炼与情绪联系起来的例子来介绍这个概念。在最近的新闻中,R 经历了一段不该经历的艰难时期,所以这篇文章将使用 R 作为对这种语言的小小慰问,尽管 Python 中也存在一个健壮的框架。

混合效应模型在政治投票分析中很常见,其中假设国家级特征发生在州级,而州级样本量可能太小,无法单独驱动这些特征。它们在科学实验中也很常见,在这些实验中,假设某一特定效应存在于所有研究个体中,需要从对治疗组的特定效应中梳理出来。同样,这一框架有助于干预措施的事前/事后研究。

数据分析

该数据模拟了对 4 个州的居民进行的调查,这些居民被问及他们的日常锻炼习惯和总体情绪,评分范围为 1-10。出于举例的目的,我们将假设情绪分数是线性的,但是在现实世界中,我们可能希望将它视为一个序数变量。我们将会看到(因为我编造了数据)锻炼改善了情绪,然而有很强的州级效应。

summary(data)

初试:固定效应线性回归

锻炼和情绪之间有明显的正相关,尽管模型拟合不是很好:锻炼是一个重要的预测因素,尽管调整后的 r 平方相当低。顺便说一下,我喜欢用 R 来解决快速回归问题:清晰、全面的输出通常很容易找到。

reg1 <- lm(Mood ~ Exercise, data = data) 
summary(reg1)

with(data, plot(Exercise, Mood))
abline(reg1)

我们可能会在这一点上得出结论,数据是有噪声的,但让我们再深入一点。回想一下,线性回归的假设之一是“同方差”,即所有自变量的方差都是常数。当存在异方差时(并且违反了同方差),回归可能会对误差方差最大的数据子集赋予过多的权重。您可以通过查看残差图来验证这一假设。

作为参考,下面是一个不违反同质性的线性回归。

x <- rnorm(25, 0, 1)
y = 2*x - 0.5 + rnorm(25, 0, 0.25)reg.test <- lm(y ~ x) 
plot(x, y)
abline(reg.test)
plot(x, resid(reg.test), ylab="Residuals", xlab="x") 
abline(0, 0)

然后是我们的数据:

plot(data$Mood, resid(reg1), ylab="Residuals", xlab="Mood") 
abline(0, 0)

该图表明,简单的线性回归是不合适的——该模型始终为低情绪得分生成负残差,为高情绪得分生成正残差。在这一点上,我们可能会怀疑情绪和状态在某种程度上是相关的,或者模型没有合并,这是一个很好的猜测= >残差的方差因状态而异。

plot(data$State, resid(reg1), ylab="Residuals", xlab="Mood") 
abline(0, 0)

第二次尝试:更稳健的线性回归

但是等等——如果状态是一个预测因子,让我们把它包含在我们的回归中并修正一切。我们会看到这个基本上是正确的。

reg2 <- lm(Mood ~ Exercise + State, data = data) 
summary(reg1)

with(data, plot(Exercise, Mood))
abline(reg2)plot(data$State, resid(reg2), ylab="Residuals", xlab="State") 
abline(0, 0)

r 平方显著改善,但现在绘制的线看起来非常愚蠢——我们一直低于预期,运动的系数估计值接近于零(并且具有不显著的 p 值)。这是异方差效应的一个例子——方差较大的组(即州)会覆盖方差较小的组。

我们有进展了。如果我们对每个州做单独的线性回归会怎么样?那样的话,我们就不会有群体相互作用扭曲我们系数的问题了,对吧?

library(ggplot2)
ggplot(data, aes(x = Exercise, y = Mood, color = State)) +
  geom_point() +
  geom_smooth(method='lm',formula=y~x)

那么,我们现在有一个相反的问题——注意,在状态 C 中,锻炼正在降低情绪。而且其他状态下的斜率系数也远低于我们在心情~运动回归中看到的 0.42951。所以现在我们忽略了高层模型中的信息,因为我们关注的是州级模型。

混合效果模型

上面的最后一个例子直接导致了一个混合效果模型。在这个模型中,我们可以允许州级回归包含来自整体回归的一些信息,但也保留一些州级组件。我们可以使用 lme4 库来做到这一点。

该符号类似于 lm 回归,但有一个关键区别:( 1 + Exercise | State)符号允许模型对每个状态值的 Mood ~ Exercise 使用具有不同斜率和截距的项。见下面的系数值。

library(lme4)reg3 <- lmer(Mood ~ Exercise + (1 + Exercise | State), data = data, REML = FALSE)
summary(reg3)
coef(reg3)

我们现在已经运行了 3 个模型:

  1. 心情~运动
  2. 心情~运动+状态
  3. 心情~运动+ (1 +运动|状态)

我们可以计算每个模型的 RMSE。

reg1_predict <- predict(reg1, data[1:2])
reg2_predict <- predict(reg2, data[1:2])
reg3_predict <- predict(reg3, data[1:2])sqrt(sum((data[3] - reg1_predict)**2))
sqrt(sum((data[3] - reg2_predict)**2))
sqrt(sum((data[3] - reg3_predict)**2))

从模型 2 到模型 3,RMSE 的进步显著——这表明状态和情绪之间的差异主要是由于每个状态的平均情绪。从模型 2 移动到模型 3 捕获了这个州级截距信息,但是也计算了每个州的 Mood ~ Exercise 的斜率系数,该斜率系数结合了来自总数据集和州级信息的信息(回想一下,仅使用州级斜率信息在州 C 中产生了负斜率)。

关于混合效应模型的最后几点说明。对于如何确定混合效应模型的 p 值,有多种方法和正在进行的研究。可以使用 anova 似然检验来确定添加的变量相对于没有添加该变量的模型是否显著。

结论

混合效应模型为平滑数据中的全局和组级别特征提供了一个框架。

我主要是从 Richard McElreath 和他的精彩文章统计学再思考中了解到这些模型的。我向所有读者强烈推荐这本书:这本书对重新思考许多在入门课上为我做的统计假设有很大帮助,我从来不知道要重新考虑这些假设。

OJ Watson 也有一个做得很好的 Kaggle post ,它为混合效果模型提供了一个基于 python 的框架。

使用 ML 进行假期规划:总结 Airbnb 评论

原文:https://towardsdatascience.com/using-ml-for-holiday-planning-summarising-airbnb-reviews-193abb002232?source=collection_archive---------29-----------------------

Photo by Arno Smit on Unsplash

当谈到假日住宿时,Airbnb 是第一个立即想到的途径。

随着 Airbnb 的流行,世界上大多数主要城市都有成千上万的 Airbnb 住处。即使按照人数、Airbnb 房产类型以及入住和退房日期进行过滤,我们仍然有很多选择。

在选择 Airbnb 时,除了明显的要求——价格、位置和便利设施,我倾向于花时间阅读客人评论,以了解更多关于主人的信息以及我在那里住宿时可以期待的体验。唯一的问题是这种手工操作非常耗时!

一定有更好的方法!

“我怎样才能在不通读一页页评论的情况下,对之前的顾客体验有一个简明的了解?”

我不仅想知道大多数评论是否是正面的。我也很想知道大多数客人对他们的经历都说了些什么。

有了我的问题框架,我决定用 3 种不同的方法来解决这个问题——主题建模,使用 TF-IDF ( T erm F 频率— I 反向 D 文档 F 频率)提取相关关键词,以及文本摘要。

目录

——数据
——我们来讨论一下途径
— — 1。主题造型
2。TF-IDF
3。文字总结
行动中的提取(我是如何利用它来度假的?)
——结尾

数据

我使用过来自 InsideAirbnb 的阿姆斯特丹 Airbnb 评论。在过去 10 年中,客人在阿姆斯特丹逗留期间对 15,000 个房源提交了 450,000 条评论。

**预处理 **

平均每年有 440 万外国游客到访阿姆斯特丹。因此,我们可以预期一部分评论会用英语以外的语言撰写。在探索数据集时,这一点很快得到了验证。

由于数据集不包含语言字段,我不得不使用 FastText 的语言识别模型来预测文档的语言,并使用该信息过滤掉非英语评论。该模型对我的用例来说非常棒,因为它快速而准确,在包含许多不同欧洲语言的 EuroGov 数据集上达到了 98%以上的准确率。

除了语言之外,相同的reviews.csv数据集对于每种方法的处理略有不同。这将在下面简要介绍。

对于每种方法,我都使用了来自同一个清单#2818 的 211 篇评论进行比较。

让我们讨论方法

1.主题建模

主题建模是一种无监督的机器学习方法,通常用于在文档集合中发现抽象主题。它认为每个文档都由主题的混合来表示,每个主题都由一组频繁出现的单词来表示。

主题建模将文档中发现的单词聚类成n个主题。每一串单词代表一个抽象的主题。例如,通过一串单词badminton, taekwondo, football,我们可以确定相关的抽象主题与sports相关。

我将使用潜在狄利克雷分配 (LDA),主题建模最流行的例子之一。

实现

  • 资料准备
  1. 符号和停用词已被删除
  2. 使用雪球算法(改进自 Porter)对令牌进行词干提取
  3. 使用 unigrams 为每次审查创建的 TF-IDF 向量
  • 代码

  • 示例输出

Topic #1:
['<host>', 'provid', 'map', 'came', 'stay', 'amsterdam', 'travel', 'took', 'late', 'would']

Topic #2:
['<host>', 'everyth', 'good', 'kind', 'well', 'part', 'clean', 'comfort', 'also', 'guest']

Topic #3:
['<host>', 'host', 'stay', 'room', 'clean', 'place', 'great', 'help', 'amsterdam', 'map']

Topic #4:
['<host>', 'jouri', 'worthi', 'chang', 'session', 'vacat', 'overal', 'weed', 'scare', 'classi']

Topic #5:
['<host>', 'stay', 'get', 'room', 'host', 'amsterdam', 'provid', 'apart', 'also', 'come']

我们来分解一下发现的话题:

  1. 主题 1 相当模糊。很难解释它的意思。“迟到”是对主持人的负面评价吗?还是客人们在谈论主人如何因为他们迟到而等待他们?或者主人会如何回应他们迟到的回复?
  2. 第二个话题暗示主人很好,很亲切,这个地方很舒适,很干净。
  3. 话题 3 表明主人帮了很大的忙,这个地方也很棒很干净。
  4. 主题#4 暗示客人们享受他们的旅程..也许包括大麻?
  5. 第五个话题也相当模糊。
  • 好与坏

好的 : 主题是从数据本身自动发现的,不需要任何标注数据。

坏处: 除非你有先验知识,否则没有正确的方法来预先决定主题的数量。这需要反复试验。在最好的情况下,LDA 只能提供数据中存在的主题的粗略概念。将一组单词解释成一个抽象的话题是一种主观的猜谜游戏。

2。TF-IDF

TF-IDFTermFfrequency-In reverseDdocumentFfrequency。这种评分机制通常用于信息检索和文本挖掘,以反映文档中单词的相关性。

这个分数有两个部分:

  • 词频—word 在文档中出现的次数
  • 逆文档频率—word 在文档集合中出现的次数的倒数。术语 值得注意,因为我们对在所有文档中频繁出现的单词不感兴趣。

在文档中频繁出现但在集合中不频繁出现的单词将具有高 TF-IDF 分数,因为该单词与文档相关。例如,在一篇讨论“8 小时睡眠的好处”的文章中,我们可以预计sleep会有较高的 TF-IDF 得分,因为该词在文章中会被频繁提及,但在其他文章中可能不会被频繁使用。

相比之下,the, good, how这样的词是常用词,可以用在各种文章中。这些词的 TF-IDF 得分较低。

同样值得一提的是,不同文档中的同一个单词会有不同的 TF-IDF 得分。

实现

  • 数据准备
  1. 符号和停用词已被删除
  2. 使用雪球算法(改进自 Porter)对令牌进行词干提取
  3. 使用二元模型为每次审查创建的 TF-IDF 向量
  • 代码

  • 示例输出

['great host', 'perfect host', 'public transport', 'high recommend', 'place clean', 'get around', 'make sure', 'stay amsterdam', 'recommend stay', 'host place']

所有客人评论的前 10 个相关关键词表明主人很棒,这个地方很干净,他们强烈推荐这个地方。还经常提到公共交通。

与 LDA 相比,从 TF-IDF 中提取的关键字不那么模糊。但是还是有像make sureget around这样的关键词有点太模糊,无法解读。

  • 好与坏

好: 使用统计方法提取相关关键词。实现简单。

不好: s 不考虑不同单词的语义。像clean apartmentclean flat这样的术语语义相同,但是在 TF-IDF 中,它们被当作两个不同的字符串。

3.文本摘要

文本摘要用于在一个文档或一组文档中找到信息最丰富的句子。摘录摘要是最流行的方法,它涉及选择最能代表文档或文档集合中的信息的句子。

一种常用的提取汇总技术是一种基于图的技术,称为 TextRank 算法。这个算法是从 PageRank (想想谷歌!).根据句子与另一个句子的相似性,句子按重要性排序。

实现

  • 数据准备
  1. 符号和停用词已被删除。
  2. 下载并提取在 Wikipedia+Gigaword 5 上预先训练的 100 个维度的手套嵌入
  3. 通过将手套嵌入应用于评论中的每个句子并使用余弦距离计算每个句子之间的相似性来构建相似性矩阵
  4. 应用文本排名算法获得句子排名
  • 代码

  • 示例输出

['HOST: <HOST> was very accomodating, has prepared everything you will need for your stay in the city, you get to have great and fun conversations with him, you will be for sure well taken care of!','Not only was the room comfortable, colourful, light, quiet, and equipped with everything we could possibly need - and <HOST>'s flat spotless and beautifully furnished and in a great location - but <HOST> himself is the perfect host, spending the first hour of our arrival talking to us about Amsterdam, answering our many questions, showing us how to get around.','He was friendly, extremely helpful & went the extra mile to make sure my friend and I were at home at his place.','His attention to details and kindness make his place an excellent alternative for those considering a bed and breakfast in Amsterdam\r\nI strongly advise to consider his place: Great location, an affordable price, a clean and organized room and a great host.','I traveled first time to Amsterdam with a friend and we stayed at <HOST>´s.He was an excelent host with helping to find out routes and gave lots of tips how to handle things in Amsterdam.The place was very clean and quiet.We recomment <HOST>´s room.']

我立即发现了 TF-IDF 的前 5 个最具信息量的句子和前 10 个相关关键词之间的一些相似之处:

  1. 伟大的主持人/完美的主持人
- <HOST> was very accomodating, has prepared everything you will need for your stay in the city, you get to have great and fun conversations with him, you will be for sure well taken care of- He was an excelent host with helping to find out routes and gave lots of tips how to handle things in Amsterdam- His attention to details and kindness make his place an excellent alternative for those considering a bed and breakfast in Amsterdam- He was friendly, extremely helpful & went the extra mile to make sure my friend and I were at home at his place.

2.放置干净

- <HOST>'s flat spotless and beautifully furnished and in a great location- a clean and organized room- The place was very clean and quiet

3.高度推荐

- We recomment <HOST>´s room.- I strongly advise to consider his place
  • 好与坏

好: 方法是无监督的,意味着不需要带标签的训练数据。

行动中的提取(我如何在假期中使用它?)

在尝试了上面的三种方法后,我发现文本摘要法是最有洞察力的,可读性和可解释性最强的,而且歧义最少。

下面的部分将展示我是如何把它应用到我最近去美丽的里斯本的旅行计划中的。

在列出了我想入住的 5 家酒店后,我把它们的网址复制到我的 Jupyter 笔记本上进行提取。

工作流程包括:

  1. 提取过去 12 个月提交的每个列表的评论
  2. 执行与上述相同的文本清理过程
  3. 使用如上所述的 TextRank 算法应用文本摘要
  4. 想象每个列表中前 5 个信息最丰富的句子

Top 5 most informative review sentences from Airbnb listings

14 reviews written in the last 12 months for Listing#888141 with summarised text highlighted

瞧啊。如果不总结评论,我将不得不通读这 5 个列表的 64 篇评论。

点击率: 所有 5 个总结都涵盖了主人关心的要点,地点,地方的清洁度和舒适度。尤其是清单#21042405 的摘要很有见地,因为它指出必须从不同的位置收集密钥。

错过: 一位来自#888141 号房源的客人抱怨这个地方没有空调,而且在他们参观期间天气非常热。总结中未提及该意见,主要原因可能是因为客人是唯一提出此类投诉的人,因此与其他意见相比,该意见并不重要。

结束了

感谢阅读!我很喜欢这个结合了我最喜欢的两件事——旅行和数据科学的小项目。希望你喜欢这篇文章,并发现这个应用程序有趣且实用。

使用的 Jupyter 笔记本可以在 Github 上的这里找到。

参考

https://www . analyticsvidhya . com/blog/2018/11/introduction-text-summary-text rank-python/

使用模式定义(和 dbt)来引导您的数据模型

原文:https://towardsdatascience.com/using-mode-definitions-and-dbt-to-bootstrap-your-data-model-9ea6c9691131?source=collection_archive---------14-----------------------

Penny model. Oh, if our network graphs were so simple.

在 Landed,我们跟踪各种产品在不同生命周期阶段的各种客户旅程。为了探索所有这些多样性,我们的团队依靠一系列分析仪表板来帮助他们预测我们的客户和合作伙伴的需求。我们的团队提出的问题会随着时间的推移而变化,这就需要一种灵活的、响应性强的实践来构建和更新数据模型。我们最近经历了一个升级数据基础设施的过程,并问自己“我们如何定义一个敏捷 sprint,让我们在几周内从原始数据到 BI 平台 MVP?”

我们知道我们正在寻找一个数据建模解决方案,它将提供版本控制、一个能够定义测试的阶段环境,以及一个良好的实践社区来支持和学习。货比三家之后,我们选定了两个可以很好地配合工作的工具,模式分析和鱼镇分析的数据构建工具( dbt )。Mode 是一个 SQL 驱动的 BI 平台,支持 R 和 Python,这意味着您可以用所有您喜欢的库(seaborn、matplotlib 等)来扩充它们的内部图表。).Dbt 是一种工具(或许也是一种心态?)允许您清理、反规范化、测试和预聚合您的数据。

这篇文章的目的是分享我们如何在 4 周的冲刺中,一起使用这两个工具来让我们的 BI 平台站稳脚跟。

下面是我们采取的一般方法:

  • 步骤 1:确认定义和计算(准备)
  • 步骤 2:创建基表(开发)
  • 步骤 3:在 dbt 中记录和定义测试。yaml 文件(暂存)
  • 步骤 4:使用 dbt 云(产品)调度构建
  • 第五步:回馈开源社区(😄)
  • 冲洗重复!(迭代)

步骤 1:确认定义和计算

遵循我的数据库前辈的明智建议,我创建了我们所有属性的目录,以及驱动我们现有报告和当前 OKR 指标的查询列表。在构建过程中,这个文档成了我的真实来源。一个简单的共享文档,团队可以在其中实时跟踪进度。

经过一段时间严格的财产定义和数据清理后,我很幸运地加入了 Landed,因此我们这个过程的起点是一个清晰和一致的地方。如果你正在构建一个不太清晰的模型,我鼓励你缩小项目规模,直到你得到少数几个每个人都同意的属性和计算(即使,起初,那只是first_namelast_name)。当您构建您的系统并在早期制图项目中取得一些成功时(“看,我们所有客户的名称列表!”),这样会激励别人稳定逻辑,清理数据,这样才能在游戏中跳跃。

步骤 2:用模式定义创建基表

从我们的查询列表开始,我为每个团队创建了基础表。这些表格仅包括驱动报告所需的属性;精选的贵宾特写。我使用模式定义定义了这些基表,这些模式定义是可以在其他查询中引用的 select 语句(最多 10 层嵌套!).这些基表是迭代定义的——当我在 Mode 中编写每个查询时,我从我们的红移集群中添加了我需要的必要属性。

这些基表确保我们的用户永远不会直接查询我们的原始数据。即使我可以完全确保我们的用户没有能力改变原始数据(凭借我们与 Mode 的只读集成),我们仍然希望为我们的分析服务的数据类型和计算有一个清晰的记录,这些基本表提供了这些记录。它们也是我们为每一列定义别名的地方,因为我们从 HubSpot 到 Redshift 的 ETL(我们使用 Stitch 来协调)拉入了我们的数据属性的内部名称,这些名称不同于我们的团队使用的字段名称。虽然我们的大多数团队成员不会直接探索我们的 SQL 查询,但规范术语总是一个好主意。

步骤 3:在 dbt 中记录表格。yaml 文件

这是我们旅程中 dbt 发挥作用的部分。老实说,一开始我并不完全清楚我们应该从在模式定义中定义模型切换到在 dbt 中设置测试并构建我们的物化视图。这部分是因为在你的模式报告中使用模式定义非常容易,而且我注意到当遇到将事情转移到 dbt 的困难时,会有一点惰性。当我想起 dbt 的测试覆盖工具时,我振作起来!

我们达成了一个内部的经验法则,那就是一旦我们在最初的计划中覆盖了 90%的查询,我们就开始从模式中转移东西,这是我们在大约三周内完成的。这个过程的这一部分包括为每个基表定义一个. yaml 文件,该文件包括对所有属性的简洁描述,以及测试定义,在 dbt 中有四种风格:not_nulluniquerelationshipsaccepted_values

这里有一个例子:

version: 2

models:
  - name: customer_id
    description: Unique customer identifier 
    columns:
      - name: uid
        tests:
          - not_null
          - unique

      - name: best_friend
        description: Customer's BFF
        tests:
          - relationships:
              to: ref('friends')
              field: uid

      - name: favorite_ice_cream_flavors
        description: Customer's favorite ice cream flavors
        tests:
          - not_null
          - accepted_values:
              values: ['cherry', 'chocolate']

值得注意的是,Mode 支持持久派生表(pdt ),它复制了 dbt 提供的物化视图功能。我被 dbt 活跃的开源社区和测试方法所吸引,但是如果您已经在为您的 BI 使用模式分析,您可能需要研究一下 pdt。

步骤 4:使用 dbt 云调度构建

这是我们现在所处的阶段。在我们的 ETL 集成之后安排我们的夜间 dbt 构建。因为我们每天晚上都从 CRM 中集成数据,所以我们安排 dbt 云作业在之后立即实现我们的基表视图。这一部分非常简单,因为至此所有构建和测试模型的艰苦工作都已完成。

有一点需要注意,如果你使用红移,你可能会想使用后期绑定视图,这样你就不会在每夜构建中遇到任何阻碍。后期绑定视图在运行时绑定表,因此您可以删除一个绑定到另一个表的构建视图,而不会引发任何错误。当我们用 Stitch 设置 ETL 时,我遇到了这个问题,并切换到后期绑定,现在一切运行良好。

第五步:回馈开源社区

无论是为 dbt 挑选一期,还是写一篇关于你所构建的东西的博文,通过回馈社区来完成一个构建周期总是好的。与他人一起学习是工程的最大乐趣之一,支持推进该领域最佳实践的项目也是如此。找一张票,通过回购交几个朋友,提交一份 PR!

冲洗重复!

就是这样!现在是无尽的循环迭代:)

Siobhán 是登陆的数据工程负责人。Landed 的使命是帮助重要的专业人士在他们服务的社区附近建立金融安全,当他们准备在昂贵的市场购买房屋时,我们会与教育工作者一起投资。听起来很棒?加入我们

使用 MongoDB 更改流将数据复制到 BigQuery 中

原文:https://towardsdatascience.com/using-mongodb-change-streams-to-replicate-data-into-bigquery-64ab54636b0e?source=collection_archive---------13-----------------------

我们在使用 MongoDB 变更流构建 MongoDB 到 BigQuery 数据管道时所获得的经验和面临的挑战

Photo by Quinten de Graaf on Unsplash

在进入技术细节之前,最好回顾一下我们为什么决定建立这个管道。我们开发它有两个主要原因:

  1. 在一定规模下,查询 MongoDB 进行分析是没有效率的。
  2. 我们没有 MongoDB 中的所有数据(例如条带计费信息)。
  3. 数据管道即服务供应商在一定规模下非常昂贵。并且,通常不提供复制删除记录的方法,如软删除(例如,使用deleted_at字段)。

复制无模式数据

在使用这个 MongoDB 数据库时,我们注意到的第一件事是一些集合有一个棘手的模式。文档内部有嵌套文档,其中一些也是数组。

通常,一个嵌套的文档代表一个一对一的关系,一个数组代表一对多的关系。幸运的是,Big Query 同时支持重复字段和嵌套字段。

根据我们的研究,复制 MongoDB 数据的最常见方式是在集合中使用时间戳字段。该字段通常被命名为updated_at,并在每次记录被插入更新时被更新。这种方法很容易用批处理方法实现,它只需要查询所需的集合。当将它应用于我们的数据和集合时,我们发现了两个主要问题:

  1. 并非所有我们想要复制的集合都有这个字段。没有 **updated_at** ,我们怎么知道哪些记录被更新复制了呢?
  2. 此方法不跟踪已删除的记录。我们只是将它们从原始集合中删除,并且永远不会在我们的大查询表中更新。

幸运的是,MongoDB 在oplog中保存了应用于集合的所有更改的日志。从 MongoDB 3.6 开始,您可以使用变更流 API 来查询它们。这样,集合中的每个变化(包括delete操作)都会提醒我们。

然后,我们的目标是构建一个管道,将 MongoDD Change Streams 返回的所有变更事件记录移动到一个大的查询表中,其中包含每个记录的最新状态。

建设管道

Photo by NeONBRAND on Unsplash

我们的第一种方法是在 Big Query 中为我们想要复制的每个集合创建一个变更流表,并从该集合的所有变更流事件中推断出模式。这被证明是相当棘手的。如果在记录中添加了一个新字段,管道应该足够智能,在插入记录之前修改大的查询表。

因为我们希望在大查询中尽快获得数据,所以我们采用了另一种方法。将所有变更流事件作为 JSON blob 转储到 BigQuery 中。然后,我们可以使用像 dbt 这样的工具来提取、转换原始的 JSON 数据,并将其转换成合适的 SQL 表。当然,这有一些缺点,但让我们很快就有了端到端的管道。

管道具有以下组件:

  1. Kubernetes ( [carden](https://github.com/bufferapp/carden))中运行的一个服务,它读取每个集合的 MongoDB 变更流,并将其推送到一个简单的大查询表中(追加所有记录)。
  2. 一个 dbt cronjob,它使用原始数据增量读取源表,并将一个查询具体化为一个新表。此表包含自上次运行以来更改的每行的最新状态。这是 dbt SQL 在生产环境中的一个示例。

有了这两个步骤,我们就有了从 MongoDB 实时流向 Big Query 的数据。我们还跟踪删除,并且我们拥有我们正在复制的集合中发生的所有更改(对于需要一段时间内的更改信息的某种分析很有用)。

由于我们在启动 MongoDB 更改流爬行服务之前没有任何数据,因此我们丢失了许多记录。为了解决这个问题,我们决定回填创建假的变化事件。我们转储了 MongoDB 集合,并制作了一个简单的脚本,将文档包装成插入。这些记录被发送到同一个 BigQuery 表中。现在,运行同一个 dbt 模型给我们最终的表,其中包含所有回填的记录。

我们发现的主要缺点是,我们需要用 SQL 编写所有的提取。这意味着大量额外的 SQL 代码和一些额外的处理。目前,使用 dbt 并不太难。另一个小问题是 BigQuery 本身不支持提取 JSON 中编码的数组的所有元素。

结论

对我们来说,好处(迭代时间、变更的容易程度、简单的管道)大于坏处。因为我们刚刚开始使用这个管道,所以让一切端到端地工作并快速迭代是非常有用的!让 BigQuery 只附加更改流表作为一个分离来服务我们。在未来,我们计划迁移到 Apache Beam 和 Cloud 数据流,但那是另一篇文章!

希望你对这些见解感兴趣!你可以在推特上找到我,账号是@davidgasquez 。如果你有任何问题,不要犹豫,尽管来找我。

用自然语言处理(NLP)和信息可视化(InfoVis)支持略读

原文:https://towardsdatascience.com/using-natural-language-processing-nlp-and-information-visualization-infovis-to-enhance-skim-e614b3f8b4a?source=collection_archive---------26-----------------------

skimfo——一个交互式界面,可视化文档旁边的“信息”(仅桌面演示@https://demo-dot-skimfo.appspot.com/)

概观

交互式可视化可以为文本分析任务提供有价值的支持。然而,这种类型的大多数可视化要么是抽象的,需要仔细检查,要么扰乱散文阅读过程。出于这些原因,在略读策略下,它们并不总是有效的——这仍然是策略性阅读散文的首选方法。略读被普遍认为是在最少的时间内获得最多信息的优化——一种信息增益模型。

使用 Skimfo ,我设计了一个界面,作为一个研究项目的一部分,以探索可视化文本旁边的信息度量是否可以通过支持我们阅读时对文本的快速判断来支持略读的任务,例如:

  • 文档中的信息在哪里?
  • 有多少信息量?
  • 我读的时候是增加还是减少?

Skimfo 仅限桌面演示@https://demo-dot-skimfo.appspot.com/

动机

对网络浏览行为的研究表明,读者通常会略读文本(略读)来有效地找到有价值的信息。略读策略概念化的一个突出而模糊的框架是在特定时间内“信息增益”的最大化(见图 1 )。虽然研究还不清楚这是如何做到的,但在这种策略下,人们认为读者在阅读过程中会对信息的价值做出判断。当一段文字的信息增益低于特定于读者的阈值(取决于上下文)时,她会放弃这段文字,跳到文档中的另一个位置。

Figure 1: The dotted line on the chart (right) is a threshold, if a reader feels the information gain from a passage of text is falling below their unique threshold, they abandon the passage, skim some text, and re-start reading at another point in the text where they judge information gain to be above the threshold.

【1】将略读概念化为信息获取模式的参考: 达根、杰佛瑞·b .等人《文本略读:在时间压力下通过文本觅食的过程和有效性》实验心理学杂志:应用 15.3(2009):228–42。

学术读者经常试图避免不必要的阅读,并将利用新技术——特别是“数字索引、检索和导航资源的广泛使用”——进行战略性阅读。然而,尽管存在提取信息的工具,阅读叙事散文仍然是阅读文本的首选方法。

这个交互界面 Skimfo ,可视化了相对于文档的重要性以及信息量,以帮助读者在略读文档时做出判断。通过从信息论的角度构建对文档的阅读,我们获得了“概率加权信息”[2]的概念基础,这是一种与文档中使用的词及其频率相关的度量,作为每个词附带的信息量(见图 2 )。有了这个量,我们就可以通过基本的计算来可视化文档中信息的传播。

Figure 2: It involves some mathematics (see [2]), but in conclusion, we arrive at a modified version of the TF-IDF score as the information (entropy) provided by each word in the document. Intuitively, the PWI of any given word w_i quantifies: How much “uncertainty/entropy” in the Document is reduced by “knowing” a word?

【2】引用‘概率加权信息’作为每个词的信息度量: [会泽,明子。“tf-idf 测量的信息论观点”Inf。过程。管理。39 (2003): 45–65.](http://An information-theoretic perspective of tf-idf measures)

交互界面设计

Skimfo 是一个交互式的基于 web 的界面,它作为一个平台,在文本旁边提供所提议的可视化。图 3 突出显示了视图中的各种特征。

Figure 3: A screenshot of the Skimfo interface from skimfo.appspot.com depicting the main features

用例

这个界面是作为一个研究项目的一部分而设计的,该项目测量左侧视觉化(水平条形图)对略读的影响。本质上,该界面被设计用于通过略读来总结文档的主要要旨。所以,当你阅读的时候,你可以点击那些你认为能提到要点的句子,然后你可以把它们总结起来。把它想象成你在阅读和强调一般重要的信息,除了视觉化是作为一种定量的辅助。

然而,关键是文档旁边的信息度量的可视化——这可以用于各种目的,包括:可视化书面草稿中的冗余信息,确定文档的范围以查看它是否有趣,快速浏览文档中的主要主题,等等。

条形的颜色/不透明度

该界面提供了每行“信息”的可视化,您可以使用它作为阅读的指南。每个条形可视化并表示其旁边的线条。使用一种算法(即完美),我已经确定了每条线上的潜在信息,并相应地给条形着色。这意味着条形的颜色越深,越有可能在相应的线上有重要的信息。

交互性

此外,它是一个交互界面——一旦你点击了一个句子,你就让算法知道你已经阅读了它。然后,该算法会降低所有与你点击的句子信息相似的线条的颜色,表明这些线条可能不再对你有很大帮助。通过这种方式,条形的颜色会发生变化,以反映最有价值和最重要的信息可能会在哪里提供给你已经知道的信息。

条的长度

条形的长度表示信息的增加或减少。这意味着如果下几行的条形越来越小,那么很可能下几行比当前行包含的信息更少。相反,如果条形越来越长,很可能会有更多的信息沿着这些线条出现。条形的长度不会交互改变。

其他功能

其他有用的功能包括页面顶部的进度条。绿色条表示您对文档的了解程度。当你点击句子时,顶部的黄色条会变满,表示到目前为止你的总结的长度。完全填满的黄色条表示您的摘要是整个文档的四分之一长。

最后,靠近页面底部的一个按钮允许你查看你的最终总结。

演示—【https://demo-dot-skimfo.appspot.com/ (仅限桌面)

为了推出一个 Skimfo 的演示,并保持其廉价,算法和处理都比最初的设计有所简化。由于使用了有限的文本处理技术,有时可能会有小的文本格式错误。目前,由于可视化的性质和大小,不支持移动视图。

使用的 Tech:
-Python(库 *: flask、nltk、scikit、pandas)

  • D3(用于可视化)*

我提供了复制粘贴文本块(500-5000 字以内)的选项,然后我对其进行处理以提供可视化和交互性。还有一个直接进入网页的选项,但是,由于网络抓取的“精细性”,这是一个有限的、错误的选项。(此外,有时网页有安全措施,以防止机器人代理抓取。)

一般来说,这种可视化最适用于非创造性的文本(短文、文章、新闻、文档等)。)以向读者提供信息为目的而写的。 用自己的文字试试吧!你可能会发现它减少了你的阅读时间,或者帮助你导航到重要的信息——支持你在略读文本时做出的快速判断。

用神经网络预测明天的用电量

原文:https://towardsdatascience.com/using-neural-nets-to-predict-tomorrows-electric-consumption-cc1ae3ae7cc2?source=collection_archive---------9-----------------------

神经网络调峰:第一部分

最小的错误都会在一天内造成数千美元的损失。神经网络可以帮助确保这种情况不会发生。

研究会同 开放建模框架【OMF】

这是关于神经网络调峰的三部分系列文章的第一部分。考虑一下另外两个:

[## 基于神经网络的⚡️负荷预测和调峰

提高日前负荷预测的准确性可以为电力公司节省数万美元。下面,我已经…

www.kmcelwee.com](https://www.kmcelwee.com/load-forecasting/)

电力分销商可以通过降低高峰需求费用来节省数十万美元。一些人试图在高峰时段将电池放电或关闭客户的热水器或空调,以减少他们的需求。但是,这些努力的有效性取决于公用事业公司预测当天能源消耗的能力。

最小的误差可能意味着数万美元之间的差异——在不正确的负荷预测下实施调峰策略甚至会增加需求成本。谢天谢地,深度学习和神经网络的进步可以为公用事业公司提供第二天能源消耗的令人难以置信的准确图片。开放建模框架(OMF)和我已经使用神经网络创建了一个日前负荷预测模型,可以很容易地实施,以通知调度决策。

为什么不简单点呢?

我们最初用 python 包 sci-kit learn 创建了一个线性回归模型。尽管这个更简单的模型达到了 10%的平均绝对误差(MAPE),但它还不足以准确可靠地降低峰值。

最大的障碍是冬季和夏季的日峰值不同。冬季月份每天出现两次高峰,夏季月份在中午出现高峰。线性模型不能同时创建这两种每日负荷形状。虽然线性回归可以找到简单的关系(因为是星期一,所以+500 千瓦,-100 千瓦,因为是三月),但神经网络可以计算更复杂的关系(因为是四月的星期一下午 3 点,所以+5100 千瓦,-1500 千瓦,因为是感恩节的凌晨 5 点)。这将我们的训练误差减少到大约 3.5 MAPE,这相当于节省了数万美元。

Load prediction captures both single and double peak behavior (from OMF’s “Virtual Battery Dispatch” model)

软件详情

为了将负荷预测软件整合到 OMF 数据库中,我们的模型是用 Python 编写的。我们使用 pandas 包来操作数据,我们已经实现了 Tensorflow 的 Keras(谷歌的机器学习软件)来创建神经网络。这里有一个到存储库的链接。该代码易于使用:

import loadForecast as fc
import pandas as pddf = pd.read_csv('test.csv')
all_X = fc.makeUsefulDf(df)
all_y = df[‘load’]
predictions, accuracy = fc.neural_net_predictions(all_X, all_y)

为了我们最初的测试目的,neural_net_predictions简单地返回最后一年的预测;但是,它可以快速更新,以便实时为公用事业服务。

结构

当我们寻找更准确和有效的方法时,神经网络的结构在不断更新;然而,我们目前已经选定了一个五层全连接网络,其中每层包含 71 个节点。我们在每一层使用一个 ReLU 函数,并最小化均方误差。

输入

我们建议模型至少训练三年的数据。该模型将 CSV 作为输入,其中每一行列出给定年、月、日和小时的负载和天气。如果公用事业公司没有可用的温度数据,OMF 还提供了“天气预报”,这是一个可以很容易地收集并返回给定邮政编码的每小时天气的程序。如果有任何空的温度值,负荷预测函数使用“向前填充”方法,其中空值被最后一个非空值替换。例如,“38,39,41,NaN,NaN,38,NaN,32”将读作“38,39,41,41,41,38,38,32”

特征

虽然每个训练示例都包含日期、温度和天气数据,但我们将这三列扩展为 72 个对机器学习模型有用的功能。以下是所有功能的列表:

  • 自 2000 年以来的年份*
  • 从 24 小时前加载*
  • 一天中的小时(凌晨 12 点,凌晨 1 点,…晚上 11 点)
  • 一周中的某一天(是星期日,是星期一,…是星期六)
  • 一年中的月份(一月,二月,…十二月)
  • 温度* **
  • 温度***
  • 前一天的负载*(前一天的 12 点,前一天的 1 点,…前一天的 11 点)
  • 节假日(NERC6 节假日)**** (isNewYears,isMemorialDay…isChristmas)

*这些特征通过减去平均值并除以标准偏差进行归一化,这有助于收集接近零的所有数据点。通过除以标准差而不是范围(正如一些数据科学家所建议的),我们将准确度提高了 1%。

**国家气象局估计他们的前一天每小时天气预报通常在 2.5 度以内。为了复制这一点,我们在训练和测试温度数据中创建噪声,方法是添加一个以零为中心的标准偏差为 2.5 的高斯分布。当这个噪音被加入时,模型的准确性下降了百分之一。

***如果您绘制负荷与温度的关系图,您会发现负荷与温度成正比——加热器用于最冷的温度,空调用于最热的温度。通过添加温度特征,我们可以使这种关系对模型更加明显。

****观察到的节假日也是“1”(或“真”)。例如,2015 年的独立日是星期六,所以它是在 7 月 3 日星期五庆祝的。对于“isIndependenceDay”功能,2015 年的 7 月 3 日和 7 月 4 日都标记为“1”。

结果

我们根据 from 2002 年至 2017 年的休斯顿数据训练了这个神经网络,并针对 2018 年的负载测试了该模型。我们达到了大约 96.5%的准确率(3.5 MAPE)。整个程序通常在 10 分钟内运行。我们在一个需求减少模型上部署了这个神经网络,其中一个公用事业公司使用电池转移负载来减少需求,并发现我们节省了 40%的最佳解决方案(例如,如果一切运行完美,公用事业公司将在按需充电方面节省 95,000 美元,但由于预测不完美,它节省了大约 40,000 美元。这假设了典型的 20 美元/千瓦的需求费用。在其他值中,需求费用是我们成本效益模型的一个输入,我们正在将这些结果扩展到其他公用事业。)

鉴于最小的改进可能对公共事业的底线产生如此深远的影响,我们目前正在追求更复杂的机器学习结构。

此外,对这些大型电池进行充电和放电需要成本,一些公用事业公司可以在有限的天数内控制客户的空调。我们研究的下一步是最好地预测一个月中的哪一天调度这些方法(假设需求费用是每月的),以便公用事业公司可以尽可能保守。

你发现错误了吗?你有什么问题吗?联系我,查看更多项目在 我的网站

使用神经网络对 fMRI 数据进行功能连接分类

原文:https://towardsdatascience.com/using-neural-networks-for-a-functional-connectivity-classification-of-fmri-data-ff0999057bc6?source=collection_archive---------7-----------------------

使用简单神经网络模型进行基于功能连接的分类的分步指南。

在本教程中,您将:

  • 探索来自 nilearn 的神经成像数据集;
  • 在 nilearn 中执行规范的独立成分分析;
  • 提取由成分分析确定的区域之间的功能连接系数;
  • 使用 Keras 将系数用于分类多层感知器模型。

所有必要的代码将在本指南中提供。完整版请见本 GitHub 页面

先决条件 :本教程使用 Python、Nilearn、Keras。您不需要以前使用过 Nilearn,但是您应该有一些使用 Python 和 Keras 的经验。如果你以前从未制作过神经网络,那么当我们建立一个模型时,这个教程可能很难理解到最后,但是请不要离开 Nilearn 部分。

目的

我们将探索一种神经网络方法来分析关于注意缺陷多动障碍的基于功能连接的数据。功能连接显示了大脑区域如何相互连接并组成功能网络。因此,它可能会洞察大脑如何交流

我们的方法不直接依赖于神经成像扫描,而是利用矢量化的功能连接性测量。这为使用机器学习进行功能连接性分析提供了一种计算简单的方法。

使用更复杂的神经网络模型的类似方法已经被用于分类,特别是在脑障碍的情况下。然而,由于数据中的众多特征和验证难度,这些已被证明是具有挑战性的(参见 Du 等人,2018 的综述)。我们自己的分析也显示了不太理想的模型精度,但是本教程的目的是提供一个如何开始的指南。鼓励你最终尝试自己的神经网络!

数据集

Nilearn 是我们将使用的用于神经成像数据的 Python 模块,具有各种预处理数据集,您可以通过内置函数轻松下载:

from nilearn import datasetsnum = 40
adhd_data = datasets.fetch_adhd(n_subjects=num)

我们将使用 ADHD-200 公共可访问数据集,该数据集由静息态 fMRI 和从多个研究中心收集的解剖数据组成。Nilearn 只有 40 名受试者的数据,所以我们加载了所有的数据。

我们可以通过查看来检查数据集。keys() —我们看到有 4 种类型的信息。“func”以通向 rs-fMRI 数据图像的路径为特征;“混杂”是 CSV 文件,包含我们希望了解的不影响我们分析的讨厌变量(混杂);“表型”为预处理步骤提供了解释;“描述”是对数据集的描述。

Examining the .keys() of the dataset object.

收集这些数据是为了增加对 ADHD 的神经相关性的理解。如果你愿意,你可以在这里了解更多关于原始数据集。出于本教程的目的,您只需要知道数据集既包括典型发育个体(“对照”),也包括诊断为 ADHD 的个体(“治疗”)。

我们将从该数据集中提取功能连接系数,以对给定受试者是“对照”还是“治疗”进行分类。我们将首先使用来自 nilearn 的独立成分分析,然后使用它来提取功能连接系数。最后,我们将使用这些系数建立一个神经网络来区分“对照组”和“治疗组”。

第一步:分解

独立成分分析(ICA)通常用于评估功能连接性。Nilearn 有一个用于群体水平 ICA (CanICA)的方法,该方法允许控制单个受试者的可变性,尤其是在我们对功能网络感兴趣的情况下。

我们使用 Nilearn 的内置函数,并获得我们正在处理的内容的可视化效果。我们根据 Nilearn 文档中为所选数据集提供的标准,选择使用 20 个组件的分解。我们使用 masker_ 得到独立的组件。inverse_transform ,然后我们使用 Nilearn 的绘图选项绘制统计和概率地图。我们需要统计方法来绘制默认模式网络(DMN)——plot _ stat _ map 函数允许绘制感兴趣区域的切割图;概率方法简单地使用从分解中产生的所有成分,并将它们层叠在默认的解剖脑图像之上。

from nilearn import decompositioncanica = decomposition.CanICA(n_components=20, mask_strategy=’background’)
canica.fit(func)#Retrieving the components
components = canica.components_#Using a masker to project into the 3D space
components_img = canica.masker_.inverse_transform(components)#Plotting the default mode network (DMN) without region extraction
plotting.plot_stat_map(image.index_img(components_img, 9), title='DMN')
plotting.show()#Plotting all the components
plotting.plot_prob_atlas(components_img, title='All ICA components')
plotting.show()

CanICA decomposition for default mode network and all individual components.

我们的成分分解很难得到决定性的解释(本质上,我们在 fMRI 数据中看到了不同的大脑区域),但我们可以使用它作为过滤器来提取我们感兴趣的区域。我们这样做是为了调用来自 Nilearn 的 NiftiMapsMasker 函数来“总结”我们使用 ICA 获得的大脑信号。一旦有了这些,我们就通过使用 fit_transform 方法将提取的数据转换成时间序列。

然后,我们使用我们所知道的关于数据集的一切(“func”、“混杂”和“表型”文件)来获得我们需要的信息,包括受试者是“治疗组”还是“对照组”以及它们相关的数据收集位置(地点)。

#Using a filter to extract the regions time series 
from nilearn import input_data
masker = input_data.NiftiMapsMasker(components_img, smoothing_fwhm=6,
 standardize=False, detrend=True,
 t_r=2.5, low_pass=0.1,
 high_pass=0.01)#Computing the regions signals and extracting the phenotypic information of interest
subjects = []
adhds = []
sites = []
labels = []
for func_file, confound_file, phenotypic in zip(
 adhd_data.func, adhd_data.confounds, adhd_data.phenotypic):
 time_series = masker.fit_transform(func_file, confounds=confound_file)
 subjects.append(time_series)
 is_adhd = phenotypic[‘adhd’]
 if is_adhd == 1:
 adhds.append(time_series) 
 sites.append(phenotypic[‘site’])
 labels.append(phenotypic[‘adhd’])

到目前为止,我们使用 CanICA 来获得确定感兴趣区域所需的组件。在我们能够建立我们的神经网络模型之前,最后要做的事情是获得功能连接系数。为此,我们需要查看我们提取的感兴趣区域之间的功能连接。我们考虑了三种不同的功能连接,并确定 相关性 是最准确的。你可以在的完整代码中找到我们是如何做到的。

相关性简单地确定成对感兴趣区域之间的边缘连通性。Nilearn 有一个计算相关矩阵的内置方法,即 ConnectivityMeasure 函数。我们只需要指定我们感兴趣的功能连接的种类,然后拟合我们在上一步中提取的时间序列数据。

from nilearn.connectome import ConnectivityMeasurecorrelation_measure = ConnectivityMeasure(kind=’correlation’)
correlation_matrices = correlation_measure.fit_transform(subjects)for i in range(40):
 plt.figure(figsize=(8,6))
 plt.imshow(correlation_matrices[i], vmax=.20, vmin=-.20, cmap=’RdBu_r’)
 plt.colorbar()
 plt.title(‘Connectivity matrix of subject {} with label {}’.format(i, labels[i]))

我们现在有了所有受试者的连接矩阵,但是让我们看看所有受试者的平均连接情况。我们将这些矩阵分为治疗组和对照组进行比较。这种比较是我们的神经网络模型将用于分类的。

#Separating the correlation matrices between treatment and control subjects
adhd_correlations = []
control_correlations = []
for i in range(40):
    if labels[i] == 1:
        adhd_correlations.append(correlation_matrices[i])
    else:
        control_correlations.append(correlation_matrices[i])#Getting the mean correlation matrix across all treatment subjects
mean_correlations_adhd = np.mean(adhd_correlations, axis=0).reshape(time_series.shape[-1],
                                                          time_series.shape[-1])#Getting the mean correlation matrix across all control subjects
mean_correlations_control = np.mean(control_correlations, axis=0).reshape(time_series.shape[-1],
                                                          time_series.shape[-1])#Visualizing the mean correlation
plotting.plot_matrix(mean_correlations_adhd, vmax=1, vmin=-1,
                               colorbar=True, title='Correlation between 20 regions for ADHD')plotting.plot_matrix(mean_correlations_control, vmax=1, vmin=-1,
                               colorbar=True, title='Correlation between 20 regions for controls')

Connectivity matrices for ADHD subjects versus controls.

我们可以看到,这两个组的连接都不是特别强(对角线可以忽略,因为它显示了与自身的相关性,因此总是等于 1)。为了更好地将联系和差异可视化,我们可以将它们投射回大脑。

#Getting the center coordinates from the component decomposition to use as atlas labels
coords = plotting.find_probabilistic_atlas_cut_coords(components_img)#Plotting the connectome with 80% edge strength in the connectivity
plotting.plot_connectome(mean_correlations_adhd, coords,
                         edge_threshold="80%", title='Correlation between 20 regions for ADHD')plotting.plot_connectome(mean_correlations_control, coords,
                         edge_threshold="80%", title='Correlation between 20 regions for controls')
plotting.show()

这给了我们一个很好的连接体,我们正在观察的 20 个区域所有连接的大脑地图。

Connectome showing correlations between the 20 regions yielded from the component analysis. Displayed are ADHD subjects on top and control subjects on the bottom.

与对照组相比,产生的 ADHD 连接似乎不那么密集,这可能与 ADHD 相关的功能连接减少的概念有关(Yang 等人,2011)。与之前的一些研究(Tomasi & Volkow,2012)一致,对于 ADHA 受试者,我们注意到上顶叶皮层(第一个冠状图的右上部分)的连接较少,这被认为与注意力有关。DMN 中似乎也有更少的连接,我们之前想象过,这是一个在休息时活跃并与“自我”相关联的网络——一个被认为在 ADHD 中发生改变的网络(Mowinckel 等人,2017)。这些虽然很小的差异,但表明在我们的神经网络模型中使用相关矩阵对治疗组和对照组进行分类应该不是不可能的。

如果您希望看到连接体的交互式可视化,您可以运行下面的代码行。否则,我们就可以开始建模了!

#Creating the interactive visualization
view = plotting.view_connectome(mean_correlations, coords, edge_threshold='80%')#To display in the cell below
view#To display in a different tab
view.open_in_browser()

神经网络方式

既然我们的相关矩阵提供了功能连接的矢量化测量,我们可以使用这些作为神经网络的输入数据。

在我们构建模型之前,我们应该将数据分为训练数据(70%)和测试数据(30%):

from sklearn.model_selection import train_test_splitX_train, X_test, y_train, y_test = train_test_split(correlation_matrices, labels, test_size=0.3)

我们的神经网络可以是从一层到五层的任何东西。在尝试了几种不同的架构之后,我们选定了由四个密集层组成的顺序模型。本教程假设您知道这些意味着什么,所以我们不会深入所有的细节,而是给出一个整体架构的简要概述。如果你需要重温这个话题,这个博客是一个好的开始。

import keras
from keras.models import Sequential
from keras.layers import Dense
from keras.optimizers import Adamclassifier = Sequential()#First Hidden Layer
classifier.add(Dense(32, activation=’tanh’, kernel_initializer=’random_normal’, input_shape=connectivity_biomarkers[‘correlation’].shape[1:]))#Second Hidden Layer
classifier.add(Dense(16, activation=’relu’, kernel_initializer=’random_normal’))#Third Hidden Layer
classifier.add(Dense(16, activation=’relu’, kernel_initializer=’random_normal’))#Output Layer
classifier.add(Dense(1, activation=’sigmoid’, kernel_initializer=’random_normal’))#Compiling the model
classifier.compile(optimizer = Adam(lr =.0001),loss='binary_crossentropy', metrics =['accuracy'])#Fitting the model
classifier.fit(np.array(X_train),np.array(y_train), batch_size=32, epochs=100)

这就是了!我们建立了一个简单的神经网络。让我们回顾一下我们模型的架构:

  • 我们使用顺序模型,这样我们可以简单地在一层之上构建另一层;
  • 我们选择密集层,它们是神经网络中的简单层——你可以把它们想象成接受多个输入并产生单个输出的线性模型。当我们处理不一定是线性可分的函数时,我们使用其中的 4 个,但是,由于我们本质上只对二元分类感兴趣,所以您不必使用 4 个,并且可能用更少的就可以了——就模型的预测能力而言,这似乎是最有效的。对于每一层,我们指定不同数量的节点(32、16、16、1 ),这在这个示例模型中也是微不足道的。唯一的经验法则是从小于或等于输入长度的数字开始;在我们的例子中,我们有 40 个矩阵,所以 32 个似乎是合适的。最终的输出图层应该与输出类别的数量相关。由于这是一个二元分类问题,我们需要使用 1。
  • 对于激活功能(主要完成输入输出信号转换),我们使用 TanhReLuSigmoidTanhSigmoid 分别用于第一层和最后一层,不用于隐藏层。这是因为两者都可以通过消失梯度问题来表征,这意味着如果输入更高,它们将输出零梯度(我们不确定,所以最好是安全的)。我们本可以使用 ReLu 函数来克服这个问题,因为它很简单(如果 x 为正,它给出 x 作为输出,否则为 0),但在非隐藏层中最好避免使用这些函数,因为它们可能不会产生梯度或“死亡”神经元。当前的架构( Tanh,ReLu,ReLu,Sigmoid )似乎又一次产生了最佳的评估指标,比如准确性;
  • 最后,我们使用一个 Adam 优化器和一个二元交叉熵损失函数。 Adam 被认为是一个不错的选择,尤其是对于有噪声的数据。二进制交叉熵是分类问题的常用选择,因为它独立于每个类别,并确保一个输出向量不受其他分量的影响。

Example four Dense layer Sequential neural network model architecture.

现在,只剩下一件事要做了——看看我们的模型表现如何。我们将使用准确性作为我们的主要衡量标准,因为它代表了正确分类的比例。

让我们从训练集开始:

eval_model=classifier.evaluate(np.array(X_train), np.array(y_train))
eval_model

万岁,我们训练数据的准确率是 1。测试数据的可怕部分。

y_pred=classifier.predict(X_test,batch_size=32)
y_pred =(y_pred>0.5)from sklearn.metrics import confusion_matrix, classification_report
cm = confusion_matrix(y_test, y_pred)
print(cm)
cr = classification_report(y_test, y_pred)
print(cr)

Confusion matrix and classification report for our model.

我们分类的总体准确率是 75%,这并不可怕,但还可以更好。我们也只得到 2 个假阴性和 1 个假阳性。现在就看你如何使用这个分步指南中构建的简单模型了!免责声明:相应的 Jupyter 笔记本中的模型比这里报告的精度低得多,可能是由于随机过程——这就更有理由进行实验并提出更好的模型。

本教程探讨了如何使用功能连接数据来筛查多动症。为此,我们根据不同区域的功能连接系数创建了一个神经网络。正如我们通过成分分析和连接体图所看到的,治疗和对照样品之间的差异并不显著,这可以解释我们筛选的准确性较低。应该对更大的数据集做更多的工作,以观察 ADHD 的功能连接是否有更一致的模式。在未来的分析中研究更多的区域和组成部分也是有意义的。

希望这已经给了你一些如何使用机器学习进行功能性磁共振成像数据的功能连接分析的想法。我们(方便地)使用了预处理数据,但如果你想了解更多关于 fMRI 数据分析的预处理步骤,请查看我的另一篇教程这里。下次见!

参考

Abraham,a .,Pedregosa,f .,Eickenberg,m .,Gervais,p .,Mueller,a .,Kossaifi,j .,… & Varoquaux,G. (2014 年)。用 scikit-learn 进行神经成像的机器学习。神经信息学前沿8 、14。

杜,杨,傅,钟,和卡尔豪,V. D. (2018)。使用功能连接对脑疾病进行分类和预测:有希望但有挑战。神经科学前沿12

Mowinckel,A. M .,Alnæ,d .,Pedersen,M. L .,Ziegler,s .,Fredriksen,m .,Kaufmann,t .,… & Biele,G. (2017)。默认模式可变性的增加与任务执行能力的降低有关,这在患有 ADHD 的成年人中很明显。神经影像:临床16 ,369–382。

Pedregosa,f .,Varoquaux,g .,Gramfort,a .,Michel,v .,Thirion,b .,Grisel,o .,… & Vanderplas,J. (2011 年)。sci kit-learn:Python 中的机器学习。机器学习研究杂志12(10 月),2825–2830。

托马斯博士和沃尔考博士(2012 年)。注意缺陷/多动障碍儿童的异常功能连接。生物精神病学71 (5),443–450。

瓦洛夸、萨达吉阿尼、皮内尔、克莱因施密特、波林、J. B .、和蒂里翁(2010 年)。fMRI 数据集上稳定的多主题 ICA 的分组模型。神经影像51 (1),288–299。

杨海红,吴,秦群,郭立涛,李,秦群,龙,黄小群,… &龚清友(2011)。首次接受药物治疗的 ADHD 儿童的异常自发脑活动:静息态 fMRI 研究。神经科学快报502 (2),89–93。

使用 NLP 为监管机构构建搜索和发现应用程序

原文:https://towardsdatascience.com/using-nlp-to-build-a-search-discovery-app-for-regulators-e674baae2288?source=collection_archive---------20-----------------------

在这个社会经济和技术快速变化的时代,法规需要不断更新。监管机构花费大量时间评估现有法案,以确定不支持创新并给企业造成负担的语言或标记的不一致使用。鉴于法案数量众多且性质复杂,能够使监管机构轻松搜索和比较法案并发现见解和模式的工具有助于加快这一过程。在我的上一篇文章中,我写了更多关于自然语言处理等技术可以帮助监管者的一些方式。

[## 论技术在监管现代化中的作用

我们需要更灵活的立法,因为监管者很难应对快速的技术变化。

towardsdatascience.com](/on-the-role-of-technology-in-regulatory-modernization-f90a8babbc05)

为了展示这些工具的样子,我与 Datadex 的团队合作,为加拿大监管机构开发了一个使用 NLP 的演示应用。该应用程序存储和分析 850 项加拿大法案,旨在使监管机构能够轻松发现相关法案,通过语义相似性链接法案,并识别冲突或不一致的语言和重叠的规则。在本文中,我将向您展示这些工具如何对监管机构有用,并解释如何轻松构建它们的简单版本。

应用程序

The Home Page

该应用程序包含 4 个主要工具:第一个是摘要工具,包含自动生成的 850 个行为的摘要。第二个是文档图形工具,它是一个交互式图形,显示行为之间的关系。第三个是一个上下文搜索工具,监管者可以在任何上下文中挑选感兴趣的词,并找到具有类似上下文的其他法案的参考文献。第四个是一个词云工具,其中包含许多来自法案语料库的重要词,使监管机构能够检索所选词重要的法案。

汇总工具

How the summaries tool works

创建摘要工具是为了方便浏览一组行为并快速评估主题。监管者可以通过输入一个与他们感兴趣的主题相关的关键词来缩小他们想要看到的行为列表。下面我们以“危险”为例,发现“危险产品法案”是一个相关的法案。该法案的摘要指出,部长可以命令供应商采取任何必要措施来补救与危险产品相关的不符合项。现在,监管机构可以决定这是否是他们想要进一步分析的行为。

Using summaries tool

使用 NLP 生成摘要的一个简单方法是对文档中的文本进行矢量化处理。文本矢量化有多种方法,其中之一是 Tf-idf 矢量化。这是一种将文本转换为向量的方法,其中文档中的每个单词都有一个分数,该分数反映了该单词在所有文档集合中对该文档的重要性。文档中一个单词的 Tf-idf 分数与该单词在该文档中出现的次数成比例地增加,并且被包含该单词的语料库中的文档数量抵消。一旦我们获得了文档中每个单词的 Tf-idf 分数,我们就可以为每个句子生成一个分数,这个分数将表明每个句子对该行为的重要性。

文档图形工具

Interactive Node-Edge graph of Acts

文档图是一个交互式节点-边图,它显示了动作之间的相互关系。通常,文档之间的关系是基于句法上的相似性,例如语法结构,或者基于它们文本中的引用。然而,使用自然语言处理,我们可以计算两个文档之间的语义相似度,使得两个文档之间的关系基于它们的含义和上下文的相似性。在上图中,高度连接的行为更靠近图的中心,而具有较少相关行为的行为更靠近图的边缘。相似性范围过滤器可用于设置图表上显示的节点的相似性阈值。

这一工具的主要目的是使监管者能够容易地发现行为之间的关系,否则很难识别。使用语义比较,我们可以发现上下文、语言选择或主题的相似性,这在整个行为语料库中很难手工完成。一旦确定了这种关系,监管者在从行为中获得洞察力或制定如何调查行为的计划方面就获得了巨大的优势。例如,监管者可以决定如何对行为进行分组,以评估其文本内容和特征。他们还可以使用链接来确认应该存在的行为之间的关系,并发现不相关的行为之间的链接。

How the document graph tool works

在上图中,我们注意到高度相互关联的法案形成集群,例如法案“加拿大-芬兰税务协定法案,2006”与加拿大和其他国家的税务协定法案形成集群,而边缘法案与许多法案几乎没有联系,但仅与一个其他法案密切相关,表明其中可能存在独特的文本特征。

前面我们讨论了将文本转换成矢量表示。我们可以使用这些向量,通过比较它们在向量空间中的接近程度来决定两个文档是否相关。当使用向量比较文本时,重要的是确定向量中存储的文本特征信息。我们上面使用的 Tf-IDF 擅长存储关于每个单词重要性的信息,但是不告诉我们单词使用的上下文。Word2Vec 是另一种有用的矢量化方法,因为它使我们能够根据单词或句子的上下文来比较它们。Word2Vec 模型接受目标单词和上下文单词的输入,其中目标单词表示主题的焦点,上下文单词是在目标单词周围(在上下文中)找到的单词。该模型在行为语料库上被训练,并且每个唯一的单词被分配一个向量。在向量空间上,共享共同上下文的单词将彼此靠近,因此计算向量空间内行为的向量表示之间的距离可以给我们一个概念,即两个行为的联系有多紧密。

上下文搜索工具

How context search tool works

上下文搜索工具被设计成从与在任何特定动作中选择的部分语义相似的文本部分中找到引用。监管者只需点击法案文本中任何带下划线的单词,即可获得同一法案或其他法案中在相同上下文中使用相同、相似或不同单词的参考章节列表。在上面的例子中,我们查看了“航空旅客安全收费法案”,并在收费航空旅行的上下文中选择了单词“transportation”。该工具检索在相同上下文中使用单词“transportation”或任何其他单词的引用列表,例如,从相同 Act 检索的第二个引用在航空旅行在设定日期后变得可收费的上下文中使用“transportation”。

在上述案例中,监管者可以通过调查“运输”一词是否在其他法案的类似上下文中使用,来确认该词在其上下文中的使用是否恰当。如果这个词出现在类似的语境中,监管者可以评估它是否是正确的用词,是否产生了正确的效果,是否有正确的解释。如果同一个词没有被一致地用来描述相似的上下文,那么就会出现语言使用不一致的问题。法案中语言使用的误解和不一致可能会对企业产生重大影响,因为这可能会导致无法理解法律和采取正确的行动。

Here’s another example of context search

上面是使用上下文搜索工具的另一个例子,在“为恐怖主义受害者伸张正义法案”中选择“恐怖主义”一词,返回“反恐怖主义法案”中在同一上下文中使用“恐怖主义”的参考。

单词云工具

How the word cloud tool works

创造“云”这个词是为了让监管者更容易找到与主题词相关的行为。在上面的例子中,我们选择“修正”并得到与该主题相关的所有行为的列表。主题词从整个行为语料库中生成,并反映文本中使用的最重要或最相关的词。每个主题词然后被链接到语料库中的每个动作,在那里它是重要的并且与主题相关。监管者以这种方式发现行为的优势在于,他们不需要事先知道与某个主题相关的所有行为的名称。此外,如果他们心中没有一个主题,他们可以在词云中探索主题的范围,并根据主题词选择行为。此外,主题词的大小取决于它们的重要性或它们在其中重要的行为的数量。这可以帮助监管机构分析不同的词在法案中是如何使用的,并回答一些问题,如为什么有些词在相关法案中被过度使用、使用不足或使用不当。

来自早期的 Tf-idf 转换可以用于识别行为中最重要的主题词。回想一下,Tf-idf 对每个单词的评分表明了该单词在行为中的重要性。我们可以为分数设置一个阈值,然后选择分数大于该阈值的任何单词作为主题单词。一旦在一个动作中识别出一个主题词,我们就可以搜索所有其他动作来查看该词是否是其他动作中的重要词,并将这些动作链接到所选的主题词。

上述应用程序显示了工具的优势,这些工具可以在语义级别上理解和比较文本,使监管机构能够更有效地搜索和分析行为。这些工具只是 NLP 这样的技术所能实现的一瞥。很快,使监管者能够做其他事情的高级工具将在监管者工具包中占据常见位置,如检测监管合规性的未来趋势,将法案文本与外部来源的数据(如公众对法案的评论)进行汇总和分析,或为需要修改的法案提供建议。

需要帮助使用 NLP 构建文档浏览工具吗?通过 Waterfront Analytics 联系我们,或者通过 LinkedIn 直接联系我。

posted @ 2024-10-13 15:24  绝不原创的飞龙  阅读(477)  评论(0)    收藏  举报