深度学习的分类变量编码的3种方法

像 Keras 中的机器学习和深度学习模型一样,需要所有输入和输出变量都是数值型。

这意味着,如果你的数据包含分类数据,你必须先将其编码为数字,然后才能拟合和评估模型。

最流行的两种技术是整数编码独热编码,尽管一种称为学习嵌入的新技术可能在这两种方法之间提供一个有用的折衷。

在本教程中,你将学习如何在 Keras 中开发神经网络模型时对分类数据进行编码。

完成本教程后,您将了解:

  • 在机器学习和深度学习模型中使用分类数据的挑战。
  • 如何对分类变量进行整数编码和独热编码以用于建模。
  • 如何学习作为神经网络一部分的分类变量的分布式表示。

开始你的项目,阅读我的新书《Python 深度学习》,其中包含分步教程和所有示例的Python 源代码文件。

让我们开始吧。

How to Encode Categorical Data for Deep Learning in Keras

如何为 Keras 中的深度学习编码分类数据
照片由 Ken Dixon 拍摄,部分权利保留。

教程概述

本教程分为五个部分;它们是:

  1. 分类数据的挑战
  2. 乳腺癌分类数据集
  3. 如何对分类数据进行序数编码
  4. 如何对分类数据进行独热编码
  5. 如何为分类数据使用学习嵌入

分类数据的挑战

分类变量是其值取标签值的变量。

例如,变量可以是“颜色”,其值可以是“红色”、“绿色”和“蓝色”。

有时,分类数据在类别之间可能具有顺序关系,例如“第一”、“第二”和“第三”。这种类型的分类数据称为序数数据,额外的排序信息可能很有用。

机器学习算法和深度学习神经网络要求输入和输出变量为数字。

这意味着在我们可以使用分类数据来拟合和评估模型之前,必须先将其编码为数字。

有许多方法可以为建模编码分类变量,尽管最常见的三个方法如下:

  1. 整数编码:将每个唯一标签映射到一个整数。
  2. 独热编码:将每个标签映射到一个二进制向量。
  3. 学习嵌入:学习类别的分布式表示。

我们将仔细研究如何使用这些方法之一,在 Keras 中为深度学习神经网络的训练编码分类数据。

乳腺癌分类数据集

作为本教程的基础,我们将使用所谓的“乳腺癌”数据集,该数据集自 20 世纪 80 年代以来已被机器学习广泛研究。

该数据集将乳腺癌患者数据分类为复发或未复发。共有286个样本和9个输入变量。这是一个二元分类问题。

在此数据集上合理的分类准确率在 68% 到 73% 之间。我们的目标是达到这个范围,但请注意,本教程中的模型并未进行优化:它们旨在演示编码方案

你可以下载数据集并将文件保存为“breast-cancer.csv”,放在当前工作目录中。

查看数据,我们可以看到所有九个输入变量都是分类变量。

具体来说,所有变量都是带引号的字符串;有些是序数,有些不是。

我们可以使用 Pandas 库将此数据集加载到内存中。

加载后,我们可以将列分为输入(X)和输出(y)用于建模。

最后,我们可以将输入数据中的所有字段强制转换为字符串,以防 Pandas 尝试自动将某些字段映射为数字(它确实会尝试)。

我们还可以将目标变量重塑为一列(例如 2D 形状)。

我们可以将所有这些内容整合到一个有用的函数中,以便以后重复使用。

加载后,我们可以将数据分为训练集和测试集,以便我们可以拟合和评估深度学习模型。

我们将使用 scikit-learn 的 train_test_split() 函数,并使用 67% 的数据进行训练,33% 的数据进行测试。

将所有这些元素结合起来,加载、分割和汇总原始分类数据集的完整示例列在下面。

运行示例报告了训练集和测试集的输入和输出元素的尺寸。

我们可以看到,我们有 191 个训练样本和 95 个测试样本。

现在我们熟悉了数据集,接下来看看如何将其编码以进行建模。

如何对分类数据进行序数编码

序数编码涉及将每个唯一标签映射到一个整数值。

因此,它有时也被称为整数编码。

这种类型的编码实际上只适用于类别之间存在已知关系的情况。

这种关系确实存在于数据集中的某些变量中,理想情况下,在准备数据时应加以利用。

在这种情况下,我们将忽略任何可能存在的序数关系,并假设所有变量都是分类的。使用序数编码,至少作为与其他编码方案的参考点,仍然很有帮助。

我们可以使用 scikit-learn 的 OrdinalEncoder() 将每个变量编码为整数。这是一个灵活的类,如果知道任何类别顺序,它允许将类别顺序指定为参数。

注意:我将留给您一项练习,以更新下面的示例,尝试为具有自然顺序的变量指定顺序,看看它是否会对模型性能产生影响。

编码变量的最佳实践是,在训练数据集上拟合编码,然后将其应用于训练集和测试集。

下面的函数名为 prepare_inputs(),它接受训练集和测试集的输入数据,并使用序数编码对其进行编码。

我们也需要准备目标变量。

这是一个二元分类问题,因此我们需要将两个类别标签映射为 0 和 1。

这是一种序数编码,scikit-learn 提供了 LabelEncoder 类,专门用于此目的。我们也可以使用 OrdinalEncoder 并获得相同的结果,尽管 LabelEncoder 是为编码单个变量而设计的。

prepare_targets() 函数对训练集和测试集的输出数据进行整数编码。

我们可以调用这些函数来准备我们的数据。

我们现在可以定义一个神经网络模型。

我们将在这所有示例中使用相同的通用模型。具体来说,一个具有一个隐藏层(10 个节点)和一个输出层(用于进行二元分类)的多层感知器(MLP)神经网络。

在不详细介绍的情况下,下面的代码定义了模型,在训练数据集上对其进行拟合,然后在测试数据集上对其进行评估。

如果你是 Keras 神经网络开发的初学者,我推荐这篇教程。

将所有这些结合起来,下面列出了使用序数编码准备数据并对数据进行神经网络拟合和评估的完整示例。

运行该示例将在任何现代硬件上(无需 GPU)仅需几秒钟即可拟合模型。

每个训练 epoch 结束时都会报告模型的损失和准确率,最后会报告模型在测试数据集上的准确率。

注意:由于算法或评估过程的随机性,或数值精度的差异,您的结果可能会有所不同。考虑运行示例几次并比较平均结果。

在这种情况下,我们可以看到模型在测试数据集上达到了约 70% 的准确率。

考虑到输入变量中只有一部分存在序数关系,并且对于那些存在的变量,编码时并未遵循该关系,这已经很不错了。

这为处理分类数据提供了一个良好的起点。

一种更好、更通用的方法是使用独热编码。

如何对分类数据进行独热编码

独热编码适用于类别之间不存在关系的分类数据。

它包括用一个二进制向量表示每个分类变量,该向量为每个唯一标签有一个元素,并将类别标签标记为 1,所有其他元素标记为 0。

例如,如果我们的变量是“颜色”,标签是“红色”、“绿色”和“蓝色”,我们将分别将这些标签编码为三个元素的二进制向量,如下所示:

  • 红色:[1, 0, 0]
  • 绿色:[0, 1, 0]
  • 蓝色:[0, 0, 1]

然后,数据集中的每个标签都将被一个向量替换(一列变为三列)。这是对所有分类变量执行的,因此对于乳腺癌数据集,我们的九个输入变量或列将变为 43 个。

scikit-learn 库提供了 OneHotEncoder 来自动对一个或多个变量进行独热编码。

下面的 prepare_inputs() 函数提供了上一个部分示例的即插即用替换函数。它使用 OneHotEncoder,而不是 OrdinalEncoder

将这一点结合起来,下面列出了对乳腺癌分类数据集进行独热编码并在神经网络上进行建模的完整示例。

该示例对输入分类数据进行独热编码,并像上一节一样对目标变量进行标签编码。然后,在准备好的数据集上拟合相同的神经网络模型。

注意:由于算法或评估过程的随机性,或数值精度的差异,您的结果可能会有所不同。考虑运行示例几次并比较平均结果。

在这种情况下,模型表现相当不错,准确率约为 72%,接近上一节的水平。

更公平的比较是运行每个配置 10 或 30 次,并使用平均准确率进行比较。请记住,在本教程中,我们更关注如何对分类数据进行编码,而不是在此特定数据集上获得最佳分数。

序数编码和独热编码可能是最流行的两种方法。

一种较新的技术类似于独热编码,专为神经网络设计,称为学习嵌入。

如何为分类数据使用学习嵌入

学习嵌入,或简称“嵌入”,是分类数据的分布式表示。

每个类别都被映射到一个不同的向量,并且在训练神经网络时,向量的属性会被调整或学习。向量空间提供了类别的投影,允许那些接近或相关的类别自然地聚集在一起。

这既提供了序数关系的优点(允许从数据中学习任何此类关系),又提供了独热编码的优点(为每个类别提供向量表示)。与独热编码不同,输入向量不是稀疏的(没有很多零)。缺点是它需要作为模型的一部分进行学习,并且创建更多的输入变量(列)。

该技术最初是为了提供词语的分布式表示而开发的,例如允许相似的词语具有相似的向量表示。因此,该技术通常被称为词嵌入,而在文本数据的情况下,已经开发出独立于神经网络学习表示的算法。有关此主题的更多信息,请参阅博文。

使用嵌入的另一个好处是,学习到的映射到每个类别的向量可以被一个具有适度技能的模型所拟合,但向量可以提取出来并普遍用作该类别在各种不同模型和应用程序上的输入。也就是说,它们可以被学习和重复使用。

嵌入可以通过 Embedding 层在 Keras 中使用。

有关在 Keras 中学习文本数据的词嵌入的示例,请参阅博文。

每个分类变量都需要一个嵌入层,并且嵌入期望类别被序数编码,尽管不假定类别之间存在任何关系。

每个嵌入还需要用于分布式表示(向量空间)的维数。在自然语言应用中,通常使用 50、100 或 300 维。对于我们的小示例,我们将维度数固定为 10,但这只是任意的;您应该尝试其他值。

首先,我们可以使用序数编码准备输入数据。

我们将开发的模型将为每个输入变量提供一个单独的嵌入。因此,模型将接受九个不同的输入数据集。因此,我们将拆分输入变量并单独对它们进行序数编码(整数编码),使用 LabelEncoder,并返回一组单独准备好的训练和测试输入数据集,这些数据集稍后可作为我们模型的输入。

下面的 prepare_inputs() 函数实现了这一点,枚举每个输入变量,使用最佳实践正确地对每个变量进行整数编码,并返回编码后的训练和测试变量列表(或单变量数据集),这些列表可用于我们模型稍后的输入。

