使用 PyTorch 进行 Seq2Seq 建模的神经机器翻译综合指南。
在本帖中,我们将构建一个基于 LSTM 的 Seq2Seq 模型,该模型采用编码器-解码器架构,用于无注意机制的机器翻译。
目录:
- 简介
- 数据准备和预处理
- 长短期记忆(LSTM) —引擎盖下
- 编码器模型架构(Seq2Seq)
- 编码器代码实现(Seq2Seq)
- 解码器模型架构(Seq2Seq)
- 解码器代码实现(Seq2Seq)
- Seq2Seq(编码器+解码器)接口
- Seq2Seq(编码器+解码器)代码实现
- Seq2Seq 模型训练
- seq 2 seq模型推断
- 资源&参考文献
1.介绍
N eural 机器翻译 (NMT)是一种机器翻译方法,它使用人工神经网络来预测单词序列的可能性,通常在一个单一的集成模型中建模整个句子。
对于计算机来说,用简单的基于规则的系统将一种语言翻译成另一种语言是最困难的问题之一,因为它们无法捕捉到翻译过程中的细微差别。然后不久,我们使用统计模型,但在深度学习进入后,该领域被统称为神经机器翻译,现在它已经取得了最先进的成果。
我希望这篇帖子对初学者友好,所以一种特定的架构(Seq2Seq)显示了成功的良好迹象,这就是我们在这里要实现的。
因此,本文中的序列到序列(seq2seq)模型使用一种编码器-解码器架构,该架构使用一种称为 LSTM(长短期记忆)的 RNN,其中编码器神经网络将输入语言序列编码为单个向量,也称为 上下文向量 。
这个 C 上下文向量 据说包含了输入语言序列的抽象表示。
这个向量然后被传递到解码器神经网络,用于输出相应的输出语言翻译句子,一次一个单词。
我正在做一个德语到英语的神经机器翻译。但是同样的概念可以扩展到其他问题,例如命名实体识别(NER),文本摘要,甚至其他语言模型等。
2.数据准备和预处理
为了以我们想要的最佳方式获取数据,我使用了 SpaCy(词汇构建)、TorchText(文本预处理)库和包含英语、德语和法语翻译序列的 multi30k 数据集
Torch text 是一个强大的库,用于为各种 NLP 任务准备文本数据。它拥有对文本数据进行预处理的所有工具。
让我们看看它能做的一些过程,
-
训练/有效/测试分割 :将你的数据分割到指定的训练/有效/测试集中。
-
文件加载 :加载各种格式的文本语料库(。txt,。json,。csv)。
-
标记化 :将句子拆分成单词列表。
-
Vocab :从文本语料库中生成词汇列表。
-
单词到整数映射器 :将整个语料库的单词映射成整数,反之亦然。
-
词向量 :将一个词从高维转换到低维(词嵌入)。
7.:生成样本的批次。
所以一旦我们理解了在 torch text 中可以做什么,让我们来讨论一下如何在 torch text 模块中实现它。这里我们将利用火炬文本下的 3 个类。
1. 字段 :
- 这是 torch text 下的一个类,在这里我们指定应该如何对我们的数据语料库进行预处理。
2.tabular dataset:
- 使用这个类,我们实际上可以定义以 CSV、TSV 或 JSON 格式存储的列的数据集,还可以将它们映射成整数。
3.😗*
- 使用这个类,我们可以填充我们的数据以进行近似,并用我们的数据进行批处理以进行模型训练。
这里,我们的源语言(SRC —输入)是德语,目标语言(TRG —输出)是英语。我们还添加了 2 个额外的标记“序列开始”和“序列结束”,用于有效的模型训练。
在设置了语言预处理标准之后,下一步是使用迭代器创建成批的训练、测试和验证数据。
创建批处理是一个详尽的过程,幸运的是我们可以利用 TorchText 的迭代器库。
这里我们使用 BucketIterator 来有效填充源句子和目标句子。我们可以使用。属性及其对应的(英语)数据批。trg 属性。此外,我们可以在标记数据之前看到数据。
我刚刚试验了 32 个批次的大小,下面显示了一个样本批次。句子被标记成单词列表,并根据词汇进行索引。“填充”令牌的索引为 1。
每一列对应一个句子,用数字索引,我们在单个目标批次中有 32 个这样的句子,行数对应于该句子的最大长度。短句用 1 填充以弥补长度。
下表(Idx.csv)包含该批次的数字索引,这些数字索引随后会被输入到 word embedding 中,并转换为密集表示以供 Seq2Seq 处理。
带索引的样本目标批次
下表(Words.csv)包含与批次的数字索引相对应的单词。
带单词的样本目标批次
3.长短期记忆(LSTM)
LSTM——引擎盖下。来源—作者
上图显示了单个 LSTM 单元下的单元。我会在最后添加一些参考资料来学习更多关于 LSTM 的知识,以及为什么它对长序列很有效。
但是简单地说,香草 RNN,门控递归单元(GRU)由于其设计的性质而不能捕获长期依赖性,并且严重地受到消失梯度问题的影响,这使得权重和偏差值的变化率可以忽略,从而导致较差的泛化能力。
在 LSTM 单元中,我们有一组小型神经网络,在最后一层有 sigmoid 和 TanH 激活,以及一些向量加法、连接和乘法操作。
*****Sigmoid NN*→压扁 0 和 1 之间的值。比方说,一个更接近 0 的值意味着忘记,一个更接近 1 的值意味着记住。
嵌入 NN →将输入的单词索引转换成单词嵌入。
TanH NN →挤压-1 和 1 之间的值。有助于调节向量值,使其不会爆炸到最大值或收缩到最小值。
大门:
GATES 盖茨。来源—作者
但是 LSTM 有一些特殊的单元,称为门(记住(添加)门,忘记门,更新门),这有助于克服前面提到的问题。
- 遗忘门 →其中有 sigmoid 激活,取值范围在(0–1)之间,它在单元状态上乘以以遗忘某些元素。(“向量”* 0 = 0)****
- 添加门 →其中有 TanH 激活,取值范围在
(-1 到+1)之间,在单元状态上添加以记住一些元素。(" Vector" * 1= "Vector ") - 更新隐藏 →根据单元格状态更新隐藏状态。
隐藏状态和单元状态在这里被称为 上下文向量 ,其是来自 LSTM 单元的输出。输入是输入到嵌入神经网络的句子的数字索引。
4.编码器模型架构(Seq2Seq)
在开始构建 seq2seq 模型之前,我们需要创建编码器、解码器,并在 seq2seq 模型中创建它们之间的接口。
让我们通过德语输入序列“Ich Liebe Tief Lernen”翻译成英语的“ 我爱深度学习 ”。
LSTM 编码器架构。X 轴对应于时间步长,Y 轴对应于批量大小。来源—作者
为了更轻松,我们来解释一下上图中发生的过程。Seq2Seq 模型的编码器一次接受一个输入。我们输入的德语单词序列是“ich Liebe Tief Lernen”。
此外,我们在输入句子的开始和结尾添加了序列“SOS”的开始标记和句子“EOS”的结束标记。********
因此在
- 在时间步骤 0,发送“SOS”令牌,
- 在时间步骤 1,发送令牌“ich ”,
- 在时间步骤 2,发送令牌“Liebe ”,
- 在时间步骤 3,发送令牌“Tief ”,
- 在时间步骤 4,发送令牌“Lernen ”,
- 在时间步骤 4,发送令牌“EOS”。
编码器架构中的第一个模块是单词嵌入层(绿色模块所示),它将输入索引单词转换为称为单词嵌入的密集矢量表示(大小为 100/200/300)。
然后,我们的字嵌入向量被发送到 LSTM 单元,在那里它与隐藏状态(hs)和前一时间步的单元状态(cs)组合,并且编码器块输出新的 hs 和 cs,其被传递到下一个 LSTM 单元。据了解,到目前为止,hs 和 cs 捕获了句子的一些矢量表示。
在时间步长-0,隐藏状态和单元状态或者完全由零或者随机数初始化。
然后在我们发送了 pass 我们输入的所有德语单词序列后,最终得到一个 上下文向量 【黄色块中所示】(hs,cs),这是单词序列的密集表示,可以发送到解码器的第一个 LSTM (hs,cs)进行相应的英语翻译。
在上图中,我们使用 2 层 LSTM 架构,其中我们将第一个 LSTM 连接到第二个 LSTM,然后我们获得堆叠在顶部的 2 个 上下文向量 作为最终输出。这纯粹是实验性的,你可以操纵它。
我们必须在 seq2seq 模型中设计相同的编码器和解码器模块。
上述可视化适用于一批句子中的单个句子。
假设我们的批量大小为 5(实验性的),那么我们将一次一个单词的 5 个句子传递给编码器,如下图所示。
批量大小为 5 的 LSTM 编码器。X 轴对应于时间步长,Y 轴对应于批量大小。来源—作者
5.编码器代码实现(Seq2Seq)
6.解码器模型架构(Seq2Seq)
LSTM 解码器架构。X 轴对应于时间步长,Y 轴对应于批量大小。来源—作者
解码器也是一次做一步。
来自编码器块的 上下文向量 被提供作为解码器的第一个 LSTM 块的隐藏状态(hs)和单元状态(cs)。
******句首“SOS”令牌被传递到嵌入 NN,然后传递到解码器的第一个 LSTM 单元,最后,它通过一个线性层【显示为粉红色】,该层提供一个输出英语令牌预测概率( 4556 个概率)【4556—如在英语语言的总词汇量中】、隐藏状态(hs)、单元状态(cs)。
从 4556 个值中选择具有最高概率的输出字,隐藏状态(hs)和单元状态(cs)作为输入被传递到下一个 LSTM 单元,并且这个过程被执行,直到它到达句子“EOS”的 结尾。
后续层将使用先前时间步长的隐藏和单元状态。
示教力比率:
除了其他模块,您还可以在 Seq2Seq 架构的解码器中看到如下所示的模块。
在模型训练时,我们发送输入(德语序列)和目标(英语序列)。从编码器获得 上下文向量 后,我们将它们向量和目标发送给解码器进行翻译。
但是在模型推断期间,目标是基于训练数据的概括从解码器生成的。因此输出预测字作为下一个输入字被发送到解码器,直到获得令牌。
所以在模型训练本身中,我们可以使用教导力比(tfr) ,在这里我们可以实际控制输入单词到解码器的流动。****
讲授力比法
- 我们可以在训练的时候把实际的目标词发送到解码器部分(以绿色显示)。
- 我们还可以发送预测的目标词,作为解码器的输入(以红色显示)。
发送单词(实际目标单词或预测目标单词)中的任何一个都可以用 50%的概率来调节,所以在任何时间步长,训练时都是通过其中一个。
这种方法的作用类似于正则化。以便模型在此过程中高效快速地训练。
上述可视化适用于一批句子中的单个句子。假设我们的批处理大小为 4(实验性的),那么我们一次向编码器传递 4 个句子,编码器提供 4 组 、 上下文向量,它们都被传递给解码器,如下图所示。
批量大小为 4 的 LSTM 解码器。X 轴对应于时间步长,Y 轴对应于批量大小。来源—作者
7.解码器代码实现(Seq2Seq)
8.Seq2Seq(编码器+解码器)接口
单个输入句子的最终 seq2seq 实现如下图所示。
- 提供输入(德语)和输出(英语)句子。
- 将输入序列传递给编码器,并提取 上下文向量。
- 将输出序列传递给解码器,来自编码器的上下文向量产生预测的输出序列。**
单句 Seq2Seq 数据流图。来源—作者
上述可视化适用于一批句子中的单个句子。假设我们的批处理大小为 4(实验性的),那么我们一次传递 4 个句子给编码器,编码器提供 4 组 、 上下文向量,它们都被传递给解码器,如下图所示。
批量大小为 4 的 Seq2Seq。来源—作者
9.Seq2Seq(编码器+解码器)代码实现
10.Seq2Seq 模型训练
例句的训练进度:
培训损失:
培训流失呈现良好趋势。
11.Seq2Seq 模型推断
现在让我们比较我们的训练模型和 SOTA 谷歌翻译。
模型推理样本
不错,但是很明显这个模型不能理解复杂的句子。因此,在接下来的一系列帖子中,我将通过改变模型的架构来增强上述模型的性能,如使用双向 LSTM,添加注意力机制,或者用变形金刚模型替换 LSTM 来克服这些明显的缺点。
12.资源和参考
我希望我能够对 Seq2Seq 模型如何处理数据提供一些直观的理解,请在评论部分告诉我您的想法。
查看包含全部代码实现的笔记本,并随意破解它。
完整的代码实现可从以下网址获得:
@GitHub
permalink dissolve GitHub 是超过 5000 万开发人员的家园,他们一起工作来托管和审查代码,管理…
github.com](https://github.com/bala-codes/Natural-Language-Processing-NLP/blob/master/Neural%20Machine%20Translation/1.%20Seq2Seq%20%5BEnc%20%2B%20Dec%5D%20Model%20for%20Neural%20Machine%20Translation%20%28Without%20Attention%20Mechanism%29.ipynb)
@Colab
编辑描述
colab.research.google.com](https://colab.research.google.com/github/bala-codes/Natural-Language-Processing-NLP/blob/master/Neural%20Machine%20Translation/1.%20Seq2Seq%20%5BEnc%20%2B%20Dec%5D%20Model%20for%20Neural%20Machine%20Translation%20%28Without%20Attention%20Mechanism%29.ipynb)
@
使用 Kaggle 笔记本探索和运行机器学习代码|使用来自非数据源的数据
www.kaggle.com](https://www.kaggle.com/balakrishcodes/seq2seq-model-for-neural-machine-translation#12.-Seq2Seq-Model-Inference)*
对于那些好奇的人来说,本文中的可视化是由Figma&Google Drawing实现的。**
完成可视化文件 在 Figma 上创建(。图)【LSTM,编码器+解码器,SEQ2SEQ】可用@ Github。
此时您不能执行该操作。您已使用另一个标签页或窗口登录。您已在另一个选项卡中注销,或者…
github.com](https://github.com/bala-codes/Natural-Language-Processing-NLP/blob/master/Neural%20Machine%20Translation/Visualizations_Figma_Files/FIGURES%20OF%20LSTM%2C%20ENCODER%2C%20DECODER%2C%20SEQ2SEQ.fig)**
参考资料: LSTM ,文字 _ 嵌入,深度 _ 学习 _ 模型 _ 部署 _ON_AWS
在那之前,下次见。
文章作者:
BALAKRISHNAKUMAR V******
开始构建物联网产品的全面指南
罗宾·格劳泽在 Unsplash 上的照片
当我开始开发我的第一个物联网项目时,我希望我有这样的指南
什么是物联网?
我们举个简单的例子。你的手机。在它连接到互联网之前,它是哑的,真的是哑的。它只能播放你放在里面的歌曲。它只能给你有联系号码的人打电话。
然后神奇的事情发生了。我们把它连上了互联网
现在它可以播放任何歌曲。你不仅仅局限于一个联系号码来联系某人。您可以访问手中放不下数 TB 数据存储的信息。这就是连接互联网的力量。
互联网和智能手机,电脑确实是强大的工具,但智能手机不会给你的植物浇水,它不会打开你的门。这些设备的体能非常有限。
物联网旨在将互联网的力量从计算机和智能手机扩展到一系列其他事物、流程和环境。
我们如何做到这一点?我们如何将力量延伸到互联网?
通过在你周围的世界中放置能与物理世界互动和感知的组件,并将它们连接到互联网。这些组件是传感器和致动器的组合。
什么是传感器?
简单来说,传感器测量的是一种物理属性。像温度传感器测量温度。
什么是执行器?
你可以把执行器理解为传感器的对立面。就像传感器将外部变化转化为信号一样,执行器将信号转化为行动。就像打开门锁一样。
当然,对于这些传感器和致动器,您需要一些额外的硬件来控制它们,如果需要,还可以传输信息。
物联网改变世界
物联网使您能够比以往更密切地监控联网设备并对其采取行动。无论是管理机器的行业、检查庄稼的农民、管理边境的政府,还是监控空气或水质的管理部门,都不需要每周手动检查一次或两次。
一切都是实时发生的!
想想当你没有牛奶时会提醒你的智能冰箱,或者当它们干了时会提醒你浇水的智能植物,这些可能性只限于你的想象。
我们已经看到物联网带来了如此巨大的变化
- 自动驾驶汽车
- 智能家居和工业安全
- 家庭自动化
- 健身追踪器、智能手表和可穿戴设备
- 自主高效农业
理解并想象一个物联网世界会是什么样子非常重要。这里有两个非常好的 Ted 演讲,可以帮助你想象物联网的未来世界
物联网:TEDxCIT 的约翰·贝瑞塔博士
物联网设计| Rodolphe el-Khoury | TEDxToronto
物联网项目的架构
物联网项目的架构
物联网项目有三个主要组成部分
- 物联网硬件设备:与环境交互的物理设备
- 连接:你的设备和云之间的链接
- 产品云:服务器获取数据,处理数据,存储在数据库中,发出命令,执行分析,以一种有用的方式向所有不同的参与者提供数据
您可能熟悉连接和云,因为它与任何网站和应用程序都一样。但在这里,您还将管理设备的硬件,这带来了额外的复杂性。
物联网硬件设备
这是物联网产品中最复杂、最独特的部分。您可能希望根据自己的需要创建一个特定于设备的。
对于智能灌溉系统,您必须添加传感器来检测湿度水平并与泵进行交互,但对于家庭安全系统,您需要传感器来检测运动或摄像头,并对入侵者进行处理,然后发出警报或通知。
人们需要选择或定制硬件组件来服务于特定的使用情形以及将在该硬件上运行的软件。
产品硬件
硬件将有一个负责逻辑执行的中央处理器/控制器,以及收集数据并根据命令行动的传感器和致动器。
将这个中央处理器/控制器视为负责所有逻辑的大脑,皮肤、眼睛、手、腿作为传感器和致动器,感知并向大脑报告,大脑发出命令,然后在此基础上执行一些操作。
基于这个中央单元,有基于微控制器的物联网板和基于微处理器的板。
基于微控制器的
- Arduino Uno,Mega :易于开发,大量引脚可连接外设,非常适合原型开发
- ESP8266 / ESP32 板:具有 WiFi 和蓝牙连接,低成本(ESP8266 成本约为 3 美元),大量开发资源
- STM32F 系列板:开发复杂,生产友好,易于制造,在生产中应用最广泛
基于微处理器:
- 树莓派:很棒的社区,容易开发,可以运行像 Linux,windows 这样的 OS
- 小猎犬骨:开源板,可以放 android、ubuntu 等 Linux,内置 flash 存储
raspberry pi model b、raspberry pi zero 和 Arduino Uno |照片由哈里森·布罗德本特在 Unsplash 上拍摄
在这些板上,你会看到一个微控制器和微处理器(中间的大黑芯片)。此外,还有许多标有数字的别针。这些引脚是 IO 引脚,用于连接您想要使用的任何传感器或执行器。此外,如果您需要使用多个微控制器/微处理器,也可以设置它们之间的通信。
因此,只需选择适合您要求的电路板,使用这些 IO 引脚,您就可以随心所欲地使用任何传感器。你选择的任何传感器都可能与所有的电路板兼容。
传感器和致动器的一些例子是:
- 温度和湿度传感器
- 压力传感器
- 接近传感器
- 气敏元件
- 烟雾传感器
- 酒精传感器
- 超声波传感器
- 继电器:以电子方式闭合和断开电路(开关)
- 发动机
所以,假设你想建立一个火灾响应系统,你可以选择任何物联网板(Arduino,ESP8266),连接烟雾传感器和洒水器的继电器开关。每当烟雾传感器探测到烟雾时,发出继电器命令启动喷水器。
当然你需要把这个逻辑写在某个地方。这就是产品软件出现的原因。
产品软件
由于代码需要专门针对微控制器或微处理器进行编译,并且由于缺少像 Linux、Windows 这样的操作系统(它抽象了硬件变量),用于开发的软件和工具在很大程度上取决于您选择的芯片。尽管有多种框架试图支持大量芯片。
你需要检查的东西
- Arduino 框架:支持多种板卡和芯片,如所有 Arduino、ESP8266、ESP32、STM32 芯片
- FreeRTOS :非常流行的微控制器操作系统,轻量级,支持多种芯片
- Amazon FreeRTOS :亚马逊版本的免费 RTOS,无缝连接到 AWS 物联网云,并支持许多其他功能,如空中更新、供应
- Apache Mynewt :专注于基于无线的物联网产品开发
此外,您选择的芯片制造商可能也有一些开发工具,如 STM 提供自己的开发工具,也可以在其芯片上进行开发。一定要检查一下。
如果您使用的是功能更强大的物联网主板,如 raspberry pi,它可以运行 Linux、Windows 等成熟的操作系统,那么当然可以归结为开发 Linux 或 Windows 应用程序。尽管你仍然需要做一些硬件交互来从传感器获取数据。
连通性
连接技术的选择取决于产品所处的环境。例如,大多数家庭物联网将使用 wifi,因为每个家庭都可以使用 WiFi,但如果您在城市中建立空气质量测量仪,WiFi 可能不可用,您可能会决定使用 GSM/GPRS。
现在,对于农业来说,你有数百个传感器分布在大片土地上,你会希望使用一些无线电通信到中央控制中心,然后在需要时将所有数据传输到互联网。
所以通信技术是基于用例来选择的。一些通信技术是:
- WiFi :适用于家庭和办公室物联网设备等室内设施
- RFID/NFC :最常见的使用案例是基于卡的访问控制
- GSM/GPRS :用于户外独立设备
- 蓝牙:可穿戴设备和可使用智能手机控制的设备的最常见选择,也用于 wifi 配置(为设备配置 wifi 凭证),还可以为多个设备创建蓝牙网格
- LoRaWAN :适用于 3-5 公里范围通信的工业和公共基础设施产品,专为物联网设备设计,可在大范围内创建网关网络
- NB-IoT :窄带物联网是一种蜂窝通信技术,专为物联网通信设计,功耗极低
接下来是通信协议,将用于设备和云之间的通信。
消息通信协议
- HTTP :最容易获取,有很多开销,不同步,非常适合单个请求,不连续通信
- HTTP WebSockets :基于 HTTP 因此开销很大,但是支持连续通信
- MQTT :最常用的物联网协议(亚马逊 FreeRTOS 等大多数解决方案默认使用这个),基于发布/订阅模型,非常轻量级,没有不必要的占用空间,非常灵活
- AMQP :开源,面向消息,排队,路由,支持点对点和发布订阅模式
产品云
云是所有处理、分析和数据库驻留的地方。当云从数以千计的设备接收原始数据时,它需要转换数据、应用业务逻辑、以有利于检索的方式存储数据,并为物联网产品的应用提供动力。它还应该维护所有现场设备的状态和健康。推送空中更新以了解任何所需的更改,并跟踪哪些设备被更新,哪些设备被保留。
云还负责应用程序(应用程序和网站)与设备之间的交互。如果应用程序给出任何任务或命令,云负责将这些命令/任务发送到设备,并且还应该跟踪命令是否被成功执行。
要设计云架构,应该考虑这些因素
- 将消息接收层与处理层分开,以避免任何消息节流
- 始终考虑设备离线和故障
- 为空中更新做好准备(需求中总会有错误和变化)
- 所有通信都应该是安全的
- 设置一个认证系统,以便一旦设备不能发布另一个设备的消息,也不能订阅不允许它的频道
- 保持云中每个设备的当前状态
- 因为数据的大小很快就会变得巨大,所以选择一个伸缩性好的数据库
有许多云解决方案可供使用:
- 微软 Azure 物联网套件
- 谷歌云的物联网平台
- AWS 物联网平台:与亚马逊 FreeRTOS 集成良好
- 沃森物联网平台
使用云将非常有益,因为它将防止许多设计错误,并且是在牢记最佳实践的基础上构建的。
你将被来自设备硬件、传感器、软件和通信的选择轰炸。你可以选择你想要的和你需要的。刚开始可能会有些不知所措,但是真的很有趣。
Seaborn 数据可视化综合介绍:分布图
基于 Python 的新冠肺炎疫情数据可视化
欢迎大家来到海波恩。在接下来的系列文章中,我将介绍 Seaborn 库的核心概念、它的优点以及如何和何时使用它。
整个系列基于来自世界各地的不同冠状病毒数据集。我们将探索时间序列数据、人口统计数据、Corona 对不同行业的经济影响等等!所有数据集都是公开的。我们将一个接一个地探索它们,并熟悉如何探索个体变量之间关系的不同方法。
海生的
Python 中的库非常丰富,它们经常相互重叠。那么我们现在在哪里?Seaborn 构建在 Matplotlib 之上,它们在可视化地探索数据时可以很好地合作。该软件包以统计图形为导向,提供许多从置信区间或核密度估计开始的功能,称为 KDE。我们将在后面解释这些术语。除此之外,Seaborn 与熊猫合作得很好,它的数据帧结构。
我们可以说 Seaborn 是 Matplotlib 的统计扩展。该库提供了许多功能,旨在帮助您更好地理解您的数据。该图书馆将可视化和数据探索置于数据分析的中心。使该软件包与众不同的一点是,它提供了广泛的图表来分析多个变量之间的关系。Seaborn 还可以很好地处理分类变量,并显示聚合统计数据和计数图。
其他很酷的特性是二元图和多点网格。这些都是很好的工具,使您能够理解表格数据中看不到的潜在关系。您可以立即看到多个变量之间的相关性。
值得一提的还有分析数据集的样式和整体外观。各种不同的背景样式、调色板和其他自定义功能将增强您的受众对数据的理解。为了让你的见解更有影响力,你需要准确恰当地传达你的发现。Seaborn 有实用的工具来支持你。
海牛和熊猫
Seaborn 的设计可以很好地处理熊猫数据帧。值得一提的是,熊猫的数据集必须组织有序。在一个整洁的数据集中,每一行代表一个观察值,每一列都是可变的,通常称为要素。如果我们希望库正常运行,对数据的第一印象和理解是至关重要的。要确定数据集是否整洁,请尝试使用。头()和。tail()方法。
Seaborn 对 Matplotlib
如果你在 python 代码中见过缩写 SNS,它指的就是 Seaborn。导入它和导入任何其他 python 库一样简单。与 seaborn 一起,我们还需要导入 Matplotlib lib Pyplot 来利用两者的协同作用。尽管大部分工作可能由 seaborn 完成,但 Matplotlib 增加了一些功能:
导入库:
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np
加载数据
主要数据源可从 Kaggle 获得:
新冠肺炎受影响病例的日水平信息
www.kaggle.com](https://www.kaggle.com/sudalairajkumar/novel-corona-virus-2019-dataset)
我们将从“COVID19_open_line_list.csv”开始,它包含冠状病毒个案的全球信息:
#loading the data
df = pd.read_csv("novel-corona-virus-2019-dataset 2/COVID19_open_line_list.csv")
让我们看看数据集是什么样子的:
#checking the structure
df.head()
输出:
#checking the shape
df.shape
输出:
(14126, 45)
让我们看看这些列:
#checking the columns
df.columns
输出:
Index(['ID', 'age', 'sex', 'city', 'province', 'country',
'wuhan(0)_not_wuhan(1)', 'latitude', 'longitude', 'geo_resolution',
'date_onset_symptoms', 'date_admission_hospital', 'date_confirmation',
'symptoms', 'lives_in_Wuhan', 'travel_history_dates',
'travel_history_location', 'reported_market_exposure',
'additional_information', 'chronic_disease_binary', 'chronic_disease',
'source', 'sequence_available', 'outcome', 'date_death_or_discharge',
'notes_for_discussion', 'location', 'admin3', 'admin2', 'admin1',
'country_new', 'admin_id', 'data_moderator_initials', 'Unnamed: 33',
'Unnamed: 34', 'Unnamed: 35', 'Unnamed: 36', 'Unnamed: 37',
'Unnamed: 38', 'Unnamed: 39', 'Unnamed: 40', 'Unnamed: 41',
'Unnamed: 42', 'Unnamed: 43', 'Unnamed: 44'],
dtype='object')
Dataframe 包含 45 列,具有许多不同的格式和数据类型。它以时间序列分析为导向,逐例描述冠状病毒。除了那些我们不确定它们代表什么的变量,我们也有明确的变量,我们在分析中探索这些变量。
重要的是,seaborn 的数据集必须整洁。因此,我们执行基本的数据转换:删除年龄的 nan 值,我们将绘制这些值,并删除范围和所有非数字值:
#keeping only numeric, not nan values and casting to integer type
df_age = df[df['age'].notna()]
df_age = df_age[df_age['age'].str.isnumeric()]
df_age['age'] = df_age['age'].astype(str).astype(int)
让我们从绘图开始:
有 Seaborn 的分布图
分析数据集时,您将一次从一个变量开始。查看数据的分布是单变量分析的一部分。为此,有分布图、散点图或直方图。
让我们绘制我们的第一个分布图,或者像在 Seaborn 中那样称为 distplot(年龄):
sns.distplot(df_age['age'])
plt.show()
输出:
为了比较 Seaborn 和 Matplotlib,让我们绘制相同的图形:
#plot the same histogram with matplotlib
df_age['age'].plot.hist()#show the plot
plt.show()
输出:
乍一看,我们可以看出 Seaborn 和 Matplolib 之间的区别。颜色是柔和的;我们在 Seaborn 中标记了 x 轴和更多有机定义的箱。除此之外,请看一条描述我们的分布的线,叫做核密度估计(KDE):
在统计学中,核密度估计 ( KDE )是一种估计随机变量概率密度函数的非参数方法。核密度估计是一个基本的数据平滑问题,其中基于有限的数据样本做出关于总体的推断。
来源:https://en.wikipedia.org/wiki/Kernel_density_estimation
基于可视化,我们可以说大多数确诊病例在 35-55 岁之间。
在 Seaborn 中,您可以随时添加一些自定义内容:
- 设置样式
- 移除 KDE 图,因为 kde=False
- 或者改变颜色
#set sns style as sns.set()
sns.set()#create distplot without kde:
sns.distplot(df_age[‘age’], kde=False, color = 'y')#show the plot()
plt.show()
输出:
…或者将参数‘vertical’= True,使绘图垂直
#create vertical ditplot
sns.distplot(df_age['age'], kde = False, vertical=True, color="y")#show the plot()
plt.show()
输出:
如果你想从不同的角度看分布,Seaborn 还提供了一个 rub plot,它画出小垂直线来代表每个观察值。
#create ditplot with rugplot and
sns.distplot(df_age['age'], rug=True, color="g")#show the plot()
plt.show()
一旦你完成了单变量分析,下一步就是理解两个或更多变量之间的关系。
理解两个变量之间分布的最常见图表是:
- 线形图
- 散点图
- 或配对图
在下一个练习中,我们将使用与已确诊、已康复和已死亡病例总数相关的数据集。同样来自 Kaggle- 'covid_19_data.csv '。
经过一些数据转换步骤后,我们得到了以下数据框架:
df_cases_a.head()
这些要素代表一个国家、一个大洲、观察日期、确诊病例、死亡病例和恢复病例。除了观察日之外,我们还对数据集进行了转换,以获得首例确诊病例的起始日。
如前所述,还有更多绘制图表的方法—在大多数情况下,您将使用。relplot()
该函数提供了对几个不同的轴级函数的访问,这些轴级函数通过子集的语义映射来显示两个变量之间的关系。kind
参数选择要使用的底层轴级函数:
**scatterplot()**
(同kind="scatter"
;默认)**lineplot()**
(与kind="line"
线形图
让我们从折线图开始—折线图以直线连接的点的形式显示信息。折线图通常用于时间序列可视化或显示连续变量的趋势。让我们在这里画一个:
#create lineplot of ’day_since_first_confirmed’ and ’Confirmed’sns.relplot(x=’day_since_first_confirmed’, y=’Confirmed’,kind = ‘line’, data=df_cases_a)
输出:
我们在这里看到的是一条线,它连接了自全球范围内第一个患者被诊断患有新冠肺炎以来每天确诊的病例数。阴影区域是每次观察汇总数据时绘制的置信区间的大小。默认情况下,它是平均值,但可能会被标准偏差代替,设置 estimator=’ std ':
#change estimator parameter to std
sns.relplot(x=’day_since_first_confirmed’, y=’Confirmed’,kind = ‘line’, data=df_cases_a, estimator = ‘std’)#show the plot
plt.show()
我们可以看到绝对值发生了变化,因为后台的计算发生了变化。我们将在下一个统计学系列中讨论标准差。
通常情况下,您希望在可视化中看到更多的值。您可以始终以颜色、标记和其他参数的形式添加尺寸:
#set hue=‘continent’ parameter and set ci=None
sns.relplot(x=’day_since_first_confirmed’, y=’Confirmed’,kind = ‘line’, data=df_cases_a, hue=’continent’, ci = None)#show the plot()
plt.show()
输出:
#set hue=‘continent’ parameter and set ci=None
sns.relplot(x=’day_since_first_confirmed’, y=’Confirmed’,kind = ‘line’, data=df_cases_a, hue=’continent’, ci = None)#show the plot()
plt.show()
我们看到的是,大多数确诊病例发生在北美,远远领先于任何其他大陆。
如果您想自定义您的绘图,您可以随时添加标记:
#set marker='o'.
sns.relplot(x='day_since_first_confirmed', y='Confirmed',kind = 'line', data=df_cases_a, hue='continent', marker='o', ci = None)#show the plot
plt.show()
输出:
为了更好地在图表中导航,在适当的位置放置标记通常是有用的。在这种情况下,由于极值,图表中的可见性和方向很麻烦。为了避免这种情况,我们可以使用对数函数,并为大陆的每个值添加不同的标记。设置 marker=True,style = ’ continental’。
#add log_value of confirmed cases for all 3 variables
df_cases_a['log_value_confirmed'] = np.log(df_cases_a['Confirmed'])
df_cases_a['log_value_deaths'] = np.log(df_cases_a['Deaths'])
df_cases_a['log_value_recovered'] = np.log(df_cases_a['Recovered'])#set parameter markers to True and style='continent'
sns.relplot(x='day_since_first_confirmed', y='log_value_confirmed',kind = 'line', data=df_cases_a, hue='continent', style = 'continent', ci = None, markers = True)#show the plot
plt.show()
输出:
每个洲变量的值都得到了它的标记,以及确诊病例的规模,现在彼此之间是可比较的。当我们有强烈的偏斜分布时,应用对数变换。它有助于预测建模,以找到模式或使数据更好地解释。
散点图
让我们来看看两个变量之间的关系。比较两个变量及其分布的简便方法是用散点图。每个点代表一个观察。我们将看看 50 个国家中确诊、死亡和康复病例的最高值。要显示散点图,请设置 kind=’ scatter ':
#plot a scatterplot with 'Confirmed' on x and 'Deaths' on y-axis
sns.relplot(x = 'Confirmed', y= 'Deaths', kind='scatter', data=df_cases_scatter)#show the plot()
plt.show()
散点图的解释相当简单。我们可以对死亡和确诊病例之间的关系做出假设。我们可以肯定地说,确诊病例越多,死亡就越多。我们将再次应用对数变换,因为我们仍然有偏斜的数据,并且大多数情况在左下角。
除了对数变换,我们再来增加维度。使用“col”参数,您可以单独显示变量的值。让我们将 col = ’ continental '和 col_wrap=3 设置为每行只有三个图:
#plot a scatterplot with 'Confirmed' on x and 'Deaths' on y-axis
sns.relplot(x = 'log_value_confirmed', y= 'log_value_deaths', kind='scatter',
data=df_cases_scatter, col='continent', col_wrap=3)
#show the plot()
plt.show()
输出:
在分析中包含维度可以帮助您获得对数据的全面理解。我们可以假设为什么大洋洲的数字如此之低,为什么美国和欧洲受到如此严重的影响,等等。
通过设置 hue = ’ continental ',size='log_value_recovered '或设置 markers=True 和 style = ’ continental ',可以获得简化但信息更丰富的图,同时具有更多维度:
#assign 'continent' to hue and log_value_recovered to size
sns.relplot(x = 'log_value_confirmed', y= 'log_value_deaths', kind='scatter',
data=df_cases_scatter, hue ='continent', size = 'log_value_recovered')#show the plot
plt.show()
输出:
此外,设置标记=真,样式=“大陆”和 alpha=0.8 (80%)以获得更好的可解释性:
对群体观察应用不同的颜色或标记来提供更详细的信息是很常见的。我们还可以根据具体值给出每个点的大小,并创建一个气泡图。
联合地块
Seaborn library 还提供了下一级分布图——联合图。联合阴谋。Seaborn 的联合图显示了两个变量之间的关系以及它们的共同分布和个别分布。要创建一次,只需使用。接合图():
#jointplot of log_value_confirmed and log_value_deaths
sns.jointplot(x=’log_value_confirmed’,y=’log_value_deaths’,
data=df_cases_scatter)#show the plot
plt.show()
默认情况下,联合图显示为散点图,分布为 log_value_confirmed 和 log_value_deaths。当你想在一个图表中检查单个分布和所有分布时,这是很方便的。
有几种不同的联合绘图图表样式,如:
- reg 图
- 十六进制图
- KDE 图
#jointplot of log_value_confirmed and log_value_deaths, regression
sns.jointplot(x=’log_value_confirmed’,y=’log_value_deaths’,data=df_cases_scatter, kind=’reg’, color=’y’)#show the plot
plt.show()
#jointplot of log_value_confirmed and log_value_deaths, hex
sns.jointplot(x=’log_value_confirmed’,y=’log_value_deaths’,data=df_cases_scatter, kind=’hex’, color=’b’)#show the plot
plt.show()
#jointplot of log_value_confirmed and log_value_deaths, kde
sns.jointplot(x=’log_value_confirmed’,y=’log_value_deaths’,data=df_cases_scatter, kind=’kde’, color=’g’)#show the plot
plt.show()
密度图是直方图的升级版。如果您有相当多的观察值,并且散点图绘制过多,建议使用密度图,它在较小的区域内计算观察值的数量。该区域通常由六边形、正方形等形状定义。另一种更先进的方法是绘制 KDE 并显示其轮廓。
我们已经介绍了如何可视化变量分布的大多数方法。对于一些具体的案例,我们将在下一篇文章中详细讨论,比如回归图。
编者按: 走向数据科学 是一份以数据科学和机器学习研究为主的中型刊物。我们不是健康专家或流行病学家,本文的观点不应被解释为专业建议。想了解更多关于疫情冠状病毒的信息,可以点击 这里 。
在 LinkedIn 上关注我
[## Filip Dzuroska —数据科学家—第一集团 IT | LinkedIn
在世界上最大的职业社区 LinkedIn 上查看 Filip Dzuroska 的个人资料。菲利普有一份工作列在他们的…
www.linkedin.com](https://www.linkedin.com/in/filipdzuroska/)
还有推特:
菲利普·祖罗斯卡(@菲利普·祖罗斯卡)的最新推文。数据科学家,加州大学洛杉矶分校机器方面的研究生研究员…
twitter.co](https://twitter.com/filipdzuroska)
来源:
[## seaborn:统计数据可视化— seaborn 0.10.0 文档
Seaborn 是一个基于 matplotlib 的 Python 数据可视化库。它为绘图提供了一个高级接口…
seaborn.pydata.org](https://seaborn.pydata.org/index.html) [## 新型冠状病毒 2019 数据集
新冠肺炎受影响病例的日水平信息
www.kaggle.com](https://www.kaggle.com/sudalairajkumar/novel-corona-virus-2019-dataset) [## Python 图表库
欢迎来到 Python 图表库。该网站展示了数百张图表,始终提供可复制的 python…
python-graph-gallery.com](http://python-graph-gallery.com/)
神经网络综合介绍
从零到工作实现
在 Flickr 上由迈克·麦肯齐拍摄的图片
人工神经网络,我们文章的主题,是受生物神经网络启发并试图模仿它们的数学模型。由于生物神经网络是针对特定任务的更多神经元的组合,因此人工神经网络是通常称为人工神经元或感知器的更多线性模型的组合。如果你想了解更多关于感知器,这是最简单的神经网络,你可以在这里阅读更多关于它的。
神经网络通常直观地表示为类似图形的结构,如下所示:
图片由 Glosser.ca / CC BY-SA 在维基共享
上面是一个有 3 层的神经网络:输入层、隐藏层和输出层,由 3、4 和 2 个神经元组成。
输入图层的结点数量与数据集的要素数量相同。对于隐藏层,你可以自由选择你想要多少个节点,你可以使用多个隐藏层。那些具有一个以上隐藏层的网络被称为深度神经网络,并且是深度学习领域的主要特征。只有一个隐藏层的网络通常被称为浅层神经网络。输出层的神经元数量应该与您想要预测的变量数量一样多。
还有更多种类的神经网络:卷积、递归、脉冲神经网络等等。但这里我们将只讨论简单的前馈神经网络或多层感知器。
神经网络可用于广泛的问题,包括分类和回归任务。为简单起见,在本文的大部分内容中,我们将只关注分类任务,正如我们将在后面看到的,我们通过本文了解到的关于神经网络的东西可以很容易地转化为回归问题。
除了输入层中的神经元之外,网络中的每个神经元都可以被认为是一个线性分类器,它将前一层中神经元的所有输出作为输入,并计算这些输出加上一个偏差项的加权和。然后,下一层中的神经元将把前一层线性分类器计算的值作为输入,然后计算这些值的加权和,等等。我们的希望是,通过以这种方式组合线性分类器,我们能够构建更复杂的分类器,可以表示我们数据中的非线性模式。
让我们看看下面的例子:
这个数据集显然不是线性可分的,我们不能用一条线将一个类与另一个类分开。但是我们可以通过使用 2 条线作为判定边界来进行这种分离。
因此,我们可能认为两个中间神经元可以完成这项工作。这两个神经元将学习上图中的两条分隔线。然后,我们将需要一个输出神经元,它将把这两个先前的神经元作为输入,然后它将能够正确地进行分类。
为了使最后一个神经元正确分类,如果我们将 n1 和 n2 个隐藏神经元绘制在 2d 平面上,则它们的输出需要是线性可分的。上面绘制的 2 条线具有以下等式:
这意味着 2 个隐藏神经元正在计算输入 x1 和 x2 的以下线性组合:
让我们现在画出 n1 和 n2,看看它们是否帮助了我们。
我们对我们小小的神经网络感到失望。n1 和 n2 的输出仍然不是线性可分的,因此输出神经元不能正确分类。
那么,问题出在哪里?事情是,任何线性函数的线性组合仍然是线性的,并不难在一张纸上说服自己这是正确的。因此,无论我们使用多少层或多少个神经元,到目前为止,我们的神经网络仍然只是一个线性分类器。我们需要更多的东西。我们需要将每个神经元计算出的加权和传递给一个非线性函数,然后将这个函数的输出视为该神经元的输出。这些函数被称为激活函数,正如你在我们的例子中看到的,它们对于神经网络学习数据中的复杂模式非常重要。已经证明[1]具有 2 层(除了输入层)和非线性激活函数的神经网络能够逼近任何函数,只要它在那些层中具有足够大数量的神经元。那么,如果只有两层就足够了,为什么现在人们使用更深的网络呢?嗯,仅仅因为这些 2 层网络“能够”学习任何东西,并不意味着它们很容易优化。实际上,如果我们让我们的网络产能过剩,他们会给我们足够好的解决方案,即使他们没有优化到他们能做到的程度。
还有更多种类的激活函数,其中两种我们想在上面的例子中使用。它们是 ReLU(RectivedLlinearUnit)和 tanh(双曲正切),如下所示。
思考神经网络的另一种方式是,它们试图同时学习分类和特征表示。如果你读过我的关于感知器的文章,你会在文章的最后看到我们如何通过向输入向量添加非线性特征,使用线性分类器来解决非线性分类问题。但是,为了获得好的结果,您如何总是知道将哪些额外的特性添加到输入向量中呢?神经网络试图通过学习什么样的特征表示是好的来解决这个问题。在隐藏层中,神经网络实际上学习输入数据的最佳表示,以便在进行实际分类的最后一层中表现良好。
现在,让我们继续我们的例子。如果我们在例子中使用 ReLU 激活,会发生什么?下面绘制了施加 ReLU 激活后神经元 n1 和 n2 的输出。
现在我们的两类点可以由一条线分开,因此输出神经元可以正确地对它们进行分类。
如果我们使用 tanh 激活,会发生类似的事情,但这次我们的点被更大的余量分开得更好。
同样,输出神经元可以正确分类这些点。
在我看来,神经网络的常见视觉表示,即讨厌的图形结构,可能有点令人困惑。尤其是如果你想实现它,就更难考虑你需要用那些到处浮动的连接和权重来做什么。在参数层次上思考可能很麻烦,但是在网络中进行的向量和矩阵运算的更高层次上思考更清晰,至少对我来说是这样。将神经网络视为函数的组合,向量函数的链,在我所做的实现中帮助了我,我希望它也能帮助你。请看下图:
如果我们将每一层的输入和输出值表示为向量,将权重表示为矩阵,将偏差表示为向量,那么我们将得到上面的神经网络的扁平化视图,它只是一系列向量函数应用。这些函数将向量作为输入,对它们进行一些变换,然后输出其他向量。在上图中,每一行代表一个函数,可以是矩阵乘法加偏置向量,也可以是激活函数。圆圈代表这些函数操作的向量。例如,我们从输入向量开始,然后将它输入第一个函数,该函数计算其分量的线性组合,然后我们获得另一个向量作为输出。我们将最后一个向量作为激活函数的输入,依此类推,直到到达序列中的最后一个函数。最后一个函数的输出将是我们网络的预测值。
这种表示也更接近我们实际要实现的东西。为了实现神经网络,我们实际上不需要存储通常用图像表示的图形。一个神经网络所做的一切就是矩阵运算,既用于预测,也用于训练。
我们已经看到了神经网络如何获得我们感兴趣的输出,它只是通过一系列函数传递其输入向量。但是这些函数依赖于一些参数:权重和偏差。
为了获得好的预测,我们实际上如何学习这些参数?
好吧,让我们回忆一下神经网络实际上是什么:它只是一个函数,一个由按顺序应用的较小函数组成的大函数。这个函数有一组参数,因为一开始我们不知道它们应该是什么,我们只是随机初始化它们。所以,一开始我们的网络只会给我们随机的值。我们如何改进它们?在尝试改进它们之前,我们首先需要一种评估网络性能的方法。如果我们没有一种方法来衡量我们的模型做得有多好或有多差,我们应该如何改进它的性能呢?为此,我们需要设计一个函数,将网络预测和数据集中的真实标签作为参数,并给出一个代表网络性能的数字。那么我们就可以把学习问题变成一个寻找这个函数的最小值或者最大值的优化问题。在机器学习社区中,这个函数通常衡量我们的预测有多糟糕,因此它被命名为损失函数。我们的问题是找到使这个损失函数最小的网络参数。
随机梯度下降
你可能熟悉微积分课上的求函数最小值的问题。在那里,你通常取函数的梯度,将其设为 0,找到所有的解(也称为临界点),然后从中选择一个使你的函数具有最小值的解。这是全球最小值。我们能做同样的事情来最小化我们的损失函数吗?不完全是。问题是神经网络的损失函数不像你通常在微积分教科书中找到的那样好和紧凑。它是一个非常复杂的函数,有几千、几十万甚至几百万个参数。甚至不可能找到这个问题的封闭解。这个问题通常通过迭代方法来解决,这种方法不试图找到一个直接的解决方案,而是从一个随机的解决方案开始,并试图在每次迭代中改进它。最终,在大量的迭代之后,我们会得到一个非常好的解决方案。
一种这样的迭代方法是梯度下降。你们可能知道,函数的梯度给了我们最陡上升的方向,如果我们取梯度的负值,就会给我们最陡下降的方向,也就是我们可以最快到达最小值的方向。因此,在每次迭代中,也称为历元,我们计算损失函数的梯度,并从旧参数中减去它(乘以称为学习速率的因子),以获得我们网络的新参数。
其中θ表示包含所有网络参数的向量。
在标准梯度下降法中,梯度是在考虑整个数据集的情况下计算的。通常这是不希望的,因为它可能在计算上很昂贵。在实践中,数据集被随机划分成更多的块,称为批,并且对这些批中的每一个进行更新。这被称为随机梯度下降。
上述更新规则在每一步仅考虑在当前位置评估的梯度。这样,在损失函数表面上移动的点的轨迹对任何扰动都是敏感的。有时,我们可能希望让这个轨迹更加稳健。为此我们使用了一个来自物理学的概念:动量。这个想法是,当我们进行更新时,也要考虑以前的更新,这就累积成一个变量δθ。如果更多的更新是在同一个方向上完成的,那么我们会“更快”地向那个方向前进,不会因为任何微小的扰动而改变我们的轨迹。想象一下速度。
其中α是确定过去梯度贡献的非负因子。当它为 0 时,我们就不用动量了。
反向传播
我们如何计算梯度呢?回想一下,神经网络和损失函数只是函数的组合。我们如何计算复合函数的偏导数?使用链式法则。让我们来看下图:
如果我们想要计算第一层权重的损失 w.r.t. ( 相对于)的偏导数:我们取第一个线性组合 w.r.t .的导数,然后我们乘以下一个函数(激活函数)w.r.t .的导数,再乘以前一个函数的输出,等等,直到我们乘以损失 w.r.t .的导数,最后一个激活函数。如果我们想计算第二层重量的导数呢?我们必须执行相同的过程,但这一次我们从第二个线性组合函数的导数 w.r.t .及其权重开始,之后,当我们计算第一层权重的导数时,我们必须相乘的其余项也存在。因此,我们不会一遍又一遍地计算这些术语,而是将倒推,因此得名反向传播。
我们将首先计算损耗对网络输出的导数,然后通过保持导数的连续乘积将这些导数向后传播到第一层。注意,我们有两种导数:一种是计算函数对输入的导数。我们将这些乘以导数的乘积,目的是跟踪网络从输出到算法中当前点的误差。第二种导数是那些我们想要优化的参数。我们不将它们与导数乘积的其余部分相乘,而是将它们存储为梯度的一部分,稍后我们将使用它来更新参数。
因此,在反向传播时,当我们遇到没有可学习参数的函数(如激活函数)时,我们只对第一类函数求导,只是为了反向传播误差。但是,当我们遇到具有可学习参数的函数时(如线性组合,我们有想要学习的权重和偏差),我们对两种类型都进行求导:第一种是误差传播的输入,第二种是权重和偏差,并将它们存储为梯度的一部分。我们从损失函数开始做这个过程,直到我们到达第一层,在那里我们没有任何要添加到梯度的可学习参数。这是反向传播算法。
生产能力过剩
在开始下一步之前,我想谈一点关于神经网络的能力过剩。回想一下我们之前的例子:
如你所见,解决这个分类任务所需的隐藏层中的神经元的最小数量是 2,上面两行中的每一行一个。在神经网络中,增加一些过剩的能力是一个好主意,即增加比解决特定问题所需的最少数量更多的神经元和/或层。这是因为添加更多的参数将使优化问题变得更容易。在上面的例子中,如果我们只使用 2 个隐藏的神经元,我们将需要它们中的每一个学习一条“几乎完美”的线,以便最终的结果是好的。但是,如果我们给我们的网络更多的自由,并在隐藏层中添加更多的神经元,它们就不需要完美。如果它们中的大多数至少对我们的分类任务有用,我们将能够得到好的结果。然后,我们可以认为最后一个神经元平均了每个神经元的决策边界。
思考为什么添加更多参数会使优化任务更容易的另一种方式是想象当我们添加更多参数时损失函数的“表面”会发生什么。在 2d 情况下,只有 2 个方向可以移动我们的(单个)参数,如果在这两个方向上损失函数的高度都比当前点大,那么我们将陷入局部最小值,并且我们可能完全错过全局最小值。现在,让我们想象一下,我们再增加一个参数,这样我们的图就变成了 3d 空间中的一个曲面。在这种情况下,我们有无限多的方向可以选择,并且有更多的机会在所有的方向中找到至少一个方向,使我们向下到达损失面上的一个更低的点。因此,陷入局部最小值的机会更少(至少与 2d 情况相比)。
增加我们网络的参数数量总是更好的?不。参数太多会使我们的网络更容易超载。因此,在使优化问题更容易和保持网络不过度拟合之间有一个权衡。
Softmax 激活和交叉熵损失
分类任务中最后一层常用的激活函数是 softmax 函数。
softmax 函数将其输入向量转换为概率分布。如果你看上面,你可以看到 softmax 的输出向量的元素都是正的,它们的和是 1。当我们使用 softmax 激活时,我们在最后一层创建与数据集中的类数量一样多的节点,softmax 激活将为我们提供可能的类的概率分布。因此,网络的输出将给出输入向量属于每一个可能类别的概率,我们选择具有最高概率的类别,并将其报告为我们网络的预测。
当 softmax 被用作输出层的激活时,我们通常使用交叉熵损失作为损失函数。交叉熵损失衡量两个概率分布的相似程度。我们可以将输入 x 的真实标签表示为概率分布:其中真实类别标签的概率为 1,其他类别标签的概率为 0。这种标签表示也称为一键编码。然后,我们使用交叉熵来衡量我们网络的预测概率分布与真实概率分布的接近程度。
其中 y 是真实标签的独热编码,y hat 是预测的概率分布,yi,yi hat 是那些向量的元素。
如果预测的概率分布接近真实标签的独热编码,那么损失将接近于 0。否则,如果它们非常不同,损失可能会增长到无穷大。
均方误差损失
到目前为止,我们专注于分类任务。但是,通过使用适当的损失函数,神经网络可以很容易地适应回归任务。例如,如果我们有一个想要近似的数字列表,我们可以使用均方误差(简称 MSE)损失来代替类别标签作为基本事实。通常当我们使用 MSE 损失时,我们在最后一层使用身份激活。
用 python 实现这个
现在是时候用 python 实际实现一个神经网络了,然后用几个例子来测试它,看看它的表现如何。
我认为真正理解神经网络如何工作的最好方法是从头开始实现一个神经网络。我向你挑战靠你自己去实现它。当你完成后,回到这里,与我的代码进行比较,做我在本文末尾做的例子,看看你是否得到类似的结果。如果你在某个时候遇到困难,可以来这里看看我是怎么做的。
我将创建一个 NeuralNetwork 类,我希望以这样一种方式设计它,使它更加灵活。我不想在其中硬编码特定的激活或损失函数,或优化器(即 SGD,Adam 或其他基于梯度的方法)。我将把它设计成从类外部接收这些,这样人们就可以获取类的代码,并传递给它他想要的任何激活/丢失/优化器。因此,我将实现激活和丢失函数,以及优化器类,我们希望在这里将它们与 NeuralNetwork 类分开使用。我们需要激活/损失函数及其导数。
为了允许批量大于 1,我们的激活和损失函数应该处理矩阵输入。这些矩阵中的行代表数据样本,列代表特征。我们的网络将允许两种激活功能:隐藏层和输出层。隐藏层激活应该对它们的输入向量进行元素方式的操作,因此它们的导数也将是元素方式的,为每个样本返回一个向量。但是输出激活允许基于输入向量中的所有元素来计算输出向量中的每个元素。这是为了能够使用 softmax 激活。正因为如此,它们的导数需要返回一个雅可比矩阵(一个由每个输出函数对每个输入分量的偏导数组成的矩阵;你可以在这里阅读更多关于每个样品的。
这里我们将只使用 ReLU 作为隐藏激活;identity 和 softmax 将用作输出激活。
我们使用 EPS 变量,它是 float64 类型的最小正表示数,以避免被 0 除。为了避免 softmax 函数中的溢出错误,我们从输入中减去了每个样本的最大值。我们被允许这样做,因为它不会改变函数的输出,因为它的效果和分数的两项除以相同的量是一样的。
损失函数应该将两个矩阵作为输入:预测的 y 和真实的 y,它们的形式与激活函数中的相同。这些损失函数应该为每个样本输出一个数字。它们的导数应该为每个样本输出一个行向量,所有样本都堆叠成一个 3 维的数组。为了能够使用 numpy 的matmul()
函数乘以输出激活的导数,需要该输出形状。注意下面的expand_dims()
函数的使用,该函数用于返回所需的形状。
这里我们将只使用带动量的随机梯度下降作为优化方法,但是还有更多基于梯度的方法。一些流行的选择是:亚当,RMSprop,阿达格拉德。为了让我们的神经网络类能够处理所有这些,我们将把优化器作为一个单独的类来实现,使用一个返回更新参数的.update(old_params, gradient)
方法。神经网络类将接收一个优化器作为参数。因此,想使用其他优化方法的人可以创建一个具有所需接口的类,并在实例化时将其传递给我们的神经网络类。
下面是新币+动量优化器:
为了将分类任务中的分类标签转换为一键编码,我们将使用to_categorical()
实用函数:
现在,让我们从 NeuralNetwork 类的代码开始。实例化方法需要以下参数:
- 层:由每层(包括输入和输出层)的节点数组成的列表
例如:【5,10,2】表示 5 个输入,10 个隐层节点,2 个输出节点 - 隐藏 _ 激活:激活隐藏层;一个形式的元组(activation_function,its_derivative)
这个激活函数和它的导数应该在输入数组
上按元素执行它们的任务,例如:(relu,d_relu) - output_activation :输出层激活;一个形式元组(activation_function,its_derivative)
这个激活函数将一个形状数组(n,m)作为输入;n 个样本,输出层 m 个神经元;并返回 shape (n,m)数组;输出数组中一行上的每个元素都是输入数组中该行上所有元素的函数输出。
它的导数将一个类似于激活所采用的数组作为输入,但它返回一个 shape (n,m,m)数组,该数组是一堆雅可比矩阵,每个样本一个。 - 损失:形式的元组(loss_function,its_derivative)
损失函数将形状(n,m)的两个数组(预测 y 和真实 y)作为输入;n 个样本,输出层 m 个神经元;并返回 shape (n,1)数组,其元素是每个样本的损失。
它的导数将 shape (n,m)的数组作为输入,并返回 shape (n,1,m)的一个数组,该数组是由 m 个输入变量的导数 w.r.t .组成的行向量的堆栈。
例如:(分类 _ 交叉熵,d _ 分类 _ 交叉熵) - 优化器:有方法的对象。update(old_params,gradient)返回新的参数
,例如:SGD()
然后,它使用 Xavier 初始化方法的变体初始化其权重和偏差。也就是说,我们从均值为 0 且标准差为的正态分布中得出权重和偏差:
其中 fan_in 和 fan_out 分别是前一层中的节点数和下一层中的神经元数。权重矩阵中的行数与前一层中的节点数相匹配,列数与下一层中的节点数相匹配。偏差是行向量,其元素数量与下一层中的节点数量相匹配。
为了方便地执行参数更新过程,我们将创建一个.__flatten_params(weights, biases)
方法,将权重矩阵列表和作为输入接收的偏差向量转换为扁平向量。我们还需要一个.__restore_params(params)
方法,将参数的扁平向量转换回权重和偏差列表。注意,方法名前面的 2 个下划线仅仅意味着该方法在 OOP 术语中是私有的。这只是意味着该方法应该只在类内部使用。
.__forward(x)
方法通过网络传递输入数组 x,在这样做的同时,它跟踪每层的输入和输出数组。然后,它将此作为一个列表返回,其中第 I 个元素是一个形式为[第 I 层的输入,第 I 层的输出]的列表。我们将需要这些数组来计算后向传递中的导数。
.__backward(io_arrays, y_true)
方法计算梯度。它将一个由.__forward(x)
方法返回的表单列表和一个包含基本事实 y 的数组作为输入。它使用本文前面描述的反向传播算法计算权重和偏差的梯度。然后它返回一个元组(d_weights,d _ biases)。
实际协调所有培训的方法是.fit(x, y, batch_size, epochs, categorical)
,其中:
- x 是输入数据
- y 是基本事实
- batch_size 是一批数据的大小
- epochs 是遍历所有输入数据的次数
- categorical 是一个可选参数,当设置为 true 时,会将 y 转换为一键编码
对于每批数据,它使用.__forward()
和.__backward()
方法计算梯度,然后使用.__flatten_params()
拉平网络的当前参数和梯度。之后,使用self.optimizer.update()
计算新的参数,然后使用__restore_params()
将返回的向量恢复为正确的格式,并将其分配给self.weights, self.biases
。每批结束时,打印进度和平均损失。维护并返回每个时期结束时所有损失值的列表。
默认情况下,.predict()
方法将在输入 x 通过网络后返回输出节点中的精确值。如果 labels 参数设置为 true,则返回预测标签;这大概就是你在一个分类问题中想要的。
.score()
方法默认返回平均损失。如果 accuracy 设置为 true,那么将返回精度。请注意,在分类问题中,如果您想要损失,那么 y 应该以一键编码格式提供,否则,如果您想要返回准确性,那么 y 应该只是常规的类标签。
最后,我们希望能够在本地保存参数,这样我们就不必在每次想要进行预测时训练我们的模型。请注意,以下方法只能保存和加载权重和偏差,而不能保存和加载关于层、激活、损失函数和优化器的全部信息。因此,您还应该保存用于实例化神经网络的代码。
以下是完整代码:
例子
下面我们将展示两个例子,其中我们使用了刚刚实现的 NeuralNetwork 类。
第一个例子包括对 MNIST 数据库中的手写数字图像进行分类。该数据集由 60,000 个训练和 10,000 个 28 x 28 像素的测试灰度图像组成。
我们使用 mnist 包(pip install mnist
)来加载这个数据集。
然后我们构建一个神经网络,训练 100 个历元。
我们来绘制训练损失图。
让我们看看我们在训练集和测试集上获得的准确性:
并且得到了 99.8% 的训练和 95.9% 的测试精度。这对我们自制的神经网络来说相当不错。
现在我们来看第二个例子,在这个例子中,我们用神经网络来解决一个回归问题。
这次我们将使用 sklearn 软件包附带的加州住房数据集。该数据集由 8 个预测属性的 20640 个样本和目标变量 ln(房屋价值中位数)组成。该数据集来自 1990 年美国人口普查,每个人口普查区块组使用一行。街区组是美国人口普查局发布样本数据的最小地理单位。
这次我们将使用均方误差作为损失函数。
让我们画出训练时的损失。
让我们看看训练集和测试集的最终损失值是多少。
对于训练和测试,我们都损失了大约 0.36 。请注意,目标变量是对数标度。所以,这里对均方误差的解释有点不直观。我们通常说预测值平均相差+/-MSE 的平方根。现在,在我们的情况下,我们的网络预测的中值房屋价值平均偏离 e 的平方根一个因子(而不是+/-我们有乘/除)(在我们的情况下,这个因子大约是 1.83 )。
参考
[1] Cybenko,G.V. (2006 年)。“通过叠加 s 形函数进行近似”。在范舒彭,简 h(编辑。).控制、信号和系统数学。斯普林格国际公司。第 303-314 页。
你可以在 Github 这里找到笔记本和 python 文件。
我希望这些信息对您有用,感谢您的阅读!
这篇文章也贴在我自己的网站这里。随便看看吧!
Tensorflow Extended 的全面 ML 元数据演练
它存在的原因以及它在 Beam 管道组件中的使用方式
图片来自https://www.tensorflow.org/tfx/guide/mlmd
在本文发布时,ML 元数据的当前版本是 v0.22(tfx 也是 v 0.22)。该 API 已经足够成熟,可以在公共云上进行主流使用和部署。Tensorflow Extended 将其广泛用于组件-组件通信、沿袭跟踪和其他任务。
我们将运行一个非常简单的管道,该管道将为著名的芝加哥出租车旅行数据集的样本 csv 生成统计数据和模式。这是一个大约 10mb 的小文件,管道可以在本地运行。
生成的工件列表
运行一次,打开metadata_store.db
文件进行检查。
ML 元数据生成的表
ML 元数据存储关于 3 事物的信息:
- 关于生成的工件的元数据
- 关于这些组件执行的元数据—步骤
- 关于管道和相关沿袭信息的元数据
Apache Beam Pipeline TFX 组件不会将整个二进制工件(由具有多个 io 的[ParDo](https://beam.apache.org/releases/javadoc/2.1.0/org/apache/beam/sdk/transforms/ParDo.html)
处理)传递给下一个节点。相反,URIs 的神器被传来传去。工件通常存储在某种云文件系统上,如云存储桶。
甚至 TFRecord tf。示例 保存的文件作为中间阶段工件处理。它们被压缩以节省空间。
> SELECT * FROM
Artifact;
被储存的藏物
您可以看到,所有这些生成的工件父目录都被存储了起来,还有一个数字(稍后将详细介绍这个数字)、创建和更新时间。
在CsvExampleGen/examples/1
的例子中,我们得到了两个子目录,train
和eval
,它们被存储为同一个工件。该路径的 /examples 部分是example_gen
产生的工件的名称(查看管道代码),statistics_gen
将其作为输入。
空值可能是正在进行的工作,因为商店是 v0.xx 版本。你可以在源代码协议缓冲区声明中看到 n 可以是UNKNOWN — PENDING — LIVE — MARKED_FOR_DELETION — DELETED
并且名字很好,这个名字,除了type_id
之外。
Types
工作台与type_id
如预期的一样:
类型
工件也支持属性映射。这些总结在ArtifactProperty
表中。(例如,保存的 TFRecord 文件的校验和。它们通过 TFX 缓存中间步骤。)
工件属性图
- 一个上下文包含多个工件、执行和事件
- 一个事件包含工件和执行
- 一个执行通常是一个独立的流水线步骤
对于工件的执行跟踪和沿袭跟踪功能(例如,告诉哪个模型或统计对应于哪个数据集或管道运行),我们必须处理事件、上下文和执行。
- 事件关联
artifact_ids
和execution_ids
- 执行只跟踪
type_ids
和时间戳 - 上下文将
type_ids
与管道运行和时间戳信息相关联
表执行属性和上下文属性包含键值形式的额外数据。
- ExecutionProperties 包含传递给每个组件的输入和输出配置,以及管道和步骤根目录,以及工件的 IO 位置。
- 上下文属性将
context_ids
与管道组件名称和时间戳相关联
对于更大的管道的其他步骤,如模型验证和祝福,产生的工件或多或少采用相同的格式。
访问数据
有大量的信息可用,仅仅是在本地运行的简单的 3 步管道。例如,这个管道可以在云中的Dataflow
runner 上运行,只需对配置进行最小的更改。
在这种情况下,使用存储在数据库中的数据要比浏览服务器场上的云存储桶和虚拟机容易得多。
从这一点开始,您可以通过直接 SQL 连接或 gRPC(通过存根或普通的旧调用)连接到 ML 元数据存储。然后,就是选择您想要手动检查的数据类型的问题。例如,这可以是模式或统计 protobuf。
通常,您只需要访问资源的资源标识符。如果您在相同的环境中,您应该能够仅通过 URI 访问它们(例如 GCP 项目 VM 内的笔记本)。
示例使用案例
假设您有一个管道在某个时间间隔(或基于事件的触发)运行,并且有时您想要查看最新管道运行与前一次运行的数据统计。
- 您需要两个不同管道运行的statistics gen/statistics工件(这些是 ExampleStatistics 类型,带有
type_id
8)。这些可以在Artifact
的桌子上找到。 - 您还需要从正确的管道运行中访问工件。
Attribution
表格将context_id
与artifact_id
相关联。唯一缺少的是精确定位您需要的 2 个context_id
,以便进行简单的选择查询。 Context
表还包含时间戳信息。例如,行Pipeline .2020–07–14T23:45:00.508181.StatisticsGen
有一个context_id
5。
上下文 Id 5 对应于属性表中的工件 Id 3。工件 Id 3 确实是我们需要的统计工件。
幸运的是,kubeflow 管道 已经自动做到了这一点
结论
现在,您应该对 ML 元数据存储确切包含的内容以及为什么它是 TFX 生态系统中如此有用的组件有了一个明确的理解。
感谢一路读到最后!
定制工件
支持自定义工件。我们不会在这里深入探讨,因为这主要是针对 TFX 的生态系统。更多信息请看这里。
用于异常检测的深度学习:综述
回顾深层异常检测的挑战、方法和机遇
这篇文章总结了一篇关于深度学习异常检测的综合调查论文——“深度学习异常检测:综述”[1],讨论了该方向的挑战、方法和机遇。
异常检测,也称为异常值检测,几十年来一直是一个活跃的研究领域,因为它在许多关键领域都有广泛的应用,如风险管理、合规性、安全、金融监控、健康和医疗风险以及人工智能安全。尽管这是一个在各个领域广泛研究的问题,包括数据挖掘、机器学习、计算机视觉和统计学,但仍然存在一些独特的问题复杂性和挑战,需要先进的方法。近年来,深度学习支持的异常检测已经成为应对这些挑战的一个重要方向。然而,对这一方向的研究进展缺乏系统的回顾和讨论。我们旨在对这一方向进行全面回顾,讨论主要挑战、大量最新方法、它们如何应对挑战以及未来的机遇。
异常检测中大量未解决的挑战
尽管异常检测是多年来持续活跃的研究领域,但由于异常的一些独特和复杂的性质,仍然存在许多基本上未解决的挑战,例如,未知性(它们在实际发生之前保持未知),异质性(不同的异常表现出完全不同的异常特征),稀有性(异常是很少发生的数据实例),不同形式的异常(点异常、上下文异常和组异常)。
最具挑战性的问题之一是难以实现高异常检测召回率(挑战#1) 。由于异常非常罕见且具有异质性,因此很难识别所有的异常。许多正常情况被错误地报告为异常情况,而真正复杂的异常情况却被遗漏了。
高维和/或非独立数据中的异常检测(挑战#2) 也是一个重大挑战。异常往往在低维空间表现出明显的异常特征,而在高维空间则变得隐蔽而不明显。高维异常检测是一个长期存在的问题。基于子空间/特征选择的方法可能是一种简单的解决方案。然而,识别复杂的(例如,高阶的、非线性的和异质的)特征相互作用和耦合在高维数据中可能是必不可少的,然而仍然是异常检测的主要挑战。
由于收集大规模标记异常数据的难度和成本,对正常/异常进行数据高效学习(挑战#3) 非常重要。两个主要的挑战是如何学习具有少量标记异常数据的表达性正常/异常表示,以及如何学习被推广到由给定标记异常数据发现的新异常的检测模型。
许多弱/半监督异常检测方法假设给定的标记训练数据是干净的,这对于被错误地标记为相反类别标签的有噪声的实例是非常脆弱的。这里的一个主要挑战是如何开发抗噪声异常检测(挑战#4) 。
现有的方法大多是针对点异常的,不能用于条件异常和组异常,因为它们表现出与点异常完全不同的行为。这里的一个主要挑战是将条件/组异常的概念结合到异常测量/模型中,用于这些复杂异常的检测(挑战#5) 。
在许多关键领域,如果将异常检测模型直接用作黑盒模型,可能会存在一些重大风险。例如,报告为异常的罕见数据实例可能会导致针对数据中出现的少数群体的算法偏见,例如欺诈检测和犯罪检测系统中代表不足的群体。减轻此类风险的有效方法是使用异常解释(挑战#6) 算法,这些算法提供了关于为什么特定数据实例被识别为异常的直接线索。在某些应用中,提供这样的解释可能与检测精度一样重要。从特定的检测方法中获得异常解释仍然是一个很大程度上未解决的问题,特别是对于复杂的模型。开发内在可解释的异常检测模型也是至关重要的,但在模型的可解释性和有效性之间取得平衡仍然是一个主要挑战。
利用深度异常检测应对挑战
简而言之,深度异常检测旨在通过神经网络学习特征表示或异常分数,以便进行异常检测。近年来,大量深度异常检测方法被引入,在解决各种现实应用中具有挑战性的检测问题时,表现出明显优于常规异常检测的性能。我们系统地回顾了当前的深度异常检测方法及其应对上述挑战的能力。
为了对该领域有一个透彻的了解,我们引入了一个层次分类法,从建模的角度将现有的深度异常检测方法分为三个主要类别和 11 个细粒度类别。图 1 显示了这些方法的分类概述,以及它们所面临的挑战。具体来说,深度异常检测由三个概念范式组成——用于特征提取的深度学习、学习常态的特征表示和端到端异常分数学习。
图一。当前深层异常检测技术的层次分类。还提出了每一类方法可以解决的检测挑战。
在用于特征提取的深度学习框架*,深度学习和异常检测在第一大类中完全分离,因此深度学习技术仅作为一些独立的特征提取器使用。在第二个主要类别中,这两个模块以某种形式相互依赖,即学习常态的特征表征*,目的是学习常态的表达表征。这类方法可以根据是否将传统的异常测量纳入其目标函数而进一步分为两个子类。这两个子类别包含七个细粒度的方法类别,每个类别采用不同的方法来制定其目标函数。这两个模块完全统一在第三个主要类别中— 端到端异常分数学习,其中的方法致力于以端到端的方式通过神经网络学习异常分数。这些方法根据神经网络支持的异常评分公式进一步分为四类。
对于每一类方法,我们回顾详细的方法和算法,包括它们的关键直觉、目标函数、基本假设、优点和缺点,并讨论它们如何解决上述挑战。这里很难展示全部细节。有关详细信息,请参阅下面的全文:
ACM 计算调查的正式出版版本:
异常检测,也称为异常检测或新奇检测,已经成为一个持久而活跃的研究领域
dl.acm.org](https://dl.acm.org/doi/abs/10.1145/3439950)
或者,预印本 arXiv 版本:
[## 用于异常检测的深度学习:综述
异常检测,也称为异常检测或新奇检测,已经成为一个持久而活跃的研究领域
arxiv.org](https://arxiv.org/abs/2007.02500)
未来的机会
通过这样的回顾,我们发现了一些令人兴奋的机会。其中一些描述如下。
探索异常监控信号
信息监控信号是深度异常检测的关键,以学习正常/异常或异常分数的表达表示,并减少假阳性。虽然已经探索了各种各样的无监督或自监督监控信号,但是为了学习这些表示,这些公式的关键问题是它们的目标函数是通用的,但是没有专门针对异常检测进行优化。当前依赖于异常度量的特征学习方法通过施加从传统异常度量导出的约束来帮助解决这个问题。然而,这些约束可能具有一些固有的限制,例如,异常测量中的隐含假设。探索异常监控信号的新来源至关重要,这些信号超出了广泛使用的公式,如数据重建和 GANs,并且对异常分布的假设很弱。另一种可能性是通过利用领域知识(如应用程序特定的异常知识和/或专家规则)作为监管来源,开发领域驱动的异常检测。
深度弱监督异常检测
深度弱监督异常检测旨在利用深度神经网络,利用一些弱监督异常信号,例如,部分/不准确/不准确标记的异常数据,学习异常通知检测模型。这些标记的数据提供了异常的重要知识,并且可以成为提高检测召回率的主要驱动力。一个令人兴奋的机会是利用少量准确标记的异常示例来增强检测模型,因为它们在现实世界应用中经常可用,例如,来自部署的检测系统/最终用户的一些入侵/欺诈,并由人类专家验证。然而,由于异常可能是高度异构的,可能存在未知/新颖的异常,其位于给定异常示例的跨度集之外。因此,这里的一个重要方向是未知异常检测,我们的目标是建立从有限的标记异常到未知异常的检测模型。
检测属于给定异常示例的相同类别的异常可能与检测新的/未知的异常一样重要。因此,另一个重要的方向是开发数据高效异常检测或少量异常检测,其中我们旨在学习已知异常类的高度表达表示,仅给出有限的异常示例。应该注意的是,有限的异常示例可能来自不同的异常类别,因此表现出完全不同的流形/类别特征。这种情况从根本上不同于一般的少量学习,在一般的少量学习中,有限的例子是特定于类的,并假设共享相同的流形/类结构。
大规模常态学习
大规模无监督/自监督表示学习在实现下游学习任务方面获得了巨大的成功。这对于学习任务尤其重要,在学习任务中很难获得足够的标记数据,例如异常检测。目标是在无监督/自监督模式下从大规模未标记数据中学习可转移的预训练表示模型,并在半监督模式下微调检测模型。基于自监督分类的异常检测方法可以为正态学习提供一些初始监督来源。然而,必须采取预防措施以确保(I)未标记数据没有异常污染和/或(ii)表示学习方法对于可能的异常污染是稳健的。这是因为大多数方法隐含地假设训练数据是干净的,并且不包含任何噪声/异常实例。这种鲁棒性在预训练建模和微调阶段都很重要。此外,不同领域中的异常和数据集差异很大,因此大规模正态学习可能需要特定于领域/应用。
如果你觉得调查报告的摘要有趣且有帮助,你可以阅读全文以了解详情。
[1]庞,关松,,,曹,和安东·范登恒。“用于异常检测的深度学习:综述。”美国计算机学会计算调查(CSUR) 54,第 2 期(2021 年):第 1–38 页。[ CSUR 来源 ] [ arXiv 来源 ]
一个全面的教程,以信任运营商的初学者
方法、相关函数、将 Python 转换成 Rust 等等
由 pikisuperstar 创建的健康矢量—www.freepik.com
**Table of Contents**[**Introduction**](#f77d)🦀 [Arithmetic Operators](#7b55)
🦀 [Comparison Operators](#ec1d)
🦀 [Logical Operators](#71e3)
🦀 [Bitwise Operators](#b809)
🦀 [Compound Assignment Operators](#06a0)
🦀 [Operator Overloading](#de94)
🦀 [XOR and Bitwise Operators Truth Table](#f515)
🦀 [Problem 1: Single Number](#bb38)
🦀 [Python Solution](#6fa3)
🦀 [Rust Code](#0af4)
🦀 [Method and Associated Functions](#c7fe)
🦀 [Solution Using an Associated Function](#7878)
🦀 [Problem 2: Number of Steps to Reduce a Number to Zero](#a615)[**Conclusion**](#678b)
[更新于 2020 年 2 月 18 日。代码更改为要点并添加了链接]
介绍
运算符告诉编译器或解释器执行特定的数学、关系或逻辑运算。许多编程语言都使用类似的操作符。
我们将讨论 Rust 中重要的算术、关系和逻辑操作符,并将它们与 Python 进行比较。
我们将学习方法和相关函数之间的区别。
我们还将两个简单的 Python 代码转换成 Rust 代码,以了解更多关于 Rust 编程的知识。
我们开始吧!
[## 通过将 Python 转换成 Rust 来学习 Rust
Rust 基础入门教程
towardsdatascience.com](/learning-rust-by-converting-python-to-rust-259e735591c6)
算术运算符
Rust 和 Python 算术运算符。图片由作者提供。
Python 和 Rust 共享相同的算术符号,如上表所示。锈称%
为 余数 而不是 模数 。
我们将在后面的操作符过载中讨论“生锈过载特性”。
输出:
a: 20, b: 20+1=21, c: 20-2=18, d: 20*3=60, e: 20/4=5, f: 20%3=2
在 Rust 中,不能在一个操作中使用不同的数据 类型。例如,如果你试图从一个 有符号整数 中减去一个 无符号整数 ,就会失败:
// This will fail.
fn main() {
let a = 8u8;
let b = 2i32;
println!("{}", a - b);
}
Rust 使用[**as**](https://doc.rust-lang.org/std/keyword.as.html)
关键字在原语类型之间进行强制转换。请点击阅读更多关于《铁锈》剧组的内容。
在线试用这个 Rust lang 代码。
输出:
6
指数 Python 使用**
符号表示指数:
输出:
2^3 is 8
3^3 is 27
3^3.2 is 33.63473536961897
锈的用途**pow**
、**powi**
、**powf**
、**、**取决于类型:
输出:
2 ^ 3 in Rust: 2u8.pow(3) = 8
2 ^ 3 in Rust: 2i32.pow(3) is 8
3.0 ^ 3 in Rust: 3.0f32.powi(3) 27
3.0 ^ 3.2 in Rust: 3.0_f32.powf(3.2) is 33.63474
a = 3, a ^ 3 in Rust: i32::pow(a,3) = 27
b = 3.1, b ^ 3 in Rust: f64::powi(b, 3) = 29.791000000000004
b = 3.1, b ^ PI in Rust: std::f64::consts::PI) = 34.96699308140392
在 Rust 中,您可以注释类似于2u8
或2_u8
的数字类型。u8
是一个无符号 8 位整数类型而i32
是一个有符号整数类型。
[i32](https://doc.rust-lang.org/std/primitive.i32.html)
和[f32](https://doc.rust-lang.org/std/primitive.f32.html)
有一组内置方法。所有的整数类型u8
、u16
、u32
、u64
、u128
、i16
、i32
、i64
、i128
、isize
、usize
都有[**pow**](https://doc.rust-lang.org/std/primitive.i32.html#method.pow)
方法。
pub fn pow(self, exp: u32) -> i32
上面的定义告诉你,使用pow
方法将 self 提升到exp
(也就是u32
)的幂,并返回i32
(有符号整数)。
浮点类型、f32
和f64
有[**powi**](https://doc.rust-lang.org/std/primitive.f32.html#method.powi)
和[**powf**](https://doc.rust-lang.org/std/primitive.f32.html#method.powf)
方法。
**powi**
对一个数字进行整数幂运算,而**powf**
对一个数字进行浮点幂运算。
pub fn powi(self, n: i32) -> f32
pub fn powf(self, n: f32) -> f32
楼层划分 在 Python 中,我们用//
来找一个楼层划分。比如5//2=2
。
输出:
5 // 2 is 2
-5 // 2 is -3
输出:
2
-3
比较运算符
Python 和 Rust 共享所有比较运算符的相同符号。
Rust 和 Python 比较运算符。图片由作者提供。
输出:
a: 7, b: 4,
c: 7 == 4 is false,
d: 7 != 4 is true,
e: 7<4 is false,
f: 7>4 is true,
g: 7<=7 is true,
h: 7>=7 is true
逻辑运算符
Rust 逻辑运算符符号不同于 Python 符号。
Rust 和 Python 逻辑运算符。图片由作者提供。
输出:
a: true, b: false,
c: !true is false,
d: true && false is false,
e: true || false is true
按位运算符
所有 Rust 和 Python 按位运算符共享相同的按位运算符符号,除了按位 NOT。
Rust 和 Python 按位运算符。图片由作者提供。
输出:
a: 1, b: 2,
c: 1 & 2 is 0,
d: 1 | 2 is 3,
e: 1 ^ 2 is 3,
f: 1 << 2 is 4,
f2: 1 << 4 is 16,
g: 1 >> 2 is 0,
g2: 1 >> 2 is 1,
h: !1 = -2
按位求反 !1
返回-2
。Rust 使用二进制补码来查找有符号类型的按位求反。Rust 的有符号整数类型被称为有符号二进制补码整数类型。
可以用1 << n
求出 2 的指数。
输出:
2 ^ 3 = 8
2 ^ 4 = 16
2 ^ 5 = 32
复合赋值运算符
所有 Rust 和 Python 复合赋值运算符具有相同的符号,除了 Rust 不具有幂赋值**=
和楼层划分赋值//=
的等价性。
Rust 和 Python 复合赋值运算符
输出:
a is 2
1: a += 5 is 7
2: a -= 2 is 5
3: a *= 5 is 25
4: a /= 2 is 12
5: a %= 5 is 2
6: a &= 2 is 2
7: a |= 5 is 7
8: a ^= 2 is 5
9: a <<= 1 is 10
10: a >>= 2 is 2
运算符重载
运算符重载就是在同一个范围内为一个运算符指定多个定义。 Python 和 Rust 提供操作符重载。你可以在标准库 ops 模块中找到 Rust 重载运算符。
输出:
Point { x: 3, y: 3 }
XOR 和按位运算符真值表
正如我们之前看到的,Python 和 Rust 对位符号AND
、OR
和XOR
使用相同的符号。
&
是按位AND
,|
是按位OR
,^
是按位异或(异或)。下面可以看到真值表和维恩图。
与、或和异或的真值表。
与、异或或文氏图
当您将XOR
用于相同数字的偶数时,输出始终为 0。
在 Rust 中,可以用{:#b}
打印二进制。
输出:
0 ^ 0 = 0
Binary: 0 ^ 0 = 0b0
1 ^ 1 = 0
Binary: 1 ^ 1 = 0b0
2 ^ 2 = 0
Binary: 2 ^ 2 = 0b0
3 ^ 5 ^ 3 ^ 5 = 0
Binary: 3 ^ 5 ^ 3 ^ 5 = 0b0
1 ^ 1 ^ 1 = 1
Binary: 1 ^ 1 ^ 1 = 0b1
1 ^ 1 ^ 5 = 5
Binary: 1 ^ 1 ^ 5 = 0b101
你可以在这里找到 Python 代码。
问题一:单号
我们要用这个XOR
来解决叫做单号的 LeetCoder 问题。
在这个问题中,一个数组输入有一对数字,除了一个,例如[1, 1, 5, 5, 2]
。你需要从这个数组中找到一个 sing 数,在这种情况下,输出应该是2
。
更多例子:输入为[2, 2, 1]
时,输出应为1
。当输入为[4, 1, 2, 1, 2]
时,输出应为4
。
这是一个使用XOR
操作符的好例子。
Python 解决方案
我们简单地浏览一下 Python 解决方案,看看这个问题是如何解决的。
在线尝试这段 Python 代码。
输出:
4
第 1 行:我们使用的 Python typing
是从 v3.5 引入的。
第 3–4 行:导入List
后,我们创建了一个名为Solution
的类和一个名为singleNumber
的方法。
使用 Python 类型提示,我们将类型的名称大写,并将集合中的类型名称放在括号中,如上所示num: List[int]
。
第 5–8 行:我们将变量ans
设置为 0。使用一个for
循环,我们使用XOR
复合赋值ans ^= n
迭代输入数组nums
。这将从数组中输出一个数字。
第 10–11 行:我们实例化类Solution
并调用方法singleNumber
。
(如果您对感兴趣,您可以在没有类型符号的情况下运行这段 Python 代码。)
以下是 LeetCode 环境的解决方案:
class Solution:
def singleNumber(self, nums: List[int]) -> int:
ans = 0
for n in nums:
ans ^= n
return ans
Python 结果。
生锈代码
Rust 结构 包含命名字段。我们使用关键字struct
并在花括号内设置字段类型。我们把方法放到一个impl
块中。
起始代码
输出:
1
第 1 行:我们取消dead_code
警告。
第 2–4 行:创建一个名为Solution
的struct
,它接受一个类型为Vec<i32>
的字段nums
。(更多关于向量。)
第 6–10 行:我们在impl Solution
中创建了一个方法single_number
。single_number
取第一个参数&self
( 详见 [self](/learning-rust-by-converting-python-to-rust-259e735591c6#f6fb)
)。)而我们现在只是返回1
。
第 12–17 行:在 main 函数中,我们创建了一个实例并使用方法打印了1
。
看起来一切正常,所以我们接下来要完成single_number
方法。
方法和相关功能
方法是在一个结构的上下文中定义的,它们的第一个参数总是
self
,它代表调用方法的结构的实例。Rust 编程语言
关联函数不把self
作为参数,它们也不是方法,因为它们没有可以使用的结构实例。
一个很好的例子就是String::from
函数。
我们使用带有结构名的::
语法来调用这个关联的函数,而当我们调用一个方法时,我们使用.
。
一个常见的关联函数是new
函数,它返回与关联函数相关联的类型的值。
输出:
x: 5, y: 4
x: 8, y: 9
最终代码
第 7–11 行:我们创建了一个类型为i32
的可变变量ans
。使用for
循环,我们使用ans ^=n
迭代&self.nums
。
输出:
5
我们根据 LeetCode 环境调整上面的代码。
impl Solution {
pub fn single_number(nums: Vec<i32>) -> i32 {
let mut ans: i32 = 0;
for n in nums {
ans ^= n;
}
ans
}
}
铁锈导致了 LeetCode
内存使用在 Rust 中是 2.2 MB,在 Python 中是 16.5 MB。(更多关于运行时&内存使用量)
使用关联函数的解决方案
既然学了关联函数,那就把它应用到这个问题上吧。
输出:
1
4
第 6–10 行:我们创建一个关联函数,new
,就像我们之前做的那样。这个new
函数采用一个参数nums
,该参数是一个带有i32
项的向量。
当参数名和 struct 字段名完全相同时,我们可以使用 字段初始化简写 语法作为nums
而不是nums: nums
。
在 main 函数中,我们调用一个关联函数new
,并将nums
作为参数传递。我们使用方法语法来调用ans3
实例上的single_number
方法。
问题 2:将一个数化为零的步骤数
在这个问题中,你输入一个非负整数num
,返回步数使其降为零。如果当前数是偶数,你就要把它除以 2,否则,你就要从中减去 1。
例如:
Input: num = 14
Output: 6
Explanation:
Step 1) 14 is even; divide by 2 and obtain 7\.
Step 2) 7 is odd; subtract 1 and obtain 6.
Step 3) 6 is even; divide by 2 and obtain 3\.
Step 4) 3 is odd; subtract 1 and obtain 2\.
Step 5) 2 is even; divide by 2 and obtain 1\.
Step 6) 1 is odd; subtract 1 and obtain 0.Input: num = 8
Output: 4
Explanation:
Step 1) 8 is even; divide by 2 and obtain 4\.
Step 2) 4 is even; divide by 2 and obtain 2\.
Step 3) 2 is even; divide by 2 and obtain 1\.
Step 4) 1 is odd; subtract 1 and obtain 0.
这是一个很好的例子,我们可以使用模数/余数运算符和复合赋值运算符。
Python 解决方案
在线尝试这段 Python 代码。
输出:
6
4
第 3–10 行:我们对num > 0
使用了一个while
循环。如果模数是 0,那么它一定是一个偶数,所以我们使用复合赋值/=2
将num
除以 2,否则,我们使用复合赋值-=1
减去 1。我们将steps
增加 1。最后,我们返回steps
。
我们根据 LeetCode 环境调整上面的代码。
class Solution:
def numberOfSteps (self, num: int) -> int:
steps = 0
while num > 0:
if num % 2 == 0:
num //= 2
else:
num -=1
steps += 1
return steps
LeetCode 的 Python 结果。
防锈液
输出:
6
4
在 Rust 中,我们采取了与 Python 相同的步骤。
第 7–16 行:我们将 0 赋给一个可变变量steps
。当self.num
大于 0 时,如果self.num
的余数为 0,我们使用复合赋值/=2
,否则,我们减去 1,并将步数增加 1。
我们根据 LeetCode 环境调整上面的代码。
impl Solution {
pub fn number_of_steps (mut num: i32) -> i32 {
let mut steps = 0;
while num > 0 {
if num % 2 == 0 {
num /= 2;
} else {
num -=1;
}
steps += 1;
}
steps
}
}
生锈是由漏电引起的
结论
我们在 Rust 中学习了算术、比较、逻辑、按位和复合赋值操作符。我们还学习了操作符重载、关联函数和方法之间的区别,以及如何通过将简单的 Python 代码转换为 Rust 来使用 Rust 中的操作符。
我希望你学到了一些东西,并为下一步做好了准备。请继续关注下一篇文章。
通过 成为 的会员,可以完全访问媒体上的每一个故事。
https://blog.codewithshin.com/subscribe
参考
以下资源用于编写这篇文章:
- https://doc . rust-lang . org/book/appendix-02-operators . html # operators
- https://www.programiz.com/python-programming/operators
理解符号和幅度、一的补码和二的补码
towardsdatascience.com](/unsinged-signed-integers-and-casting-in-rust-9a847bfc398f)
囚徒困境的计算方法
在这种充满犯罪的“棘手情况”下,最好的决定是什么
你和你的朋友犯了谋杀罪。几天后,警察把你们两个带走,把你们放在两个独立的审讯室里,这样你们就不能互相交流了。你认为你的生活结束了,但是警察提出了一个交易:
出卖你的朋友,你的刑期会轻一些。
比尔·牛津在 Unsplash 上的照片
关键是你的朋友也能得到这笔交易。
更具体地说,如果你出卖了你的朋友,但你的朋友什么也没说,他们会被判重刑,而你会被判轻刑。如果你们出卖对方,双方都会受到重罚。如果你们两个都保持沉默,对你和你的朋友来说,判决都是轻的。
这些决定必须在彼此不沟通的情况下做出,你和你的朋友只有两个选择:“叛逃”并告发他们,或者“隐瞒”信息,保持沉默。
看看下面的图表,它描述了你的选择和句子:
给你和你朋友的惩罚图。
矩阵描述了根据你和你的朋友独立选择做的事情,你们两个人得到的年数。第一个数字代表你的入狱时间,第二个代表你朋友的。
例如,如果你向警察隐瞒信息,但你的朋友选择出卖你,你会在最高安全监狱服刑五年,但你的朋友只服刑一年。
在这种情况下,你会怎么做?
在这种情况下,你应该做什么?
这个问题没有简单的解决办法,对此有很多解释。功利主义者可能会说,扣留是更好的选择,因为它可以最大限度地减少两个人在监狱里度过的总年数(5 + 1 或 3 + 3,而不是 10 + 10)。概率怎么说?
解决困境
我创造了一群 1000 名囚犯,每个人都有 50-50 的机会成为叛逃者或扣留者。然后,我模拟了 500 对囚犯的互动,并记录了结果。这个实验我重复了 200 次。
叛逃者与扣留者(对半分)。
如你所见,如果叛逃者和扣留者的数量大致相同,那么试图扣留信息要好得多。大多数时候,回报会对你有利。叛逃者在监狱度过的平均年数是 5.75 年,而扣留者是 4.01 年。
我们可以通过改变叛逃者和扣留者的比例来让这变得更有趣一点。假设你在一个国家,每个人都不信任对方,75%的人是叛逃者,25%的人不信任对方。
叛逃者与扣留者(75-25 分)。
你最好的办法是向警方隐瞒信息。这是有道理的,因为如果你也背叛了,你很有可能以游戏中最糟糕的选择结束——10 年一件。
让我们再试一次。假设每个人都过度信任他人(尽管事实上他们刚刚犯了一桩谋杀案)。
叛逃者与扣留者(25-75 人)。
这个更有趣。**看起来你隐瞒信息会稍微好一点,但是回报是非常不一致的(在某些情况下,结果比背叛还要糟糕!).**这是因为在其他缺陷的情况下,扣留的刑期可能是三年或五年,而在其他缺陷的情况下,叛逃的刑期可能是一年或十年。3 和 5 之间的差异比 1 和 10 之间的差异要小得多,所以在后一种情况下差异要大得多。
在这种特殊情况下,你会怎么做?
如果你喜欢这篇文章,你可以在 Medium 上关注我,了解更多类似的内容。感谢阅读!
数据科学爱好者简明指南
给数据科学领域求职新手的建议和对现实的一瞥!
(与目前的时尚相反,文章标题传达了关于数据科学的负面观点,尽管它们揭示了真相和现实,但我决定用一个陈词滥调的标题:-P 既然每个人都在写数据科学——为什么一个人应该/不应该成为数据科学家,为什么它有趣/不有趣,我想我不妨写一个。我是一名数据分析师,在一家初创公司工作过一段时间,与数据科学家和产品经理共事过。我在这里根据我的经验分享我的观点,并在某些方面提供帮助)
TLDR: 这篇文章是为那些想进入这个领域的人写的,让他们知道应该/不应该从这个领域期待什么,在申请数据科学领域的工作时应该注意什么,以及当你想尝试管理角色而仍然与“数据”相关时有哪些不同的选择。
1。角色不同是什么意思?
让我先简单解释一下这些人们经常互换使用的流行语的意思,以澄清困惑。
数据分析师 — 数据分析师的角色主要包括(不限于,可以超越这一点,这取决于你所在公司的角色的灵活性)获取、争论或管理数据,然后从中获得洞察力,构建仪表板以可视化它们。现在, 业务分析师 和 产品分析师 是 DA 的专门角色,他们与专注于具体工作的业务/产品团队密切合作
数据科学家——向前迈出一步,利用所获得的见解来制定决策和采取行动,用特定的假设进行实验,通过连接各个点来构建框架/流程,整合不同的部分以得出最终的解决方案
ML 工程师【1】—数据科学是关于在数据中寻找模式,ML 是关于使用机器对数据中的模式进行建模,以便解决特定问题,当涉及大型数据集时,自动化人类无法手动完成的任务。这项工作主要包括功能工程、构建模型、验证模型和部署模型。与数据科学不同,这里可能没有太多惊喜。
数据工程师 确保分析师和科学家随时可以获得他们需要的数据。他们的工作是:
- 制作并提供实时数据集
- 设置运行脚本、分析、模型
- 帮助生产解决方案——通过建立工作岗位、管道、亲测试环境
图 2 - 数据流 (图片由作者提供)
扎实的数学和统计学基础是数据分析和科学的关键。当你转向 ML 工程和数据工程时,你需要做大量的编码工作,并且精通分布式系统和架构。然而,学术界/研究领域的 ML 涉及更多的理论和数学。担任这些角色的每个人都必须齐心协力为生活带来一个目标。也就是说,这些不同角色的工作在某种程度上是重叠的。
已经有一些关于这些与软件开发和工程的角色有多么不同的讨论。这是另一天的话题
【注:以上纯属我在印度市场的经验和观察】
2。想闯入 DS 的人应该警惕什么?
每个公司都想赶上数据科学的潮流,并开始对他们的业务产生巨大影响。但是你应该知道的是,并不是每家公司都确切地知道他们想怎么做和为什么要做。
*1.很多时候,我碰到主题为——‘*数据科学/ ML 人才供需有缺口’的文章。我不认为那是真的。但是,也不是那么容易被聘为 DS。原因如下。每个公司都在寻找不同的东西
- 很少有公司在发布招聘广告时甚至不知道自己在寻找什么。他们可能刚刚开始从数据驱动的解决方案中寻找一些商业价值,但他们不知道要雇用谁,如何开始,做什么。有些是非常有选择性的,只雇佣博士候选人,研究生,在我看来,这不是筛选候选人的最佳方式。
- 很少有其他公司知道他们在做什么,他们可能会开始自己的内部数据团队,因此,需要有经验的个人与领域专业知识开始。
- 一些正在组建团队的公司会愿意雇佣刚毕业的大学生和有 1-2 年工作经验的人。
2.你需要知道你的目标是否与公司正在做的事情和他们的愿景一致。了解 DS/ML 是否被视为其业务的驱动力之一。如果那里不崇拜数据,那你就不会想去那里。因此,对你想加入的公司进行调查是至关重要的。让你内心深处的夏洛克开始挖掘信息吧!
3.你的角色可以是特定的,也可以是不同角色的组合(如上所述),这取决于公司所处的阶段。你的工作是了解工作范围。而且,这个范围可以根据个人的主动性和能力而超出界限。特别是,当公司处于初级阶段时,你可能会被期望戴上不同的帽子,扮演不同的角色。
4.你必须了解在同一个部门工作的员工(他们的资格),因为这些人将不时地指导你,你希望他们有经验,具备良好的知识和技能,并在遇到困难时指导你。在工作中,协作和分享知识是发展个人技能的核心。
3。期望与现实
你应该摆脱这样的错觉,即你所要做的只是使用你所学的那些花哨的算法,炮制一个将被公司不同团队的用户采用的解决方案/产品,以产生有意义的影响。好吧,走出幻想,看清现实——不像你想的那样梦幻而简单。哎哟!【3】
- 作为数据分析师或数据科学家,你的工作将主要围绕统计和数学中的基本概念——比率、比例、概率、线性代数、何时使用哪些指标、什么是原因、统计建模和一些基本算法。它可以从清理、转换数据到使用基础知识来发现数据中的模式,再到构建管道来生产可供其他团队使用的成品/工具。有时,数据修剪和预处理构成了一半以上的工作。你应该愿意做所有这些。
- 大多数商业问题可以用简单的统计方法来解决。这里有一个完美的迷因来说明这一点。
图 3- 一个人用剑,而不是刀来切他的食物 (图片由knowyourmeme*)*
然而,你应该跟上这个领域的最新发展以保持相关性。
3.通向解决方案的旅程可能不像你想象的那么顺利。你可能花了几个星期做某件事,结果却发现它不会成功。然后,你必须重新制定你的计划,重新发明轮子。因为有很多探索和实验,你可以预料到一些不确定性,耐心是关键。
4.生产(如果需要,部署和扩展)解决方案与实现它同等重要。重要的是,这些想法/解决方案以产品/工具的形式实现,可供其目标用户使用。努力必须持续到最后一英里。
5.要知道比起编写算法本身,更强调的是正确使用算法(ML/ DL /或 any)来解决你的问题。由于微软、亚马逊、谷歌(checkout H2O.ai)等大公司都有工具,可以帮助你在任何数据集上应用算法,所以没有必要从头开始构建。从功能工程到部署,他们可以做任何事情。尽管 AutoML 使用的增加减轻了数据科学家肩上的一些负担,但我相信它不能完全取代他们[4]。
6.你被期望拥有良好的沟通技巧,因为你会-
- 在日常工作中积极与数据分析师和数据工程师合作
- 与产品经理紧密合作;与他们交流来自不同团队的依赖关系,为制定服务于长期目标的路线图做出贡献。
- 需要说服或传达给你的观众,为什么你做了你所做的,它是如何工作的,它会产生什么影响
7.精疲力竭并不罕见。你得想出如何应付和处理他们。在那些时候,让自己挺过来是这个过程的一部分。
4。想转向管理角色?
如果您想探索 Data domain 中的管理领域,那么这个角色非常适合您— 数据产品经理
典型的数据 PM 的工作如下所示:
- 充当产品、业务和数据团队之间的 POC,以沟通和管理最终目标的依赖性和期望
- 根据这些数据驱动的决策的业务需求和附加值,对要完成的项目和任务进行优先级排序
- 监督这些项目的开发,并协助在设定的期限内完成
- 创建符合公司长期愿景的路线图
现在,监督专门为公司内部用户服务的数据产品开发的数据产品经理被称为数据平台产品经理 [5]
你不妨为自己创新一个新角色!
5。破解求职申请
这里有一些建议或提示,你可以遵循,这有助于你从那些追逐圣杯的人中脱颖而出
数字媒体正在蓬勃发展,你需要在你想从事的领域展示你的能力。所以,发表关于你的项目的文章和博客。把它们放到 Github 上。尽一切努力让招聘人员了解你的工作。
给负责招聘你的相关人员发电子邮件(或在 LinkedIn 上联系)。在起草电子邮件时,请记住以下几点:
- 邮件要简洁直接。
- 不要使用“但是”、“如果”这样的词语(不要贬低或贬低自己)。请改用“and”
- 大致把邮件分成三部分-
- 介绍
- 中间部分:
- 你是谁
- 过去的相关项目(在线链接)
- 为什么你对在这家公司工作感到兴奋
- 向他们展示你对那里发生的事情有所了解
3.结论
F 在面试数据科学家职位的候选人时,一些被候选人忽略但被招聘人员认为很重要的事情:
- 你如何将一个问题分解成更小的部分
- 你如何与你的队友合作——沟通和反馈
- 为了让其他人相信你的项目,你能在多大程度上有效地与各种利益相关者交流你的发现,讲述数据
假设有大量的应用程序可以通过利用数据来使用 DS 和 ML,并且这些应用程序每天都在增加,人们可以找到许多机会在这个领域开始他们的职业生涯。
例如,医疗保健、银行咨询投资部门、市场营销、地理信息学。见鬼,有一个专门的数据科学家为一个具有国际地位的足球俱乐部工作!![7]自然语言处理和计算机视觉的使用越来越普及,人们需要随时了解它们和其他发展的最新情况。走出去,为自己创造机会,建造东西,发明东西,享受这个过程。
祝所有想在数据科学领域发展的人好运。希望你觉得这有用!请在评论区留下你的反馈和建议。
参考
[1]更多关于 ML 工程师的期望— Ian Xiao ,数据科学很无聊
[2] Harshit Ahuja ,为什么数据科学正在失去魅力?
[3] Jonny Brooks-Bartlett ,这就是这么多数据科学家离职的原因
[4]深度洞察为什么 AutoML 无法取代数据科学家— Joseph Chin ,数据科学家之死
[5] Allyson Gale ,我从消费者到数据平台产品管理的转变中学到了什么
苏珊·霍尔科姆,数据科学家的非技术性职业技能,Spotify TDS 播客
[7]看看这段视频利物浦足球俱乐部的数据科学家利用以往赛事的数据点评估一名球员的控球能力
10+牛逼 Python 编辑器的简明指南,以及如何选择最适合你的编辑器:有利弊!
帮助您在各种 python 开发环境中进行选择的简明指南
罗布·兰伯特在 Unsplash 上拍摄的照片
简介:
集成开发环境(IDE)是一种软件,它为程序的编译和解释提供了全面的工具。它为编码人员、爱好者和开发人员提供了一个平台,通过源代码编辑器、自动化工具和调试器来试验和解释代码/程序。IDE 既可以支持单一的编程语言,如 Python 独有的 Pycharm,也可以支持多种编程语言,如 Visual Studio 代码。
因为 python 是现代的流行语言,所以它有很多可用的开发软件,如 Pycharm、visual studio code、Jupyter notebooks 等。让我们对每个编辑器做一个完整的分解,以及你应该考虑什么时候使用它们。我将提供更详细的指南,介绍我更熟悉的编辑,以及我认为更有吸引力的内容。然而,我也将给出一些我不太熟悉的编辑器的概要。
**注:**文中提到的每一位编辑都绝对是梦幻般的牛逼。这个列表根据我个人的使用经验提供了一个简明的指南。你可能比其他人更喜欢一些。最终选择挑编辑器还是开发环境,完全是你自己的事情,不存在选择的对错。这些都有它的优点和缺点,每件事都以自己的方式令人惊叹。
5 个我最有经验并且经常使用的编辑器
1.Python 空闲
作者截图
这是在系统上安装 python 后得到的默认安装。这是编写 python 程序的最基本和最简单的模式。但是对于初学者来说,入门编程,了解 python 的基础知识,还是一个不错的选择。它附带了一些特性,比如 python shell,这是一个交互式解释器。它具有广泛的特性,如自动完成、语法高亮、智能缩进和一个基本的集成调试器。
优点:
- 轻量级。
- 适合初学者。
缺点:
- 不适合复杂的项目。
- 缺少高级功能。
2.崇高的文本
作者截图
Sublime Text 是一款免费软件,拥有广泛的社区支持,能够运行多种编程语言,包括 python。您可以在大多数情况下使用未注册的 Sublime Text,但偶尔您会收到一个弹出窗口,要求您注册该产品并获得许可证。它是高度可定制的,可以添加各种安装来提高 python 语言的工作质量,如调试、自动完成、代码林挺等。
优点:
- 易于使用并且大部分是免费的。
- 高度可定制。
- 紧凑有效。
缺点:
- 需要额外安装才能获得更好的 Python 体验。
3.Visual Studio 代码
作者截图
Visual Studio Code 是微软为 Windows、Linux 和 macOS 开发的免费源代码编辑器。特性包括对调试、语法高亮、智能代码完成、代码片段、代码重构和嵌入式 Git 的支持。它支持包括 python 在内的各种编程语言。您可能需要一些额外的安装来开始使用 Python,但是这非常简单。它不断更新,是 Python 和其他编程语言的最佳平台之一。我经常使用它,也强烈推荐它。
优点:
- 不断更新的奇妙平台。
- 与其他庞大的开发工具相比,软件内存的消耗非常低。
- 控制台终端集成,易于使用。
缺点:
- 有时,终端会变得有点问题,不能按预期运行。
4.Jupyter 笔记本
作者截图
Jupyter Notebook 是一个开源的 web 应用程序,允许您创建和共享包含实时代码、等式、可视化和叙述性文本的文档。用途包括:数据清理和转换、数值模拟、统计建模、数据可视化、机器学习等等。Jupyter 笔记本绝对是开始学习数据科学和机器学习的绝佳选择。这些笔记本可以与任何人共享,有助于更高效地协作编写代码。我强烈推荐使用 Jupyter 笔记本,因为你可以单独使用每个代码块,也可以选择使用降价。它被广泛应用于许多盈利的公司。
优点:
- 数据科学入门的最佳平台。
- 易于共享笔记本和可视化。
- 降价和其他附加功能的可用性。
缺点:
- 缺少一些 IDE 中包含的强大功能。
5.皮查姆
作者截图
PyCharm 是一个用于计算机编程的集成开发环境,专门用于 Python 语言。它是由捷克公司 JetBrains 开发的。因为这是专门为 Python 开发的,所以它拥有你想要的所有广泛的特性和额外的支持。这些包括代码完成、代码检查、错误突出显示、修复、调试、版本控制系统和代码重构。它可以在多种平台上使用,例如 Microsoft Windows、Linux 和 macOS。它有免费版和付费专业版。付费专业版有一些额外的功能,但免费版对于大多数编码和编程相关的活动来说已经足够了。如果你有至少 8GB 的内存和一台高质量的电脑,我会强烈推荐 Pycharm。
优点:
- 惊人的内置功能。
- 由对 python 支持最好的顶尖公司开发。
- 也支持 anaconda 虚拟环境。
缺点:
- Pycharm 的主要问题是,如果你有一台个人电脑或笔记本电脑是低端的,没有至少 8 GB 的内存,会有点滞后,速度很慢。
其他优秀的编辑:
1.Thonny 编辑
作者截图
Thonny 集成开发环境(IDE),预安装在 Linux 和基于 Linux 的平台上。但是,您必须在 Windows 平台上手动安装它。我对 Thonny 编辑器的体验主要是在树莓 Pi 上。这是一个很好的开发环境,初学者很容易上手。对于树莓 Pi 项目来说是极其牛逼的。它的一些特性包括语法错误突出显示、调试器、代码完成、单步执行表达式求值等。
优点:
- 互动环境。
- 适合初学者。
- 可用于树莓 Pi 项目。
缺点:
- 有时容易出问题。
- 没有广泛的功能。
2.Spyder
作者截图
Spyder 是用 Python 语言进行科学编程的开源跨平台集成开发环境。Spyder 是一个强大的科学环境,它用 Python 编写,面向 Python,由科学家、工程师和数据分析师设计,并为他们服务。它将综合开发工具的高级编辑、分析、调试和分析功能与科学包的数据探索、交互式执行、深度检查和漂亮的可视化功能进行了独特的结合。在任何 Spyder 支持的平台上启动和运行 Spyder 的简单方法是下载它作为 Anaconda 发行版的一部分,并使用 conda 包和环境管理器来保持它和其他包的安装和更新。开发人员推荐最新的 64 位 Python 3 版本,除非您有特别的要求。
优点:
- anaconda 提供的免费编辑器。
- 很好的工作环境,可以并排看到解释和代码。
- 拥有 python 独有的大量选项。
缺点:
- 界面略显生疏。
3.原子
作者截图
这个 IDE 类似于 Sublime 文本编辑器,但对 Python 有额外的要求。它是高度可定制的,并支持 python 所需的许多包。这是崇高文本的另类选择。我在这方面的经验比较少,所以我会推荐 sublime text 而不是 Atom,但是对这两者都比较有经验的观众,请让我知道你更喜欢哪一个。Atom 中用于 Python 开发的一些常用包有 autocomplete-python、linter-flake8、python-debugger 等。
优点:
- 好用。
- 通过附加安装支持 python。
缺点:
- 需要额外的 python 插件。
- 更适合 git 应用。
4.精力
作者截图
Vim 是预装在 macOS 和 UNIX 系统中的文本编辑器。但是,您需要在 Windows 平台上手动下载它。由于 vim 的高计算能力和轻量级紧凑开发工作环境,大多数专家都非常喜欢它。不建议初学者使用它,因为它有一个陡峭的学习曲线,你必须花费额外的时间和精力来理解 VIM 软件。您可以添加插件来突出语法、代码完成、调试、重构等。到 Vim,并将其用作 Python IDE。
优点:
- 轻量级。
- 有效。
- 富有成效。
缺点:
- 你必须花费专门的时间来学习整个编辑器,它有一个陡峭的学习曲线。
5.记事本++
作者截图
Notepad++是一个文本和源代码编辑器,用于 Microsoft Windows。它支持选项卡式编辑,允许在一个窗口中处理多个打开的文件。项目的名字来自 C 增量运算符。Notepad++作为免费软件分发。notepad ++支持各种编程语言的许多开发环境,是一个值得考虑的选择。在我看来,有更好的选择,你也需要做一些额外的安装,以使它完全适用于 python。
优点:
- 易于使用类似于记事本。
- 可用于包括 python 在内的多种编程语言。
缺点:
- 需要更多的设置和调整来运行 python。
- 不在我的首选名单上,因为有很多更好的选择。
6.其他在线编辑
Programiz、tutorials point、w3schools 和其他一些网站为在线编辑提供了一些很棒的选择。我已经错过了一些,但检查了所有的在线编辑器,因为他们大多数都是免费的,玩起来很有趣。如果你懒得完成 python 的所有设置过程,那么就跳进在线编辑器的世界去探索吧。
优点:
- 没有额外的安装或额外的设置程序。
- 简单的代码可以轻松运行,没有太多的麻烦。
缺点:
- 不如其他 IDE 强大。
结论:
唷!那是一个很长的名单。我已经介绍了几乎所有我使用过的 python 编辑器。然而,有趣的是,我可能错过了一些甚至很多,因为有太多的开发环境。也有大量的编辑器正在构建中,以使用户体验更加可定制和有趣。我希望这本简明指南能够帮助观众。如果我错过了什么,请随时告诉我。有这么多选择,但不要不知所措。我想重申,选择没有对错之分。
最后,选择你觉得最舒服、最喜欢的编辑器。
查看我最近的一篇文章,关于几乎任何人都可能犯的 5 个常见 python 错误以及如何避免它们。
从初学者到专家,每个人在 python 和机器学习中都容易出现这些错误。
towardsdatascience.com](/5-common-python-errors-and-how-to-avoid-them-63d9afc1a58f)
请随意查看下面的文章系列,这些文章将从头开始涵盖对机器学习的全部掌握。它们将不断更新,本系列将从头开始涵盖与 python 进行机器学习相关的每个主题和算法。
了解精通机器学习的基本要求
towardsdatascience.com](/starting-your-journey-to-master-machine-learning-with-python-d0bd47ebada9) [## 机器学习所需的 Python 基础知识及其库模块
学习 python 数据结构的基础知识,对机器所需的每个库有直观的理解…
towardsdatascience.com](/basics-of-python-and-its-library-modules-required-for-machine-learning-51c9d26026b8)
感谢大家阅读这篇文章。祝大家度过美好的一天!
参考资料:
- 【https://www.spyder-ide.org/
- https://www.programiz.com/python-programming/ide
- https://notepad-plus-plus.org/downloads/
- https://www.vim.org/
- www.trustradius.com
- https://en.wikipedia.org/wiki/Wiki
码头工人手册
码头工人简明指南
有几门关于这个主题的课程。有些非常短,除了“入门课程”之外没有任何其他用途,而另一些则非常长,需要你花几天时间来学习和理解一切。我写这篇教程的目的是在简洁和详尽之间找到平衡。
接下来的部分更多的是 Docker 的欣赏部分。如果你已经知道 Docker 是什么以及它是如何有用的,你可以跳到下一节来节省一些时间。
Docker 是一个工具,旨在通过使用容器更容易地创建、部署和运行应用程序。容器允许开发人员将应用程序所需的所有部分打包,如库和其他依赖项,并作为一个包发送出去。
当您的应用程序需要多个组件相互交互时,通常会出现依赖库的版本需求冲突。一旦所有组件之间就其依赖关系的版本达成一致,添加另一个组件或甚至升级其中一个组件都会破坏这一协议。
没有码头工人的生活
Docker 解决这个问题的方法是将这些组件放入单独的隔离环境中,称为“容器”,并带有各自的依赖关系。所有这些容器仍然共享同一个内核。
简单的 docker 示例
与虚拟机相比,Docker 容器更轻(尺寸更小),启动时间更短,并且不是完全隔离的。
虚拟机架构
码头建筑
问题不在于使用虚拟机还是 Docker 容器。现代生产部署同时使用这两者。这种体系结构允许您减少虚拟机数量,从而减少资源消耗并加快启动速度。
docker-虚拟机架构
简单地说,docker 映像是应用程序及其环境的模板。我们可以从一个图像中旋转出多个容器。映像包含运行应用程序所需的一切,包括源代码、库、配置文件和环境变量。docker 容器是这个映像的运行时实例。
Docker 图像及其容器
Docker image 是一个超级强大的机制,可以扩展您的应用程序。您可以从单个映像运行任意数量的容器,所有容器都将支持完全相同的依赖关系。如果你正在使用一个容器编制器,像 Kubernetes 一样,你只需要说明你想要多少容器用于一个特定的图像,编制器就会在你所有的 Docker 服务器上创建和维护它们。
如果您使用 Docker 容器并且没有停机时间,那么升级生产系统是无缝的!您只需指示 orchestrator 您想要运行一个新的映像版本,它就会逐渐用运行新版本的容器替换每个容器。
在的下一节中,我们将看到什么是 Dockerfile 以及如何编写 docker file?
参考:
[1] Docker, Docker 概述 (2020),Docker 文档
[2]穆姆沙德·曼南贝斯,为绝对初学者准备的 Docker(2020),KodeKloud.com
一种基于内容的电子商务网站推荐系统
矩阵相乘和余弦相似的简单算法实例研究
rupixen.com在 Unsplash 上拍照
从电子商务、社交媒体到新闻媒体,推荐系统在消费者日常生活的在线平台上已经无处不在。我们的偏好和偏见被机器学习算法超级充电,这些算法从我们的口味中学习,并推荐更多我们希望看到的东西。因为推荐系统对我们的生活,进而对社会有着如此深远的影响,我决定将 Metis 数据科学训练营(新加坡,第 5 批)的最后一个项目用于为电子商务网络商店创建一个简单的推荐算法。在我们开始我的项目之前,我想给你一个关于两种推荐系统的概述:
基于内容的过滤推荐器:顾名思义,这种推荐器利用项目或用户背景信息之间的相似性向用户提出推荐。例如,如果用户 A 通常给科幻电影一个好的评级,推荐系统将向用户 A 推荐更多的科幻类型的电影。在另一个例子中,如果用户 B 是较高收入群体的个人,银行推荐系统可能将用户 B 标记为额外投资计划的潜在客户。
- 优点:容易克服冷启动问题——当没有或很少有用户-项目交互时,推荐器仍然能够向用户提供好的推荐。
- **缺点:**需要物品/用户的背景信息。每当有新的项目/用户时,这些背景信息必须被编目和添加进去。
协同过滤推荐器:这种类型的推荐器识别先前和其他用户-项目交互中的趋势和模式,并基于当前用户现有的交互向他建议类似的推荐。核心思想是基于将相似口味的消费者聚集在一起。例如,一个新闻推荐器检测到,消费支持唐纳德·特朗普的新闻的用户也对阴谋论相关的新闻感兴趣。因此,如果有用户最近对特朗普新闻感兴趣,他也将被推荐与阴谋论相关的新闻。
- 优点:利用用户-项目交互背后隐藏的相关性,不需要大量的手工映射和数据编目。
- 缺点:容易出现冷启动问题,在能够向现有用户提供有意义的推荐之前,需要现有的用户-项目交互库。
还有混合推荐系统,它结合了基于内容的过滤和协同过滤,实现了两个世界的最佳效果。然而,这种推荐系统通常是先进的,并且需要设计神经网络。
对于这个项目,由于短时间内数据的稀疏性,我决定采用基于内容的过滤来推荐电子商务网上商店的产品,方法是定制一个算法来处理不同类别的产品信息。
1.数据转换
从 Kaggle 开始,我在 2 个多月的时间里获得了一个电子商务网店大约 1.1 亿的用户-产品交互数据。由于数据量巨大,我决定将数据缩减到大约 5 天,并且只从产品类别中过滤“计算机”,这样就剩下大约 35 万个用户-产品交互数据。原始数据集如下所示:
列特性‘event _ type’将作为我的推荐器模型的目标,它有 3 个类别:视图、购物车和购买。然后,我根据这些用户-商品交互提供一个用户分数——查看:1,购物车:10,购买:50。此外,我还将物品分为 5 个不同的价格类别。稍后讨论的一些模型中的假设是,客户倾向于购买低端或高端产品。代码和生成的数据帧如下所示:
注意,每个用户项目条目被记录用于一个用户会话,因此每个用户每个项目可能有多个交互。因此,我进一步执行了一个 groupby 操作,以发现每个独特的用户-项目交互的用户得分总和。这形成了用于稍后建模的用户项目矩阵的“评级”。此外,我将 MinMaxScaler 应用于用户分数,以获得一个介于 0 和 1 之间的交互分数。高于 0.5 的交互分数指示发生购买的概率非常高,而低于 0.5 的阈值则没有购买发生。代码和生成的分组数据帧如下所示:
2.探索性数据分析
用条形图和直方图剖析数据集的目标(查看/购物车/购买)(图片由作者提供)
在模型选择和开发之前,我深入研究了推荐系统目标的数据可视化(查看/购物车/购买)。不出所料,这个目标高度失衡,从观看到购买的转化率约为 1.8%。此外,根据直方图,大多数顾客根本没有购买任何东西。正如我们将看到的,这表明推荐系统准确预测购买是具有挑战性的。
3.型号选择
继续进行模型选择,我首先使用一个简单的验证范例将所有“组”数据集分为训练、验证和测试数据集:
将数据集分成 60%的训练、20%的验证和 20%的测试。(图片由作者提供)
随后,我将训练集转换成一个稀疏的用户项目矩阵,将空条目填充为零作为用户得分:
现在,我将考虑 3 种不同的基于内容的过滤模型:
- 按项目类别过滤
- 按项目类别和价格类别过滤
- 按项目类别、价格类别和品牌过滤
对于每个模型,我将根据下面所示的算法在用户-项目矩阵和项目-项目相似性矩阵之间应用矩阵乘积:
模型 1:按项目类别过滤(图片按作者)
模型 2:按项目类别和价格类别过滤(图片按作者)
模型 3:按商品类别、价格类别和品牌过滤(按作者分类的图片)
一旦矩阵乘法完成,就再次应用最小最大缩放器来获得预测交互得分的训练的用户-项目矩阵。为了简化说明,我将演示模型 3 的代码,如下所示:
然后,经过训练的用户项目矩阵被重新转换回数据框,然后与验证数据集合并。同样,预测交互得分高于 0.5 的项目被标记为客户的预测购买。
现在,比较客户对三个模型的实际购买和预测购买,模型 3 似乎是最有希望的,具有最高的精确度,与模型 2 相比,在召回方面没有牺牲太多。尽管如此,所有模型的精度和召回率都非常低,正如我在 EDA 过程中的分析所预期的那样。
三种基于内容的推荐模型在简单验证中的性能。(图片由作者提供)
4.模型评估
选择模型 3 作为我的推荐系统的最终模型,我继续一起重新训练训练和验证数据集,然后在测试数据集上进行评估,实现了 5.0%的召回率和 7.8%的精确度。
测试集的混淆矩阵,显示召回率和精确度。(图片由作者提供)
然而,当我根据独特购买的数量来评估精确度和召回率时,一个有趣的趋势是显而易见的。对于至少购买过一次的客户来说,模型的精确度实际上要高得多!因此,这意味着当模型向购买的顾客作出推荐时,我们更有信心顾客会实际购买该产品。因此,最终没有购买的客户的预测购买的假阳性降低了模型的整体精度。
此外,据观察,购买更多产品的客户召回率更高。这可能是因为衡量模型的方式更偏向于购买客户。因此,可以做进一步的调优和调整来提高模型的召回率。
5.模型演示
在这一部分中,我将演示在训练/验证数据集和测试数据集内特定客户(用户 ID: 518044530)的用户-项目交互,以及模型将为客户提供的潜在建议。在训练/验证数据集中捕获以下用户-项目交互:
训练/验证数据集中的客户(用户 ID: 518044530)。
在测试数据集中,我们看到模型准确地预测了用户购买。这是因为在训练/验证数据集中,客户对类似项目的互动得分很高。
测试数据集中的客户(用户 ID: 518044530)。
从这位客户(用户 ID: 518044530)的热门推荐中随机抽取一个样本,我们看到该模型产生了与他/她之前互动过的相似类别、价格范围和品牌的产品:
针对客户的随机前 10 项建议(用户 ID: 518044530)
6.结论
该项目详细介绍了执行基于内容的推荐系统的端到端管道,并作为 Metis 数据科学训练营最终项目的一部分完成。尽管这个模型远非完美,但它展示了一个基于内容的推荐器是如何过滤多个类别的产品信息的。在未来,理想情况下,可以通过建立深度神经网络来尝试更有效的混合推荐系统。
在这次为期 12 周的训练营结束之际,我真的要衷心感谢我的天才导师尼奥·韩伟,他让我学到了很多东西,我还要感谢我的队友,特别是丹尼尔·张和李心妮,他们给予了我精神和情感上的支持,使这次学习之旅成为可能。
另外,如果你感兴趣,下面是我在训练营期间精心制作的一些其他项目的链接:
项目 3
案例研究与 KNN,逻辑回归,高斯 NB,决策树和随机森林。
towardsdatascience.com](/predicting-satisfaction-of-airline-passengers-with-classification-76f1516e1d16)
项目 2
线性、套索、岭、弹性网和多项式回归的案例研究。
towardsdatascience.com](/predicting-market-value-of-fifa-soccer-players-with-regression-5d79aed207d9)
项目 1
Metis 数据科学训练营的一个简单的探索性数据分析项目
towardsdatascience.com](/mta-turnstile-traffic-analysis-to-optimize-street-engagements-a7391adc4d45)
P.S .如果你对 加速学习数据科学 感兴趣,这里还有一篇关于养成良好学习习惯的极其有用的文章:
让你在数据科学(或任何学科)领域飞速发展的基本指南
towardsdatascience.com](/a-brief-guide-to-effective-learning-in-data-science-637de316da0e)
最后,非常感谢您的阅读!这里是到我的 GitHub 的链接,它包含了这个项目的所有代码和演示幻灯片。也可以通过我的 LinkedIn 联系我或者在下面评论来讨论!
支持我! —如果你没有订阅 Medium,并且喜欢我的内容,请考虑通过我的推荐链接加入 Medium 来支持我。
阅读谭·师鹏·阿尔文(以及媒体上成千上万其他作家)的每一个故事。您的会员费直接…
tanpengshi.medium.com](https://tanpengshi.medium.com/membership)