TowardsDataScience 博客中文翻译 2020(四百二十三)

原文:TowardsDataScience Blog

协议:CC BY-NC-SA 4.0

量子位的实践探索

原文:https://towardsdatascience.com/hands-on-exploration-of-the-qubit-815bee3f30dd?source=collection_archive---------38-----------------------

量子计算入门

本帖是本书的一部分: 用 Python 实践量子机器学习

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

作者弗兰克·齐克特的图片

量子力学的世界是…不同的。量子系统可以处于叠加态。一个流行的叠加概念是系统同时处于不同的状态,除非你测量它。

例如,一个粒子的自旋不是向上或向下,而是同时向上和向下。但是当你看它的时候,你会发现它不是向上就是向下

或者,假设你掷一枚量子硬币。在空中,它有两个值头尾。当且仅当你抓住它,看着它,它决定一个值。一旦落地,它就是一枚正面朝上或反面朝上的普通硬币。

叠加的另一个概念是,系统是真正随机的,因此与我们已知的系统不同。例如,投掷一枚(正常的)硬币似乎是随机的,因为无论何时你这样做,情况都略有不同。即使是微小的差异也会改变结果。硬币对初始条件有敏感的依赖性。

如果我们能够精确地测量所有的条件,我们就能知道结果。在经典力学中,没有随机性。我们日常生活中的事物,比如硬币,似乎是随机的。但事实并非如此。如果用无限精确的方法测量,随机性就会消失。相比之下,量子系统是真正随机的。

也许你会疑惑:好吧,随机。有什么大不了的?

重要的是后果。在一个经典系统中,一个对初始条件敏感的系统,在我们提问之前,问题的答案就已经确定了。

今晚你没有去看棒球比赛,而是和朋友一起度过了这个夜晚。当你回到家,即使你不知道结果,比赛已经结束,有了确定的结果。可能会有不同的结果,但你只是在看到它之前不知道结果。

相反,在量子系统中,问题的答案直到你问它的时候才确定。因为还没有确定,你仍然可以改变测量不同状态的概率。

如果你有疑问,很好!甚至连爱因斯坦都不喜欢这个想法。这让他说出了他的名言:上帝不掷骰子(T21)。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

作者弗兰克·齐克特的图片

包括爱因斯坦在内的许多物理学家提出,尽管量子态是隐藏的,但它是一个定义明确的态。这就是所谓的隐变量理论

在遵循隐藏变量理论的系统和遵循叠加原理的量子系统之间存在统计上不同的行为。实验表明量子力学的预测是正确的。

现在,让我们接受量子态是不同的。在本书的后面,我们将更仔细地研究它。以及它的后果。但这需要更多的理论和数学知识。

我们求助于量子计算机。假设你有一个量子比特。我们称之为量子位。除非你观察它的值,否则它处于01的叠加状态。一旦你观察到它的值,你就会得到0或者1

一个量子位产生任何一个值的几率不需要 50:50。可以是 25:75,67:33,甚至 100:0。它可以是任何加权概率分布。

一个量子位被观察时的概率分布取决于它的状态。量子态。

在量子力学中,我们用矢量来描述量子态。表示量子状态向量的一种流行方式是狄拉克符号的“ket”,看起来像|ψ⟩|ψ⟩.在 Python 中,我们没有向量。但是我们有数组。幸运的是,它们的结构相似。

让我们看一看。我们从最简单的例子开始。比方说,我们有一个量子位,当被观察时,它的值总是0。如果你认为这个量子位在被观察到之前就必须有值0,你就不会完全错了。然而,你会不精确。在被观察到之前,这个量子位有 1 (=100%=100%)的概率在被观察时具有值0

这些是一个量子位的等价表示(ket,vector,array ),当观察时总是产生0:

|0⟩=[1 0]和 Python 中的[1, 0]

因此,下面的表示描述了一个量子位,当观察时,它总是产生1:

|1⟩=[0 1]和 Python 中的[0, 1]

好了,理论到此为止。我们来看看这样一个量子位的代码。

您将需要一个 Python 环境。我会推荐在虚拟环境中运行的 Jupyter 笔记本电脑。我整理了一个关于如何建立这样一个环境的简要说明。

除了一般的设置,我们还需要两个库: QiskitMatplotlib 。Qiskit 是 IBM 的 Python SDK,用于量子编程。Matplotlib 是一个用于在 Python 中创建静态、动画和交互式可视化的综合库

您可以使用pip安装两者:

pip install qiskit — user
pip install matplotlib

在您的主目录中安装 Qiskit。使用--user在安装过程中不依赖任何特权(即管理员权限)。

如果您还没有配置您的工作站,请看一下如何设置工作环境的简要说明(参见{ configuring-your-quantum-machine-learning-workstation })。

现在,打开 Jupyter 笔记本,测试 Qiskit 是否工作。

import qiskit
qiskit.__qiskit_version__{'qiskit-terra': '0.15.1',
 'qiskit-aer': '0.6.1',
 'qiskit-ignis': '0.4.0',
 'qiskit-ibmq-provider': '0.8.0',
 'qiskit-aqua': '0.7.5',
 'qiskit': '0.20.0'}

如果你得到这样的回应, Qiskit 有效。太好了!我们已经准备好创造我们的第一个量子比特。

第一个量子位

Qiskit 的基本单元是量子电路。量子电路是量子计算的模型。这个项目,如果你愿意的话。我们的电路由一个量子位组成(第 4 行)。

我们将[0,1]定义为我们量子位的initial_state(第 7 行),并用它初始化我们量子电路的第一个也是唯一的量子位(在阵列的位置0)(第 10 行)。

还记得[0,1]吗?这相当于|1⟩=[0 1]。用简单的英语来说,它是一个量子位,当观察时产生值1

这就是了。现在是时候启动我们的量子计算机了。万一你没有,没问题。我们可以模拟一下。(万一你有:“酷,让我知道”)。

准备模拟后端

Qiskit 提供了Aer包(我们在第 1 行导入它)。它为模拟量子电路提供了不同的后端。最常见的后端是statevector_simulator(第 4 行)。

execute-函数(我们也在第 1 行导入)在指定的backend运行我们的量子电路(qc)。它返回一个具有有用方法job.result()job-对象。一旦我们的程序完成它,它就返回result对象。

让我们来看看我们的量子位在起作用。

Qiskit 使用 Matplotlib 来提供有用的可视化。简单的直方图就可以了。result对象提供了get_counts方法来获取被执行电路的直方图数据(第 5 行)。

方法plot_histogram返回一个 Jupyter 自动绘制的 Matplotlib 图形(第 8 行)。

我们看到我们有 100%的机会观察到值1

测量的量子位

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

作者弗兰克·齐克特的图片

现在,让我们来看一个更高级的案例。比方说,我们希望我们的量子位以相同的概率(50:50)产生01

在量子力学中,有基本的叠加原理。它说,任何两个(或更多)量子态可以加在一起(“叠加”),结果将是另一个有效的量子态。

等等!我们已经知道两个量子态,|0⟩和|1⟩.我们为什么不把它们加进去呢?|0⟩和|1⟩是媒介。将两个向量相加非常简单。

向量是一种具有大小(或长度)和方向的几何对象。通常,它们用直箭头表示,从坐标轴上的一点开始,到另一点结束。

通过将一个向量的尾部放在另一个向量的头部,可以添加两个向量。尚未连接的尾部和尚未连接的尾部之间的直线是两个向量的和。看看下图。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

作者弗兰克·齐克特的图片

从数学上来说,这很容易。

设 u=[u1 u2]和 v=[v1 v2]为两个向量。

u 和 v 之和为:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

相应地,我们的叠加态应该是ψ∫:
∑ψ(“psi”)是一种常用于量子系统状态的符号。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我们手里有一台电脑。我们为什么不试试呢?

首次尝试叠加两种状态

QiskitError: 'Sum of amplitudes-squared does not equal one.'

它不太管用。它告诉我们:QiskitError: 'Sum of amplitudes-squared does not equal one.'

振幅是数组中的值。它们与概率成正比。所有的概率加起来应该正好是 1 (100%)。我们需要增加量子态|0⟩和|1⟩.的重量姑且称之为α和β。

我们用α加权|0⟩,用β加权|1⟩。像这样:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

振幅与概率成正比。我们需要将它们规范化,以便:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

如果|0⟩和|1⟩两个州应该有相同的权重,那么 α=β 。因此,我们可以求解等式到α:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我们插入α和β的值(两者相等)。让我们试试这个量子态:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Python 中对应的数组是:[1/sqrt(2), 1/sqrt(2)]。别忘了进口sqrt

加权初始状态

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

作者弗兰克·齐克特的图片

唷。在这篇文章中,我们介绍了相当多的术语和方程,只是为了对量子力学有所了解。但是实际的源代码非常简洁,不是吗?

我们引入了量子态的概念。特别是二元量子系统的状态。量子位或量子位。

在我们观察到一个量子比特之前,它是处于叠加态的。与可能是01的经典比特相反,量子比特是两种状态的叠加。但是一旦你观察它,就有明显的概率测量出01

这意味着对处于相同状态的多个量子位进行多次测量不会总是得到相同的结果。当观察时,量子比特具有α^2 导致0和β^2 导致1的概率的等效表示为:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在 Python 中,数组[alpha, beta]表示这种状态。

本帖是本书的一部分: 用 Python 动手做量子机器学习。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

免费获取前三章点击这里

NBA 球员统计数据 R 包“ggplot2”中数据可视化的实践指导

原文:https://towardsdatascience.com/hands-on-guidance-of-data-visualization-in-r-package-ggplot2-of-nba-players-stats-d812ed272d66?source=collection_archive---------25-----------------------

工具

应用于 NBA 数据的 R 数据可视化工具“ggplot2”的 6 分钟之旅。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

卢克·切瑟在 Unsplash 上的照片

我最近通读了关于数据科学 的书 R,发现 R 中的【gg plot 2】比我想象的更强大。

所以,我通过将它应用于 2019-2020 赛季的 NBA 球员统计数据来玩这个工具。在本文中,我将一步一步地分享我的探索,并希望 R 中的“ggplot2”可以成为您的数据科学工具箱中的另一个有用工具。

我要澄清一下,下面的材料是通过探究 ggplot2 中的函数来驱动的,而不是理解数据。

1.基本指挥结构。

数据科学中的 R描述了在 ggplot2 中生成图的方程如下图所示:

ggplot(data = <DATA>) +
      <GEOM_FUNCTION>(
                     mapping = aes(<MAPPINGS>),
                     stat = <STAT>,
                     position = <POSITION>
                     )+ 
      <COORDINATE_FUNCTION> + <FACET_FUNCTION>

其中 数据 是您的数据框,GEOM _ 函数 是您要使用的绘图类型(如柱状图), 映射 是要绘图的变量(如 x 和 y),统计是应用于您的数据框中原始数据的方程式(如计算观察值), 坐标 _ 函数

2.数据集。

2019-2020 NBA 赛季每场比赛的球员统计数据*。*

数据集已经通过删除“NA”和纠正赛季中交易的球员的统计数据进行了清理。

3.代码和图。

a.散点图和折线图

ggplot2 生成的复杂图形通常包含多个 ,基本上是一个GEOM _ 函数* s 序列生成的图的重叠,因此,如果没有指定GEOM _ 函数 的话,这个图将是空的。*

我们先把 放一层 在图上,这是一个散点图,x 是出场分钟数(MP),y 是做的分钟数(PTS)。

*ggplot(data = df, mapping = aes(x = MP, y=PTS)) + 
  geom_point()*

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

裕丰的 ggplot 几何点()

在这里,我将 映射 放在 ggplot() 函数中,而不是 geom_point() 函数中,以将其设置为一个全局变量,该变量将被后面的所有图层使用。但也可以放入 geom_point() 中,作为局部变量代替。

看起来,球员的上场时间和每场比赛的得分之间存在着正相关,然而,它并不是严格的线性关系,这表明即使在相同的上场时间内,普通球员也不能像超级明星那样获得那么多的得分。

太简单了?

是的,您可以通过指定数据中相应的列名来添加 颜色形状

*ggplot(data = df, mapping = aes(x = MP, y=PTS, color = Pos, shape = Pos)) + 
  geom_point()*

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

裕丰的 ggplot 几何点()

这里,我使用数据集中的变量 Pos 将玩家分成五组,并用不同的颜色和形状突出显示这些点。

也可以将颜色分配给连续变量,而不是分类变量,如下例所示。

*ggplot(data = df, mapping = aes(x = MP, y=PTS, color = Age)) + 
  geom_point()*

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

裕丰的 ggplot 几何点()

ggplot2 的神奇之处在于,你甚至可以在参数中指定一个条件。比如我们要把 LA 湖人 和其他球队分开。

*ggplot(data = df, mapping = aes(x = MP, y=PTS, color = Tm == "LAL")) + 
  geom_point()*

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

裕丰的 ggplot 几何点()

这里, Tm 代表数据集中的球队,“拉尔”就是 湖人

事实上,散点图非常混乱,所有的东西都相互重叠,很难得出任何结论。

接下来,让我们尝试根据数据集中的分类变量将数据分成不同的组。

例如,我想按团队划分数据。我将使用与之前相同的 ggplot 等式,但是使用FACET _ FUNCTION调整刻面中的输出。

*ggplot(data = df, mapping = aes(x = MP, y=PTS,color = Pos)) + 
  geom_point() + 
  facet_wrap(~Tm, nrow = 6)*

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

裕丰的 ggplot 几何点()

您还可以在 facet 函数中使用多个分类变量来实现这一点,方法是将 facet_wrap() 替换为 facet_grid()

*ggplot(data = df, mapping = aes(x = MP, y=PTS)) + 
  geom_point() + 
  facet_grid(Pos~Tm)*

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

裕丰的 ggplot 几何点()

很乱,对吧?这是我们需要避免的视觉化现象之一。

接下来,我将添加另一层的情节。

*ggplot(data = df,mapping = aes(x = MP, y=PTS, color = Pos)) + 
  geom_point() +
  geom_smooth()*

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

裕丰的 ggplot 几何点()

这个图现在有了另一层由 geom_smooth() 生成的折线图。由于我们在 ggplot() 中的全局变量中指定了参数“颜色”,散点图和折线图都用相同的颜色设置按位置划分玩家。

为了让情节看起来不那么混乱,我决定添加 facet 函数来更好地组织它们。

*ggplot(data = df,mapping = aes(x = MP, y=PTS, color = Pos)) + 
  geom_point() +
  geom_smooth() +
  facet_grid(Pos~.)*

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

裕丰的 ggplot 几何点()

好多了,对吧?

