Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
tensorflow
GitHub Repository: tensorflow/docs-l10n
Path: blob/master/site/es-419/tutorials/load_data/csv.ipynb
25118 views
Kernel: Python 3
#@title Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License.

Cargar datos CSV

Este tutorial da ejemplos de cómo usar datos CSV con TensorFlow.

Hay dos partes principales:

  1. Cargar los datos del disco

  2. Preprocesarlos en una forma adecuada para el entrenamiento.

Este tutorial se centra en la carga y ofrece algunos ejemplos rápidos de preprocesamiento. Para aprender más sobre el aspecto del preprocesamiento, consulte la guía Trabajar con capas de preprocesamiento y el tutorial Clasificar datos estructurados utilizando capas de preprocesamiento Keras.

Preparación

import pandas as pd import numpy as np # Make numpy values easier to read. np.set_printoptions(precision=3, suppress=True) import tensorflow as tf from tensorflow.keras import layers

Cargar datos en la memoria

Para cualquier conjunto de datos CSV pequeño, la forma más sencilla de entrenar un modelo TensorFlow en él es cargarlo en memoria como un Dataframe pandas o un arreglo de NumPy.

Un ejemplo relativamente sencillo es el conjunto de datos de abalones.

  • El conjunto de datos es pequeño.

  • Todas las características de entrada son valores de punto flotante de rango limitado.

Así es como se descargan los datos en un DataFrame pandas:

abalone_train = pd.read_csv( "https://storage.googleapis.com/download.tensorflow.org/data/abalone_train.csv", names=["Length", "Diameter", "Height", "Whole weight", "Shucked weight", "Viscera weight", "Shell weight", "Age"]) abalone_train.head()

El conjunto de datos contiene una serie de mediciones de abalones, un tipo de molusco marino.

una concha de abalón

“Concha de abalón” (por Nicki Dugan Pogue, CC BY-SA 2.0)

La tarea nominal de este conjunto de datos es predecir la edad a partir de las demás medidas, por lo que se separan las características y las etiquetas para el entrenamiento:

abalone_features = abalone_train.copy() abalone_labels = abalone_features.pop('Age')

Para este conjunto de datos tratará todas las características de forma idéntica. Empaquete las características en un único arreglo NumPy.:

abalone_features = np.array(abalone_features) abalone_features

Luego haga que un modelo de regresión prediga la edad. Dado que sólo hay un único tensor de entrada, basta aquí con un modelo tf.keras.Sequential.

abalone_model = tf.keras.Sequential([ layers.Dense(64, activation='relu'), layers.Dense(1) ]) abalone_model.compile(loss = tf.keras.losses.MeanSquaredError(), optimizer = tf.keras.optimizers.Adam())

Para entrenar ese modelo, pase las características y las etiquetas a Model.fit:

abalone_model.fit(abalone_features, abalone_labels, epochs=10)

Acaba de ver la forma más básica de entrenar un modelo usando datos CSV. Ahora, aprenderá a aplicar el preprocesamiento para normalizar las columnas numéricas.

Preprocesamiento básico

Es una buena práctica normalizar las entradas a su modelo. Las capas de preprocesamiento Keras aportan una forma cómoda de incorporar esta normalización a su modelo.

La capa tf.keras.layers.Normalization calcula previamente la media y la varianza de cada columna, y las usa para normalizar los datos.

En primer lugar, cree la capa:

normalize = layers.Normalization()

Luego, use el método Normalization.adapt para adaptar la capa de normalización a sus datos.

Nota: Utilice únicamente sus datos de entrenamiento con el método PreprocessingLayer.adapt. No use sus datos de validación o de prueba.

normalize.adapt(abalone_features)

Luego, use la capa de normalización en su modelo:

norm_abalone_model = tf.keras.Sequential([ normalize, layers.Dense(64, activation='relu'), layers.Dense(1) ]) norm_abalone_model.compile(loss = tf.keras.losses.MeanSquaredError(), optimizer = tf.keras.optimizers.Adam()) norm_abalone_model.fit(abalone_features, abalone_labels, epochs=10)

Tipos de datos mezclados

El conjunto de datos "Titanic" contiene información sobre los pasajeros del Titanic. La tarea nominal en este conjunto de datos es predecir quién sobrevivió.

El Titanic

Imagen de Wikimedia

Los datos sin procesar pueden cargarse fácilmente como un DataFrame de Pandas, pero no son inmediatamente utilizables como entrada para un modelo TensorFlow.