现在我们可以构建模型。

在这种情况下,我们必须以不同的方式构建模型,因为我们将有九个输入层,九个嵌入的输出(九个不同的 10 元素向量)需要连接成一个长向量,然后才能作为输入传递给密集层。

我们可以使用 Keras 的函数式 API 来实现这一点。如果您不熟悉 Keras 函数式 API,请参阅博文。

首先,我们可以枚举每个变量并构建一个输入层,将其连接到嵌入层,并将这两个层存储在列表中。在定义模型时,我们需要引用所有输入层,并且我们需要引用每个嵌入层来与合并层进行连接。

然后我们可以合并所有嵌入层,定义隐藏层和输出层,然后定义模型。

使用具有多个输入的模型时,我们需要指定一个列表,其中包含每个输入的 一个数据集,例如,对于我们的数据集,是九个数组,每个数组有一列。幸运的是,这正是我们从 prepare_inputs() 函数返回的格式。

因此,拟合和评估模型看起来与上一节中的一样。

此外,我们将通过调用 plot_model() 函数来绘制模型,并将其保存到文件中。这需要安装 pygraphviz 和 pydot,这在某些系统上可能很麻烦。如果您遇到问题,只需注释掉导入语句和对 plot_model() 的调用。

将所有这些结合起来,下面列出了在多输入层模型中使用每个分类输入变量的单独嵌入的完整示例。

运行示例将按上述说明准备数据,拟合模型,并报告性能。

注意:由于算法或评估过程的随机性,或数值精度的差异,您的结果可能会有所不同。考虑运行示例几次并比较平均结果。

在这种情况下,模型表现相当不错,与上一节的独热编码结果相当。

由于学习到的向量是在一个技能模型中训练的,因此可以保存它们并将它们用作在操作相同数据的各种模型上的通用表示。这是探索此编码的一个有用且引人注目的原因。

为确认我们对模型的理解,我们创建了一个图并将其保存到当前工作目录中的 embeddings.png 文件。

该图显示了九个输入,每个输入都映射到一个 10 元素向量,这意味着模型的实际输入是一个 90 元素向量。

注意:点击图片查看大图。

Plot of the Model Architecture With Separate Inputs and Embeddings for each Categorical Variable

具有单独输入和每个分类变量嵌入的模型架构图
点击放大。

常见问题

本节列出了一些在编码分类数据时常见的问答。

问:如果我有混合的数字和分类数据怎么办?

或者,如果我有混合的分类和序数数据怎么办?

您需要单独准备或编码数据集中的每个变量(列),然后将所有准备好的变量连接回一个数组,以进行模型的拟合或评估。

问:如果我有数百个类别怎么办?

或者,如果我连接许多独热编码向量来创建一个包含数千个元素的输入向量怎么办?

您可以使用独热编码处理数千甚至数万个类别。另外,拥有大的向量作为输入听起来很吓人,但模型通常可以处理。

尝试使用嵌入;它提供了更小的向量空间(投影)的好处,并且表示可以具有更多意义。

问:哪种编码技术最好?

这是未知的。

在您的数据集和您选择的模型上测试每种技术(以及更多技术),然后找出最适合您的情况。

进一步阅读

如果您想深入了解,本节提供了更多关于该主题的资源。

文章

API

数据集 (Dataset)

总结

在本教程中,您学习了在 Keras 中开发神经网络模型时如何对分类数据进行编码。

具体来说,你学到了:

  • 在机器学习和深度学习模型中使用分类数据的挑战。
  • 如何对分类变量进行整数编码和独热编码以用于建模。
  • 如何学习作为神经网络一部分的分类变量的分布式表示。

你有什么问题吗?
在下面的评论中提出你的问题,我会尽力回答。