似乎所有五个职位的趋势都是相似的。然而,与其他三个位置相比, SGSF 在高 MP 区域,我确实观察到了稍微小一点的变化。这些结果让我想起了那些超级巨星的共同立场。

b.柱状图和 Combcox 图

条形图是数据可视化中另一种流行的绘图类型。不过 ggplot2 中的 有点特殊 ,因为它的默认功能是而不是绘制数据中的原始值。

原因与 ggplot2 中的 STAT 功能有关。条形图( geom_bar )的默认 STAT 函数是 stat_count() ,它计算由参数 x 定义的每个类别中的观察值数量。

*ggplot(data = df) + 
  geom_bar(mapping=aes(x = Pos))*

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

裕丰的 ggplot 几何点()

该图在 Y 轴上显示了每个类别的玩家数量,这是 ggplot2 中 geom_bar()函数的默认行为。

此外,条形的颜色需要通过来定义,而不是通过 【颜色】 来定义,这是与散点图的另一个区别。**

**ggplot(data = df) + 
  geom_bar(mapping=aes(x = Pos, fill = Pos))**

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

裕丰的 ggplot 几何点()

然而,大多数情况下,数据集中原始值的条形图比计数的条形图更重要,因此使用*‘stat = " identity "’*作为参数。

**ggplot(data = df,mapping = aes(x = Pos, y = PTS, fill = Pos)) +
  geom_bar(stat = "identity")**

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

裕丰的 ggplot 几何点()

现在上图中的 y 轴从计数变为点数之和。

代码的最后一部分展示了您可以用不同的坐标类型显示生成的图形。我最喜欢的一个叫做鸡冠图**,如下图所示。**

**ggplot(data = df,mapping = aes(x = Pos, y = PTS, fill = Pos)) +
  geom_bar(stat = "identity",width = 1) + 
  coord_polar()**

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

裕丰的 ggplot 几何点()

是不是很酷?

我们可以从数据中解读出,得分后卫在赛季场均总得分中贡献最大。然而,这可能是因为这个位置的玩家数量最多。

尽管 NBA 在球员冠状病毒检测呈阳性后暂停赛季,但我希望所有的球员、球迷和世界人民保持健康,并赢得这场对抗病毒的战争。

希望 ggplot2 成为你作为数据科学家的可视化武器之一。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Max DuzijUnsplash 上拍照

参考资料:

  1. Garrett Grolemund 和 Hadley Wickham,R 为数据科学

Python 中要素工程的实践指南

原文:https://towardsdatascience.com/hands-on-guide-to-feature-engineering-de793efc785?source=collection_archive---------39-----------------------

一步一步地从数据中提取有用的见解

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

照片由约书亚·索蒂诺Unsplash 上拍摄

介绍

在本指南中,我将介绍如何利用数据操作来手动提取特征。

手动特征工程可能会令人疲惫不堪,并且需要大量的时间、经验和领域知识来开发正确的特征。有许多可用的自动特征工程工具,如 FeatureTools 和 AutoFeat。然而,手动特征工程对于理解这些高级工具是必不可少的。此外,这将有助于建立一个稳健的通用模型。我将使用 Kaggle 平台上可用的住房信贷违约风险数据集。我将只使用主文件夹中的两个表bureaubureau_balance。根据竞争页面上的数据集描述,表格如下:

bureau.csv

  • 此表包括所有客户以前从其他金融机构向信用局报告的信用。

bureau_balance.csv

  • 信用局早期贷款的每月余额。
  • 该表中有一行记录了每个月向信用局报告的每笔贷款的历史。

本教程将涵盖相关主题

  1. 读取和管理数据—定制 KDE 图
  2. 调查相关性
  3. 聚合数字列
  4. 获取 bureau_balance 的统计数据
  5. 调查分类变量
  6. 将计算出的特征插入训练数据集中
  7. 检查缺失的数据
  8. 相关
  9. 共线性

1.读取和管理数据

我将从导入一些有助于理解数据的重要库开始。

*# pandas and numpy for data manipulation* import pandas as pd
import numpy as np

*# matplotlib and seaborn for plotting*
import matplotlib.pyplot as plt
import seaborn as sns

*# Suppress warnings from pandas*
import warnings
warnings.filterwarnings('ignore')

plt.style.use('fivethirtyeight')

我先开始分析 bureau.csv:

*# Read in bureau*
bureau = pd.read_csv('../input/home-credit-default-risk/bureau.csv')
bureau.head()

该表有 1716428 个观察值和 17 个特征。

SK_ID_CURR                  int64
SK_ID_BUREAU                int64
CREDIT_ACTIVE              object
CREDIT_CURRENCY            object
DAYS_CREDIT                 int64
CREDIT_DAY_OVERDUE          int64
DAYS_CREDIT_ENDDATE       float64
DAYS_ENDDATE_FACT         float64
AMT_CREDIT_MAX_OVERDUE    float64
CNT_CREDIT_PROLONG          int64
AMT_CREDIT_SUM            float64
AMT_CREDIT_SUM_DEBT       float64
AMT_CREDIT_SUM_LIMIT      float64
AMT_CREDIT_SUM_OVERDUE    float64
CREDIT_TYPE                object
DAYS_CREDIT_UPDATE          int64
AMT_ANNUITY               float64
dtype: object

我们需要得到每个客户 id 是多少以前的贷款SK_ID_CURR。我们可以使用 pandas 聚合函数groupbycount().来得到这个结果,然后在为了可读性而将SK_ID_BUREAU重命名为previous_loan_count之后,将新的结果存储在一个新的数据帧中。

*# groupby client-id, count #previous loans*
**from** **pandas** **import** DataFrame

prev_loan_count = bureau.groupby('SK_ID_CURR', as_index = **False**).count().rename(columns = {'SK_ID_BUREAU': 'previous_loan_count'})

新的prev_loan_count只有 305811 个观测值。现在,我将通过客户端 id SK_ID_CURRprev_loan_count数据帧合并到train数据集中,然后用 0 填充缺失的值。最后,检查新列是否已经使用dtypes函数添加。

# join with the training dataframe
# read train.csvpd.set_option('display.max_column', None)
train = pd.read_csv('../input/home-credit-default-risk/application_train.csv')
train = train.merge(prev_loan_count, on = 'SK_ID_CURR', how = 'left')# fill the missing values with 0train['previous_loan_count'] = train['previous_loan_count'].fillna(0)
train['previous_loan_count'].dtypesdtype('float64')

它已经在那里了!

2.调查相关性

下一步是通过特征重要性探索属性之间的皮尔逊相关值或( r 值)。它不是衡量新变量重要性的标准;但是,它提供了一个变量对模型是否有帮助的参考。

因变量的相关性越高,意味着该变量的任何变化都会导致因变量的显著变化。因此,在下一步中,我将研究相对于因变量的 r 值的最高绝对值。

核密度估计(KDE)是描述因变量和自变量之间关系的最佳方法。

# Plots the disribution of a variable colored by value of the dependent variabledef kde_target(var_name, df):

    # Calculate the correlation coefficient between the new variable and the target
    corr = df['TARGET'].corr(df[var_name])

    # Calculate medians for repaid vs not repaid
    avg_repaid = df.loc[df['TARGET'] == 0, var_name].median()
    avg_not_repaid = df.loc[df['TARGET'] == 1, var_name].median()

    plt.figure(figsize = (12, 6))

    # Plot the distribution for target == 0 and target == 1
    sns.kdeplot(df.loc[df['TARGET'] == 0, var_name], label = 'TARGET == 0')
    sns.kdeplot(df.loc[df['TARGET'] == 1, var_name], label = 'TARGET == 1')

    # label the plot
    plt.xlabel(var_name); plt.ylabel('Density'); plt.title('%s Distribution' % var_name)
    plt.legend();

    # print out the correlation
    print('The correlation between %s and the TARGET is %0.4f' % (var_name, corr)) # Print out average values
    print('Median value for loan that was not repaid = %0.4f' % avg_not_repaid) print('Median value for loan that was repaid =     %0.4f' % avg_repaid)

然后对照Target检查previous_loan_count的分配

kde_target('previous_loan_count', train)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

上一次贷款计数的 KDE 图

很难看出TARGETprevious_loan_count之间有任何显著的相关性。从图上看不出有明显的相关性。因此,需要使用聚合函数来研究更多的变量。

3.聚合数字列

我将选择按客户端 id 分组的数字列,然后应用统计函数min, max, sum, mean, and count来获得每个数字特性的汇总统计信息。

*# Group by the client id, calculate aggregation statistics*
bureau_agg = bureau.drop(columns = ['SK_ID_BUREAU']).groupby('SK_ID_CURR', as_index = **False**).agg(['count', 'mean', 'min','max','sum']).reset_index()

为可读性起见,为每个列创建一个新名称。然后与train数据集合并。

*# List of column names*
columns = ['SK_ID_CURR']

*# Iterate through the variables names*
**for** var **in** bureau_agg.columns.levels[0]:
    *# Skip the id name*
    **if** var != 'SK_ID_CURR':

        *# Iterate through the stat names*
        **for** stat **in** bureau_agg.columns.levels[1][:-1]:
            *# Make a new column name for the variable and stat*
            columns.append('bureau_**%s**_**%s**' % (var, stat))*# Assign the list of columns names as the dataframe column names*
bureau_agg.columns = columns# merge with the train dataset
train = train.merge(bureau_agg, on = 'SK_ID_CURR', how = 'left')

使用TARGET变量获取相关性,然后使用sort_values() Python 函数按绝对值对相关性进行排序。

# Calculate correlation between variables and the dependent variable
# Sort the correlations by the absolute valuenew_corrs = train.drop(columns=['TARGET']).corrwith(train['TARGET']).sort_values(ascending=False)
new_corrs[:15]

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

与目标变量的相关性

现在检查新创建的变量的 KDE 图

kde_target('bureau_DAYS_CREDIT_mean', train)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

bureau_DAYS_CREDIT_mean 和目标之间的相关性

如图所示,相关性非常弱,可能只是噪声。此外,较大的负数表示该贷款在当前贷款申请之前。

4.获取 bureau_balance 的统计数据

bureau_balance = pd.read_csv('../input/home-credit-default-risk/bureau_balance.csv')bureau_balance.head()

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

bureau_balance.csv

5.调查分类变量

下面的函数遍历 dataframe,选择分类列并为其创建一个虚拟变量。

def process_categorical(df, group_var, col_name):
    """Computes counts and normalized counts for each observation
    of `group_var` of each unique category in every categorical variable

    Parameters
    --------
    df : dataframe 
        The dataframe to calculate the value counts for.

    group_var : string
        The variable by which to group the dataframe. For each unique
        value of this variable, the final dataframe will have one row

    col_name : string
        Variable added to the front of column names to keep track of columnsReturn
    --------
    categorical : dataframe
        A dataframe with counts and normalized counts of each unique category in every categorical variable
        with one row for every unique value of the `group_var`.

    """
    # pick the categorical column 
    categorical = pd.get_dummies(df.select_dtypes('O'))

    # put an id for each column
    categorical[group_var] = df[group_var]

    # aggregate the group_var
    categorical = categorical.groupby(group_var).agg(['sum', 'mean'])

    columns_name = []

    # iterate over the columns in level 0
    for var in categorical.columns.levels[0]:
        # iterate through level 1 for stats
        for stat in ['count', 'count_norm']:
            # make new column name
            columns_name.append('%s_%s_%s' %(col_name, var, stat))

    categorical.columns = columns_name

    return categorical

这个函数将为每个分类列返回一个统计数据summean

bureau_count = process_categorical(bureau, group_var = 'SK_ID_CURR',col_name = 'bureau')

对 bureau_balance 执行相同的操作

bureau_balance_counts = process_categorical(df = bureau_balance, group_var = 'SK_ID_BUREAU', col_name = 'bureau_balance')

现在,我们有了每笔贷款的计算结果。我们需要为每个客户端进行聚合。我将把所有以前的数据帧合并在一起,然后再次汇总按SK_ID_CURR分组的统计数据。

# dataframe grouped by the loan 
bureau_by_loan = bureau_balance_agg.merge(bureau_balance_counts, right_index = True, left_on = 'SK_ID_BUREAU', how = 'outer')# Merge to include the SK_ID_CURR
bureau_by_loan = bureau[['SK_ID_BUREAU', 'SK_ID_CURR']].merge(bureau_by_loan, on = 'SK_ID_BUREAU', how = 'left')# Aggregate the stats for each client
bureau_balance_by_client = agg_numeric(bureau_by_loan.drop(columns = ['SK_ID_BUREAU']), group_var = 'SK_ID_CURR', col_name = 'client')

6.将计算出的特征插入训练数据集中

original_features = list(train.columns)
print('Original Number of Features: ', len(original_features))

输出:原始特征数:122

# Merge with the value counts of bureau
train = train.merge(bureau_counts, on = 'SK_ID_CURR', how = 'left')# Merge with the stats of bureau
train = train.merge(bureau_agg, on = 'SK_ID_CURR', how = 'left')# Merge with the monthly information grouped by client
train = train.merge(bureau_balance_by_client, on = 'SK_ID_CURR', how = 'left')new_features = list(train.columns)
print('Number of features using previous loans from other institutions data: ', len(new_features))# Number of features using previous loans from other institutions data:  333

输出为:使用以前从其他机构贷款的特征数数据:333

7.检查缺失的数据

合并新特征后,检查训练集中缺失的数据非常重要。

# Function to calculate missing values by column# Funct 
def missing_percent(df):"""Computes counts and normalized counts for each observation
    of `group_var` of each unique category in every categorical variable

    Parameters
    --------
    df : dataframe 
        The dataframe to calculate the value counts for.Return
    --------
    mis_column : dataframe
        A dataframe with missing information .

    """
        # Total missing values
        mis_val = df.isnull().sum()

        # Percentage of missing values
        mis_percent = 100 * df.isnull().sum() / len(df)

        # Make a table with the results
        mis_table = pd.concat([mis_val, mis_percent], axis=1)

        # Rename the columns
        mis_columns = mis_table.rename(
        columns = {0 : 'Missing Values', 1 : 'Percent of Total Values'})

        # Sort the table by percentage of missing descending
        mis_columns = mis_columns[
            mis_columns.iloc[:,1] != 0].sort_values(
        'Percent of Total Values', ascending=False).round(2)

        # Print some summary information
        print ("Your selected dataframe has " + str(df.shape[1]) + " columns.\n"      
            "There are " + str(mis_columns.shape[0]) +
              " columns that have missing values.")

        # Return the dataframe with missing information
        return mis_columnstrain_missing = missing_percent(train)
train_missing.head()

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

火车 _ 失踪

有相当多的列有大量缺失数据。我将删除任何缺失数据超过 90%的列。

missing_vars_train = train_missing.loc[train_missing['Percent of Total Values'] > 90, 'Percent of Total Values']
len(missing_vars_train)
# 0