titanic = pd.read_csv("https://storage.googleapis.com/tf-datasets/titanic/train.csv") titanic.head()
titanic_features = titanic.copy() titanic_labels = titanic_features.pop('survived')

Como los tipos de datos y rangos son diferentes, no puede simplemente acumular las funciones en un arreglo NumPy y pasarlo a un modelo tf.keras.Sequential. Cada columna necesita ser manejada individualmente.

Como opción, podría preprocesar sus datos fuera de línea (usando cualquier herramienta que desee) para convertir columnas categóricas en columnas numéricas, y luego pasar la salida procesada a su modelo TensorFlow. La desventaja de ese enfoque es que si guarda y exporta su modelo, el preprocesamiento no se guarda con él. Las capas Keras de preprocesamiento evitan este problema porque forman parte del modelo.

En este ejemplo, construirá un modelo que implementa la lógica de preprocesamiento usando la API funcional de Keras. También podría hacerlo mediante subclases.

La API funcional opera con tensores "simbólicos". Los tensores "eager" normales tienen un valor. En cambio, estos tensores "simbólicos" no lo tienen. En su lugar, llevan un seguimiento de las operaciones que se ejecutan sobre ellos, y construyen una representación del cálculo, que puede ejecutar más tarde. He aquí un ejemplo rápido:

# Create a symbolic input input = tf.keras.Input(shape=(), dtype=tf.float32) # Perform a calculation using the input result = 2*input + 1 # the result doesn't have a value result
calc = tf.keras.Model(inputs=input, outputs=result)
print(calc(1).numpy()) print(calc(2).numpy())

Para construir el modelo de preprocesamiento, se empieza por construir un conjunto de objetos simbólicos tf.keras.Input, que coincidan con los nombres y tipos de datos de las columnas CSV.

inputs = {} for name, column in titanic_features.items(): dtype = column.dtype if dtype == object: dtype = tf.string else: dtype = tf.float32 inputs[name] = tf.keras.Input(shape=(1,), name=name, dtype=dtype) inputs

El primer paso en su lógica de preprocesamiento es concatenar las entradas numéricas y hacerlas pasar por una capa de normalización:

numeric_inputs = {name:input for name,input in inputs.items() if input.dtype==tf.float32} x = layers.Concatenate()(list(numeric_inputs.values())) norm = layers.Normalization() norm.adapt(np.array(titanic[numeric_inputs.keys()])) all_numeric_inputs = norm(x) all_numeric_inputs

Recoge todos los resultados del preprocesamiento simbólico, para concatenarlos posteriormente:

preprocessed_inputs = [all_numeric_inputs]

Para las entradas de cadena use la función tf.keras.layers.StringLookup para mapear de cadenas a índices enteros en un vocabulario. A continuación, use tf.keras.layers.CategoryEncoding para convertir los índices en datos float32 apropiados para el modelo.

Los ajustes predeterminados para la capa tf.keras.layers.CategoryEncoding crean un vector de un solo golpe para cada entrada. Una capa tf.keras.layers.Embedding también funcionaría. Consulte la guía Trabajar con capas de preprocesamiento y el tutorial Clasificar datos estructurados usando capas de preprocesamiento Keras para más información sobre este tema.

for name, input in inputs.items(): if input.dtype == tf.float32: continue lookup = layers.StringLookup(vocabulary=np.unique(titanic_features[name])) one_hot = layers.CategoryEncoding(num_tokens=lookup.vocabulary_size()) x = lookup(input) x = one_hot(x) preprocessed_inputs.append(x)

Con la recolección de inputs y preprocessed_inputs, puede concatenar todas las entradas preprocesadas y construir un modelo que se encargue del preprocesamiento:

preprocessed_inputs_cat = layers.Concatenate()(preprocessed_inputs) titanic_preprocessing = tf.keras.Model(inputs, preprocessed_inputs_cat) tf.keras.utils.plot_model(model = titanic_preprocessing , rankdir="LR", dpi=72, show_shapes=True)

Este modelo sólo contiene el preprocesamiento de entrada. Puede ejecutarlo para ver lo que hace con sus datos. Los modelos Keras no convierten automáticamente los pandas DataFrames porque no está claro si se debe convertir a un tensor o a un diccionario de tensores. Por lo tanto, conviértalo en un diccionario de tensores:

titanic_features_dict = {name: np.array(value) for name, value in titanic_features.items()}

Corte el primer ejemplo de entrenamiento y páselo a este modelo de preprocesamiento, verá las características numéricas y las cadenas de un solo paso todas concatenadas:

