使用 tf.data 的 One-hot 编码混合了列

Posted

技术标签:

【中文标题】使用 tf.data 的 One-hot 编码混合了列【英文标题】:One-hot encoding using tf.data mixes up columns 【发布时间】:2020-02-04 19:29:53 【问题描述】:

最少的工作示例

考虑以下 CSV 文件 (example.csv)

animal,size,weight,category
lion,large,200,mammal
ostrich,large,150,bird
sparrow,small,0.1,bird
whale,large,3000,mammal
bat,small,0.2,mammal
snake,small,1,reptile
condor,medium,12,bird

目标是将所有分类值转换为 one-hot 编码。在 Tensorflow 2.0 中执行此操作的 standard 方法是使用 tf.data。按照那个例子,上面处理数据集的代码是

import collections
import tensorflow as tf

# Load the dataset.
dataset = tf.data.experimental.make_csv_dataset(
    'example.csv',
    batch_size=5,
    num_epochs=1,
    shuffle=False)

# Specify the vocabulary for each category.
categories = collections.OrderedDict()
categories['animal'] = ['lion', 'ostrich', 'sparrow', 'whale', 'bat', 'snake', 'condor']
categories['size'] = ['large', 'medium', 'small']
categories['category'] = ['mammal', 'reptile', 'bird']

# Define the categorical feature columns.
categorical_columns = []
for feature, vocab in categories.items():
  cat_col = tf.feature_column.categorical_column_with_vocabulary_list(
        key=feature, vocabulary_list=vocab)
  categorical_columns.append(tf.feature_column.indicator_column(cat_col))

# Retrieve the first batch and apply the one-hot encoding to it.
iterator = iter(dataset)
first_batch = next(iterator)
categorical_layer = tf.keras.layers.DenseFeatures(categorical_columns)

print(categorical_layer(first_batch).numpy())

问题

运行上面的代码,得到

[[1. 0. 0. 0. 0. 0. 0. 1. 0. 0. 1. 0. 0.]
 [0. 1. 0. 0. 0. 0. 0. 0. 0. 1. 1. 0. 0.]
 [0. 0. 1. 0. 0. 0. 0. 0. 0. 1. 0. 0. 1.]
 [0. 0. 0. 1. 0. 0. 0. 1. 0. 0. 1. 0. 0.]
 [0. 0. 0. 0. 1. 0. 0. 1. 0. 0. 0. 0. 1.]]

看起来最后两列 sizecategory 已被翻转,尽管事实上 categories 是一个 有序 字典并且在实际的数据集。就好像tf.feature_column.categorical_column_with_vocabulary_list() 对列进行了一些毫无根据的字母排序。

上面的原因是什么。这真的是本着tf.data的精神进行one-hot编码的最佳方式吗?

【问题讨论】:

【参考方案1】:

排序在哪里?

tf.feature_column.categorical_column_with_vocabulary_list() 没有进行排序。如果你打印categorical_columns,你会看到这些列仍然按照你添加到feature_column的顺序:

[
  IndicatorColumn(categorical_column=VocabularyListCategoricalColumn(key='animal', vocabulary_list=('lion', 'ostrich', 'sparrow', 'whale', 'bat', 'snake', 'condor'), dtype=tf.string, default_value=-1, num_oov_buckets=0)),
  IndicatorColumn(categorical_column=VocabularyListCategoricalColumn(key='size', vocabulary_list=('large', 'medium', 'small'), dtype=tf.string, default_value=-1, num_oov_buckets=0)),
  IndicatorColumn(categorical_column=VocabularyListCategoricalColumn(key='category', vocabulary_list=('mammal', 'reptile', 'bird'), dtype=tf.string, default_value=-1, num_oov_buckets=0))
]

排序发生在tf.keras.layers.DenseFeatures 对象中。

在代码中,您可以看到排序发生在here 的位置(我通过跟踪从tf.keras.layers.DenseFeatures 类到tensorflow.python.feature_column.dense_features.DenseFeatures 类到tensorflow.python.feature_column.feature_column_v2._BaseFeaturesLayer 类到_normalize_feature_columns 函数的类继承找到了这一点)。

为什么要排序?

那么为什么要排序呢? Elsewhere 在包含_normalize_feature_columns 函数(即数据排序的函数)的同一个文件中,有一个类似的排序函数与此注释:

# Sort the columns so the default collection name is deterministic even if the
# user passes columns from an unsorted collection, such as dict.values().

我认为这个解释也适用于为什么在使用 tf.keras.layers.DenseFeatures 类时对列进行排序。你的列和数据是一致的,但是 tensorflow 不假设输入是一致的,所以它会对其进行排序以确保顺序一致。

【讨论】:

感谢您的彻底调查。我认为 TensorFlow 在底层进行排序的基本原理会让许多人感到困惑,尽管......

以上是关于使用 tf.data 的 One-hot 编码混合了列的主要内容,如果未能解决你的问题,请参考以下文章

独热编码(one-hot)是什么?什么数据类型需要进行独热编码?pandas如何进行独热编码(one-hot)?

为啥要用one-hot编码

机器学习多分类:为啥使用“one-hot”编码而不是数字

one-hot code 独热编码

类别的one-hot编码

机器学习入门-数据预处理-数字映射和one-hot编码 1.LabelEncoder(进行数据自编码) 2.map(进行字典的数字编码映射) 3.OnehotEncoder(进行one-hot编码)