我将对测试数据做同样的事情

*# Read in the test dataframe*
test = pd.read_csv('../input/home-credit-default-risk/application_test.csv')

*# Merge with the value counts of bureau*
test = test.merge(bureau_counts, on = 'SK_ID_CURR', how = 'left')

*# Merge with the stats of bureau*
test = test.merge(bureau_agg, on = 'SK_ID_CURR', how = 'left')

*# Merge with the value counts of bureau balance*
test = test.merge(bureau_balance_by_client, on = 'SK_ID_CURR', how = 'left')

然后,将对齐traintest数据集,并检查它们的形状和相同的列。

*# create a train target label* 
train_label = train['TARGET']

*# align both dataframes, this will remove TARGET column*
train, test = train.align(test, join='inner', axis = 1)

train['TARGET'] = train_label
print('Training Data Shape: ', train.shape)
print('Testing Data Shape: ', test.shape)#Training Data Shape:  (307511, 333)
#Testing Data Shape:  (48744, 332)

让我们检查一下test组的缺失百分比。

test_missing = missing_percent(test) 
test_missing.head()

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

test_missing.head()

8.相关

我将检查与TARGET变量和新创建的特征的相关性。

# calculate correlation for all dataframes
corr_train = train.corr()# Sort the resulted values in an ascending order
corr_train = corr_train.sort_values('TARGET', ascending = False)# show the ten most positive correlations
pd.DataFrame(corr_train['TARGET'].head(10))

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

与目标变量相关的前 10 个特征

从上面的例子中可以看出,最相关的变量是早期设计的变量。然而,相关性并不意味着因果关系,这就是为什么我们需要评估这些相关性,并选择对TARGET有更深影响的变量。为此,我将坚持使用KDE剧情。

kde_target('bureau_DAYS_CREDIT_mean', train)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

KDE 图为局 _ 天 _ 信用 _ 均值

该图表明,每月每笔贷款记录较多的申请人倾向于偿还新贷款。让我们更深入地研究一下bureau_CREDIT_ACTIVE_Active_count_norm变量,看看这是不是真的。

kde_target('bureau_CREDIT_ACTIVE_Active_count_norm', train)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

局的 KDE 图 _ 信用 _ 活跃 _ 活跃 _ 计数 _ 定额

这里的相关性很弱,我们看不出有什么意义。

9.共线性

我将设置一个 80%的阈值来删除任何与TARGET高度相关的变量

*# Set the threshold*
threshold = 0.8

*# Empty dictionary to hold correlated variables*
above_threshold_vars = {}

*# For each column, record the variables that are above the threshold*
**for** col **in** corr_train:
    above_threshold_vars[col] = list(corr_train.index[corr_train[col] > threshold])*# Track columns to remove and columns already examined*
cols_to_remove = []
cols_seen = []
cols_to_remove_pair = []

*# Iterate through columns and correlated columns*
**for** key, value **in** above_threshold_vars.items():
    *# Keep track of columns already examined*
    cols_seen.append(key)
    **for** x **in** value:
        **if** x == key:
            next
        **else**:
            *# Only want to remove one in a pair*
            **if** x **not** **in** cols_seen:
                cols_to_remove.append(x)
                cols_to_remove_pair.append(key)

cols_to_remove = list(set(cols_to_remove))
print('Number of columns to remove: ', len(cols_to_remove))

输出是:要删除的列数:134

然后,我们可以从数据集中删除这些列,作为用于模型构建的准备步骤

rain_corrs_removed = train.drop(columns = cols_to_remove)
test_corrs_removed = test.drop(columns = cols_to_remove)

print('Training Corrs Removed Shape: ', train_corrs_removed.shape)
print('Testing Corrs Removed Shape: ', test_corrs_removed.shape)

训练 Corrs 删除形状:(307511,199)
测试 Corrs 删除形状:(48744,198)

摘要

本教程的目的是向您介绍许多在开始时可能会令人困惑的概念:

  1. 使用熊猫函数的特征工程。
  2. 定制核密度估计图。
  3. 评估新提取的特征
  4. 消除数据中的共线性

参考

  1. 特征工程简介 —威尔·科尔森
  2. GitHub 上本教程的完整笔记本
  3. Kaggle的完整笔记本——准备运行
  4. Kaggle 上的住房信贷违约风险竞赛

用 Python 绘制 ML 决策面的实践指南

原文:https://towardsdatascience.com/hands-on-guide-to-plotting-a-decision-surface-for-ml-in-python-149710ee2a0e?source=collection_archive---------15-----------------------

利用 matplotlib 可视化 Python 中分类算法的决策边界

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

扬·坎迪Unsplash 拍摄的照片

介绍

最近,我一直在努力将一个分类模型的生成模型可视化。我只依靠分类报告和混淆矩阵来衡量模型性能。

然而,将分类结果可视化有其魅力,也更有意义。所以,我建立了一个决策面,当我成功的时候,我决定把它作为一个学习的过程写下来,并且写给任何可能陷入同样问题的人。

教程内容

在本教程中,我将从 Sklearn 库中内置的数据集包开始,重点介绍实现步骤。之后,我将使用一个预处理数据(没有缺失数据或异常值)在应用标准缩放器后绘制决策面。

  • 决策面
  • 导入重要的库
  • 数据集生成
  • 生成决策面
  • 申请真实数据

决策面

机器学习中的分类是指训练你的数据给输入的例子分配标签。

每个输入特征在特征空间上定义一个轴。平面的特征在于最少两个输入要素,点表示输入空间中的输入坐标。如果有三个输入变量,特征空间将是三维体积。

分类的最终目标是分离特征空间,以便尽可能正确地将标签分配给特征空间中的点。

这种方法称为决策面或决策边界,它是一种演示工具,用于解释分类预测建模任务中的模型。如果您有两个以上的输入要素,我们可以为每对输入要素创建一个决策表面。

导入重要的库

import numpy as np
import pandas as pdimport matplotlib.pyplot as plt
from matplotlib.colors import ListedColormapfrom sklearn import datasets
from sklearn.linear_model import LogisticRegression
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import accuracy_score, confusion_matrix
from sklearn.model_selection import train_test_split

生成数据集

我将使用 Sklearn 库中 datasets 类中的make_blobs()函数来生成一个定制数据集。这样做可以将重点放在实现上,而不是清理数据。然而,步骤是相同的,并且是典型的模式。
为了简单起见,让我们从定义具有 1000 个样本、只有两个特征和标准偏差为 3 的数据集变量开始。

X, y = datasets.make_blobs(n_samples = 1000, 
                           centers = 2, 
                           n_features = 2, 
                           random_state = 1, 
                           cluster_std = 3)

一旦数据集生成,我们就可以绘制一个散点图来查看变量之间的可变性。

# create scatter plot for samples from each class
for class_value in range(2): # get row indexes for samples with this class
    row_ix = np.where(y == class_value) # create scatter of these samples
    plt.scatter(X[row_ix, 0], X[row_ix, 1])# show the plot
plt.show()

在这里,我们循环遍历数据集,并在每个由类标签着色的Xy 之间绘制点。在下一步中,我们需要建立一个预测分类模型来预测看不见的点的类别。在这种情况下可以使用逻辑回归,因为我们只有两个类别。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

散点图 1

开发逻辑回归模型

regressor = LogisticRegression()# fit the regressor into X and y
regressor.fit(X, y)# apply the predict method 
y_pred = regressor.predict(X)

所有的y_pred都可以使用sklearn库中的accuracy_score类进行评估。

accuracy = accuracy_score(y, y_pred)
print('Accuracy: %.3f' % accuracy)## Accuracy: 0.972

生成决策面

matplotlib提供了一个叫做contour()的便捷函数,可以在点与点之间插入颜色。然而,正如文档所建议的,我们需要在特征空间中定义y的点X的网格。起点是找到每个特征的最大值和最小值,然后加 1,以确保覆盖整个空间。

min1, max1 = X[:, 0].min() - 1, X[:, 0].max() + 1 #1st feature
min2, max2 = X[:, 1].min() - 1, X[:, 1].max() + 1 #2nd feature

然后我们可以使用numpy库中的arange()函数定义坐标的比例,分辨率为0.01以获得比例范围。

x1_scale = np.arange(min1, max1, 0.1)
x2_scale = np.arange(min2, max2, 0.1)

下一步是将x1_scalex2_scale转换成网格。numpy库中的函数meshgrid()正是我们所需要的。

x_grid, y_grid = np.meshgrid(x1_scale, x2_scale)

生成的x_grid是一个二维数组。为了能够使用它,我们需要使用来自numpy库的flatten()方法将大小减少到一维数组。

# flatten each grid to a vector
x_g, y_g = x_grid.flatten(), y_grid.flatten()
x_g, y_g = x_g.reshape((len(x_g), 1)), y_g.reshape((len(y_g), 1))

最后,像原始数据集一样,以更高的分辨率将向量并排堆叠为输入数据集中的列。

grid = np.hstack((x_g, y_g))

现在,我们可以拟合模型来预测值。

# make predictions for the grid
y_pred_2 = model.predict(grid)#predict the probability
p_pred = model.predict_proba(grid)# keep just the probabilities for class 0
p_pred = p_pred[:, 0]# reshaping the results
p_pred.shape
pp_grid = p_pred.reshape(x_grid.shape)

现在,已经生成了跨特征空间的值和预测类标签的网格。

随后,我们将使用contourf()将这些网格绘制成等高线图。
contourf()功能需要每个轴独立的网格。为了实现这一点,我们可以利用x_gridy_grid并重塑预测(y_pred)使其具有相同的形状。

# plot the grid of x, y and z values as a surface
surface = plt.contourf(x_grid, y_grid, pp_grid, cmap='Pastel1')
plt.colorbar(surface)# create scatter plot for samples from each class
for class_value in range(2):
# get row indexes for samples with this class
    row_ix = np.where(y == class_value) # create scatter of these samples
    plt.scatter(X[row_ix, 0], X[row_ix, 1], cmap='Pastel1')# show the plot
plt.show()

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

两个特征的决策面

应用于真实数据

现在是时候将前面的步骤应用于真实数据以连接一切。正如我前面提到的,这个数据集已经被清理过了,没有遗漏点。该数据集根据年龄和年薪代表了样本人群的购车历史。

dataset = pd.read_csv('../input/logistic-reg-visual/Social_Network_Ads.csv')dataset.head()

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

社交网络广告数据集

数据集有两个特性AgeEstimatedSalary以及一个作为二进制列购买的因变量。值 0 表示年龄和薪水相似的人没有买车。然而,一个意味着这个人确实买了这辆车。下一步是将因变量从 X 和 y 特征中分离出来

X = dataset.iloc[:, :-1].values
y = dataset.iloc[:, -1].values# splitting the dataset
X_train, X_test, y_train, y_test = train_test_split(
                                               X, y, 
                                               test_size = 0.25,
                                               random_state = 0)

特征缩放

我们需要这一步,因为Agesalary不在同一尺度上

sc = StandardScaler()
X_train = sc.fit_transform(X_train)
X_test = sc.transform(X_test)

建立逻辑模型并拟合训练数据

classifier = LogisticRegression(random_state = 0)# fit the classifier into train data
classifier.fit(X_train, y_train)# predicting the value of y 
y_pred = classifier.predict(X_test)

绘制决策面—训练结果

#1\. reverse the standard scaler on the X_train
X_set, y_set = sc.inverse_transform(X_train), y_train#2\. Generate decision surface boundaries
min1, max1 = X_set[:, 0].min() - 10, X_set[:, 0].max() + 10 # for Age
min2, max2 = X_set[:, 1].min() - 1000, X_set[:, 1].max() + 1000 # for salary#3\. Set coordinates scale accuracy
x_scale ,y_scale = np.arange(min1, max1, 0.25), np.arange(min2, max2, 0.25)#4\. Convert into vector 
X1, X2 = np.meshgrid(x_scale, y_scale)#5\. Flatten X1 and X2 and return the output as a numpy array
X_flatten = np.array([X1.ravel(), X2.ravel()])#6\. Transfor the results into it's original form before scaling
X_transformed = sc.transform(X_flatten.T)#7\. Generate the prediction and reshape it to the X to have the same shape
Z_pred = classifier.predict(X_transformed).reshape(X1.shape)#8\. set the plot size
plt.figure(figsize=(20,10))#9\. plot the contour function
plt.contourf(X1, X2, Z_pred,
                     alpha = 0.75, 
                     cmap = ListedColormap(('#386cb0', '#f0027f')))#10\. setting the axes limit
plt.xlim(X1.min(), X1.max())
plt.ylim(X2.min(), X2.max())#11\. plot the points scatter plot ( [salary, age] vs. predicted classification based on training set)for i, j in enumerate(np.unique(y_set)):
    plt.scatter(X_set[y_set == j, 0], 
                X_set[y_set == j, 1], 
                c = ListedColormap(('red', 'green'))(i), 
                label = j)

#12\. plot labels and adjustments
plt.title('Logistic Regression (Training set)')
plt.xlabel('Age')
plt.ylabel('Estimated Salary')
plt.legend()
plt.show()

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

决策面—训练集

测试集的决策图

它与前面的代码完全相同,但是不使用 train,而是使用 test set。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

决策图—测试集

结论

最后,我希望这个样板文件可以帮助可视化分类模型的结果。我建议使用另一个分类模型应用相同的步骤,例如,具有两个以上特征的 SVM。
感谢阅读,我期待着任何建设性的意见。

参考

  1. Sklearn.datasets A PI
  2. 利用熊猫转换数据
  3. matplotlib . contour()API
  4. numpy.meshgrid() A PI
  5. 在 iris 数据集上绘制决策树的决策面 — sklearn 示例
  6. 全工作卡格尔笔记本
  7. GitHub 回购

Python 最优传输工具箱实践指南:第 1 部分

原文:https://towardsdatascience.com/hands-on-guide-to-python-optimal-transport-toolbox-part-1-922a2e82e621?source=collection_archive---------26-----------------------

最佳运输的第一步

作为 Ievgen Redko 的关于最优传输的介绍性文章的后续文章,我将在下面介绍如何在实践中使用 Python 最优传输(POT) 工具箱求解最优传输(OT)。

首先,让我们从终端使用 pip 安装 POT,只需运行

pip3 install pot

或与康达

conda install -c conda-forge pot

如果一切顺利,您现在已经安装了 POT,可以在您的计算机上使用了。

POT Python 最佳运输工具箱

导入工具箱

import numpy as np # always need it
import scipy as sp # often use it
import pylab as pl # do the plotsimport ot # ot

获得帮助

POT 的在线文档可从 http://pot.readthedocs.io、获得,或者您可以查看在线帮助help(ot.dist)