features_dict = {name:values[:1] for name, values in titanic_features_dict.items()} titanic_preprocessing(features_dict)

Ahora, construya el modelo sobre esto:

def titanic_model(preprocessing_head, inputs): body = tf.keras.Sequential([ layers.Dense(64, activation='relu'), layers.Dense(1) ]) preprocessed_inputs = preprocessing_head(inputs) result = body(preprocessed_inputs) model = tf.keras.Model(inputs, result) model.compile(loss=tf.keras.losses.BinaryCrossentropy(from_logits=True), optimizer=tf.keras.optimizers.Adam()) return model titanic_model = titanic_model(titanic_preprocessing, inputs)

Cuando entrene el modelo, pase el diccionario de características como x, y la etiqueta como y.

titanic_model.fit(x=titanic_features_dict, y=titanic_labels, epochs=10)

Dado que el preprocesamiento forma parte del modelo, puede guardar el modelo y volver a cargarlo en otro lugar y obtener resultados idénticos:

titanic_model.save('test.keras') reloaded = tf.keras.models.load_model('test.keras')
features_dict = {name:values[:1] for name, values in titanic_features_dict.items()} before = titanic_model(features_dict) after = reloaded(features_dict) assert (before-after)<1e-3 print(before) print(after)

Usar tf.data

En la sección anterior, usted confió en el mezclado y procesamiento por lotes de datos incorporado en el modelo durante el entrenamiento del mismo.

Si necesita más control sobre la canalización de los datos de entrada o necesita usar datos que no caben fácilmente en la memoria: use tf.data.

Para más ejemplos, consulte la tf.data: Construir canalizaciones de entrada TensorFlow.

Sobre datos en memoria

Como primer ejemplo de aplicación de tf.data a datos CSV, considere el siguiente código para trocear manualmente el diccionario de características de la sección anterior. Para cada índice, toma ese índice para cada característica:

import itertools def slices(features): for i in itertools.count(): # For each feature take index `i` example = {name:values[i] for name, values in features.items()} yield example

Ejecútelo e imprima el primer ejemplo:

for example in slices(titanic_features_dict): for name, value in example.items(): print(f"{name:19s}: {value}") break

El cargador de datos en memoria tf.data.Dataset más básico es el constructor Dataset.from_tensor_slices. Éste devuelve un tf.data.Dataset que implementa una versión generalizada de la función slices anterior, en TensorFlow.

features_ds = tf.data.Dataset.from_tensor_slices(titanic_features_dict)

Puede iterar sobre un tf.data.Dataset como cualquier otro iterable de python:

for example in features_ds: for name, value in example.items(): print(f"{name:19s}: {value}") break

La función from_tensor_slices puede manejar cualquier estructura de diccionarios anidados o tuplas. El siguiente código crea un conjunto de datos de pares (features_dict, labels):

titanic_ds = tf.data.Dataset.from_tensor_slices((titanic_features_dict, titanic_labels))

Para entrenar un modelo usando este Dataset, necesitará al menos hacer shuffle y batch los datos.

titanic_batches = titanic_ds.shuffle(len(titanic_labels)).batch(32)

En lugar de pasar features y labels a Model.fit, se pasa el conjunto de datos:

titanic_model.fit(titanic_batches, epochs=5)

Desde un único archivo

Hasta ahora este tutorial ha trabajado con datos en memoria. tf.data es un conjunto de herramientas altamente escalable para construir canalizaciones de datos, y ofrece algunas funciones para tratar la carga de archivos CSV.

titanic_file_path = tf.keras.utils.get_file("train.csv", "https://storage.googleapis.com/tf-datasets/titanic/train.csv")

Ahora lea los datos CSV del archivo y cree un tf.data.Dataset.

(Para ver la documentación completa, consulte tf.data.experimental.make_csv_dataset)