177 条回复关于“3 种对深度学习的分类变量进行编码的方法”

  1. Rahil Shaikh 2019年11月22日 凌晨5:28 #

    印度时间午夜了,我的眼睛都要睁不开了……但当我读到你的邮件主题时……我就知道我必须读完它!!
    你问为什么?
    因为嵌入的解释。虽然当我尝试它时,我会有我的疑问…
    ……我想表达我对你与世界分享的惊人知识的感激之情!

    • Jason Brownlee 2019年11月22日 凌晨6:13 #

      谢谢,希望它能在你的下一个项目上有所帮助!

    • ANTHONY LINS 2020年2月27日 下午12:02 #

      嗨,Jason,

      我想了解如何处理同一数据集中的多类别和多标签问题,例如发色、肤色和眼色(多输出),这些通过基因标记的属性集(如 CC、TC 等)来定义。
      如果您有任何关于这类问题的参考资料,我将非常感谢您的帮助。

      提前感谢。

    • Akash Saha 2020年4月6日 下午4:37 #

      你好,先生,
      最近我一直有一个关于如何编码以 bin 形式提供的分类数据的疑问。我实际上想使用“年龄”数据来构建我的决策树。在一些博客中,建议在使用 DT 之前将连续数值数据转换为分类 bin 数据。
      我的疑问是,在通过离散化创建 bin 之后,如何使用这些 bin 数据来构建我的决策树??提前感谢!

  2. martin 2019年11月22日 凌晨9:33 #

    你好,Jason:关于“嵌入期望类别被序数编码”,这对任何类型的实体嵌入都适用吗?也就是说,“序数”编码是必需的。

    • Jason Brownlee 2019年11月22日 下午2:07 #

      很好的问题!

      是的,但从标签到整数的映射不必有意义。

      我应该说“标签编码”或“整数编码”听起来不那么吓人。抱歉。

      • Erik 2021年6月23日 下午8:47 #

        你好,

        你能解释一下为什么这不必有意义吗?

        我不知道我是否理解正确,但我想发生的是这个
        LabelEncoder() 将输入列中的所有单词转换为整数值,每个唯一值对应一个整数。然后将其用作嵌入层的输入。

        数字会不会影响词嵌入?例如,假设输入词是 [bad, good, great, horrible, good, good, bad, great],而标签编码器将其转换为 [0, 1, 2, 3, 1, 1, 0, 2]。
        数字对词嵌入没有影响吗?那些没有相似性的词语是否相等?

        • Jason Brownlee 2021年6月24日 凌晨6:01 #

          不,嵌入层学习每个词的向量表示,使得词语的“接近度”对模型在所选损失和数据集下的意义/有用性有意义。

  3. martin 2019年11月22日 凌晨10:39 #

    虽然它说“期望类别被序数编码”,但输入仍然使用 LabelEncoder() 而不是 OrdinalEncoder() 进行准备。为什么是这样?

    • Jason Brownlee 2019年11月22日 下午2:08 #

      另一个热门问题,谢谢!

      它们都做同样的事情。

      Label encoder 是针对一列——明确的。Ordinal encoder 是针对可变数量的列。

  4. martin 2019年11月22日 下午5:30 #

    另一个问题是为什么两个 Embedding 对象类型不同?一个是本教程中的,由于函数式 API,其类型为“Tensor(“embedding_1/embedding_lookup/Identity_2:0″, shape=(None, 1, 5), dtype=float32)”,并且其形状为 (None, 1, 5)。在另一个教程 https://machinelearning.org.cn/what-are-word-embeddings/ 中,Embedding 对象是“” ,它甚至没有“_shape”变量。我之所以这样问,是因为在第二个教程中它必须使用 Flatten() 层,而在第一个教程中,它不使用。两者都是嵌入对象,为什么它们的内部属性不同?

    • Jason Brownlee 2019年11月23日 凌晨6:45 #

      嵌入通常与序列词语作为输入一起使用。

      这里,我们有一个类别的一个嵌入。不需要展平。

  5. eppane 2019年11月23日 凌晨1:06 #

    你好!非常有帮助的文章,特别是嵌入部分。在我自己的应用程序中遇到的一个问题。

    您有什么建议来处理测试集中存在训练集中未见过标签的情况吗?例如,下面,我们使用训练数据拟合 LabelEncoder,

    le.fit(X_train[:, i])
    # 编码
    train_enc = le.transform(X_train[:, i])
    —> test_enc = le.transform(X_test[:, i])

    最后一行将引发关于测试集包含先前未见标签的值错误。一个选项是使用所有数据拟合 LabelEncoder,但这会导致信息泄露,这是不可取的。实际上,测试集(或验证集)确实可能包含先前未见的标签。

    祝好!

    • Jason Brownlee 2019年11月23日 凌晨6:53 #

      谢谢!

      绝佳的问题!!!

      是的,您可以删除带有未知标签的行(很麻烦),或者将未知标签映射到嵌入中的“未知”向量,通常保留索引 0 的向量用于此目的——在 NLP 应用中。

      这需要更仔细的标签到整数的编码,最好是编写一个自定义函数来确保它是一致的。

      这有帮助吗?

      • eppane 2019年11月25日 凌晨8:07 #

        你好!

        感谢您快速而有用的回复!不幸的是,删除带有未知标签的行是不可能的。我曾担心这需要自定义编码。但这一个有趣的问题,并且可能对我的应用程序至关重要,我正在分析基于流的网络数据并尝试编码 IP 地址和端口。一个理想的解决方案是,当引入新数据点时,动态更新标签,使其可以馈送到神经网络(在这种情况下是自动编码器)。

        干杯,保持出色的工作!

      • Mikkel Hansen 2019年12月9日 下午9:37 #

        您是否有适用于 XGBoost 模型的解决方案(我正在使用 Sklearn 的 OrdinalEncoder)。

      • Crystalizzedsirup 2021年10月27日 下午2:32 #

        你好,我希望你仍在回复此线程。您如何做到这一点?这是否在对值进行标签编码时完成?

        • Adrian Tam
          Adrian Tam 2021年10月28日 凌晨3:25 #

          是的,标签编码步骤用于识别所有未知标签。

  6. Zineb_Morocco 2019年11月24日 凌晨5:22 #

    你好,

    这篇文章对于理解嵌入技术非常有帮助。我建议您关注并运行示例以获得深刻的认识。
    我只想补充一点,这项技术现在已广泛用于许多领域,如 NLP、生物学领域、图像处理,尤其是在数据结构化为图的情况下,通过模拟节点为单词,边为句子。

    谢谢你,Jason。

  7. Niall Xie 2019年11月27日 凌晨2:59 #

    你好,当我在我的乳腺癌数据集上尝试使用最后一个代码时,我遇到了一个错误。我该如何修复这个错误?谢谢 ValueError: y 包含先前未见过的标签:[‘clump_thickness’]

    • Jason Brownlee 2019年11月27日 凌晨6:12 #

      听到这个消息我很难过。

      如果您在使用 OneHotEncoder 时遇到此问题,您可以将 handle_unknown 设置为 ‘ignore’,例如:

  8. Markus 2019年12月6日 凌晨6:58 #

    在这篇文章中它说:

    注意:我将留给您一项练习,以更新下面的示例,尝试为具有自然顺序的变量指定顺序,看看它是否会对模型性能产生影响。

    我试过了,模型在准确率方面并没有比 70% 提高多少。您是否也尝试过?准确率没有提高也是您所期望的吗?

    另一个问题:您不能仅为具有自然顺序的变量指定顺序,您必须为所有变量或都不指定顺序,或者我说错了?我为此目的使用了 categories 参数,请参阅

    https://scikit-learn.cn/stable/modules/generated/sklearn.preprocessing.OrdinalEncoder.html

    谢谢

    • Jason Brownlee 2019年12月6日 下午1:37 #

      很酷,谢谢你的尝试。

      不,我没有尝试。

      不,您可以单独处理每个变量,并在建模之前将它们联合/堆叠起来。这很麻烦,这也是我将其留作练习的原因。

  9. Ken 2019年12月10日 下午8:34 #

    如何为具有一万个唯一值的列进行编码,该列表示为城市名称,
    用于无监督聚类技术。

    • Jason Brownlee 2019年12月11日 凌晨6:52 #

      很好的问题!

      我建议使用神经网络进行学习嵌入,然后将结果与其他方法(如独热编码、哈希编码等)进行比较。

  10. Ken 2019年12月12日 凌晨12:26 #

    谢谢你,

    • Ken 2019年12月12日 凌晨12:36 #

      是否有关于神经网络嵌入的资源或解决方案?

      • Jason Brownlee 2019年12月12日 凌晨6:26 #

        上面的教程显示了如何做。

        另外,我在博客上还有很多其他例子,可以使用搜索框。

        你具体遇到什么麻烦了?

        • SJ 2020年11月25日 凌晨3:24 #

          嗨,Jason,

          我没理解你的建议

          如何使用“带神经网络的学习嵌入”来编码具有一万个唯一值的列,该列为城市名称?

          上面的例子使用了 NN,因此嵌入是作为模型训练的一部分学习的。

          如何为像城市这样的列构建嵌入,然后将其用于例如 Logistic 回归?

          • Jason Brownlee 2020年11月25日 凌晨6:47 #

            您可以独立训练嵌入,例如通过自动编码器。

      • SJ 2020年11月25日 凌晨3:26 #

        你好 Ken

        我也在寻找一些东西,找到的最接近的是

        https://medium.com/analytics-vidhya/categorical-embedder-encoding-categorical-variables-via-neural-networks-b482afb1409d

    • Jason Brownlee 2019年12月12日 凌晨6:25 #

      不客气。

    • Hussain 2019年12月24日 下午5:48 #

      您是否参加过 NIPS 会议?

  11. mskilic 2020年1月12日 凌晨1:43 #

    非常感谢这篇出色且非常有用的文章。

    但我想问一个关于编码阶段的问题。分别对训练和测试数据进行编码是否合乎逻辑?例如,如果一个特征在测试和训练数据中具有不同的分类值,是否可以信任模型?或者模型运行是否正确?也许在编码之后再将数据拆分为训练集和测试集会更优?

    此致,

    • Jason Brownlee 2020年1月12日 凌晨8:06 #

      不客气。

      训练集必须充分代表问题——例如,包含每个变量的一个示例。

  12. scott 2020年1月25日 凌晨6:03 #

    嗨,Jason,

    我正在尝试将您的嵌入代码应用于我的数据。数据集中的所有 y 和 x 变量都是字符串数据类型。

    当我运行以下部分时:

    in_layers = list()
    em_layers = list()
    for i in range(len(X_train_enc))
    # 计算唯一输入的数量
    n_labels = len(unique(X_train_enc[i]))
    # 定义输入层
    in_layer = Input(shape=(1,))
    # 定义嵌入层
    em_layer = Embedding(n_labels, 10)(in_layer)
    # 存储层
    in_layers.append(in_layer)
    em_layers.append(em_layer)

    我得到了错误:

    —————————————————————————
    NameError Traceback (最近一次调用)
    in
    2 in_layers = list()
    3 em_layers = list()
    —-> 4 for i in range(len(X_train_enc))
    5 # 计算唯一输入的数量
    6 n_labels = len(unique(X_train_enc[i]))

    NameError: name ‘X_train_enc’ is not defined

    您对可能的问题有什么想法吗?

    谢谢。

    Scott

    • Jason Brownlee 2020年1月25日 凌晨8:45 #

      您可能跳过了一些行。

      也许可以从工作示例开始,然后慢慢地将其改编为使用您自己的数据集。

  13. scott 2020年1月28日 凌晨1:52 #

    嗨,Jason,

    我一直在尝试将您的嵌入代码应用于多标签分类,但尚未成功。我试图预测 14 个二元标签,使用 89 个分类预测变量。我该如何修改您的代码来处理多标签问题?谢谢。

    • Jason Brownlee 2020年1月28日 凌晨7:57 #

      听起来很棒。

      所有编码方案都是针对输入变量的。实际上不需要任何更改,您可以直接使用它们。

      • Scott 2020年1月29日上午1:07 #

        感谢您及时的回复 Jason。我不确定您说的“编码方案是针对输入变量”的确切含义。

        不过,我再次通读了您的教程,但仍然无法弄清楚如何将其应用于多标签案例。

        正如我所提到的,我试图预测 14 个二元标签,有 89 个特征。所以,与单个输出向量/矩阵 outcome nx1 不同,我有一个 nx14 的矩阵。我不确定如何在您的代码中处理这种情况。

        我相信在尝试将其应用于多标签分类时,我可能在您代码的几个区域遇到了问题。我将在下面尝试解释这些问题。

        我不确定为什么您需要在下面的示例代码中转换为二维数组,以及如果我预测的是 14 个标签而不是 1 个标签,我应该如何更改它。

        – # 将目标重塑为二维数组
        – y = y.reshape((len(y), 1))

        另外,我的 14 个目标已经是二进制形式且是字符串数据类型——14 列单独编码为 0 和 1——所以我不太确定是否需要包含以下代码。我认为我仍然需要生成 y_train_enc 和 y_test_enc,但我不确定它们的格式应该是怎样的。

        – # 准备目标
        – def prepare_targets(y_train, y_test)
        – le = LabelEncoder()
        – le.fit(y_train)
        – y_train_enc = le.transform(y_train)
        – y_test_enc = le.transform(y_test)
        – return y_train_enc, y_test_enc

        另外,这部分让我感到困惑。我不知道您为什么将输出格式化为三维(?数组?)。如何将以下代码更改为处理 14 个标签的结果/预测?

        – # 使输出为三维
        – y_train_enc = y_train_enc.reshape((len(y_train_enc), 1, 1))
        – y_test_enc = y_test_enc.reshape((len(y_test_enc), 1, 1))

        另外,在您的示例中,您有 9 个分类特征和 1 个二元结果。
        我有 89 个特征和 14 个二元结果。我不确定为什么您在下面的代码片段中指定“10”。在我的情况下,我是否需要指定 103(89+14)?

        – # 定义嵌入层
        – em_layer = Embedding(n_labels, 10)(in_layer)

        另外,“n_labels”到底代表什么?
        (即,不确定这意味着什么——len(unique(X_train_enc[i]))),
        以及在您的示例中,这个数字实际是多少?

        最后,您下面的代码中的“10”是因为您的示例包含总共 10 个变量(9 个特征和 1 个结果)吗?

        – dense = Dense(10, activation=’relu’, kernel_initializer=’he_normal’)(merge)

        最终,我也想能够生成一个 nx14 的 pd 数据框,其中包含所有 14 个标签的类别(0/1,不是概率)预测,然后我可以使用 scikit learn 来生成多标签性能指标。

        我找不到另一个例子能接近我需要做的——即在多标签分类案例中使用分类特征嵌入。
        我非常感谢您花时间回答我的问题。我一直觉得您的教程和帖子非常有价值。

        Scott

        • Jason Brownlee 2020年1月29日上午6:43 #

          这是一个很大的评论,我无法全部阅读/处理。

          听起来您正在尝试对目标变量进行编码,而不是对输入变量进行编码。本教程专注于对输入变量进行编码。

          如果您想为具有 n 个类别的多标签分类对目标变量进行编码,您必须使用此
          https://scikit-learn.cn/stable/modules/generated/sklearn.preprocessing.MultiLabelBinarizer.html

          • Scott 2020年1月29日晚上11:06 #

            Jason,

            抱歉评论太长了。

            我不是在尝试对目标进行编码——我有 14 个二元目标列——14 个标签。

            也许您可以只回答这一个问题。

            您为什么将输出格式化为三维(?数组?)。您示例中的以下代码将如何更改以处理 14 个二元标签结果/预测(与您将 1 个二元标签分类的示例相反)?

            – # 使输出为三维
            – y_train_enc = y_train_enc.reshape((len(y_train_enc), 1, 1))
            – y_test_enc = y_test_enc.reshape((len(y_test_enc), 1, 1))

            我猜我会将最后一个 1 改为 14

            – y_train_enc = y_train_enc.reshape((len(y_train_enc), 1, 14))
            – y_test_enc = y_test_enc.reshape((len(y_test_enc), 1, 14))

            我说的对吗?

            再次感谢。

            Scott

          • Jason Brownlee 2020年1月30日上午6:52 #

            我们在这篇文章中没有将任何输出数组设置为三维。您是否指的是另一篇文章?

            对于某些模型,例如编码器-解码器模型,我们需要具有三维输出,例如,每个输入序列的输出序列。我认为您指的是这个。

            如果是这样,您将有 n 个样本,t 个时间步,f 个特征,其中 f 个特征将是 14 个标签。

  14. Scott 2020年1月30日晚上11:53 #

    Jason。

    那么您完整的嵌入代码中的第 59-61 行是做什么的?

    它们似乎表明将二维转换为三维。下面是您嵌入示例中第 59-61 行的代码。

    # 使输出变为 3D
    y_train_enc = y_train_enc.reshape((len(y_train_enc), 1, 1))
    y_test_enc = y_test_enc.reshape((len(y_test_enc), 1, 1))

    再次感谢。

    • Jason Brownlee 2020年1月31日上午7:53 #

      啊,我明白了。谢谢,我漏掉了。

      嗯,我认为在输入到密集层之前应该将嵌入展平。我们没有这样做,所以结构会一直保持三维直到输出。它并不是真正的三维,只是每个样本有一个时间步和一个特征。

      您可以尝试处理三维输出,或者尝试在连接嵌入后添加一个展平层。我认为从我目前的想法来看,这应该能起作用。我认为我在处理 NLP 模型时做过。

  15. Scott 2020年2月1日上午1:58 #

    Jason,

    我找到了我的主要问题。我只需要将第三个维度从 1 改为 14,假设我有 14 个标签要预测。

    仅供参考——下面是我用于运行嵌入模型然后计算多标签指标(使用 sklearn.metrics)的部分代码。

    从 14 个标签和 89 个预测变量开始,作为 pandas 数据框

    希望这个例子对大家有用

    再次感谢您的帮助,Jason。

    Scott

  16. Scott 2020年2月8日凌晨12:55 #

    Jason,你好,又见面了

    您似乎在您的“准备头部”代码部分使用了 10 作为嵌入维度。这是否意味着您对所有分类变量都使用 10 作为维度?

    如果是这样,我想为每个分类变量指定不同的嵌入维度,因为每个分类变量的级别数可能不同。我认为我的以下代码可以做到这一点,但我不确定它是否能与您的代码正确集成——请注意我添加的关键部分是“cat_embsizes[cat]”,它取代了您的条目“10”,代表嵌入维度。这里我计算每个分类变量的唯一值数量,计算我想要的每个变量的维度,然后将该列表应用于您的“准备头部”代码。请告诉我您的想法——这会奏效吗?再次感谢。

  17. Dana 2020年2月13日晚上11:58 #

    我认为这句话“在这种情况下,我们将忽略任何可能的现有顺序关系,并假定所有变量都是分类的。使用顺序编码仍然有用,至少作为与其他编码方案的参考点。”不合适。
    我错了?

  18. kiki 2020年3月12日晚上7:00 #

    您好。我想问一下,如何分割 x 和 y 变量,而不使用“,”分隔符?我从 excel 中获取的数据没有分隔符。我总是遇到这个类型的错误

    ValueError: Error when checking target: expected dense_18 to have shape (1,) but got array with shape (31,)

    需要对此进行解释。谢谢

  19. Cesar 2020年3月18日晚上1:00 #

    嗨,Jason,
    很棒的文章,非常感谢!

    我想问一下,我试图对热编码和序数编码进行操作,但我的数据集同时包含这两种类型的变量,分类变量和连续变量。正如您所说,对于序数编码,我预处理了每一列并将所有变量连接回一个数组,并且有效,但是用热编码做同样的事情,没有成功。当我尝试进行“np.concatenate((x_cont,x_cat)”时,我收到一个错误“”所有输入数组都必须具有相同的维度,但索引 0 处的数组有 2 个维度,索引 1 处的数组有 0 个维度“”但我知道如何解决。

    谢谢!

  20. Pierre 2020年3月21日下午3:46 #

    嗨,Jason,
    关于具有数字和分类数据以及学习嵌入技术的案例,我还有其他问题:我是否需要为数字数据在模型中添加一个输入层(除了分类变量的层)?
    谢谢!

  21. Jim 2020年4月11日上午11:17 #

    你好 Jason,
    出色的帖子,非常感谢。

    我注意到,当我查看 sklearn 关于 LabelEncoder 的文档时
    (https://scikit-learn.cn/stable/modules/generated/sklearn.preprocessing.LabelEncoder.html)
    文档说
    “此转换器应用于编码目标值,即 y,而不是输入 X。”

    在此示例中,您毫不犹豫地在输入上使用了 LabelEncoder。您知道将 LabelEncoder 用于输入有什么问题,或者为什么 sklearn 会警告不要这样做吗?(我正在尝试弄清楚它可能对我的模型造成什么限制。)

    谢谢!

    • Jason Brownlee 2020年4月11日上午11:56 #

      谢谢。

      是的,您应该改用序数编码器。它们做的事情相同。我在这里使用了它,因为我们正在处理一维数据,就像目标一样。

  22. John White 2020年4月21日上午6:50 #

    仅为举例,假设我们有 3 个目标类别:上涨、下跌或持平。作为替代方案,我们能否通过编程将这些目标类别映射到 0、1 或 2,而不是对其运行 OneHotEncoder()/OrdinalEncoder()?感谢您的工作!

  23. Xavier Moser 2020年5月27日凌晨4:23 #

    谢谢!

    我正试图让它用于回归模型,但我遇到了以下错误(在一个 epoch 之后),该错误会因运行而异。我曾尝试增加嵌入的输入形状,通过特征数+1 等方法,但未能奏效。

    感谢您的帮助!

    错误消息

    InvalidArgumentError: indices[3,0] = 5 is not in [0, 5)
    [[node model_51/embedding_243/embedding_lookup (defined at :99) ]] [Op:__inference_distributed_function_31433]

    Errors may have originated from an input operation.
    输入源操作连接到节点 model_51/embedding_243/embedding_lookup
    model_51/embedding_243/embedding_lookup/29082

    在下一次运行时,该消息将变为

    InvalidArgumentError: indices[0,0] = 1 is not in [0, 1)
    [[node model_52/embedding_325/embedding_lookup (defined at :99) ]] [Op:__inference_distributed_function_38501]

    Errors may have originated from an input operation.
    输入源操作连接到节点 model_52/embedding_325/embedding_lookup
    model_52/embedding_325/embedding_lookup/36354

    • Jason Brownlee 2020年5月27日上午8:02 #

      Embedding 仅期望整数编码输入。不是浮点值。

      • Xavier Moser 2020年5月28日凌晨4:13 #

        谢谢!事实证明是另一个问题:我不得不将‘n_labels’设置为具有最多唯一标签的类别的长度+1(在我的情况下是 16),用于所有嵌入。希望这不会改变模型。

  24. Ale 2020年6月13日早上10:51 #

    你好先生,

    谢谢,内容很棒!我遇到了一个问题,我的分类变量被分组到 bin 中:“0 年”、“1-3 年”、“3-5 年”、“5 年以上”。我认为我不应该使用序数编码,因为这样它们看起来会相差一步(1,2,3),而独热编码可能会错过这些 bin 的自然顺序。

    您有什么建议?

    • Jason Brownlee 2020年6月14日上午6:29 #

      我建议探索这两种方法,并使用能为您的选定模型和测试套件带来最佳性能的方法。

      指定顺序的序数编码听起来是合适的。

      • Ale 2020年6月14日下午2:30 #

        非常感谢您的回复。在提到的示例中,您推荐使用哪种序数编码?

        0 年:0
        1-3 年:1
        3-5 年:2
        这样是否是正确的做法?

        • Jason Brownlee 2020年6月15日上午6:00 #

          唯一“正确”的方法是您尝试过的并且比其他方法表现更好的方法。

          我建议对多种方法进行原型设计,并找出最适合您特定数据和模型选择的方法。

          • Ale 2020年6月17日凌晨1:05 #

            好的,谢谢。

          • Jason Brownlee 2020年6月17日上午6:24 #

            不客气。

  25. NEERAJ SINGH 2020年6月24日晚上9:15 #

    你好,
    我有一个问题……我的数据包含分类和连续变量的混合。目标变量是一个多类变量(而不是二元变量)。它需要预测 3 个不同的类别。我已经对分类变量进行了独热编码。我是否也应该对目标变量进行编码,因为如果我这样做,将会有 3 个独立的列(值为 0-1),而且我不确定预测会是什么样子??

  26. Sivan Kinreich 2020年7月4日凌晨2:07 #

    嗨,Jason,
    非常感谢您提供这些信息。
    我想知道您是否知道为什么运行
    merge = concatenate(em_layers)
    会导致以下错误
    ValueError: zero-dimensional arrays cannot be concatenated

  27. Jose Danie Mosquera 2020年7月10日上午10:24 #

    嗨,Jason!
    我读了很多关于您特征编码的帖子,它们非常有帮助!
    但我有一个很大的疑问。对具有大量类别的分类特征(例如,一个特征超过 500 个类别)的最佳编码方法是什么?我试过 sklearn 的 LabelBinarizer,但不确定我是否做得对!

    提前非常感谢。

  28. Abhilash Neog 2020年7月11日上午6:24 #

    你好 Jason,如果我的数据集中有分类属性,这些属性包含多个分类值(例如,大约 1000 个。例如,“Name”列中有 1000 个不同的名字),标签编码将创建 1000 个整数值。
    那么,如果我想在数据集上训练神经网络,我应该使用这个列的原始(标签编码)格式,还是有办法减少值?将如此大的值输入神经网络是否可以,特别是当其他属性的值可能在 (0-10) 范围内时?
    独热编码会使特征向量非常稀疏。所以,我不知道这样做是否正确

    • Jason Brownlee 2020年7月12日上午5:36 #

      您可以缩放值,例如标准化。

      还将结果与独热编码和嵌入进行比较。我预计嵌入会表现良好。

      独热编码将是稀疏的,也许还是尝试一下以确认其性能。

  29. JG 2020年7月12日凌晨3:32 #

    嗨 Jason

    很棒的教程!我非常重视您的所有教诲。谢谢!

    如果您允许,我将分享一些评论和问题

    评论

    1) 我尝试在拆分(X,Y)“张量”为训练集和测试集之前,将“编码”转换应用于整个(X, Y)分类数据集。因此,确保我收集了所有可能的数据集标签或分类类型,但另一方面,在拆分之前应用“嵌入”编码需要将数组列表转换为 numpy 并进行转置,反之亦然,然后才能馈送输入嵌入模型。

    顺便说一句,在应用“嵌入”编码时,我无法将“stratify”选项应用于“train_test_split()”函数,代码会崩溃!我不知道为什么。

    2) 我尝试应用新的“tf.keras”API,但在定义“Concatenate”层时,它似乎与“keras.layers.merge.concatenate”的工作方式不同,而且代码也会崩溃。所以,我改回导入所有库自 keras 独立,如您的“keras.layers.merge.concatenate”。

    3) 我尝试添加“batchnormalization”和“dropout”层,作为完全连接模型头部的一部分。我还对密集层应用了“Kernel_regularizer”。
    但没有明显的准确率提升!

    4) 我尝试在嵌入层定义之后添加“Conv1D”(kernel_size=1)和“MaxPool1D”(pool_size=1),并在连接层之前应用 Flatten 层转换。
    但没有发现显著变化!

    5) 我应用 KFold() 函数来自 Sklearn 库,此外还重复相同的训练以进行统计影响的不同训练-测试验证。

    6) 考虑到数据集明显不平衡(81 次复发 vs. 205 次非复发标签),我很惊讶地发现,将类权重()参数应用于训练模型(.fit() 方法)不仅没有提高准确率,反而使其变得更糟,从 72% 降至 68.4% 的准确率。
    我不知道为什么!

    7) 我获得了最佳编码结果,应用了“OneHotEncoder”(76%),其次是“OrdinalEncoder”(75%),最后是 Embedding(72%)。尽管 OneHotEncoder 和 OrdinalEncoder 是比应用 Embedding 编码简单得多的技术!

    8) 我与此时间线中的一些回复有相同的评论,即更好地解释输入张量 X、Y 的维度变化,这很难理解(在教程中),并且还需要一些列表到 numpy 的转换,包括在嵌入层实现中。

    据我所知,编码的总结可以是
    当应用“OrdinalEncoder”时,我们将分类标签转换为整数,并且,数据集的 9 个原始特征作为模型输入保持不变 [286, 9]。但是,当应用“OneHotencoder”时,它将分类转换为许多 0 和一个 1,那么输入特征将从 9 扩展到 43,因此输入模型维度现在是 [286, 43]。
    最后,当应用“Embedding 编码和深度学习层”时,输入特征的原始二维维度 [286, 9] 得到保留,但在嵌入层中引入了额外的维度(与新的嵌入向量维度相关,例如 10),因此总维度变为三维 [286, 9, 10]

    问题

    a) 为什么在 NLP 技术(例如情感分析文本分类)中,我们可以将单词(即文本的不同特征)编码到单个嵌入层(所有输入共享)中,但在这里,我们需要为每个特征引入一个单独的输入+嵌入层?
    能否在此应用与 NLP 文本分类相同的嵌入层来处理所有输入特征?

    b) 在 NLP 技术中,我们需要始终使用展平层将所有特征提取呈现给全连接头部模型,从这些深度层开始,为什么在这里不(强制)应用?

    c) 当应用 PCA、特征选择等降维方法时,我们显然希望专注于简化输入和提高学习效率……但是当我们应用嵌入、Onehot 或其他深度学习层(卷积等)时,它似乎会引入新的额外维度(向量、张量)来投影新的特征提取……所以概念上,维度扩展和特征减少是两个走向相反方向的思想 :-(!!

    对不起,文字太长了!

    致敬
    JG

    • Jason Brownlee 2020年7月12日上午6:00 #

      Stratify 需要一个用于分层的标签。一个具有有限值的列。

      哇,进行了这么多很棒的测试!您也可以比较不同的嵌入大小。

      在 NLP 中,我们只有一个“变量”。这里我们有许多不同的变量。

      这取决于模型是否需要展平层。例如,来自嵌入的向量输出可以直接由密集层使用。

      我认为 PCA 和嵌入做的是同一件事。投影到新的向量空间,以保持观察之间的关系。

      • comsubpac 2020年7月20日凌晨6:34 #

        您好,我正在处理一个类似的问题,并尝试对我的 y_train 进行分层。我已经对我的数据进行了独热编码。我是否必须更改“stratify = y_train”在

        “X_train, X_val, y_train, y_val = train_test_split(X_train, y_train, test_size = 0.15, shuffle = True, stratify = y_train)”

        因为当我添加它时,它并没有真正产生任何区别。

        • Jason Brownlee 2020年7月20日下午1:48 #

          您必须先拆分数据,然后再对其进行编码。

  30. JG 2020年7月13日凌晨1:42 #

    谢谢。

  31. Qi 2020年7月24日中午12:33 #

    嗨,Jason,

    我是深度学习的新手,我的数据集有 60 个变量都是二元变量(0 为“好”,1 为“坏”)。在这种情况下,我是否需要使用您在本帖中分享的方法来进一步转换我的二元变量?或者我应该直接使用原始数据集进行基于 CNN 的分类?

    非常感谢!

  32. Sunny 2020年8月6日早上10:05 #

    您好 Jason——我遇到了一种将分类数据转换为正态分布的方法,使用以下过程:您是否知道如何在 Python 中实现?

    离散列使用以下方法编码为数值 [0,1] 列。
    1. 离散值首先根据其在数据集中的比例按降序排序。
    2. 然后,[0,1] 区间根据每个类别 c 的比例分割成段 [ac,bc]。
    3. 要将离散值转换为数值,我们用一个从以 [ac,bc] 中点为中心且标准差为 σ = (bc - ac)/6 的高斯分布中采样的值替换它。

  33. Jayant Raavan 2020年8月12日 下午3:46 #

    如果我对具有 A、B、AB 和 O 四个级别的血型变量进行编码。为了执行编码,我希望删除 AB 和 O 两个级别。请建议一种合适的编码方法来表示这四个级别。

    • Jason Brownlee 2020年8月13日 上午6:06 #

      也许可以尝试不同的编码方案,然后发现哪种最适合您选择的模型。

    • Viditya Tyagi 2020年12月26日 上午3:05 #

      试试这个

      A B
      A 1 0
      B 0 1
      AB 1 1
      O 0 0

  34. Pavel Komarov 2020年10月16日 下午3:30 #

    “您需要分别准备或编码数据集中的每个变量(列),然后将所有准备好的变量连接回单个数组,以便拟合或评估模型。”

    我最近阅读了 https://www.cs.otago.ac.nz/staffpriv/mccane/publications/distance_categorical.pdf,这是一篇关于混合变量简单距离函数的优秀论文。他们的建议之一是将不相关的变量编码为常规单纯形坐标。技术上可以按照他们的建议,用比您的分类变量选择数少一维的方式来做到这一点。实际上,独热编码(one-hot encoding)就是单纯形顶点,使用了与选择数相同的维度:http://www.math.brown.edu/~banchoff/Beyond3d/chapter8/section03.html

    但是,为某些输入变量找到一个完整的向量,将其与不占用这么多输入的连续变量连接起来,然后通过模型进行传递,会不会导致某种不平衡?看起来模型自然会更看重占用如此多输入空间的那个东西,而它必须学会将那些单输入的数值输入视为更重要。

  35. Milind Dalvi 2020年10月21日 上午10:56 #

    你好 Jason,

    感谢您提供了关于处理分类数据和嵌入(embeddings)的又一个精彩话题。

    一个问题,

    循环……
    em_layer = Embedding(n_labels, 10)(in_layer)

    merge = concatenate(em_layers)

    我可以看到在上面的代码中,您为所有分类特征选择了固定的嵌入向量大小 10。但实际上,情况可能并非如此,可以根据每个特征的唯一类别数量来设置不同的向量大小。

    在这种情况下,直接连接所有嵌入层会失败,所以,

    em_layer = Embedding(n_labels, 10)(in_layer)
    em_layer = Reshape((10, ))(em_layer)

    上面的代码有意义吗?您能提出其他解决方案吗?

    • Jason Brownlee 2020年10月21日 下午1:46 #

      不客气。

      是的,您将为每个输入变量创建一个嵌入层。每个层都有相同的输入层。

      您不希望像在代码中所做的那样堆叠嵌入层。

      • Milind Dalvi 2020年10月21日 下午5:58 #

        抱歉,我没有理解最后一句话。

        您说的“不希望堆叠”是什么意思?

        这是我的全部代码,模型编译好了,但是嵌入层的逻辑结构是否正确?

        def emb_sz_rule(n_cat:int)->int: return min(600, round(1.6 * n_cat**0.56))

        embedding_inputs=[]
        embedding_output=[]
        non_embedding_inputs = [Input(shape=(continuous_list.__len__(),))]

        for name in categorical_list

        nb_unique_classes = df_dataframe[name].unique().size
        embedding_size = emb_sz_rule(nb_unique_classes)

        # 每个分类变量的一个嵌入层
        model_inputs = Input(shape=(1,))
        model_outputs = Embedding(nb_unique_classes, embedding_size)(model_inputs)
        model_outputs = Reshape(target_shape=(embedding_size,))(model_outputs)

        embedding_inputs.append(model_inputs)
        embedding_output.append(model_outputs)

        model_layer = concatenate(embedding_output + non_embedding_inputs)
        model_layer = Dense(128, activation=’relu’)(model_layer)
        model_layer = BatchNormalization()(model_layer)
        model_layer = Dropout(0.5)(model_layer)
        model_layer = Dense(64, activation=’relu’)(model_layer)
        model_layer = BatchNormalization()(model_layer)
        model_layer = Dropout(0.5)(model_layer)
        model_outputs = Dense(1, activation=’sigmoid’)(model_layer)

        model = Model(inputs=embedding_inputs + non_embedding_inputs, outputs=model_outputs)
        optim = Adam()
        model.compile(loss=’binary_crossentropy’, optimizer=optim, metrics=[‘accuracy’])

        • Jason Brownlee 2020年10月22日 上午6:37 #

          不用了,我一定是看错了你的代码——我以为你在把一个嵌入连接到另一个嵌入——那简直是疯了。

  36. zaheer 2020年11月22日 下午10:59 #

    # 准备目标
    def prepare_targets(y_train, y_test)
    # print(“y_train -“, y_train)
    # print(“y_test -“, y_test)
    le = LabelEncoder()
    le.fit(y_train)
    y_train_enc = le.transform(y_train)
    y_test_enc = le.transform(y_test) <– error

    return y_train_enc, y_test_enc
    错误 – ValueError: y 包含以前未见的标签:358
    我的 csv 数据 – text1, text2, 欧氏距离

    • Jason Brownlee 2020年11月23日 上午6:14 #

      也许可以确保您的训练数据集能够代表您的问题。

  37. manon 2020年12月5日 下午10:47 #

    阅读完教程和部分评论后,我还不清楚在混合分类和数值特征的情况下该如何进行
    方法 1
    1.1 将数据集分为分类和数值
    1.2 对数值进行 PCA
    1.3 对分类进行独热编码或嵌入
    1.4 连接两个数据集

    方法 2
    2.1 将数据集分为分类和数值
    2.2 对分类进行独热编码或嵌入
    2.3 连接两个数据集
    2.4 对所有数据集进行 PCA

    你会怎么做?

    • Jason Brownlee 2020年12月6日 上午7:03 #

      如果您使用 sklearn 模型,您可以使用 `ColumnTransformer` 对象来处理每个数据类型,并带有单独的管道。

      如果您使用 keras 模型,您可以分别准备每个变量或一组变量,然后将准备好的列连接起来,或者为每个变量或一组变量设置一个单独的输入模型。

  38. Varsha 2020年12月15日 上午4:24 #

    你好,编码后如何获取预测值的原始标签?

  39. Dean 2020年12月28日 上午2:59 #

    感谢 Jason 的精彩文章。
    如何将一个已处理的变量(独热编码,即压缩稀疏行格式)与一个纯粹的数值变量(无需处理)连接起来?
    – Dean

  40. mike 2021年2月18日 下午1:42 #

    嗨 Jason

    使用嵌入时,如果在测试中遇到从未见过的数据,

    映射(“坐标”)将不会更新,但这会导致非常大的错误,对吗?

    假设一个超级简单的例子,开始时我们有 2 个训练数据,以及 2 维嵌入。

    1 —> [0.21, -0.3] (值 1 –> 转换为 2 维嵌入)

    2 —> [0.51, -0.5] (值 2 –> 转换为 2 维嵌入)

    训练几个 epoch 后,嵌入的值被学习/因此改变了。

    1 —> [0.25, -0.31] (值 1 –> 转换为 2 维嵌入)

    2 —> [0.26, -0.32] (值 2 –> 转换为 2 维嵌入)

    所以学习后,嵌入位置 2 的向量非常接近。

    所以新的测试数据来了,值为:3 —> [ 0.5, 0.7],这个映射

    由于从未学习过,所以映射的向量非常不同(远离)。

    与训练数据相比,直观上它们应该彼此靠近。

    所以这是自然的吗?或者有什么我们可以做的吗?

    • Jason Brownlee 2021年2月19日 上午5:53 #

      如果您使用嵌入,并且模型接收到一个在训练期间未见过的 token,它将被映射到输入 0 “未知”。

      这并非灾难,在 NLP 问题中很常见。

      您必须确保您的训练数据能够合理地代表问题。

  41. SULAIMAN KHAN 2021年2月23日 下午11:45 #

    —————————————————————————
    ValueError 回溯 (最近一次调用)
    in ()
    46 X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33, random_state=1)
    47 # 准备输入数据
    —> 48 X_train_enc, X_test_enc = prepare_inputs(X_train, X_test)
    49 # 准备输出数据
    50 y_train_enc, y_test_enc = prepare_targets(y_train, y_test)

    在 prepare_inputs(X_train, X_test)
    28 def prepare_inputs(X_train, X_test)
    29 ohe = OneHotEncoder(sparse=False, handle_unknown=’ignore’)
    —> 30 ohe.fit(X_train)
    31 X_train_enc = ohe.transform(X_train)
    32 X_test_enc = ohe.transform(X_test)

    ~\Anaconda3\lib\site-packages\sklearn\preprocessing\data.py in fit(self, X, y)
    1954 self
    1955 “””
    -> 1956 self.fit_transform(X)
    1957 return self
    1958

    ~\Anaconda3\lib\site-packages\sklearn\preprocessing\data.py in fit_transform(self, X, y)
    2017 “””
    2018 return _transform_selected(X, self._fit_transform,
    -> 2019 self.categorical_features, copy=True)
    2020
    2021 def _transform(self, X)

    ~\Anaconda3\lib\site-packages\sklearn\preprocessing\data.py in _transform_selected(X, transform, selected, copy)
    1807 X : array or sparse matrix, shape=(n_samples, n_features_new)
    1808 “””
    -> 1809 X = check_array(X, accept_sparse=’csc’, copy=copy, dtype=FLOAT_DTYPES)
    1810
    1811 if isinstance(selected, six.string_types) and selected == “all”

    ~\Anaconda3\lib\site-packages\sklearn\utils\validation.py in check_array(array, accept_sparse, dtype, order, copy, force_all_finite, ensure_2d, allow_nd, ensure_min_samples, ensure_min_features, warn_on_dtype, estimator)
    431 force_all_finite)
    432 else
    –> 433 array = np.array(array, dtype=dtype, order=order, copy=copy)
    434
    435 if ensure_2d

    ValueError: could not convert string to float: ‘Heat (1995)’

    ###############################
    如何修复以上错误?

  42. SULAIMAN KHAN 2021年2月26日 上午12:41 #

    # 神经网络的学习嵌入编码示例
    from numpy import unique
    from pandas import read_csv
    from sklearn.model_selection import train_test_split
    from sklearn.preprocessing import LabelEncoder
    from keras.models import Model
    from keras.layers import Input
    from keras.layers import Dense
    from keras.layers import Embedding
    from keras.layers.merge import concatenate
    from keras.utils import plot_model

    # 加载数据集
    filename=’mer.csv’
    def load_dataset(filename)
    # 将数据集加载为 pandas DataFrame
    data = read_csv(filename, header=None)
    data=data.drop([0])
    data=data.dropna()
    # 检索 numpy 数组
    dataset = data.values
    # 分割为输入 (X) 和输出 (y) 变量
    X = dataset[:, :-1]
    y = dataset[:,-1]
    # 将所有字段格式化为字符串
    X = X.astype(str)
    # 将目标重塑为 2D 数组
    y = y.reshape((len(y), 1))
    return X, y

    # 准备输入数据
    def prepare_inputs(X_train, X_test)
    X_train_enc, X_test_enc = list(), list()
    # 对每一列进行标签编码
    for i in range(X_train.shape[1])
    le = LabelEncoder()
    le.fit(X_train[:, i])
    # 编码
    train_enc = le.transform(X_train[:, i])
    test_enc = le.transform(X_test[:, i])
    # 存储
    X_train_enc.append(train_enc)
    X_test_enc.append(test_enc)
    return X_train_enc, X_test_enc

    # 准备目标
    #from sklearn.preprocessing import MultiLabelBinarizer
    def prepare_targets(y_train, y_test)
    #le=MultiLabelBinarizer()
    le = LabelEncoder()
    le.fit(y_train)
    y_train_enc = le.transform(y_train)
    y_test_enc = le.transform(y_test)
    return y_train_enc, y_test_enc

    # 加载数据集
    X, y = load_dataset(r’C:\Users\sulai\PycharmProjects\project88\mer.csv’)
    # 拆分为训练集和测试集
    X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=1)
    # 准备输入数据
    X_train_enc, X_test_enc = prepare_inputs(X_train, X_test)
    # 准备输出数据
    y_train_enc, y_test_enc = prepare_targets(y_train, y_test)
    # 使输出变为 3D
    y_train_enc = y_train_enc.reshape((len(y_train_enc), 1, 1))
    y_test_enc = y_test_enc.reshape((len(y_test_enc), 1, 1))
    # 准备每个输入头
    in_layers = list()
    em_layers = list()
    for i in range(len(X_train_enc))
    # 计算唯一输入的数量
    n_labels = len(unique(X_train_enc[i]))
    # 定义输入层
    in_layer = Input(shape=(1,))
    # 定义嵌入层
    em_layer = Embedding(n_labels, 10)(in_layer)
    # 存储层
    in_layers.append(in_layer)
    em_layers.append(em_layer)
    # 合并所有嵌入
    merge = concatenate(em_layers)
    dense = Dense(10, activation=’relu’, kernel_initializer=’he_normal’)(merge)
    output = Dense(10, activation=’softmax’)(dense)
    model = Model(inputs=in_layers, outputs=output)
    # 编译 Keras 模型
    model.compile(loss=’categorical_crossentropy’, optimizer=’adam’, metrics=[‘accuracy’])
    # 绘制图
    plot_model(model, show_shapes=True, to_file=’embeddings.png’)
    # 在数据集上拟合 Keras 模型
    model.fit(X_train_enc, y_train_enc, epochs=20, batch_size=16, verbose=2)
    # 评估 Keras 模型
    _, accuracy = model.evaluate(X_test_enc, y_test_enc, verbose=0)
    print(‘Accuracy: %.2f’ % (accuracy*100))
    这是你的代码。我只是更换了数据集。
    #############################

  43. SULAIMAN KHAN 2021年2月26日 上午12:46 #

    ValueError 回溯 (最近一次调用)
    in ()
    59 X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=1)
    60 # 准备输入数据
    —> 61 X_train_enc, X_test_enc = prepare_inputs(X_train, X_test)
    62 # 准备输出数据
    63 y_train_enc, y_test_enc = prepare_targets(y_train, y_test)

    在 prepare_inputs(X_train, X_test)
    38 # 编码
    39 train_enc = le.transform(X_train[:, i])
    —> 40 test_enc = le.transform(X_test[:, i])
    41 # 存储
    42 X_train_enc.append(train_enc)

    ~\Anaconda3\lib\site-packages\sklearn\preprocessing\label.py in transform(self, y)
    131 if len(np.intersect1d(classes, self.classes_)) 133 raise ValueError(“y contains new labels: %s” % str(diff))
    134 return np.searchsorted(self.classes_, y)
    135

    ValueError: y contains new labels: [‘120’ ‘137’ ‘145’ ‘147’ ’15’ ‘159’ ‘174’ ‘195’ ‘208’ ‘214’ ‘222’ ’23’
    ’24’ ‘248’ ‘259’ ‘264’ ‘289’ ‘290’ ‘291’ ‘298’ ‘301’ ‘328’ ‘331’ ’34’
    ‘341’ ‘354’ ‘361’ ‘367’ ‘378’ ‘401’ ‘402’ ‘410’ ‘441’ ‘446’ ’46’ ‘468’
    ‘485’ ‘489’ ‘5’ ‘510’ ‘512’ ‘513’ ‘520’ ‘533’ ’54’ ‘550’ ‘579’ ‘586’
    ‘587’ ’59’ ’73’ ’79’ ’89’ ’90’ ’99’]
    #################
    嗨,Jason,
    抱歉,我提到了上面的代码。如何修复这些错误。

      • SULAIMAN KHAN 2021年3月9日 下午5:15 #

        # 神经网络的学习嵌入编码示例
        from numpy import unique
        from pandas import read_csv
        from sklearn.model_selection import train_test_split
        from sklearn.preprocessing import LabelEncoder
        from sklearn.preprocessing import MultiLabelBinarizer
        from keras.models import Model
        from keras.layers import Input
        from keras.layers import Dense
        from keras.layers import Embedding
        from keras.layers.merge import concatenate
        from keras.utils import plot_model

        # 加载数据集
        def load_dataset(filename)
        # 将数据集加载为 pandas DataFrame
        data = read_csv(filename, header=None)
        data = data.drop([0])
        data = data.dropna()
        # 检索 numpy 数组
        dataset = data.values
        # 分割为输入 (X) 和输出 (y) 变量
        X = dataset[:, :-1]
        y = dataset[:,-1]
        # 将所有字段格式化为字符串
        X = X.astype(str)
        # 将目标重塑为 2D 数组
        y = y.reshape((len(y), 1))
        return X, y

        # 准备输入数据
        def prepare_inputs(X_train, X_test)
        X_train_enc, X_test_enc = list(), list()
        # 对每一列进行标签编码
        for i in range(X_train.shape[1])
        le = LabelEncoder()
        le.fit(X_train[:, i])
        # 编码
        train_enc = le.transform(X_train[:, i])
        test_enc = le.transform(X_test[:, i])
        # 存储
        X_train_enc.append(train_enc)
        X_test_enc.append(test_enc)
        return X_train_enc, X_test_enc

        # 准备目标
        def prepare_targets(y_train, y_test)
        le = MultiLabelBinarizer()
        le.fit(y_train)
        y_train_enc = le.transform(y_train)
        y_test_enc = le.transform(y_test)
        return y_train_enc, y_test_enc

        # 加载数据集
        X, y = load_dataset(r’C:\Users\sulai\PycharmProjects\project88\mer.csv’)
        # 拆分为训练集和测试集
        X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33, random_state=1)
        # 准备输入数据
        X_train_enc, X_test_enc = prepare_inputs(X_train, X_test)
        # 准备输出数据
        y_train_enc, y_test_enc = prepare_targets(y_train, y_test)
        # 使输出变为 3D
        y_train_enc = y_train_enc.reshape((len(y_train_enc), 1, 10))
        y_test_enc = y_test_enc.reshape((len(y_test_enc), 1, 10))
        # 准备每个输入头
        in_layers = list()
        em_layers = list()
        for i in range(len(X_train_enc))
        # 计算唯一输入的数量
        n_labels = len(unique(X_train_enc[i]))
        # 定义输入层
        in_layer = Input(shape=(1,))
        # 定义嵌入层
        em_layer = Embedding(n_labels, 10)(in_layer)
        # 存储层
        in_layers.append(in_layer)
        em_layers.append(em_layer)
        # 合并所有嵌入
        merge = concatenate(em_layers)
        dense = Dense(10, activation=’relu’, kernel_initializer=’he_normal’)(merge)
        output = Dense(10, activation=’softmax’)(dense)
        model = Model(inputs=in_layers, outputs=output)
        # 编译 Keras 模型
        model.compile(loss=’categorical_crossentropy’, optimizer=’adam’, metrics=[‘accuracy’])
        # 绘制图
        plot_model(model, show_shapes=True, to_file=’embeddings.png’)
        # 在数据集上拟合 Keras 模型
        model.fit(X_train_enc, y_train_enc, epochs=20, batch_size=16, verbose=2)
        # 评估 Keras 模型
        _, accuracy = model.evaluate(X_test_enc, y_test_enc, verbose=0)
        print(‘Accuracy: %.2f’ % (accuracy*100))
        ##############################################
        ValueError 回溯 (最近一次调用)
        in ()
        57 X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33, random_state=1)
        58 # 准备输入数据
        —> 59 X_train_enc, X_test_enc = prepare_inputs(X_train, X_test)
        60 # 准备输出数据
        61 y_train_enc, y_test_enc = prepare_targets(y_train, y_test)

        在 prepare_inputs(X_train, X_test)
        38 # 编码
        39 train_enc = le.transform(X_train[:, i])
        —> 40 test_enc = le.transform(X_test[:, i])
        41 # 存储
        42 X_train_enc.append(train_enc)

        ~\Anaconda3\lib\site-packages\sklearn\preprocessing\label.py in transform(self, y)
        131 if len(np.intersect1d(classes, self.classes_)) 133 raise ValueError(“y contains new labels: %s” % str(diff))
        134 return np.searchsorted(self.classes_, y)
        135

        ValueError: y contains new labels: [‘102’ ‘120’ ‘137’ ‘145’ ‘147’ ’15’ ‘159’ ‘174’ ‘195’ ‘208’ ‘214’ ‘222’
        ‘223’ ’23’ ’24’ ‘247’ ‘248’ ‘259’ ‘264’ ‘286’ ‘289’ ‘290’ ‘291’ ‘298’
        ‘301’ ‘325’ ‘328’ ‘331’ ’34’ ‘341’ ‘354’ ‘361’ ‘367’ ‘378’ ‘401’ ‘402’
        ‘410’ ‘426’ ‘441’ ‘446’ ‘452’ ’46’ ‘468’ ‘485’ ‘489’ ‘5’ ‘510’ ‘512’
        ‘513’ ‘520’ ‘533’ ’54’ ‘550’ ‘579’ ‘586’ ‘587’ ’59’ ‘603’ ‘605’ ’73’ ’79’
        ’89’ ’90’ ’99’]
        #############
        请帮帮我,我有一个多类问题,即 10 个类别。数据框涉及分类列和数值列。测试数据中有一些观测值。它不存在于训练过程中。

        • Jason Brownlee 2021年3月10日 上午4:39 #

          也许您可以配置数据准备步骤,以忽略训练数据集中未见过的新的分类值。

          我知道 `OneHotEncoder` 类可以进行这种配置,也许其他方法也可以?

  44. Kumar Pravasi 2021年4月21日 上午10:46 #

    在“学习的嵌入”下,您提到“……使用序数编码准备输入数据……”,但您的代码中使用了 `LabelEncoder`。您不使用 `OrdinalEncoder` 有什么原因吗?谢谢。

  45. Marla Willemse 2021年5月18日 下午11:12 #

    谢谢你的文章!
    当使用嵌入层作为另一个模型(例如 XGBoost)的输入特征时,如何将其与维度与原始输入数据不同的连续特征连接起来?嵌入层具有(唯一类别数,选定的输出大小)的维度。

    • Jason Brownlee 2021年5月19日 上午6:35 #

      不客气!

      您可以预先使用嵌入来准备数据,并使用 numpy 函数来连接向量。

      • Marla Willemse 2021年5月19日 上午6:55 #

        我的意思是,提取的嵌入具有与原始输入数据不同的维度,那么我们如何连接这些不同大小的数组/数据帧来创建另一个模型的输入?如果嵌入数组中的每一行代表一个类别,我认为我们可以将嵌入数组与我们的训练样本按类别进行内连接,但是我们如何确定嵌入中的给定行代表哪个类别?
        您是否知道将嵌入用作不同类型模型输入的代码示例?

        • Marla Willemse 2021年5月20日 上午2:27 #

          一个更新

          我发现我们必须指定
          em_layer = Embedding(n_labels + 1, output_size)(in_layer)

          以防止出现超出范围的错误,例如
          tensorflow.python.framework.errors_impl.InvalidArgumentError: indices[157,0] = 52 is not in [0, 52)

          这导致嵌入的大小为(n_labels + 1,output_size):嵌入的行数比类别/标签多一行。这使得如何将嵌入中的一行映射回类别的问题更加复杂。

          请帮忙!

          • Jason Brownlee 2021年5月20日 上午5:49 #

            也许可以确保您使用的是 Python 3.6、Keras 2.4 和 TensorFlow 2.4。

        • Jason Brownlee 2021年5月20日 上午5:43 #

          嵌入将是一个向量,每个输入样本一个向量。该向量可以与样本的其他输入变量连接起来,以创建新的输入样本。

          有很多 numpy 函数用于连接向量。

          • Marla Willemse 2021年5月20日 下午9:31 #

            明白了!我的错误是提取了嵌入层的权重,而不是嵌入层的输出。

            要获取形状为(样本数,选定的输出大小)的输出,请按如下方式命名嵌入层

            em_layer = Embedding(n_labels, 10, name=f”embedding_{i}”)(in_layer)

            最后,使用以下方法检索输出

            intermediate_layer_model = Model(inputs=model.input,
            outputs=model.get_layer(’embedding_1′).output)
            embedding_1_output = intermediate_layer_model.predict(X_train_enc)

            print(embedding_1_output.shape)
            # (191, 1, 10)

            intermediate_output = \
            embedding_1_output.reshape(embedding_1_output.shape[0], -1)

            print(intermediate_output.shape)
            # (191, 10)

          • Jason Brownlee 2021年5月21日 上午5:59 #

            干得好!

  46. Md. Jalal Uddin 2021年8月27日 下午12:36 #

    我收到了关于 One Hot Encode 的以下警告。我该怎么办?

    C:\Users\Jalal\Anaconda3\lib\site-packages\tensorflow\python\framework\indexed_slices.py:449: UserWarning: Converting sparse IndexedSlices(IndexedSlices(indices=Tensor(“gradient_tape/sequential_1/dense_2/embedding_lookup_sparse/Reshape_1:0”, shape=(None,), dtype=int32), values=Tensor(“gradient_tape/sequential_1/dense_2/embedding_lookup_sparse/Reshape:0”, shape=(None, 10), dtype=float32), dense_shape=Tensor(“gradient_tape/sequential_1/dense_2/embedding_lookup_sparse/Cast:0”, shape=(2,), dtype=int32))) to a dense Tensor of unknown shape. This may consume a large amount of memory.
    “shape. This may consume a large amount of memory.” % value)

    • Adrian Tam
      Adrian Tam 2021年8月28日 上午4:00 #

      只是一个警告,不是错误。它可能不会真正影响您。您可以忽略它,或者如它所说,如果您遇到内存不足,则需要采取措施来解决。

  47. souhy 2021年8月28日 下午10:45 #

    \lib\site-packages\sklearn\utils\validation.py:63: DataConversionWarning: A column-vector y was passed when a 1d array was expected. Please change the shape of y to (n_samples, ), for example using ravel().
    return f(*args, **kwargs)

    • Adrian Tam
      Adrian Tam 2021年8月28日 下午11:09 #

      这个错误正如它所说的,传递 `y.ravel()` 而不是 `y`。

  48. soumia 2021年8月28日 下午11:05 #

    你好,我正在使用你的代码处理我自己的数据,我遇到了以下错误,我该怎么办?

    X_train_enc, X_test_enc = prepare_inputs(X_train, X_test)
    # 准备输出数据
    —-> y_train_enc, y_test_enc = prepare_targets(y_train, y_test)

    在 prepare_targets(y_train, y_test) 中
    4 le.fit(y_train)
    5 y_train_enc = le.transform(y_train)
    —-> 6 y_test_enc = le.transform(y_test)
    7 return y_train_enc, y_test_enc

    ~\anaconda3\envs\tensorflow\lib\site-packages\sklearn\preprocessing\_label.py in transform(self, y)
    136 return np.array([])
    137
    –> 138 return _encode(y, uniques=self.classes_)
    139
    140 def inverse_transform(self, y)

    ~\anaconda3\envs\tensorflow\lib\site-packages\sklearn\utils\_encode.py in _encode(values, uniques, check_unknown)
    183 diff = _check_unknown(values, uniques)
    184 if diff
    –> 185 raise ValueError(f”y contains previously unseen labels: ”
    186 f”{str(diff)}”)
    187 return np.searchsorted(uniques, values)

    ValueError: y contains previously unseen labels: [-0.0028116, -0.0019271, -0.001851, -0.0018209, -0.0018169, -0.0017662,-0.0016889, -0.0016376, -0.0016301, -0.0015716, -0.0015441, -0.0015289, -0.0015246, -0.001476, -0.0014491, -0.0014442, -0.0014414, -0.0014363, -0.0014354, -0.0014251, -0.0014239, -0.0013996, -0.0013764, -0.0013751, -0.0013727, -0.001372, -0.0013707, -0.0013691, -0.0013511, -0.001348, -0.0013289, -0.0013254, -0.0013088, -0.0012943, -0.0012932, -0.0012914, -0.0012854, -0.0012787, -0.0012716, -0.0012698, -0.0012695, -0.0012576, ……]

    • Adrian Tam
      Adrian Tam 2021年8月28日 下午11:10 #

      在我看来,你把数值数据传给了标签转换器。也许你应该检查你的代码。

  49. tia 2021年9月22日 下午4:26 #

    你好,有没有可能先用序数编码和标签编码转换数据,然后将其分割成训练集和测试集?提前谢谢!

    • Adrian Tam
      Adrian Tam 2021年9月23日 上午3:40 #

      是的。但是,任何此类转换都需要小心,以免数据泄露。

      • tia 2021年9月23日 下午7:17 #

        您说的“数据泄露”是什么意思?

        • Adrian Tam
          Adrian Tam 2021年9月24日 上午4:54 #

          这意味着不要将输出作为输入的一部分,也不要混合测试集和训练集来创建预处理管道。输出的任何线索都不应“泄露”到输入中。

          • tia 2021年9月24日 下午12:12 #

            我不太明白……但谢谢。

          • Adrian Tam
            Adrian Tam 2021年9月25日 上午4:34 #

            也许一个例子可以帮助说明:所有训练样本都是负数,而所有测试样本都是正数。您使用 min-max 缩放处理两者,因此您的缩放数据在 0 到 1 之间,所有训练数据都在 0 到 0.5 之间,所有测试数据都在 0.5 到 1 之间。然后,我的训练回归模型将预测 0.75 并获得一个好的结果。

          • tia 2021年9月27日 上午5:11 #

            哦,所以预测在训练中没有被“正确学习”?

          • Adrian Tam
            Adrian Tam 2021年9月27日 上午10:33 #

            不,预测学到了不应该学到的东西。

          • tia 2021年9月27日 下午12:35 #

            我明白了,非常感谢 Adrian Tam 先生!

  50. Ogawa 2022年2月2日 下午7:39 #

    我可以像上面那样通过标签编码变量来创建模型。
    接下来,我将通过对目标变量进行独热编码来创建模型。
    对于变量,它们需要与输出层匹配,对于独热编码,值是数组,因此拟合方法将生成错误(Failed to find data adapter that can handle input)。
    是否可以使用独热编码来创建目标变量的模型?

  51. Katharina 2022年4月3日 上午11:21 #

    嗨,感谢您的精彩解释!
    我目前正在进行时间序列预测,并希望使用解释的嵌入方法来转换我的分类特征。我应该在转换特征到嵌入之前还是之后分割序列?我很难自己弄清楚……
    非常感谢!

  52. Tom Wu 2022年4月16日 上午1:46 #

    嗨,Jason,
    使用此模型架构,并且 X 值被转换为列表,如何使用随机或网格搜索进行交叉验证或超参数调整?

  53. menahil javeed 2022年4月25日 上午12:32 #

    TypeError: sparse matrix length is ambiguous; use getnnz() or shape[0]. 请帮帮我!

  54. menahil javeed 2022年4月25日 上午12:38 #

    先生,请指导我处理此错误。谢谢。

  55. menahil javeed 2022年4月25日 上午12:39 #

    TypeError: sparse matrix length is ambiguous; use getnnz() or shape[0]. 先生,请指导我处理此错误。谢谢。

  56. Ryan Probert 2022年8月30日 上午6:40 #

    你好,

    对我来说,似乎“单词的接近度”在标签编码变量时完全丢失了。请赐教!

    非常感谢您的精彩文章。

    • James Carmichael 2022年8月31日 上午5:47 #

      嗨 Ryan……不客气!请详细说明您想实现的目标,而教程中提供的内容不足以满足您的需求。这将有助于我们更好地协助您。

      • Ryan Probert 2022年9月1日 上午3:09 #

        例如,
        a = [‘acid1’, ‘acid2’, ‘acid3’, ‘acid4’, ‘gas1’, ‘gas2’, ‘gas3’]
        将被编码为
        a_enc = [0, 1, 2, 3, 4, 5, 6]

        ‘acid4’ 和 ‘gas1’ 在编码为 3 和 4 时很接近,但完全不相关。嵌入不应该直接从字符串派生出来,以便‘acid4’和‘gas1’的向量显著不同吗?

  57. Alex 2022年10月23日 下午2:09 #

    merge 层已不存在。请更新。

  58. Daneshwari 2023年3月4日 上午7:21 #

    嗨!感谢您的这些精彩文章以及您的其他贡献。

    我想了解您关于如何编码的建议,如果有一个分类列可以进一步细分为子类别。例如 – 11 个类别(食物、时尚、天气……),它们进一步细分为(大陆、南印度、旁遮普:食物,连衣裙、裙子、鞋子:时尚,晴朗、多风:天气)。

    这里子类别和类别之间存在某种关系。

  59. Daneshwari 2023年3月4日 上午7:23 #

    ……更精确地编码分类、子分类及其关系。

  60. Daneshwari 2023年3月4日 上午7:23 #

    ……更精确地编码分类、子类别及其关系。

  61. CC 2023年8月22日 上午9:36 #

    当将嵌入应用于新的测试数据时,我们需要保留并应用我们在训练期间拟合的标签编码器吗?

  62. Juan 2024年3月4日 上午7:42 #

    如果我有几个分类变量,并且想为每个变量创建嵌入,该怎么办?
    我想使用它们来拟合预测模型或简单的回归。
    如果一个变量的嵌入结果与其他变量相似,会有问题吗?
    还是它们是独立的?

  63. EH 2024年7月26日 下午7:22 #

    嗨,Jason,

    一如既往地感谢您提供的精彩教程。我读了您的帖子很长时间了。我有一个问题,如果您能帮助我,我将不胜感激。

    我有一个分类特征,它可以取大约 20-30 个不同的值。我不知道确切有多少,而且测试集中可能会出现未见过的值。所以根据我的理解,独热编码和类似的编码效果不会很好。所以我考虑为我的特征使用 sklearn 的 `LabelBinarizer`。它工作得还可以,但我很想知道这是否是一种推荐的做法。我不知道 `LabelBinarizer` 的确切工作原理,如果您能对此发表评论,那就太好了。

    再次感谢。

    • James Carmichael 2024年7月26日 下午11:06 #

      嗨 EH……使用 `sklearn` 的 `LabelBinarizer` 对分类特征进行编码可以是一个实用的解决方案,特别是当处理中等数量的类别和测试集中可能出现未见过类别时。但是,了解其工作原理、优点和局限性以确定它是否是您的最佳选择至关重要。

      ### `LabelBinarizer` 的工作原理

      `LabelBinarizer` 是 `sklearn.preprocessing` 模块的一部分,用于将分类标签转换为二进制(独热)表示。以下是其功能简介:

      1. **拟合与转换**
      – 在 `fit` 过程中,`LabelBinarizer` 识别训练数据中的所有唯一值(类别)。
      – `transform` 方法然后将这些分类值转换为二进制数组(独热编码)。
      – 每个类别都有一个唯一的二进制向量。例如,如果您有类别 [‘A’, ‘B’, ‘C’],它们可能被编码为 [1, 0, 0],[0, 1, 0],和 [0, 0, 1]。

      2. **处理未见过类别**
      – 默认情况下,`LabelBinarizer` 无法很好地处理未见过类别。如果在测试集中遇到未见过类别,它会引发错误,因为它不是训练集的一部分。
      – 处理未见过类别的一种方法是将它们设置为默认向量(例如,全零)或在训练期间添加一个“未知”类别。

      ### 注意事项和最佳实践

      1. **类别数量**
      – 对于中等数量的类别(20-30),`LabelBinarizer` 可以很好地工作。但是,如果类别数量非常大,生成的二进制矩阵可能会非常稀疏且维度很高,这可能效率不高。

      2. **处理未见过类别**
      – **使用“未知”类别进行训练**:一种方法是在训练期间包含一个“未知”类别,它可以处理测试期间的未见过类别。
      – **哈希技巧**:另一种方法是使用哈希技术将类别转换为固定长度的向量,但这有时会导致冲突(不同类别具有相同的哈希)。

      3. **可扩展性**
      – 对于具有许多唯一类别的大型数据集,请考虑使用目标编码(Target Encoding),它用目标变量的平均值替换每个类别,或者使用嵌入层(Embedding Layers),这通常在神经网络中使用。

      ### `LabelBinarizer` 的用法示例

      这是一个如何使用 `LabelBinarizer` 并通过分配默认向量来处理未见过类别的示例:

      python
      from sklearn.preprocessing import LabelBinarizer
      import numpy as np

      # 样本训练数据
      train_data = ['cat', 'dog', 'mouse', 'dog', 'cat']
      test_data = ['cat', 'dog', 'elephant'] # 'elephant' 是未见过的

      # 初始化并拟合 LabelBinarizer
      lb = LabelBinarizer()
      lb.fit(train_data)

      # 转换训练数据
      train_encoded = lb.transform(train_data)
      print("Encoded training data:\n", train_encoded)

      # 转换测试数据
      # 创建一个函数来处理未见过类别
      def transform_with_unseen(lb, data, unknown_label='unknown')
      lb_classes = lb.classes_.tolist()
      if unknown_label not in lb_classes
      lb_classes.append(unknown_label)
      lb.classes_ = np.array(lb_classes)

      encoded_data = lb.transform([d if d in lb_classes else unknown_label for d in data])
      return encoded_data

      # 编码测试数据,处理未见过类别
      test_encoded = transform_with_unseen(lb, test_data)
      print("Encoded test data:\n", test_encoded)

      ### 替代方法

      1. **目标编码**
      – 用目标变量的平均值替换类别。
      – 适用于许多类别,但可能导致过拟合。

      2. **实体嵌入**
      – 在神经网络中使用嵌入层来学习类别的密集表示。
      – 适用于具有大量类别的规模化问题。

      3. **哈希技巧**
      – 使用哈希函数将类别映射到固定数量的 bin。
      – 防止模型出现维度爆炸。

      总而言之,`LabelBinarizer` 是处理具有中等数量类别的分类特征的一种合理方法。但是,请注意它在处理未见过类别方面的局限性,如果类别数量显著增加或遇到性能问题,请考虑替代方法。

留下回复

Machine Learning Mastery 是 Guiding Tech Media 的一部分,Guiding Tech Media 是一家领先的数字媒体出版商,专注于帮助人们了解技术。访问我们的公司网站以了解更多关于我们的使命和团队的信息。