我们现在准备开始我们的例子。

简单 OT 问题

我们将解决面包店/咖啡馆将羊角面包从一个城市(在本例中为曼哈顿)的多个面包店运送到咖啡馆的问题。我们在谷歌地图上快速搜索了曼哈顿的面包店和咖啡馆:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我们从这一搜索中提取他们的位置,并生成虚构的生产和销售数字(两者的总和相同)。

我们可以访问描述来源分布的面包店bakery_pos的位置及其各自的生产bakery_prod。出售羊角面包的咖啡馆也由其位置cafe_poscafe_prod决定,并描述了目标分布

现在我们加载数据

data = np.load('[https://github.com/PythonOT/POT/raw/master/data/manhattan.npz](https://github.com/PythonOT/POT/raw/master/data/manhattan.npz)')bakery_pos = data['bakery_pos']
bakery_prod = data['bakery_prod']
cafe_pos = data['cafe_pos']
cafe_prod = data['cafe_prod']
Imap = data['Imap']print('Bakery production: {}'.format(bakery_prod))
print('Cafe sale: {}'.format(cafe_prod))
print('Total croissants : {}'.format(cafe_prod.sum()))

这给出了:

Bakery production: [31\. 48\. 82\. 30\. 40\. 48\. 89\. 73.]
Cafe sale: [82\. 88\. 92\. 88\. 91.]
Total croissants : 441.0

策划城市中的面包店

接下来,我们在地图上标出面包店和咖啡馆的位置。圆圈的大小与它们的产量成正比。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

成本矩阵

