2

我正在查看对大量文本数据的数据预处理任务,并希望将预处理后的数据加载到 TensorFlow 2.x 中。预处理数据包含整数值数组,因为预处理步骤生成:

  • 一个热编码数组作为标签列
  • 每个数据行的标记化标记列表
  • 用于变压器的激活掩码

所以,我一直在想我会使用 pyspark 来预处理数据并将结果转储到JSON文件中(因为 CSV 无法存储结构化数据)。到目前为止,一切正常。但是我在处理JSON文件时遇到了麻烦tf.data.Dataset(或任何其他可以有效扩展并可以与 TensorFlow 2.x 接口的文件)。

我不想使用/安装除 Tensorflow 和 PySpark 之外的其他库(例如 TensorFlowOnSpark),所以我想知道是否可以使用 JSON 文件以有效的方式链接两者,因为似乎没有其他方法可以保存/加载记录包含数据列表(?)。JSON 测试文件如下所示:

readDF = spark.read.format('json').option('header',True).option('sep','|').load('/output.csv')
readDF.select('label4').show(15, False)

+---------------------------------------------------------+
|label4                                                   |
+---------------------------------------------------------+
|[0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]|
|[0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]|
|[0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]|
|[0, 1, 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, 1, 0, 0, 0, 0]|
|[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0]|
|[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0]|
|[0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]|
|[0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]|
|[0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]|
|[0, 0, 0, 0, 0, 0, 0, 0, 1, 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, 1, 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, 1, 0, 0, 0, 0]|
|[0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]|
+---------------------------------------------------------+

因此,label4列已经进行了一次热编码,并且一旦将标记器应用于它,标记化的文本列将看起来相似。所以,我的问题是:JSON文件可以有效地加载(可能通过生成器函数)tf.data.Dataset还是我应该为此走一条不同的道路(使用额外的库)?

4

1 回答 1

1

tf.data提供了几种有效使用来自不同来源的数据的方法。虽然我会说一个“更清洁”的解决方案可能是使用 TensorFlow 本身来处理预处理,但让我为您的用例提出一些想法:

1) one-hot编码

我可以看到您对数据进行了预处理并存储了整个 one-hot 编码向量,这将惩罚您的数据传输,因为您将读取的大部分内容都是零,而不是实际感兴趣的标签。我建议将其编码为整数,并在摄取时使用 python 生成器将其转换为单热编码。或者,如果您使用分类交叉熵损失函数,则可以使用标签编码(将每个类编码为整数),并改用稀疏分类交叉熵

如果你已经有 one-hot-encoded 列表,你可以简单地使用my_list.index(1)来获取标签编码(它毕竟与向量中唯一 1 的索引相同。)

2) 使用生成器

这完全可以使用tf.data. 事实上,它们提供了from_generator包装 python 生成器的功能,用于将数据摄取到模型中。如文档中所述,这是您使用它的方式:

def gen():
  ragged_tensor = tf.ragged.constant([[1, 2], [3]])
  yield 42, ragged_tensor

dataset = tf.data.Dataset.from_generator(
     gen,
     output_signature=(
         tf.TensorSpec(shape=(), dtype=tf.int32),
         tf.RaggedTensorSpec(shape=(2, None), dtype=tf.int32)))

list(dataset.take(1))

3) 考虑回到 CSV

如果您正在处理大量数据,您可能可以处理 JSON 编码并在类似 CSV 的格式中编码某些结构,例如 TSV,如果您需要类似列表的列,您可以使用其他分隔符(例如,您可以用 分隔列\t,然后您可以使用,|或任何字符分隔每列中的元素,从而减少与现有数据的冲突。

例如,假设您的 CSV 文件具有以下结构:

comlumn name 1, column name 2, column name 3, column name 4
0.1,0.2,0.3,0:0:0:1
0.1,0.2,0.3,0:0:1:0
0.1,0.2,0.3,0:1:0:0
...

也就是说,您有 4 列由 分隔,,第 4 列本身就是一个由 分隔的值列表:,这也是 4 个类的一个热门表示,您可以与上面的代码一起使用的生成器是:

def my_generator(filename):
    first_line = True
    with open(filename) as f:
        for line in f:
            if first_line:
                # do something to handle the header
                first_line = False
                continue
            fields = line.split(',')
            # here you extract the index of the one-hot encoded class
            label = fields[3].split(':').index(1)
            fields[3] = label
            yield fields # return a list of features and the class
于 2021-03-17T15:18:00.323 回答