titanic_csv_ds = tf.data.experimental.make_csv_dataset( titanic_file_path, batch_size=5, # Artificially small to make examples easier to show. label_name='survived', num_epochs=1, ignore_errors=True,)

Esta función incluye muchas características convenientes, por lo que es fácil trabajar con los datos. Esto incluye:

  • Usar las cabeceras de las columnas como claves del diccionario.

  • Determinar automáticamente el tipo de cada columna.

Precaución: Asegúrese de establecer el argumento num_epochs en tf.data.experimental.make_csv_dataset, de lo contrario el comportamiento predeterminado para tf.data.Dataset es hacer un bucle sin fin.

for batch, label in titanic_csv_ds.take(1): for key, value in batch.items(): print(f"{key:20s}: {value}") print() print(f"{'label':20s}: {label}")

Nota: Si ejecuta la celda anterior dos veces producirá resultados diferentes. Los ajustes predeterminados para tf.data.experimental.make_csv_dataset incluyen shuffle_buffer_size=1000, que es más que suficiente para este pequeño conjunto de datos, pero puede no serlo para un conjunto de datos del mundo real.

También puede descomprimir los datos sobre la marcha. Aquí tiene un archivo CSV descomprimido que contiene el conjunto de datos de tráfico interestatal de metro.

Un atasco de tráfico.

Imagen de Wikimedia

traffic_volume_csv_gz = tf.keras.utils.get_file( 'Metro_Interstate_Traffic_Volume.csv.gz', "https://archive.ics.uci.edu/ml/machine-learning-databases/00492/Metro_Interstate_Traffic_Volume.csv.gz", cache_dir='.', cache_subdir='traffic')

Ajuste el argumento compression_type para leer directamente del archivo comprimido:

traffic_volume_csv_gz_ds = tf.data.experimental.make_csv_dataset( traffic_volume_csv_gz, batch_size=256, label_name='traffic_volume', num_epochs=1, compression_type="GZIP") for batch, label in traffic_volume_csv_gz_ds.take(1): for key, value in batch.items(): print(f"{key:20s}: {value[:5]}") print() print(f"{'label':20s}: {label[:5]}")

Nota: Si necesita analizar esas cadenas de fecha y hora en la canalización tfa.data, puede usar tfa.text.parse_time.

Almacenamiento en caché

El análisis sintáctico de los datos CSV conlleva algunos esfuerzos. Para los modelos pequeños esto puede ser el cuello de botella en el entrenamiento.

Dependiendo de su caso de uso, puede ser una buena idea usar Dataset.cache o tf.data.Dataset.snapshot, para que los datos CSV sólo se parseen en la primera época.

La principal diferencia entre los métodos cache y snapshot es que los archivos cache sólo pueden ser usados por el proceso TensorFlow que los creó, pero los archivos snapshot pueden ser leídos por otros procesos.

Por ejemplo, iterar sobre el traffic_volume_csv_gz_ds 20 veces puede llevar unos 15 segundos sin almacenamiento en caché, o unos dos segundos con almacenamiento en caché.

%%time for i, (batch, label) in enumerate(traffic_volume_csv_gz_ds.repeat(20)): if i % 40 == 0: print('.', end='') print()

Nota: Dataset.cache almacena los datos de la primera época y los reproduce en orden. Por tanto, usar el método cache desactiva cualquier mezcla anterior en la canalización. Más adelante, Dataset.shuffle se vuelve a añadir después de Dataset.cache.

%%time caching = traffic_volume_csv_gz_ds.cache().shuffle(1000) for i, (batch, label) in enumerate(caching.shuffle(1000).repeat(20)): if i % 40 == 0: print('.', end='') print()

Nota: Los archivos tf.data.Dataset.snapshot están pensados para el almacenamiento temporal de un conjunto de datos mientras se usa. Este no es un formato para el almacenamiento a largo plazo. El formato de archivo se considera un detalle interno, y no se garantiza entre las versiones de TensorFlow.

%%time snapshotting = traffic_volume_csv_gz_ds.snapshot('titanic.tfsnap').shuffle(1000) for i, (batch, label) in enumerate(snapshotting.shuffle(1000).repeat(20)): if i % 40 == 0: print('.', end='') print()

Si la carga de sus datos se ralentiza al cargar archivos CSV, y Dataset.cache y tf.data.Dataset.snapshot son insuficientes para su caso de uso, considere la posibilidad de recodificar sus datos en un formato más ágil.

Múltiples archivos

Todos los ejemplos hasta ahora en esta sección podrían hacerse fácilmente sin tf.data. Un lugar donde tf.data puede realmente simplificar las cosas es cuando se trata de colecciones de archivos.

Por ejemplo, el conjunto de datos imágenes de fuentes de caracteres se distribuye como una recopilación de archivos csv, uno por fuente.

Fuentes

Imagen por Willi Heidelbach de Pixabay

Descargue el conjunto de datos y revise los archivos que contiene:

fonts_zip = tf.keras.utils.get_file( 'fonts.zip', "https://archive.ics.uci.edu/ml/machine-learning-databases/00417/fonts.zip", cache_dir='.', cache_subdir='fonts', extract=True)
import pathlib font_csvs = sorted(str(p) for p in pathlib.Path('fonts').glob("*.csv")) font_csvs[:10]
len(font_csvs)

Cuando trabaje con numerosos archivos, puede pasar un file_pattern de tipo glob a la función tf.data.experimental.make_csv_dataset. El orden de los archivos se mezcla en cada iteración.

Use el argumento num_parallel_reads para establecer cuántos archivos se leen en paralelo y se intercalan juntos.

fonts_ds = tf.data.experimental.make_csv_dataset( file_pattern = "fonts/*.csv", batch_size=10, num_epochs=1, num_parallel_reads=20, shuffle_buffer_size=10000)

Estos archivos CSV tienen las imágenes aplanadas en una sola fila. Los nombres de las columnas tienen el formato r{row}c{column}. Aquí está el primer lote:

for features in fonts_ds.take(1): for i, (name, value) in enumerate(features.items()): if i>15: break print(f"{name:20s}: {value}") print('...') print(f"[total: {len(features)} features]")

Opcional: Campos de empaquetado

Probablemente no querrá trabajar con cada pixel en columnas separadas como esta. Antes de intentar usar este conjunto de datos asegúrese de empaquetar los pixeles en un tensor de imagen.

Este es el código que analiza los nombres de las columnas para construir las imágenes de cada ejemplo:

import re def make_images(features): image = [None]*400 new_feats = {} for name, value in features.items(): match = re.match('r(\d+)c(\d+)', name) if match: image[int(match.group(1))*20+int(match.group(2))] = value else: new_feats[name] = value image = tf.stack(image, axis=0) image = tf.reshape(image, [20, 20, -1]) new_feats['image'] = image return new_feats

Aplique esa función a cada lote del conjunto de datos:

fonts_image_ds = fonts_ds.map(make_images) for features in fonts_image_ds.take(1): break

Trace las imágenes resultantes:

from matplotlib import pyplot as plt plt.figure(figsize=(6,6), dpi=120) for n in range(9): plt.subplot(3,3,n+1) plt.imshow(features['image'][..., n]) plt.title(chr(features['m_label'][n])) plt.axis('off')

Funciones de nivel inferior

Hasta ahora este tutorial se ha centrado en las utilidades de más alto nivel para la lectura de datos csv. Existen otras dos API que pueden ser útiles para usuarios avanzados si su caso de uso no se ajusta a los patrones básicos.

  • tf.io.decode_csv: una función para parsear líneas de texto en una lista de tensores de columnas CSV.

  • tf.data.experimental.CsvDataset: un constructor de conjuntos de datos CSV de nivel inferior.

Esta sección recrea la funcionalidad proporcionada por tf.data.experimental.make_csv_dataset, para demostrar cómo se puede usar esta funcionalidad de nivel inferior.

tf.io.decode_csv

Esta función decodifica una cadena o una lista de cadenas en una lista de columnas.

A diferencia de tf.data.experimental.make_csv_dataset esta función no intenta adivinar los tipos de datos de las columnas. Usted especifica los tipos de columna mediante una lista de record_defaults que contiene un valor del tipo correcto, para cada columna.

Para leer los datos del Titanic como cadenas usando tf.io.decode_csv usted pondría:

text = pathlib.Path(titanic_file_path).read_text() lines = text.split('\n')[1:-1] all_strings = [str()]*10 all_strings
features = tf.io.decode_csv(lines, record_defaults=all_strings) for f in features: print(f"type: {f.dtype.name}, shape: {f.shape}")

Para parsearlos con sus tipos reales, cree una lista de record_defaults de los tipos correspondientes:

print(lines[0])
titanic_types = [int(), str(), float(), int(), int(), float(), str(), str(), str(), str()] titanic_types
features = tf.io.decode_csv(lines, record_defaults=titanic_types) for f in features: print(f"type: {f.dtype.name}, shape: {f.shape}")

Nota: Es más eficiente llamar a tf.io.decode_csv en grandes lotes de líneas que en líneas individuales de texto CSV.

tf.data.experimental.CsvDataset

La clase tf.data.experimental.CsvDataset ofrece una interfaz mínima Dataset CSV sin las características convenientes de la función tf.data.experimental.make_csv_dataset: análisis sintáctico de cabeceras de columna, inferencia del tipo de columna, mezclado automático, intercalación de archivos.

Este constructor usa record_defaults del mismo modo que tf.io.decode_csv:

simple_titanic = tf.data.experimental.CsvDataset(titanic_file_path, record_defaults=titanic_types, header=True) for example in simple_titanic.take(1): print([e.numpy() for e in example])

El código anterior equivale básicamente a:

def decode_titanic_line(line): return tf.io.decode_csv(line, titanic_types) manual_titanic = ( # Load the lines of text tf.data.TextLineDataset(titanic_file_path) # Skip the header row. .skip(1) # Decode the line. .map(decode_titanic_line) ) for example in manual_titanic.take(1): print([e.numpy() for e in example])

Múltiples archivos

Para parsear el conjunto de datos de fuentes usando tf.data.experimental.CsvDataset, primero necesita determinar los tipos de columna para el record_defaults. Empiece por inspeccionar la primera fila de un archivo:

font_line = pathlib.Path(font_csvs[0]).read_text().splitlines()[1] print(font_line)

Sólo los dos primeros campos son cadenas, el resto son números enteros o flotantes, y puede obtener el número total de características contando las comas:

num_font_features = font_line.count(',')+1 font_column_types = [str(), str()] + [float()]*(num_font_features-2)

El constructor tf.data.experimental.CsvDataset puede tomar una lista de archivos de entrada, pero los lee secuencialmente. El primer archivo de la lista de CSV es AGENCY.csv:

font_csvs[0]

Así, cuando pase la lista de archivos a CsvDataset, se leerán primero los registros de AGENCY.csv:

simple_font_ds = tf.data.experimental.CsvDataset( font_csvs, record_defaults=font_column_types, header=True)
for row in simple_font_ds.take(10): print(row[0].numpy())

Para intercalar varios archivos, use Dataset.interleave.

Aquí tiene un conjunto de datos inicial que contiene los nombres de los archivos CSV:

font_files = tf.data.Dataset.list_files("fonts/*.csv")

Esto mezcla los nombres de los archivos en cada época:

print('Epoch 1:') for f in list(font_files)[:5]: print(" ", f.numpy()) print(' ...') print() print('Epoch 2:') for f in list(font_files)[:5]: print(" ", f.numpy()) print(' ...')

El método interleave toma un map_func que crea un Dataset hijo para cada elemento del Dataset padre.

En este caso, desea crear un tf.data.experimental.CsvDataset a partir de cada elemento del conjunto de datos de archivos:

def make_font_csv_ds(path): return tf.data.experimental.CsvDataset( path, record_defaults=font_column_types, header=True)

El Conjunto de datos devuelto por interleave devuelve elementos haciendo un ciclo sobre un número de los Datasets hijo. Observe, a continuación, cómo el conjunto de datos cicla sobre cycle_length=3 tres archivos de fuentes:

font_rows = font_files.interleave(make_font_csv_ds, cycle_length=3)
fonts_dict = {'font_name':[], 'character':[]} for row in font_rows.take(10): fonts_dict['font_name'].append(row[0].numpy().decode()) fonts_dict['character'].append(chr(row[2].numpy())) pd.DataFrame(fonts_dict)

Rendimiento

Antes, se observó que tf.io.decode_csv es más eficiente cuando se ejecuta sobre un lote de cadenas.

Es posible aprovechar este hecho, cuando se usan lotes de gran tamaño, para mejorar el rendimiento de la carga de CSV (pero pruebe caching primero).

Con el cargador integrado 20, los lotes de 2048 muestras tardan unos 17 s.

BATCH_SIZE=2048 fonts_ds = tf.data.experimental.make_csv_dataset( file_pattern = "fonts/*.csv", batch_size=BATCH_SIZE, num_epochs=1, num_parallel_reads=100)
%%time for i,batch in enumerate(fonts_ds.take(20)): print('.',end='') print()

El paso de lotes de líneas de texto a decode_csv se ejecuta más rápido, por unos 5 s:

fonts_files = tf.data.Dataset.list_files("fonts/*.csv") fonts_lines = fonts_files.interleave( lambda fname:tf.data.TextLineDataset(fname).skip(1), cycle_length=100).batch(BATCH_SIZE) fonts_fast = fonts_lines.map(lambda x: tf.io.decode_csv(x, record_defaults=font_column_types))
%%time for i,batch in enumerate(fonts_fast.take(20)): print('.',end='') print()

Para ver otro ejemplo de cómo aumentar el rendimiento de CSV usando grandes lotes, consulte el tutorial Sobreajuste y subajuste.

Este tipo de enfoque puede funcionar, pero considere otras opciones como Dataset.cache y tf.data.Dataset.snapshot, o recodifique sus datos en un formato más ágil.