我们现在可以计算面包店和咖啡馆之间的成本矩阵,这将是运输成本矩阵。这可以使用[ot.dist](https://pythonot.github.io/all.html#ot.dist)函数来完成,该函数默认为平方欧几里得距离,但可以返回其他值,如城市街区(或曼哈顿距离)。

M = ot.dist(bakery_pos, cafe_pos)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

面包店-咖啡馆问题的平方欧氏距离成本矩阵 M

矩阵图中的红色单元显示的是距离较远的面包店和咖啡馆,因此从一个地方到另一个地方的运输成本更高,而蓝色单元显示的是距离平方欧几里得距离非常近的面包店和咖啡馆。

用推土机的距离解决加班问题

我们现在来看问题本身,即找到将羊角面包从面包店运送到咖啡馆的最佳解决方案。为了做到这一点,让我们来看一点数学。

目标是找到传输矩阵gamma,使得

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

其中 M 是成本矩阵,a 和 b 分别是源和目标的样本权重。

这意味着,我们考虑了通过 M 将羊角面包从一家面包店运送到一家咖啡馆的成本,我们希望每一行gamma的总和是相应的面包店要出售的羊角面包的数量,每一列的总和是相应的咖啡馆需要的羊角面包的数量。因此,运输矩阵的每个元素将对应于面包店必须送到咖啡馆的羊角面包的数量。

这个问题被称为推土机的距离,或 EMD,也称为离散 Wasserstein 距离。

让我们看看它在我们的例子中给出了什么。

gamma_emd = ot.emd(bakery_prod, cafe_prod, M)

下图(左图)显示了从面包店到咖啡馆的运输,线的宽度与要运输的羊角面包数量成比例。在右边,我们可以看到带有精确值的传输矩阵。我们可以看到,面包店只需要将羊角面包运输到一两家咖啡馆,运输矩阵非常稀疏。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

EMD 下的最优运输

用 Sinkhorn 正则化 OT

EMD 的一个问题是它的算法复杂度是 O( n log( n ), n 是源和目标之间的最大维度。在我们的例子中, n 很小,所以可以使用 EMD,但是对于更大的 n 值,我们可能需要考虑其他选项。

当一个算法的计算时间很长时,我们可以将其正则化,以获得一个更简单或更快的问题的解决方案。Sinkhorn 算法通过添加熵正则化项来实现这一点,从而解决了以下问题。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

其中 reg 是超参数, Omega 是熵正则项,定义如下:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Sinkhorn 算法的编码非常简单。您可以使用以下伪代码直接实现它:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

小心数字问题。Sinkhorn 的一个好的预处理是用成本矩阵M除以它的最大值。

reg = 0.1
K = np.exp(-M / M.max() / reg)
nit = 100
u = np.ones((len(bakery_prod), ))
for i in range(1, nit):
    v = cafe_prod / np.dot(K.T, u)
    u = bakery_prod / (np.dot(K, v))
gamma_sink_algo = np.atleast_2d(u).T * (K * v.T)  # Equivalent to np.dot(np.diag(u), np.dot(K, np.diag(v)))

另一种方法是使用带有 ot.sinkhorn 的 POT 工具箱:

gamma_sinkhorn = ot.sinkhorn(bakery_prod, cafe_prod, reg=reg, M=M/M.max())

当绘制最终的运输矩阵时,我们马上注意到,使用 Sinkhorn,它一点也不稀疏,每个面包店都使用该解决方案向所有 5 家咖啡馆运送羊角面包。此外,这个解决方案给出了分数的传输,这在羊角面包的情况下没有意义。EMD 的情况并非如此。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

带 Sinkhorn 的正则化最优运输

改变 Sinkhorn 中的正则化参数

显然,新疆的正则化超参数 reg 起着重要的作用。让我们通过下面的图表,从不同的值来看它是如何影响运输矩阵的。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

reg 对运输矩阵的影响

这一系列图表显示,对于非常小的正则化参数值reg,Sinkhorn 的解开始于非常类似于 EMD 的东西(尽管不是稀疏的),并且随着reg的增加而趋向于更一致的解。

结论

第一部分展示了一个使用 POT 库应用优化传输的简单示例。正如 Ievgen Redko 在第二部分中所讨论的,最优运输是一个可以在许多方面应用的强大工具。

Python 最优传输工具箱实践指南:第 2 部分

原文:https://towardsdatascience.com/hands-on-guide-to-python-optimal-transport-toolbox-part-2-783029a1f062?source=collection_archive---------32-----------------------

色彩转换、图像编辑和自动翻译

作为我上一篇关于最优传输的介绍性文章的后续,我将在下面介绍如何使用 Python 最优传输(POT) 工具箱来解决不同的最优传输(OT)任务。

首先,让我们从终端使用 pip 安装 POT,只需运行

pip3 install ot

瞧!如果一切顺利,您现在已经安装了 POT,可以在您的计算机上使用了。现在让我解释一下如何复制我以前文章中的结果。

颜色转移

在这个应用程序中,我们的目标是以尽可能平滑的方式将一个图像的颜色风格转移到另一个图像上。为此,我们将遵循 POT library 官方网页上的示例并从定义处理图像时所需的几个补充功能开始:

import numpy as np
import matplotlib.pylab as pl
import ot

[r](https://numpy.org/doc/stable/reference/random/legacy.html#numpy.random.RandomState) = [np.random.RandomState](https://numpy.org/doc/stable/reference/random/legacy.html#numpy.random.RandomState)(42)

def im2mat(img):
    """Converts an image to a matrix (one pixel per line)"""
    return img.reshape((img.shape[0] * img.shape[1], img.shape[2]))

def mat2im(X, shape):
    """Converts a matrix back to an image"""
    return X.reshape(shape)

因此,这里的前三行只是 numpy、matplotlib.pylab 和 ot 包的导入。然后,我们有两个函数,允许我们转换由 3d 矩阵(有人称之为张量)表示的图像,其中第一维是图像的高度,第二维是其宽度,而第三维由像素的 RGB 坐标给出。现在让我们加载一些图像来看看它的含义。

[I1](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray) = pl.imread('../../data/ocean_day.jpg').astype([np.float64](https://docs.python.org/3/library/functions.html#float))/256
[I2](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray) = pl.imread('../../data/ocean_sunset.jpg').astype([np.float64](https://docs.python.org/3/library/functions.html#float))/256

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

它们在这里,白天的海洋图像和日落图像直接在 POT 工具箱中提供。注意,最初所有的像素 RGB 坐标都是整数,所以 astype( np.float64 )将它们转换成浮点数。然后,每个值除以 256(每个像素坐标的最大值),以将数据标准化为位于[0,1]区间内。如果我们检查它们的尺寸,我们得到如下结果

print(I1[0,0,:])
[0.0234375 0.2421875 0.53125]

这意味着左下角的第一个像素具有由向量[R = 0.0234375,G= 0.2421875,B = 0.53125]给出的 RGB 坐标(蓝色如白天图像所预期的那样占主导)。现在,我们将张量转换为 2d 矩阵,其中每条线是一个像素,由其 RGB 坐标描述,如下所示:

day = im2mat(I1)
sunset = im2mat(I2)

请注意,这些矩阵相当大,通过运行以下代码可以看出:

print(day.shape)
(669000, 3)

让我们从每幅图像中随机抽取 1000 个像素,以减少将要应用 OT 的矩阵的大小。我们可以这样做:

nb = 1000
idx1 = r.randint(day.shape[0], size=(nb,)) 
idx2 = r.randint(sunset.shape[0], size=(nb,))

Xs = day[idx1, :]
Xt = sunset[idx2, :]

我们现在有两个矩阵,每个矩阵只有 1000 行和 3 列。让我们将它们绘制在 RB(红-蓝)平面上,看看我们实际采样的是什么颜色的像素:

plt.subplot(1, 2, 1)
plt.scatter(Xs[:, 0], Xs[:, 2], c=Xs)
*#plt.axis([0, 1, 0, 1])* plt.xlabel(**'Red'**)
plt.ylabel(**'Blue'**)
plt.xticks([])
plt.yticks([])
plt.title(**'Day'**)

plt.subplot(1, 2, 2)

plt.scatter(Xt[:, 0], Xt[:, 2], c=Xt)
*#plt.axis([0, 1, 0, 1])* plt.xlabel(**'Red'**)
plt.ylabel(**'Blue'**)
plt.title(**'Sunset'**)
plt.xticks([])
plt.yticks([])
plt.tight_layout()plt.show()

结果将如下所示:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

一切似乎都是为了最终在它们身上运行我们的 OT 算法而设置的。为此,我们创建了一个 Monge-Kantorovich 问题类的实例,并将其放在我们的图像上:

ot_emd = ot.da.EMDTransport()
ot_emd.fit(Xs=Xs, Xt=Xt)

请注意,我们创建了一个 ot.da.EMDTransport() 类的实例,它提供了使用 ot 进行域自适应的功能,并在调用其 fit() 方法时自动定义了均匀经验分布(每个像素是一个概率为 1/1000 的点)和成本矩阵(像素坐标向量之间的平方欧几里德距离)。我们现在可以使用耦合矩阵将一个图像“传输”到另一个图像上,如下所示:

transp_Xt_emd = ot_emd.inverse_transform(Xt=sunset)

我们刚刚调用的函数 inverse_transform() 使用重心映射将日落图像传输到白天图像:最终结果中每个传输的像素是日落图像中像素的平均值,由耦合矩阵的相应值加权。您也可以通过调用 transform(Xs=day) 反过来做同样的事情。我们现在将最终结果绘制如下:

I2t = mat2im(transp_Xt_emd, I2.shape)

plt.figure()
plt.imshow(I2t)
plt.axis(**'off'**)
plt.title(**'Color transfer'**)
plt.tight_layout()
plt.show()

并且它给出了期望的结果:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图像编辑

我们现在想做一个无缝拷贝,即通过用另一个图像的补丁替换图像的一部分来编辑图像。例如,这可以是你的脸被传送到蒙娜丽莎的画像上。要继续,我们首先需要从这个 github 库下载 poissonblending.py 文件。然后,我们将从数据文件夹中加载三个图像(您需要事先将它们放在那里),如下所示:

**import** matplotlib.pyplot **as** plt
**from** poissonblending **import** blend

img_mask = plt.imread(**'./data/me_mask_copy.png'**)
img_mask = img_mask[:,:,:3] *# remove alpha* img_source = plt.imread(**'./data/me_blend_copy.jpg'**)
img_source = img_source[:,:,:3] *# remove alpha* img_target = plt.imread(**'./data/target.png'**)
img_target = img_target[:,:,:3] *# remove alpha*

第一个图像是我的肖像,第二个图像提供了我的肖像将被复制到蒙娜丽莎的脸的区域。预处理还去除了透明度,并且只保留每个像素的 RGB 值。总体而言,它们将如下所示:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

您可以使用任何带有简单几何对象的图像编辑器来调整遮罩。

然后可以使用如下调用的 blend() 函数获得最终结果:

nbsample = 500
off = (35,-15)seamless_copy = blend(img_target, img_source, img_mask, reg=5, eta=1, nbsubsample=nbsample, offset=off, adapt=**'kernel'**)

同样,我们只对 500 个像素的子集应用 OT,因为对整个图像应用 OT 需要一些时间。该函数背后的代码涉及许多图像预处理例程,但我们特别感兴趣的是 OT 部分。这由来自poisson blending . pyadapt_Gradients_kernel()表示,它包含以下代码:

Xs, Xt = subsample(G_src,G_tgt,nb)

ot_mapping=ot.da.MappingTransport(mu=mu,eta=eta,bias=bias, max_inner_iter = 10,verbose=**True**, inner_tol=1e-06)
ot_mapping.fit(Xs=Xs,Xt=Xt)**return** ot_mapping.transform(Xs=G_src)

这里的第一行从梯度 G_src、G_tgt 中提取两个 500 像素的样本。然后, ot.da.MappingTransport() 函数学习非线性(内核化)变换,该变换近似于我们在前面的示例中使用的重心映射。你可能想知道为什么需要这样做?嗯,重心映射依赖于耦合矩阵,该矩阵仅对齐它所拟合的样本(它的形状是来自第一个分布的样本数*来自第二个分布的样本数),因此它不能用于样本外点。最后,返回使用这个近似,就像以前一样,把我的脸的渐变转移到蒙娜丽莎肖像的渐变上。最终结果由下式给出:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

作者最右边的图片。

自动翻译

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

对于最后一个应用程序,我们的目标是找到不同语言给出的两个句子中的单词之间的最佳对齐。例如,我们将使用英语命题"猫坐在垫子上"及其法语翻译" le chat est assis sur le tapis ",目标是恢复提供对应关系" “- " 聊天”,"坐在 "- " assis “和"垫子”-"tapis为此,我们需要可以通过 pip 安装的 nltk 库,如下所示:**

pip3 install nltk

我们还需要克隆下面的 github 库并遵循它的自述文件,以便下载将用于描述我们的主张的嵌入(我在这里还提供了一个快捷方式,在这里您可以直接找到所考虑的对的嵌入)。

现在让我们做一些通常的导入,并添加两个以后会用到的函数。

**import** numpy **as** np, sys, codecs
**import** ot
**import** nltk
nltk.download(**'stopwords'**) # download stopwords
nltk.download(**'punkt'**) # download punctuation 

**from** nltk **import** word_tokenize
**import** matplotlib.pyplot **as** plt

**def** load_embeddings(path, dimension):
    *"""
    Loads the embeddings from a file with word2vec format.
    The word2vec format is one line per words and its associated embedding.
    """* f = codecs.open(path, encoding=**"utf8"**).read().splitlines()
    vectors = {}
    **for** i **in** f:
        elems = i.split()
        vectors[**" "**.join(elems[:-dimension])] =  **" "**.join(elems[-dimension:])
    **return** vectors

**def** clean(embeddings_dico, corpus, vectors, language, stops, instances = 10000):
    clean_corpus, clean_vectors, keys = [], {}, []
    words_we_want = set(embeddings_dico).difference(stops)
    **for** key, doc **in** enumerate(corpus):
        clean_doc = []
        words = word_tokenize(doc*)* **for** word **in** words:
            word = word.lower()
            **if** word **in** words_we_want:
                clean_doc.append(word+**"__%s"**%language)
                clean_vectors[word+**"__%s"**%language] = np.array(vectors[word].split()).astype(np.float)
        **if** len(clean_doc) > 5 :
            keys.append(key)
        clean_corpus.append(**" "**.join(clean_doc))
    **return** clean_vectors

第一个函数用于加载嵌入内容,而第二个函数用于预处理文本以删除所有停用词和标点符号。

接下来,我们加载英语和法语语言的嵌入,如下所示:

vectors_en = load_embeddings(**"concept_net_1706.300.en"**, 300) vectors_fr = load_embeddings(**"concept_net_1706.300.fr"**, 300) 

并定义要翻译的两个命题:

en = [**"the cat sits on the mat"**]
fr = [**"le chat est assis sur le tapis"**]

现在让我们清理我们的句子如下:

clean_en = clean(set(vectors_en.keys()), en, vectors_en, **"en"**, set(nltk.corpus.stopwords.words(**"english"**)))clean_fr = clean(set(vectors_fr.keys()), fr, vectors_fr, **"fr"**, set(nltk.corpus.stopwords.words(**"french"**)))

这将只返回嵌入的有意义的单词""、"、assistapis 。现在一切都准备好了,可以使用最佳的运输方式。如上图所示,我们定义了两个经验均匀分布,并在它们之间运行 OT,成本矩阵由成对平方欧几里得距离给出。

emp_en = np.ones((len(en_emd),))/len(en_emd)
emp_fr =  np.ones((len(fr_emd),))/len(fr_emd)
M = ot.dist(en_emd,fr_emd)

coupling = ot.emd(emp_en, emp_fr, M)

一旦获得了耦合,我们现在可以用 t-SNE 找到我们的嵌入到 2d 空间的投影,然后如下绘制相应的单词及其匹配对:

np.random.seed(2) # fix the seed for visualization purpose

en_embedded = TSNE(n_components=3).fit_transform(en_emd)
fr_embedded = TSNE(n_components=3).fit_transform(fr_emd)

f, ax = plt.subplots()
plt.tick_params(top=**False**, bottom=**False**, left=**False**, right=**False**, labelleft=**False**, labelbottom=**False**)
plt.axis(**'off'**)
ax.scatter(en_embedded[:,0], en_embedded[:,1], c = **'blue'**, s = 50, marker = **'s'**)

**for** i **in** range(len(en)):
    ax.annotate(en[i], (en_embedded[i,0], en_embedded[i,1]), ha = **'right'**, va = **'bottom'**, fontsize = 30)

ax.scatter(fr_embedded[:,0], fr_embedded[:,1], c = **'red'**, s = 50, marker = **'s'**)

**for** i **in** range(len(fr)):
    ax.annotate(fr[i], (fr_embedded[i,0], fr_embedded[i,1]), va = **'top'**, fontsize = 30)

coupling /= np.max(coupling)

**for** i, j **in** enumerate(np.array(np.argmax(coupling, axis= 1)).flatten()):
    ax.plot([en_embedded[i, 0], fr_embedded[j, 0]], [en_embedded[i, 1], fr_embedded[j, 1]], c=**'k'**)

plt.show()

这给出了最终结果:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图片作者。

请注意,后面的例子可以扩展为基于 github 存储库中可用的 wikipidea 数据进行自动翻译,我们从 github 存储库中获取了初始代码。要了解更多细节,您还可以查看相应的论文和其中的结果,以进一步提高性能。

手把手的 Jupyter 笔记本黑客

原文:https://towardsdatascience.com/hands-on-jupyter-notebook-hacks-f59f313df12b?source=collection_archive---------23-----------------------

编程;编排

您应该使用的技巧、提示和快捷方式

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Toa HeftibaUnsplash 上拍摄的照片

**Table of Contents**[**Introduction**](#782f)1\. [Gist](#0756)
2\. [display() over print() for dataFrame](#ceee)
3\. [Output without print()](#1400)
4\. [Bash commands without !](#cb0f)
5\. [Other useful shortcuts](#1498)
6\. [Nbextensions](#a90b)
7\. [Move Selected Cells](#0986)
8\. [Tabnine](#03ba)
9\. [Autopep8](#3284)

介绍

在这篇短文中,我将写一些我在使用 Jupyter Notebook 时发现有用的技巧、扩展和窍门。关于 Jupyter 笔记本的写作技巧,请阅读这篇文章。

要点

要点是分享由 Github 托管的片段的简单方法。这个黑客可以让你在 Juptyer 笔记本的单元格中从你的代码中创建一个要点。

假设你有一个 Github 账号,首先,你需要安装 gist 。如果您使用的是 brew,请在您的终端中运行下面的

brew update
brew outdated
brew upgrade
brew cleanup
brew install gist

现在你需要登录 Github。

gist --login
Obtaining OAuth2 access_token from GitHub.
GitHub username: your-github-name
GitHub password: your-github-pw
2-factor auth code:
Success! https://github.com/settings/tokens

gist 将允许你从文件或剪贴板上传内容,添加文件名和描述。

将以下代码放入 Jupyter 笔记本的一个单元格中。你需要改变myfile.pymy description

%%bash
gist -P -f myfile.py -d "my description"

将你想发送给 Gist 的单元格中的代码复制到你的剪贴板上,CTRL+C/⌘C,然后运行上面的单元格就会将你的剪贴板发送给 Gist。

它返回你的要点网址。

[https://gist.github.com/b9e4b509cb6ed80631b617b53a65f0b9](https://gist.github.com/b9e4b509cb6ed80631b617b53a65f0b9)

当你想更新你的要点时,你需要使用你的本地文件名。您可以在单元格中添加以下内容,并运行它来更新要点。

%%bash
gist -u your-gist-id your-filename-with-extension

[## 如何在 Docker 上运行 Jupyter 笔记本

不再有 Python 环境和包更新

towardsdatascience.com](/how-to-run-jupyter-notebook-on-docker-7c9748ed209f) [## 使用 Jupyter 笔记本进行版本控制

Jupytext 循序渐进指南

towardsdatascience.com](/version-control-with-jupyter-notebook-b9630bc5996e)

在数据帧的打印()上显示()

IPython.display已经安装在朱庇特的笔记本上了。如果你正在打印一个项目,你不需要print()方法。如果你要打印一个以上的项目,display()将显示更好的输出。

import pandas as pd
df = pd.DataFrame(
    [
        [48,22,33,47],
        [35,36,42,27]
    ],
    index=["Male","Female"],
    columns=["Black","White","Red","Blue"])print(df)
display(df)
df

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

不打印输出()

如果你觉得懒得为所有输出键入print(),那么这是给你的。

对于 Conda 用户,您需要在一个单元格中添加以下代码。

from IPython.core.interactiveshell import InteractiveShell
InteractiveShell.ast_node_interactivity = "all"

我们来测试一下。

testvar=2
testvar
testvar

这将会回来,

2
2

如果你用 PIP 安装了 Jupyter Notebook,你可以把它作为默认设置,不需要上面的代码。请用编辑器打开~/.ipython/profile_default/ipython_config.py并粘贴以下内容。

c = get_config()
c.InteractiveShell.ast_node_interactivity = "all"

您需要重新启动 Jupyter 笔记本才能使其工作。

[## 用 Jupyter 笔记本写作的 7 个基本技巧

第一篇数据科学文章指南

towardsdatascience.com](/7-essential-tips-for-writing-with-jupyter-notebook-60972a1a8901)

Bash 命令没有!

您可以在没有!的情况下使用 bash 命令。尝试一下。您可以使用的一些示例有:

ls -al
pwd
cat Readme.md
man ls
mkdir newfolder

其他有用的快捷方式

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

nb 扩展

请在使用以下扩展之前安装 Nbextensions 。jupyter_contrib_nbextensions 包包含一组社区贡献的非官方扩展,这些扩展为 jupyter 笔记本增加了功能。

如何安装 jupyter _ contrib _ nb extensions

我用了相当多的 nb 扩展。方程式自动编号选择 CodeMirror 键图目录(2)上升。我想向您展示另外三个非常有用的扩展。

[## 如何创建一个有吸引力的泡泡图

从 Github repo 抓取数据的分步指南

towardsdatascience.com](/how-to-create-an-attractive-bubble-map-5cf452c244e9)

移动选定的单元格

请从 Nbextensions 选项卡中启用移动所选单元格进行安装。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

当你组织你的细胞时,这是非常有用的。您可以使用 Option/Alt +向上/向下移动选定的一个或多个单元格。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

泰伯宁

jupyter-tabnine 支持使用基于深度学习的编码自动完成。

让我们安装它。

pip install jupyter-tabnine
jupyter nbextension install --py jupyter_tabnine
jupyter nbextension enable --py jupyter_tabnine
jupyter serverextension enable --py jupyter_tabnine

你可能需要重启几次 Jupyter 笔记本才能工作。你可以在下面的 gif 图片中看到 Tabnine 的动作。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Autopep8

缩进的键盘快捷键是“CMD+]”表示右缩进,“CMD+[”表示左缩进。

Nbextensions Autopep8 只需点击一下鼠标,即可格式化代码单元格中的代码。

您可以使用 pip 安装它:

pip install autopep8

然后在 Nbextsions 中启用它。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Nbextensions 中的 Autopep8

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

缩进和 Autopep8 的作用

你最喜欢什么?你还有什么要分享的吗?

通过 成为 会员,可以完全访问媒体上的每一个故事。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

https://blog.codewithshin.com/subscribe

[## Jupyter 的技巧和窍门

Jupyter 技巧和提示的集合

medium.com](https://medium.com/series/jupyter-hacks-and-tips-1b1a3a10bc79) [## Jupyter 用户的生产力提示

使用 Jupyter 笔记本和 JupyterLab 让您的工作流程更加高效

towardsdatascience.com](/stepping-into-intermediate-with-jupyter-f6647aeb1184)

Python 中的动手机器学习—决策树分类

原文:https://towardsdatascience.com/hands-on-machine-learning-in-python-decision-tree-classification-eba67a37a39c?source=collection_archive---------43-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

fietzfotosPixabay 拍摄的照片

实现决策树模型的完整工作流程

作为最流行的经典机器学习算法之一,决策树在可解释性方面比其他算法更直观。今天,在本文中,我将向您展示实现决策树分类模型的整个工作流程。

机器学习任务的典型工作流程通常始于数据争论,因为我们最初获得的数据通常无法直接使用。这就是所谓的原始数据。典型的工作流程通常如下。

  1. 问题陈述
  2. 探索性数据分析
  3. 数据清理
  4. 特征工程
  5. 模特培训
  6. 模型评估

请注意,工作流程可能不是线性的。比如有时候在我们做了模型评估之后,模型的表现并不是很好,我们还有其他的想法可以尝试。然后,我们可能会回到第 3-5 步中的任何一步,应用我们的想法来改进模型。

在本文中,我将以线性方式展示这些步骤。我假设你已经知道什么是决策树,以及它是如何工作的。然而,如果没有,我写了许多文章来介绍决策树模型的直觉。如果需要的话,请在本文末尾查看它们。

1.问题陈述

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

照片由 pixel2013Pixabay 上拍摄

泰坦尼克号生存数据集在数据科学领域很有名,也被认为是 Kaggle 的“第一课”。当然,很多优秀的解都可以很好的预测存活数,事实证明决策树并不是最好的解。但是,这并不妨碍我们使用这个数据集作为例子来训练我们的决策树分类模型。

数据集可以在 Kaggle 中找到,可以免费下载。

[## 泰坦尼克号:机器从灾难中学习

从这里开始!预测泰坦尼克号上的生存并熟悉 ML 基础知识

www.kaggle.com](https://www.kaggle.com/c/titanic/data)

请注意,我们将只使用train.csvtest.csv用于提交你的预测结果,因为 Kaggle 是用于比赛目的的。gender_submission.csv与机器学习模型无关,请忽略。

数据集的说明,包括变量、训练/测试集等。可以在上面的链接中找到,还有可下载的数据集。

然而,在实践中,给定原始数据集的所有信息可能不够清楚。知道问题是“预测生存”是远远不够的。可能有必要与数据所有者和其他利益相关者召开研讨会。

相信我,阐明一个数据集不是一件容易的工作。大多数时候,我们可能不得不在没有 100%理解的情况下开始处理数据集,因为有时这是不可能的。

2.探索性数据分析

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

照片由 Julius_SilverPixabay 上拍摄

EDA 的成果并不直接用于模型训练,但也不可忽视。我们需要详细了解数据集,以便于数据清洗和特征选择。

这里我将展示一些基本的和常用的 EDA。

数据预览

在一切之前,我们通常想知道数据集是什么样子的。然而,数据集太大以至于我们无法完全打印出来的情况并不少见。有一个简单的函数head()可以预览前 5 行。

df_train.head()

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

数据剖析

Pandas 为我们提供了一个非常方便的功能来分析我们拥有的数据框架。简单调用数据框的info()函数如下。

df_train.info()

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

特征统计

检查特征的统计数据也非常重要。熊猫数据框也可以很容易地为我们做到这一点。

df_train.describe()

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

describe()功能将自动选择数字特征并为我们计算它们的统计数据。然而,如果我们也想得到这些分类的或字符串类型的特征的图片呢?我们可以在describe()函数中使用include参数,并显式传入一个对象类型列表,如下所示。

df_train.describe(include=['O'])

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

请注意,类型'O'是指字符串类型。在 Pandas 中,默认情况下,没有变量会被读取为分类变量,除非您明确要求它这样做。如果您真的有任何分类类型的列(可以在数据配置文件中找到),您还需要在列表中传递'categorical'

EDA 成果

在实践中,您可能需要为 EDA 执行更多的任务,例如绘制直方图中的特征以查看它们的分布或获取相关矩阵等等。本文将在此停止,因为它意味着向您展示在 EDA 中做什么类型的事情。

完成上述 EDA 任务后,我们发现了一些需要在数据清理阶段解决的问题。

  • AgeCabinEmbarked栏中有一些缺失的数据。
  • 在那些有缺失数据的列中,Age是数值型的,而CabinEmbarked是分类型的。
  • AgeEmbarked有很少的缺失值,而Cabin有大部分的缺失值。

3.数据清理

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

照片由 Sztrapacska74Pixabay 上拍摄

我们先来看一下Age栏。我们可以首先仔细检查是否有缺少的带有年龄的数据条目。

df_train[df_train['Age'].isna()].head()

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

有许多方法可以修复数据缺口,例如

  • 如果有任何缺失,请删除整行
  • 保持原样(对于某些类型的机器学习算法,空值会导致问题。因此,此选项将不适用)
  • 用平均值填补空白(仅适用于数值变量)
  • 用模式值填补空白(适用于数值和分类变量)
  • 定制的间隙填充算法(可能非常复杂,例如使用另一个机器学习模型来预测缺失值)

在这里,让我们采取相对简单的方法。也就是说,使用平均值填充数值列,然后使用模式填充分类值。

要用均值填充Age缺失数据,我们可以如下操作。

df_train['Age'] = df_train['Age'].fillna(df_train['Age'].mean())

对于Embarked列,我们用模式值来填充。这里我们不需要再次寻找模式,因为describe(include=['O'])已经告诉我们'S'具有最大的频率,即 889 个条目中的 644 个。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

因此,让我们使用'S'来填充Embarked列中的空值。

df_train['Embarked'] = df_train['Embarked'].fillna('S')

最后,对于Cabin栏,有超过 70%的缺失。这是绝对不能填补的。事实上,对于这样的专栏,我想暂时忽略它。换句话说,我们不会用它来进行模型训练。

4.特征工程

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

西尔维娅丽塔皮克斯拜拍摄的照片

特征工程对于训练一个机器学习模型是非常重要的一步,尤其是对于经典的机器学习算法(不是深度学习)。有时它占据了整个工作流的大部分时间,因为我们可能需要多次重新访问这个阶段来提高模型的性能。

在我们的数据集中,首先我们需要识别一些不可用或无用的特征。

  • PassengerId特性需要被拒绝,因为它没有用
  • Name功能也应该被拒绝,因为它对乘客能否幸存没有任何影响。
  • Cabin特征可以被拒绝,因为有超过 70%的缺失。
  • Ticket特性也应该被拒绝,因为它在 EDA 中没有显示任何模式。他们只是另一种“身份”。

对于其余的特性:PclassSexAgeSibSpParchFareEmbarked,它们似乎都很有用,我们应该选择它们。因为我们将使用决策树,所以如果有任何对模型没有帮助的特征,它们将不太可能被选择来分割树节点。让算法告诉我们。

因此,让我们构建我们的要素数据框和标注系列。

features = ['Pclass', 'Sex', 'Age', 'SibSp', 'Parch', 'Fare', 'Embarked']label = 'Survived'df_train_features = df_train[features]s_train_label = df_train[label]

5.模特培训

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

照片由 stevepbPixabay 上拍摄

现在,我们可以使用这些特征来训练我们的模型。然而,由于我们将使用 Sci-kit 学习库,并且其决策树算法不接受字符串类型的分类值,因此我们必须对我们的特征数据集进行一次热编码。具体来说,我们的SexEmbarked特征是字符串类型的,需要转换成数字。

编码是数据预处理中最重要的技术之一,值得另写一篇文章来介绍。因此,在本文中,我们将跳过一个热门编码的讲座。如果你不明白它是什么,你将能够在网上获得许多优秀的教程。

首先,让我们从 Sci-kit 学习库中导入 One Hot 编码器。

from sklearn.preprocessing import OneHotEncoder

初始化编码器非常容易。之后,让我们用两个分类特征来拟合编码器:SexEmbarked

encoder = OneHotEncoder()
encoded_arr = encoder.fit_transform(df_train_features[['Sex', 'Embarked']]).toarray()

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

可以看出,我们得到了一个 891×5 的矩阵,这意味着编码的特征集有 5 列。这是因为Sex特性有 2 个不同的值:femalemaleEmbarked特性有 3 个不同的值:SCQ。所以,总数是五。

我们可以通过调用编码器的categories_得到标签的顺序。

encoder.categories_

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

一旦我们知道了新要素的顺序,我们就可以使用新要素标签从编码矩阵生成数据框。

df_encoded = pd.DataFrame(encoded_arr, columns=[
    'Sex=female', 'Sex=male', 'Embarked=C', 'Embarked=Q', 'Embarked=S'
]).astype(int)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

新的编码特性集是有意义的。例如,上述数据框中的第一行显示乘客是一名男性,乘坐的是 s。

现在,我们可以将编码的要素集与原始要素数据框连接起来。不要忘记从原来的列中删除SexEmbarked列,因为它们应该被编码的新特性所取代。

df_train_features = df_train_features.drop(columns=['Sex', 'Embarked'])
df_train_features = pd.concat([df_train_features, df_encoded], axis=1)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

现在,我们可以训练我们的决策树模型。

from sklearn.tree import DecisionTreeClassifiermodel = DecisionTreeClassifier()
model.fit(df_train_features, s_train_label)

完了!

但是等等,我们的模型长什么样?通常,对于大多数机器学习算法来说,不太容易“看到”模型看起来是什么样子。然而,决策树不在其中。我们可以可视化我们的模型,看看节点是如何分裂的。

import matplotlib.pyplot as plt 
from sklearn import treefig, _ = plt.subplots(nrows=1, ncols=1, figsize=(100,50), dpi=300)
tree.plot_tree(
    model,
    feature_names=df_train_features.columns,
    filled=True
)fig.savefig('tree.png')

上面的代码将使用 Matplotlib 绘制树,并将图形保存为图像文件。建议检查图像文件中的树,因为如果您使用 Jupyter Notebook,它太大了,无法在网页中显示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这是“tree.png”图片中的一部分树。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

6.模型评估

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

奇莫诺Pixabay 上的照片

在最后阶段,但可能不是我们工作流程的结束,我们需要评估我们的模型。

评估我们的模型的最佳方式是从上面的 Kaggle 页面下载 test.csv 并预测测试数据集的存活率,然后提交它。但是,这是因为 Kaggle 是一个提供这样一个功能的竞赛平台。在实践中,我们通常需要将原始数据集分成训练数据集和测试数据集。

然而,在本文中,我想使用另一种方法来评估我们的模型,这就是交叉验证。

交叉验证的基本思想是评估模型训练方法和超参数,而不是已训练的模型。可以认为是以下步骤。

  1. 将数据集分割成大小相等的 n 个片段。
  2. 使用 n-1 个片段训练模型,剩余 1 个片段将用作测试集。
  3. 计算模型预测精度。
  4. 重复步骤 2-3,使用不同的段作为测试集,直到所有段都被评估。
  5. 获取 n 个精度数字的平均值,该值将被视为模型的得分。

我们来实施吧。

import numpy as np
from sklearn.model_selection import cross_val_scoreaccuracy_list = cross_val_score(model, df_train_features, s_train_label, cv=10)print(f'The average accuracy is {(np.mean(accuracy_list)*100).round(2)}%')

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

请注意,参数cv是提到的段数 n 。为此使用 10 是很常见的。

事实证明,结果可能并不理想。在实践中,我们可能会重新访问前面的某个阶段,看看我们是否可以重塑数据集以获得更好的结果,例如在数据清理阶段更改间隙填充机制。

摘要

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

照片由拉里莎-KPixabay 上拍摄

嗯,我要说的是,我们从交叉验证中得到的平均准确度确实不是很理想。你可以去 Kaggle 问题网页上找到其他人已经完成的其他解决方案,其中一些已经达到了非常高的准确率。

在本文中,我展示了机器学习作业的整个典型工作流程。它从问题陈述开始,如何处理数据等等,而不是像大多数其他文章一样直接跳到训练机器学习模型。虽然有太多的细节可以扩展,如 EDA 和功能工程步骤,但我希望本文展示了数据科学家将遵循的典型步骤,并为您提供一个大致的描述。

希望你喜欢阅读!

[## 通过我的推荐链接加入 Medium 克里斯托弗·陶

作为一个媒体会员,你的会员费的一部分会给你阅读的作家,你可以完全接触到每一个故事…

medium.com](https://medium.com/@qiuyujx/membership)

如果你觉得我的文章有帮助,请考虑加入 Medium 会员来支持我和成千上万的其他作者!(点击上面的链接)

其他相关作品

下面是我之前的一些介绍决策树算法的文章。如果你有兴趣,请去看看!

【ID3 算法决策树(熵)

[## 出去锻炼还是不锻炼?让数据科学来决定

决策树机器学习算法简介

towardsdatascience.com](/go-out-for-exercise-or-not-let-data-science-decide-34f8f28ce7b4)

决策树采用 C4.5 算法(信息增益比)

[## 不要像这样使用决策树

展示 ID3 中信息获取的局限性以及使用 C4.5 的优势

towardsdatascience.com](/do-not-use-decision-tree-like-this-369769d6104d)

决策树逐车算法(基尼指数)

[## 让您的决策树模型随车移动

基尼杂质——另一种决策树节点划分标准

towardsdatascience.com](/get-your-decision-tree-model-moving-by-cart-82765d59ae09)

回归问题决策树

[## 每个人都能理解机器学习——回归树模型

没有公式、方程和科学陈述回归树模型介绍

medium.com](https://medium.com/towards-artificial-intelligence/everyone-can-understand-machine-learning-regression-tree-model-28e3541b3e79)

TensorFlow 2 中的动手 NLP 深度学习模型准备。X

原文:https://towardsdatascience.com/hands-on-nlp-deep-learning-model-preparation-in-tensorflow-2-x-2e8c9f3c7633?source=collection_archive---------22-----------------------

这是一个逐步完成 NLP 模型准备流程的教程:标记化、序列填充、单词嵌入和嵌入层设置。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

NLP 模型准备步骤,(作者创建)

简介:我为什么写这篇文章

NLP 问题中的许多最先进的结果是通过使用 DL(深度学习)实现的,并且很可能您也想使用深度学习风格来解决 NLP 问题。虽然有很多资料讨论如何选择和训练“最佳”神经网络架构,如 RNN,但选择和配置合适的神经网络只是解决实际 NLP 问题的一部分。另一个重要的部分,但经常被低估,是模型准备。NLP 任务通常需要在模型准备阶段进行特殊的数据处理。换句话说,在我们将数据输入神经网络进行训练之前,还有很多事情要做。遗憾的是,没有多少教程给出模型准备的详细指导。

此外,支持最新的 NLP 理论和算法的软件包或 API 通常是最近才发布的,并且更新速度很快。(如 2015 年首次发布 TensorFlow,2016 年发布 PyTorch,2015 年发布 spaCy。)为了获得更好的性能,很多时候,你可能必须在你的深度学习管道中集成几个包,同时防止它们彼此崩溃。

这就是为什么我决定写这篇文章给你一个详细的教程。

  • 我将向您介绍从标记原始数据到配置 Tensorflow 嵌入的模型准备流程,以便您的神经网络为训练做好准备。
  • 示例代码将帮助您对模型准备步骤有一个坚实的理解。
  • 在教程中,我将选择专门研究 NLP 的流行包和 API,并建议参数默认设置,以确保您在 NLP 深度学习之旅中有一个良好的开端。

在这篇文章中可以期待什么

  • 我们将使用 TensorFlow 2 完成 NLP 模型准备流程。x 和空间。流水线中的四个主要步骤是标记化、填充、单词嵌入、嵌入层设置。
  • 将介绍动机(为什么我们需要这个)和直觉(它是如何工作的),所以如果你是 NLP 或深度学习的新手,不要担心。
  • 我将提到模型准备期间的一些常见问题和潜在的解决方案。
  • ColabGithub 上有你可以玩的笔记本。虽然我们在示例中使用了一个玩具数据集(取自 IMDB 电影评论数据集),但代码可以应用于更大、更实用的数据集。

事不宜迟,我们从第一步开始。

标记化

什么是标记化?

在 NLP 中,记号化意味着将原始文本分割成唯一的单元(也称为记号)。令牌可以是句子、短语或单词。每个令牌都有一个唯一的令牌 id。标记化的目的是我们可以使用这些标记(或标记 id)来表示原始文本。这里有一个例子。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

符号化插图,(作者创作)

标记化通常包括两个阶段:

阶段 1:创建一个令牌字典,在这个阶段,

  • 通过首先将原始文本分成句子,然后将句子分解成单词,来选择候选标记(通常是单词)。
  • 应该包括某些预处理,例如,小写,标点符号删除等。
  • 请注意,令牌应该是唯一的,并被分配给不同的令牌 id,例如,“汽车”和“汽车”是不同的令牌,“汽车”和“汽车”也是不同的令牌。所选择的令牌和相关的令牌 id 将创建一个令牌字典。

阶段 2:文本表示,在此阶段,

  • 通过参考标记字典,用标记(或相关的标记 id)表示原始文本。
  • 有时标记被部分选择用于文本表示(例如,仅选择最频繁的标记。);因此,最终的令牌化序列将只包括这样选择的令牌。

在张量流中

我们将使用一个 IMDB 电影评论数据集来演示管道。

from tensorflow.keras.preprocessing.text import Tokenizertokenizer = Tokenizer()
tokenizer.fit_on_texts(raw_text)
train_sequences = tokenizer.texts_to_sequences(raw_text) #Converting text to a vector of word indexes
word_index = tokenizer.word_index
print('Found %s unique tokens.' % len(word_index))
print('1st token-id sequnce', train_sequences[0])>>Found 212 unique tokens.
>>1st token-id sequnce [21, 4, 2, 12, 22, 23, 50, 51, 13, 2, 52, 53, 54, 24, 6, 2, 55, 56, 57, 7, 2, 58, 59, 4, 25, 60]

现在,让我们看看我们从标记化步骤中得到了什么。

令牌字典

# display the token dictionary (from most freqent to rarest)
# these are the 2 useful attributes, (get_config will show the rest)
print(tokenizer.word_index)
print(tokenizer.word_counts)
# tokenizer.get_config()>>{'the': 1, 'a': 2, 'and': 3, 'of': 4, 'to': 5, 'with': 6, 'is': 7, 'this': 8, 'by': 9, 'his': 10, 'movie': 11, 'man': 12, 'for': 13, ...
>>OrderedDict([('story', 2), ('of', 8), ('a', 11), ('man', 3), ('who', 2), ('has', 2), ('unnatural', 1), ('feelings', 1), ('for', 3), ('pig', 1), ('br', 1), ('starts', 1), ('out', 2), ('with', 6), ...

说明:

  • 记号赋予器对每个单词(记号)的数量进行计数,并根据计数对记号进行排序。例如,“the”是语料库中最频繁出现的标记,因此排在第一位,将标记 id 关联为“1”。这个排名在一本字典里有描述。我们可以使用tokenizer.word_index属性来检查失真。
  • 我们可以使用tokenizer.word_counts来检查与每个令牌相关的计数。

**重要提示:**使用 TensorFlow Tokenizer 时,0-token-id 保留给 empty-token,即 token-id 从 1 开始,

令牌标识序列

# compare the number of tokens and tokens after cut-off
train_sequences = tokenizer.texts_to_sequences(raw_text) #Converting text to a vector of word indexes
# print(len(text_to_word_sequence(raw_text[0])), len(train_sequences[0]))
print(raw_text[0])
print(text_to_word_sequence(raw_text[0]))
print()
tokenizer.num_words = None # take all the tokens
print(tokenizer.texts_to_sequences(raw_text)[0])
tokenizer.num_words = 50 # take the top 50-1 tokens
print(tokenizer.texts_to_sequences(raw_text)[0])>>Story of a man who has unnatural feelings for a pig.  <br>  Starts out with a opening scene that is a terrific example of absurd comedy. 
>>['story', 'of', 'a', 'man', 'who', 'has', 'unnatural', 'feelings', 'for', 'a', 'pig', 'br', 'starts', 'out', 'with', 'a', 'opening', 'scene', 'that', 'is', 'a', 'terrific', 'example', 'of', 'absurd', 'comedy']>>[21, 4, 2, 12, 22, 23, 50, 51, 13, 2, 52, 53, 54, 24, 6, 2, 55, 56, 57, 7, 2, 58, 59, 4, 25, 60]
>>[21, 4, 2, 12, 22, 23, 13, 2, 24, 6, 2, 7, 2, 4, 25]

说明:

  • 我们使用train_sequences = tokenizer.texts_to_sequences(raw_text)将文本转换成单词索引/id 的向量。转换后的序列将适合管道中的下一步。
  • 当有太多令牌时,存储和计算可能是昂贵的。我们可以使用num_words参数来决定使用多少标记来表示文本。在本例中,由于我们设置了参数num_words=50,这意味着我们将获取前 50-1=49 个令牌。换句话说,像“不自然:50”,“感情:51”这样的记号不会出现在最终的记号化序列中。
  • 默认情况下,num_words=None,这意味着它将带走所有的令牌。
  • 提示:您可以随时设置 num_words,而无需重新安装分词器。

**注意:**num _ words 值应该是什么,没有简单的答案。但这里是我的建议:构建一个管道,可以先从一个比较小的数字开始,比如说 num _ words = 10,000,进一步分析后再回来修改。(我发现这个堆栈溢出帖子分享了一些关于如何选择 num_words 值的见解。另外,查看标记器的文档了解其他参数设置。)

一个问题:OOV

让我们来看看对深度学习和传统 MLs 都非常有害的标记化中的一个常见问题,以及我们如何处理它。考虑下面的例子,来标记这个序列[《一个女人的故事……']。

test_sequence = ['Storys of a woman...'] 
print(test_sequence)
print(text_to_word_sequence(test_sequence[0]))
print(tokenizer.texts_to_sequences(test_sequence))>>['Storys of a woman...']
>>['storys', 'of', 'a', 'woman']
>>[[4, 2]]

由于用于训练的语料库不包括单词“storys”或“woman ”,这些单词也不包括在令牌字典中。这是 OOV 词汇之外的问题。虽然 OOV 是难以避免的,但有一些解决方案可以缓解这些问题:

  • 一个经验法则是在一个相对大的语料库上训练,以便创建的字典可以覆盖更多的单词,因此不要认为它们是可以丢弃的新单词。
  • 设置参数oov_token=捕捉 OOV 现象。注意,这个方法只通知你 OOV 在某个地方发生了,但它不能解决 OOV 问题。查看 Kerras 文档了解更多详情。
  • 在标记化之前执行文本预处理。例如,“storys”可以被拼写纠正或用信号表示为“story ”,其被包括在令牌字典中。有一些 NLP 包为标记化和预处理提供了更健壮的算法。一些好的记号化选项有 spaCyGensim
  • 采用(并微调)一个预训练的记号赋予器(或变压器),例如 Huggingface 的预训练记号赋予器

简短讨论:艰难的开始?

记号化的想法可能看起来非常简单,但是迟早,你会意识到记号化可能比这个例子中看起来要复杂得多。复杂度主要来源于各种预处理方法。预处理的一些常见做法是小写、删除标点、单词单数化、词干化词条化。此外,我们还有可选的预处理步骤,如测试标准化(例如,数字到文本,扩展缩写)、语言识别代码混合和翻译;以及高级预处理,如词性标注(也称为词性标注)、解析共指消解。取决于采取什么预处理步骤,标记可以不同,因此标记化的文本也不同。

如果你不知道上面这些令人困惑的名字,也不用担心。事实上,确定在 NLP 管道中包含哪种预处理方法是非常困难的。例如,决定在文本表示中包含哪些标记并不容易。整合大量的候选记号是存储和计算昂贵的。还不清楚哪个标记更重要:最常出现的单词如“the”、“a”对于文本表示来说信息不多,这就是为什么我们需要在预处理中处理停用词

尽管可以说,我们在这里有一个好消息:深度学习比传统的机器学习算法需要相对较少的预处理。原因是深度学习可以利用传统 ML 模型在预处理和特征工程阶段执行的特征提取的神经网络架构。因此,这里我们可以保持标记化步骤简单,如果需要更多的预处理和/或后处理,稍后再回来。

标记化翘曲

虽然大多数深度学习教程仍然使用 list 或 np.array 来存储数据,但我发现使用 DataFrame(例如,Pandas 或 PySpark)来完成工作更加可控和可伸缩。这一步是可选的,但我建议您这样做。下面是示例代码。

# store in dataframe
df_text = pd.DataFrame({'raw_text': raw_text})
df_text.head()# updata df_text
df_text['train_sequence'] = df_text.raw_text.apply(lambda x: tokenizer.texts_to_sequences([x])[0])
df_text.head()>>																				raw_text	               train_sequence
0	Story of a man who has unnatural feelings for ...	[21, 4, 2, 12, 22, 23, 13, 2, 24, 6, 2, 7, 2, ...
1	A formal orchestra audience is turned into an ...	[2, 26, 7, 27, 14, 9, 1, 4, 28]
2	Unfortunately it stays absurd the WHOLE time w...	[15, 25, 1, 29, 6, 15, 30]
3	Even those from the era should be turned off. ...	[1, 16, 17, 27, 30, 1, 5, 2]
4	On a technical level it's better than you migh...	[31, 2, 28, 6, 32, 9, 33]

这就是你需要了解的记号化。让我们进入下一步:填充。

填料

大多数(如果不是全部)神经网络要求输入序列数据具有相同的长度,这就是为什么我们需要填充:将序列截断或填充(通常用 0 填充)成相同的长度。这是一个填充的例子。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

填充插图,(作者创作)

让我们看看下面的示例代码,在 TensorFlow 中执行填充。

from tensorflow.keras.preprocessing.sequence import pad_sequences# before padding
print(type(train_sequences))
train_sequences
>> <class 'list'>
>>  [[21, 4, 2, 12, 22, 23, 13, 2, 24, 6, 2, 7, 2, 4, 25],
		 [2, 26, 7, 27, 14, 9, 1, 4, 28],
		 [15, 25, 1, 29, 6, 15, 30],
		 [1, 16, 17, 27, 30, 1, 5, 2],
		 [31, 2, 28, 6, 32, 9, 33],
		...MAX_SEQUENCE_LENGTH = 10 # length of the sequence
trainvalid_data_pre = pad_sequences(train_sequences, maxlen=MAX_SEQUENCE_LENGTH, 
                                padding='pre',
                                truncating='pre',)
trainvalid_data_pre>>array([[23, 13,  2, 24,  6,  2,  7,  2,  4, 25],
	       [ 0,  2, 26,  7, 27, 14,  9,  1,  4, 28],
	       [ 0,  0,  0, 15, 25,  1, 29,  6, 15, 30],
	       [ 0,  0,  1, 16, 17, 27, 30,  1,  5,  2],
	       [ 0,  0,  0, 31,  2, 28,  6, 32,  9, 33],
	   ...

解说:

  • 在填充之前,令牌表示的序列具有不同的长度;填充后都是一样长的。
  • 参数“maxlen”定义了填充序列的长度。当标记化序列的长度大于“maxlen”时,“maxlen”之后的序列的标记将被截断;当标记化序列的长度小于“maxlen”时,将用“0”填充。
  • 截断和填充序列的位置分别由“padding=”和“truncating=”确定。

讨论和提示

前置还是后置?

默认情况下,pad_sequences 参数设置为 padding='pre ',truncating='pre '。然而,根据 TensorFlow 文档,建议“在处理 RNN 图层时使用‘后’填充”。(建议在英文中,最重要的信息出现在开头。所以截断或填充后的序列能更好地代表原文。)下面是示例代码。

MAX_SEQUENCE_LENGTH = 10
trainvalid_data_post = pad_sequences(train_sequences, maxlen=MAX_SEQUENCE_LENGTH, 
                                padding='post',
                                truncating='post',)
trainvalid_data_post
>>array([[21,  4,  2, 12, 22, 23, 13,  2, 24,  6],
	       [ 2, 26,  7, 27, 14,  9,  1,  4, 28,  0],
	       [15, 25,  1, 29,  6, 15, 30,  0,  0,  0],
	       [ 1, 16, 17, 27, 30,  1,  5,  2,  0,  0],
	       [31,  2, 28,  6, 32,  9, 33,  0,  0,  0],
	     ...

关于马克伦。

另一个问题是,maxlen 值应该是多少。这里的折衷是,较大的 maxlen 值会导致序列保留更多的信息,但会占用更多的存储空间和更大的计算开销,而较小的 maxlen 值可以节省存储空间,但会导致信息丢失。

  • 在管道构建阶段,我们可以选择均值或中值作为 maxlen。当序列的长度变化不大时,它工作得很好。
  • 如果序列的长度在很大的范围内变化,那么这是一个个案的决定,一些试错法是可取的。例如,对于 RNN 体系结构,我们可以选择更高端的 maxlen 值(即,大 maxlen ),并利用屏蔽(我们将在后面看到屏蔽)来减少存储和计算浪费。请注意,如果处理不当,用 0 填充序列会给模型带来噪声。使用非常大的 maxlen 值不是一个好主意。如果你不确定使用什么样的神经网络结构,最好坚持使用无填充序列的平均值或中值。

由于我们将令牌序列数据存储在数据帧中,因此获取序列长度统计数据非常简单,下面是示例代码:

# ckeck sequence_length stats
df_text.train_sequence.apply(lambda x: len(x))
print('sequence_length mean: ', df_text.train_sequence.apply(lambda x: len(x)).mean())
print('sequence_length median: ', df_text.train_sequence.apply(lambda x: len(x)).median())>> sequence_length mean:  9.222222222222221
>> sequence_length median:  8.5

序列填充应该很容易。让我们进入下一步,准备 word2vec 单词嵌入。

Word2vec 单词嵌入

直觉

单词嵌入在人类对语言的理解和机器之间架起了一座桥梁。这对于许多 NLP 问题是必不可少的。你可能听说过“ word2vec ”、“ GloVe ”和“ FastText ”这些名字。

如果您不熟悉单词嵌入,也不用担心。我简单介绍一下单词嵌入应该能提供足够的直觉,在 TensorFlow 中应用单词嵌入。

首先,让我们了解一些关键概念:

嵌入:对于语料库中的词集,嵌入是来自分布式表示的向量空间到来自分布式表示的向量空间之间的映射。

**向量语义:**这是指一组 NLP 方法,旨在基于大型语料库中单词的分布属性来学习单词表示。

让我们看看一些使用 spaCy 预训练嵌入模型的可靠示例。

import spacy
# if first use, download en_core_web_sm
nlp_sm = spacy.load("en_core_web_sm")
nlp_md = spacy.load("en_core_web_md")
# nlp_lg = spacy.load("en_core_web_lg")doc = nlp_sm("elephant")
print(doc.vector.size)
doc.vector
>>96
>>array([ 1.5506991 , -1.0745661 ,  1.9747349 , -1.0160941 ,  0.90996253,
	       -0.73704714,  1.465313  ,  0.806101  , -4.716807  ,  3.5754416 ,
	        1.0041305 , -0.86196965, -1.4205945 , -0.9292773 ,  2.1418033 ,
	        0.84281194,  1.4268254 ,  2.9627366 , -0.9015219 ,  2.846716  ,
	        1.1348789 , -0.1520077 , -0.15381837, -0.6398335 ,  0.36527258,
	...

解说:

  • 使用 spaCy(一个著名的 NLP 包)将单词“elephant”嵌入到一个 96 维向量中。
  • 基于要加载的模型,向量将具有不同的维度。(例如“en_core_web_sm”、“en_core_web_md”和“en_core_web_lg”的维数分别为 96、300 和 300。)

现在“大象”这个词已经用向量来表示了,那又如何?不要看别处。一些奇迹即将发生。🧙🏼‍♂️

因为我们可以用向量来表示单词,所以我们可以计算单词之间的相似度(或距离)。考虑下面的代码。

# demo1
word1 = "elephant"; word2 = "big"
print("similariy {}-{}: {}".format(word1, word2, nlp_md(word1).similarity(nlp_md(word2))) )
word1 = "mouse"; word2 = "big"
print("similariy {}-{}: {}".format(word1, word2, nlp_md(word1).similarity(nlp_md(word2))) )
word1 = "mouse"; word2 = "small"
print("similariy {}-{}: {}".format(word1, word2, nlp_md(word1).similarity(nlp_md(word2))) )>>similariy elephant-big: 0.3589780131997766
>>similariy mouse-big: 0.17815787869074504
>>similariy mouse-small: 0.32656001719452826# demo2
word1 = "elephant"; word2 = "rock"
print("similariy {}-{}: {}".format(word1, word2, nlp_md(word1).similarity(nlp_md(word2))) )
word1 = "mouse"; word2 = "elephant"
print("similariy {}-{}: {}".format(word1, word2, nlp_md(word1).similarity(nlp_md(word2))) )
word1 = "mouse"; word2 = "rock"
print("similariy {}-{}: {}".format(word1, word2, nlp_md(word1).similarity(nlp_md(word2))) )
word1 = "mouse"; word2 = "pebble"
print("similariy {}-{}: {}".format(word1, word2, nlp_md(word1).similarity(nlp_md(word2))) )>>similariy elephant-rock: 0.23465476998562218
>>similariy mouse-elephant: 0.3079661539409069
>>similariy mouse-rock: 0.11835070985447328
>>similariy mouse-pebble: 0.18301520085660278

评论:

  • 在测试 1 中:“大象”比“老鼠”更像“大”;而“老鼠”更类似于“小”,而不是“大象”更类似于“小”。当提到大象和老鼠的通常尺寸时,这符合我们的常识。
  • 在测试 2 中:“大象”与“岩石”的相似度低于“大象”本身与“老鼠”的相似度;同样,“老鼠”与“岩石”的相似程度,不如“老鼠”本身与“大象”的相似程度。这大概可以解释为“大象”和“老鼠”都是动物,而“石头”没有生命。
  • test2 中的向量不仅表示活性的概念,还表示大小的概念:单词“rock”通常用于描述大小更接近于大象和老鼠的物体,因此“rock”更类似于“大象”而不是“老鼠”。同样,“pebble”通常用来形容比“rock”小的东西;因此,“卵石”和“老鼠”之间的相似性大于“岩石”和“老鼠”。
  • 请注意,单词之间的相似性可能并不总是与你头脑中的相似性相匹配。一个原因是相似性只是一个度量(即标量)来表示两个向量之间的关系;当相似性将高维向量压缩成标量时,那么多信息都丢失了。同样,一个词可以有几个意思。例如,单词 bank 可以与金融或河流相关;没有背景,很难说我们在谈论什么样的银行。毕竟,语言是一个可以解释的概念。

不要掉进兔子洞

Word2Vec 非常强大,是一个相当新的概念(Word2vec 是 2013 年创建并发布的)。有太多的东西要谈,比如

  • 你可能想知道向量中的值是如何分配的。什么是跳格?CBOW 是什么?
  • 还有其他的单词嵌入模型,像“ GloVe ”和“ FastText ”。有什么区别?我们应该使用哪一个?

单词嵌入是一个非常激动人心的话题,但是不要卡在这里。对于不熟悉单词嵌入的读者来说,最重要的是理解

  • 单词嵌入的作用:将单词转换成向量。
  • 为什么我们需要这些嵌入向量:这样一台机器就可以做令人惊奇的事情;计算单词间的相似度是其中之一,但绝对不止这些。
  • OOV 仍然是单词嵌入的一个问题。考虑以下代码:
print(nlp_md("elephan")[0].has_vector)
print(nlp_md("elephan")[0].is_oov)
nlp_md("elephan").vector>>False
>>True
>>array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
	       0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
....

由于单词“elephan”在我们之前加载的 spaCy“en _ core _ web _ MD”模型中不存在,spaCy 返回一个 0 向量。再说一次,治疗 OOV 不是一项简单的任务。但是我们可以使用.has_vector.is_oov来捕捉 OOV 现象。

希望您现在对单词嵌入有了很好的理解。让我们回到主轨道,看看我们如何在管道中应用单词嵌入。

采用预先训练的单词嵌入模型

预训练的单词嵌入是在一个任务中学习的嵌入,用于解决另一个类似的任务。预先训练的单词嵌入模型也称为变换器。使用预先训练好的单词嵌入模型可以省去我们从头训练一个的麻烦。此外,预先训练的嵌入向量从大数据集生成的事实通常导致更强的生成能力。

应用预先训练的单词嵌入模型有点像在字典中搜索,我们已经在前面使用 spaCy 看到了这样的过程。(例如,输入单词“大象”, spaCy 返回一个嵌入向量。)在这一步的最后,我们将创建一个“嵌入矩阵”,其中嵌入向量与每个令牌相关联。(嵌入矩阵是 TensorFlow 将用来连接令牌序列和单词嵌入表示的矩阵。)

这是代码。

# import pandas as pd
# nlp_sm = spacy.load("en_core_web_sm")
df_index_word = pd.Series(tokenizer.index_word)
# df_index_word
df_index_word_valid = df_index_word[:MAX_NUM_TOKENS-1]
df_index_word_valid = pd.Series(["place_holder"]).append(df_index_word_valid)
df_index_word_valid = df_index_word_valid.reset_index()
# df_index_word_valid.head()
df_index_word_valid.columns = ['token_id', 'token']
# df_index_word_valid.head()
df_index_word_valid['word2vec'] = df_index_word_valid.token.apply(lambda x: nlp_sm(x).vector)
df_index_word_valid['is_oov'] = df_index_word_valid.token.apply(lambda x: nlp_sm(x)[0].is_oov)
df_index_word_valid.at[0, "word2vec"] = np.zeros_like(df_index_word_valid.at[0, "word2vec"])
print(df_index_word_valid.head())>>
		token_id token                                           word2vec  is_oov
0         0   NAN  [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...    True
1         1   the  [-1.3546131, -1.7212939, 1.7044731, -2.8054314...    True
2         2     a  [-1.9769197, -1.5778058, 0.116705105, -2.46210...    True
3         3   and  [-2.8375597, 0.8632377, -0.69991976, -0.508865...    True
4         4    of  [-2.7217283, -2.1163979, -0.88265955, -0.72048...    True# Embbeding matrix
embedding_matrix = np.array([vec for vec in df_index_word_valid.word2vec.values])
embedding_matrix[1:3]print(embedding_matrix.shape)
>>(50, 96)

解释:

  • 我们首先使用 spaCy 来寻找与每个令牌相关联的嵌入向量(存储在数据帧中)。经过一些数据角力,我们创建了一个嵌入矩阵(采用 TensorFlow 约定,这次存储在 np.array 中)。
  • 嵌入矩阵的行数:总行数为 50,第一行包含一个表示空标记的零向量,其余 50–1 个标记是在标记化步骤中选择的标记。(很快,你就会明白为什么我们在下一节课设置嵌入层的时候要在第一行放一个零向量。)
  • 嵌入矩阵的列数:word2vec 维数为 96(使用“en_core_web_sm”时),所以列数为 96。

这里我们有形状为(50,96)的嵌入矩阵(即 2-d 数组)。该嵌入矩阵将在该 NLP 模型准备流水线的最后一步中被馈入 TensorFlow 嵌入层。

注意:您可能会注意到所有的 is_oov 值都是 True。但是你仍然会得到非零的嵌入向量。使用 spaCy“en _ core _ web _ sm”模型会发生这种情况。

小贴士:如何看待单词嵌入中的 OOV

与“en_core_web_md”在令牌不在嵌入模型中时返回零向量不同,“en_core_web_sm”的工作方式将使其总是返回一些非零向量。然而,根据 spaCy 纪录片,“en_core_web_sm”返回的向量并不像“en_core_web_md”或“en_core_web_lg”那样“精确”。

取决于应用,您可以决定选择“不太精确”的嵌入模型,但总是给出非零向量或模型返回“更精确”的向量,但有时在看到 oov 时是零向量。

在演示中,我选择了“en_core_web_sm”模型,它总是给我一些非零的嵌入向量。一种策略可以是在训练期间使用为子词片段学习的向量,类似于人们通常可以从熟悉的词根中找出单词的要点。有些人把这种策略称为“不精确总比什么都没有好”。(虽然我不确定 spaCy 如何给 OOVs 分配非零值。)

最后,嵌入层设置

到目前为止,我们有填充的标记序列来表示原始文本数据。此外,我们还创建了一个嵌入矩阵,每行都与令牌相关联。现在是时候设置 TensorFlow 嵌入层了。

下图总结了嵌入层机制。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

嵌入层插图,(作者创作)

解说:

嵌入层通过嵌入矩阵(作为权重)在标记序列(作为输入)和单词嵌入表示(作为输出)之间建立桥梁。

  • 嵌入层的输入:填充后的序列作为嵌入层的输入送入;填充序列的每个位置被指定给一个令牌 id。
  • 嵌入层的权重:通过查找嵌入矩阵,嵌入层可以找到与 token-id 相关联的单词(令牌)的 word2vec 表示。注意,填充序列使用零来指示空的令牌,从而产生零嵌入向量。这就是为什么我们在嵌入矩阵中为空令牌保存了第一行。
  • 嵌入层的输出:在遍历输入的填充序列后,嵌入层用代表向量(word2vec)“替换”token-id,并输出嵌入序列。

**注意:**现代 NLP 特征提取的关键:**如果一切正常,嵌入层的输出应该很好地代表原始文本,所有特征都存储在单词嵌入权重中;这是现代自然语言处理特征提取的核心思想。**你很快就会看到,我们可以通过为嵌入层设置 trainable = True 来微调这个权重。

还要注意,在这个例子中,我们将空令牌的 word2vec 显式指定为零,只是为了进行演示。事实上,一旦嵌入层看到 0-token-id,它将立即为该位置分配一个零向量,而无需查看嵌入矩阵。

在张量流中

以下示例代码显示了如何在 TensorFlow 中完成嵌入,

from tensorflow.keras.initializers import Constant
from tensorflow.keras.layers import Embedding# MAX_NUM_TOKENS = 50
EMBEDDING_DIM = embedding_matrix.shape[1]
# MAX_SEQUENCE_LENGTH = 10
embedding_layer = Embedding(input_dim=MAX_NUM_TOKENS,
                            output_dim=EMBEDDING_DIM,
                            embeddings_initializer=Constant(embedding_matrix),
                            input_length=MAX_SEQUENCE_LENGTH,
														mask_zero=True,
                            trainable=False)

解说:

  • 与维度相关的参数是“输入尺寸”、“输出尺寸”和“输入长度”。通过参考图示,您应该对如何设置这些参数有很好的直觉。
  • 在使用预先训练好的单词嵌入模型时,我们需要使用tensor flow . keras . initializer . constant将嵌入矩阵馈入一个嵌入层。否则,嵌入层的权重将用一些随机数初始化,称为“从零开始训练单词嵌入”。
  • trainable=在本例中设置为 False,这样在神经网络训练过程中 word2vec 的权重不会改变。这有助于防止过度拟合,尤其是在相对较小的数据集上训练时。但如果你想微调权重,你知道该怎么做。(设置trainable=True
  • mask_zero=是你应该注意的另一个论点。掩膜是一种告知序列处理层输入中的某些位置缺失的方式,因此在处理数据时应该跳过。通过设置参数mask_zero=True,不仅加快了训练速度,而且更好地再现了原文。

我们可以使用一个测试用例来检查嵌入层的输出。嵌入层的输出张量的形状应该是[num_sequence,padded_sequence_length,embedding_vector_dim]。

# output
embedding_output = embedding_layer(trainvalid_data_post)
# result = embedding_layer(inputs=trainvalid_data_post[0])
embedding_output.shape>>TensorShape([18, 10, 96])# check if tokens and embedding vectors mathch
print(trainvalid_data_post[1])
embedding_output[1]>>[21  4  2 12 22 23 13  2 24  6]
>><tf.Tensor: shape=(10, 96), dtype=float32, numpy=
array([[-1.97691965e+00, -1.57780576e+00,  1.16705105e-01,
        -2.46210432e+00,  1.27643692e+00,  4.56989884e-01,
         ...
			[ 2.83787537e+00,  1.16508913e+00,  1.27923262e+00,
        -1.44432998e+00, -7.07145482e-02, -1.63411784e+00,
				 ...

仅此而已。您已经准备好训练您的文本数据。(您可以参考笔记本,查看使用 RNN 和 CNN 的培训。)

摘要

为 NLP 深度学习准备数据,我们经历了很长的路。使用以下清单来测试您的理解程度:

**记号化:**在语料库上进行训练,创建记号字典,并参照创建的记号字典,用记号(或记号-id)表示原文。在 TensorFlow 中,我们可以使用 Tokenizer 进行标记化。

  • 在标记化过程中通常需要预处理。虽然使用 Tensorflow 的令牌化器及其默认设置有助于启动管道,但几乎总是建议在令牌化期间执行高级预处理和/或后处理。
  • 词汇外(OOV)是标记化的一个常见问题。潜在的解决方案包括在更大的语料库上训练或使用预先训练的标记器。
  • 在 TensorFlow 约定中,0-token-id 保留给空令牌,而其他 NLP 包可能会将令牌分配给 0-token-id。小心这种冲突,如果需要的话,调整令牌 id 命名。

**填充:**将序列填充或截断至相同长度,即填充后的序列具有相同数量的标记(包括空标记)。在 TensorFlow 中,我们可以使用 pad_sequences 进行填充。

  • 对于 RNN 体系结构,建议在(设置为“post”)之后填充和截断序列。
  • 填充序列长度可以设置为填充(或截断)前序列的平均值或中值。

**单词嵌入:**可以通过参考嵌入模型,例如 word2vec,将记号映射到向量。嵌入向量拥有人类和机器都能理解的信息。我们可以使用 spaCy“en _ core _ web _ sm”、“en_core_web_md”或“en_core_web_lg”进行单词嵌入。

  • 使用预先训练的单词嵌入模型是一个好的开始。不需要找到“完美的”预训练单词嵌入模型;首先,就拿一个。由于 Tensorflow 还没有 word embeddings API,所以选择一个可以在深度学习管道中轻松应用的包。在此阶段,构建管道比实现更好的性能更重要。
  • 对于使用预训练模型的单词嵌入,OOV 也是一个问题。处理 OOV 的一个潜在解决方案是通过使用在训练期间为子词片段学习的向量。如果可能的话,这种“猜测”通常比使用零向量来预测 oov 给出更好的结果,因为零向量会给模型带来噪声。

**TensorFlow 中的嵌入层:**为了利用预训练的单词嵌入,tensor flow 中的嵌入层的输入包括由 token-id 表示的填充序列,以及存储与填充序列内的令牌相关联的嵌入向量的嵌入矩阵。输出是一个三维张量,其形状为[数字序列,填充序列长度,嵌入向量尺寸]。

  • 嵌入层有许多参数设置。使用玩具数据集来确保嵌入图层的行为符合您的理解。应该特别注意输入和输出张量的形状。
  • 我们可以通过设置 trainable = True 来微调嵌入矩阵。
  • 通过设置 mask_zero=True,可以加快训练速度。此外,它更好地再现了原文,尤其是在使用 RNN 式建筑的时候。例如,机器将跳过零数据,并且无论如何都将相关重量保持为 0,即使 trainable = True。

如果你还没有检查过笔记本,这里有链接:

[## TF _ NLP _ tokenizer _ embedding . ipynb

合作笔记本

drive.google.com](https://drive.google.com/file/d/1E7l_XJ1HnhaGXwUo4jpYv5WZwmULqU92/view?usp=sharing)

我希望你喜欢这篇文章。下次见。

参考:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值