Questa pagina è stata tradotta dall'API Cloud Translation.
Switch to English

Carica i dati CSV

Visualizza su TensorFlow.org Esegui in Google Colab Visualizza sorgente su GitHub Scarica notebook

Questo tutorial fornisce un esempio di come caricare i dati CSV da un file in un tf.data.Dataset .

I dati utilizzati in questo tutorial sono presi dalla lista dei passeggeri del Titanic. Il modello prevede la probabilità che un passeggero sia sopravvissuto in base a caratteristiche come età, sesso, classe del biglietto e se la persona viaggiava da sola.

Impostare

import functools

import numpy as np
import tensorflow as tf
TRAIN_DATA_URL = "https://storage.googleapis.com/tf-datasets/titanic/train.csv"
TEST_DATA_URL = "https://storage.googleapis.com/tf-datasets/titanic/eval.csv"

train_file_path = tf.keras.utils.get_file("train.csv", TRAIN_DATA_URL)
test_file_path = tf.keras.utils.get_file("eval.csv", TEST_DATA_URL)
Downloading data from https://storage.googleapis.com/tf-datasets/titanic/train.csv
32768/30874 [===============================] - 0s 0us/step
Downloading data from https://storage.googleapis.com/tf-datasets/titanic/eval.csv
16384/13049 [=====================================] - 0s 0us/step

# Make numpy values easier to read.
np.set_printoptions(precision=3, suppress=True)

Caricare dati

Per iniziare, diamo un'occhiata all'inizio del file CSV per vedere come è formattato.

head {train_file_path}
survived,sex,age,n_siblings_spouses,parch,fare,class,deck,embark_town,alone
0,male,22.0,1,0,7.25,Third,unknown,Southampton,n
1,female,38.0,1,0,71.2833,First,C,Cherbourg,n
1,female,26.0,0,0,7.925,Third,unknown,Southampton,y
1,female,35.0,1,0,53.1,First,C,Southampton,n
0,male,28.0,0,0,8.4583,Third,unknown,Queenstown,y
0,male,2.0,3,1,21.075,Third,unknown,Southampton,n
1,female,27.0,0,2,11.1333,Third,unknown,Southampton,n
1,female,14.0,1,0,30.0708,Second,unknown,Cherbourg,n
1,female,4.0,1,1,16.7,Third,G,Southampton,n

Puoi caricarlo usando i panda e passare gli array NumPy a TensorFlow. Se è necessario scalare fino a un ampio set di file o è necessario un caricatore che si integri con TensorFlow e tf.data, utilizzare la funzione tf.data.experimental.make_csv_dataset :

L'unica colonna che devi identificare in modo esplicito è quella con il valore che il modello intende prevedere.

LABEL_COLUMN = 'survived'
LABELS = [0, 1]

Ora leggi i dati CSV dal file e crea un set di dati.

(Per la documentazione completa, vedere tf.data.experimental.make_csv_dataset )

def get_dataset(file_path, **kwargs):
  dataset = tf.data.experimental.make_csv_dataset(
      file_path,
      batch_size=5, # Artificially small to make examples easier to show.
      label_name=LABEL_COLUMN,
      na_value="?",
      num_epochs=1,
      ignore_errors=True, 
      **kwargs)
  return dataset

raw_train_data = get_dataset(train_file_path)
raw_test_data = get_dataset(test_file_path)
def show_batch(dataset):
  for batch, label in dataset.take(1):
    for key, value in batch.items():
      print("{:20s}: {}".format(key,value.numpy()))

Ogni elemento nel set di dati è un batch, rappresentato come una tupla di ( molti esempi , molte etichette ). I dati degli esempi sono organizzati in tensori basati su colonne (anziché tensori basati su righe), ciascuno con tanti elementi quante sono le dimensioni del batch (5 in questo caso).

Potrebbe essere utile vederlo da soli.

show_batch(raw_train_data)
sex                 : [b'male' b'male' b'male' b'female' b'female']
age                 : [30. 20. 16. 31. 28.]
n_siblings_spouses  : [0 1 0 0 1]
parch               : [0 1 0 0 0]
fare                : [ 7.896 15.742 26.     8.683 14.454]
class               : [b'Third' b'Third' b'Second' b'Third' b'Third']
deck                : [b'unknown' b'unknown' b'unknown' b'unknown' b'unknown']
embark_town         : [b'Southampton' b'Cherbourg' b'Southampton' b'Southampton' b'Cherbourg']
alone               : [b'y' b'n' b'y' b'y' b'n']

Come puoi vedere, le colonne nel CSV sono denominate. Il costruttore del set di dati prenderà questi nomi automaticamente. Se il file con cui stai lavorando non contiene i nomi delle colonne nella prima riga, make_csv_dataset in un elenco di stringhe all'argomento column_names nella funzione make_csv_dataset .

CSV_COLUMNS = ['survived', 'sex', 'age', 'n_siblings_spouses', 'parch', 'fare', 'class', 'deck', 'embark_town', 'alone']

temp_dataset = get_dataset(train_file_path, column_names=CSV_COLUMNS)

show_batch(temp_dataset)
sex                 : [b'male' b'female' b'female' b'male' b'male']
age                 : [28. 35. 31. 20. 30.]
n_siblings_spouses  : [0 0 1 0 0]
parch               : [0 0 0 0 0]
fare                : [  7.796 135.633  18.      7.854   7.896]
class               : [b'Third' b'First' b'Third' b'Third' b'Third']
deck                : [b'unknown' b'C' b'unknown' b'unknown' b'unknown']
embark_town         : [b'Southampton' b'Southampton' b'Southampton' b'Southampton'
 b'Southampton']
alone               : [b'y' b'y' b'n' b'y' b'y']

Questo esempio utilizzerà tutte le colonne disponibili. Se è necessario omettere alcune colonne dal set di dati, creare un elenco delle sole colonne che si prevede di utilizzare e passarlo all'argomento select_columns (facoltativo) del costruttore.

SELECT_COLUMNS = ['survived', 'age', 'n_siblings_spouses', 'class', 'deck', 'alone']

temp_dataset = get_dataset(train_file_path, select_columns=SELECT_COLUMNS)

show_batch(temp_dataset)
age                 : [34.   22.    0.83 14.5  28.  ]
n_siblings_spouses  : [0 0 0 1 0]
class               : [b'Second' b'Third' b'Second' b'Third' b'Third']
deck                : [b'F' b'unknown' b'unknown' b'unknown' b'unknown']
alone               : [b'y' b'y' b'n' b'n' b'y']

Preelaborazione dei dati

Un file CSV può contenere una varietà di tipi di dati. In genere si desidera convertire da quei tipi misti a un vettore di lunghezza fissa prima di inserire i dati nel modello.

TensorFlow ha un sistema integrato per descrivere le conversioni di input comuni: tf.feature_column , vedere questo tutorial per i dettagli.

Puoi preelaborare i tuoi dati utilizzando qualsiasi strumento che ti piace (come nltk o sklearn ) e passare l'output elaborato a TensorFlow.

Il vantaggio principale di eseguire la preelaborazione all'interno del modello è che quando esporti il ​​modello include la preelaborazione. In questo modo puoi passare i dati grezzi direttamente al tuo modello.

Dati continui

Se i tuoi dati sono già in un formato numerico appropriato, puoi impacchettare i dati in un vettore prima di passarli al modello:

SELECT_COLUMNS = ['survived', 'age', 'n_siblings_spouses', 'parch', 'fare']
DEFAULTS = [0, 0.0, 0.0, 0.0, 0.0]
temp_dataset = get_dataset(train_file_path, 
                           select_columns=SELECT_COLUMNS,
                           column_defaults = DEFAULTS)

show_batch(temp_dataset)
age                 : [24. 28. 61. 32. 28.]
n_siblings_spouses  : [0. 0. 0. 0. 0.]
parch               : [0. 2. 0. 0. 0.]
fare                : [ 7.896  7.75  32.321  8.363  7.75 ]

example_batch, labels_batch = next(iter(temp_dataset)) 

Ecco una semplice funzione che riunirà tutte le colonne:

def pack(features, label):
  return tf.stack(list(features.values()), axis=-1), label

Applicalo a ogni elemento del set di dati:

packed_dataset = temp_dataset.map(pack)

for features, labels in packed_dataset.take(1):
  print(features.numpy())
  print()
  print(labels.numpy())
[[28.     1.     0.    15.5  ]
 [34.     1.     0.    21.   ]
 [24.     0.     0.     7.142]
 [ 2.     0.     1.    12.288]
 [62.     0.     0.    10.5  ]]

[0 0 1 1 1]

Se si dispone di tipi di dati misti, è possibile separare questi campi numerici semplici. L'api tf.feature_column può gestirli, ma ciò comporta un certo sovraccarico e dovrebbe essere evitato a meno che non sia realmente necessario. Torna al set di dati misto:

show_batch(raw_train_data)
sex                 : [b'male' b'female' b'male' b'male' b'male']
age                 : [23. 29. 25. 43. 71.]
n_siblings_spouses  : [0 0 0 0 0]
parch               : [0 4 0 0 0]
fare                : [ 7.854 21.075 13.     8.05  49.504]
class               : [b'Third' b'Third' b'Second' b'Third' b'First']
deck                : [b'unknown' b'unknown' b'unknown' b'unknown' b'unknown']
embark_town         : [b'Southampton' b'Southampton' b'Southampton' b'Southampton' b'Cherbourg']
alone               : [b'y' b'n' b'y' b'y' b'y']

example_batch, labels_batch = next(iter(temp_dataset)) 

Quindi definisci un preprocessore più generale che seleziona un elenco di caratteristiche numeriche e le raggruppa in una singola colonna:

class PackNumericFeatures(object):
  def __init__(self, names):
    self.names = names

  def __call__(self, features, labels):
    numeric_features = [features.pop(name) for name in self.names]
    numeric_features = [tf.cast(feat, tf.float32) for feat in numeric_features]
    numeric_features = tf.stack(numeric_features, axis=-1)
    features['numeric'] = numeric_features

    return features, labels
NUMERIC_FEATURES = ['age','n_siblings_spouses','parch', 'fare']

packed_train_data = raw_train_data.map(
    PackNumericFeatures(NUMERIC_FEATURES))

packed_test_data = raw_test_data.map(
    PackNumericFeatures(NUMERIC_FEATURES))
show_batch(packed_train_data)
sex                 : [b'female' b'female' b'male' b'male' b'male']
class               : [b'Third' b'Second' b'First' b'Second' b'First']
deck                : [b'unknown' b'unknown' b'B' b'unknown' b'C']
embark_town         : [b'Southampton' b'Southampton' b'Southampton' b'Southampton' b'Cherbourg']
alone               : [b'y' b'n' b'y' b'y' b'y']
numeric             : [[31.     0.     0.     7.854]
 [33.     1.     2.    27.75 ]
 [40.     0.     0.     0.   ]
 [47.     0.     0.    15.   ]
 [30.     0.     0.    27.75 ]]

example_batch, labels_batch = next(iter(packed_train_data)) 

Normalizzazione dei dati

I dati continui dovrebbero essere sempre normalizzati.

import pandas as pd
desc = pd.read_csv(train_file_path)[NUMERIC_FEATURES].describe()
desc
MEAN = np.array(desc.T['mean'])
STD = np.array(desc.T['std'])
def normalize_numeric_data(data, mean, std):
  # Center the data
  return (data-mean)/std

Ora crea una colonna numerica. L'API tf.feature_columns.numeric_column accetta un argomento normalizer_fn , che verrà eseguito su ogni batch.

Associare MEAN e STD al normalizzatore fn utilizzando functools.partial .

# See what you just created.
normalizer = functools.partial(normalize_numeric_data, mean=MEAN, std=STD)

numeric_column = tf.feature_column.numeric_column('numeric', normalizer_fn=normalizer, shape=[len(NUMERIC_FEATURES)])
numeric_columns = [numeric_column]
numeric_column
NumericColumn(key='numeric', shape=(4,), default_value=None, dtype=tf.float32, normalizer_fn=functools.partial(<function normalize_numeric_data at 0x7f4f38248510>, mean=array([29.631,  0.545,  0.38 , 34.385]), std=array([12.512,  1.151,  0.793, 54.598])))

Quando addestrate il modello, includete questa colonna delle caratteristiche per selezionare e centrare questo blocco di dati numerici:

example_batch['numeric']
<tf.Tensor: shape=(5, 4), dtype=float32, numpy=
array([[26.   ,  0.   ,  0.   ,  7.896],
       [28.   ,  0.   ,  0.   , 12.35 ],
       [17.   ,  1.   ,  0.   , 57.   ],
       [15.   ,  0.   ,  0.   ,  7.225],
       [25.   ,  0.   ,  0.   , 13.   ]], dtype=float32)>
numeric_layer = tf.keras.layers.DenseFeatures(numeric_columns)
numeric_layer(example_batch).numpy()
array([[-0.29 , -0.474, -0.479, -0.485],
       [-0.13 , -0.474, -0.479, -0.404],
       [-1.01 ,  0.395, -0.479,  0.414],
       [-1.169, -0.474, -0.479, -0.497],
       [-0.37 , -0.474, -0.479, -0.392]], dtype=float32)

La normalizzazione basata sulla media usata qui richiede di conoscere in anticipo le medie di ciascuna colonna.

Dati categoriali

Alcune delle colonne nei dati CSV sono colonne categoriali. Cioè, il contenuto dovrebbe far parte di un insieme limitato di opzioni.

Utilizza l'API tf.feature_column per creare una raccolta con una tf.feature_column.indicator_column per ogni colonna categoriale.

CATEGORIES = {
    'sex': ['male', 'female'],
    'class' : ['First', 'Second', 'Third'],
    'deck' : ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J'],
    'embark_town' : ['Cherbourg', 'Southhampton', 'Queenstown'],
    'alone' : ['y', 'n']
}

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))
# See what you just created.
categorical_columns
[IndicatorColumn(categorical_column=VocabularyListCategoricalColumn(key='sex', vocabulary_list=('male', 'female'), dtype=tf.string, default_value=-1, num_oov_buckets=0)),
 IndicatorColumn(categorical_column=VocabularyListCategoricalColumn(key='class', vocabulary_list=('First', 'Second', 'Third'), dtype=tf.string, default_value=-1, num_oov_buckets=0)),
 IndicatorColumn(categorical_column=VocabularyListCategoricalColumn(key='deck', vocabulary_list=('A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J'), dtype=tf.string, default_value=-1, num_oov_buckets=0)),
 IndicatorColumn(categorical_column=VocabularyListCategoricalColumn(key='embark_town', vocabulary_list=('Cherbourg', 'Southhampton', 'Queenstown'), dtype=tf.string, default_value=-1, num_oov_buckets=0)),
 IndicatorColumn(categorical_column=VocabularyListCategoricalColumn(key='alone', vocabulary_list=('y', 'n'), dtype=tf.string, default_value=-1, num_oov_buckets=0))]
categorical_layer = tf.keras.layers.DenseFeatures(categorical_columns)
print(categorical_layer(example_batch).numpy()[0])
[1. 0. 0. 0. 1. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 1. 0.]

Questo diventerà parte di un input per l'elaborazione dei dati in un secondo momento quando si costruisce il modello.

Strato di preelaborazione combinato

Aggiungi le due raccolte di colonne di funzionalità e tf.keras.layers.DenseFeatures a tf.keras.layers.DenseFeatures per creare un livello di input che estrarrà e preelaborerà entrambi i tipi di input:

preprocessing_layer = tf.keras.layers.DenseFeatures(categorical_columns+numeric_columns)
print(preprocessing_layer(example_batch).numpy()[0])
[ 1.     0.     0.     0.     1.     0.     0.     0.     0.     0.

  0.     0.     0.     0.     0.     0.     0.     0.    -0.29  -0.474
 -0.479 -0.485  1.     0.   ]

Costruisci il modello

Crea un tf.keras.Sequential , iniziando con preprocessing_layer .

model = tf.keras.Sequential([
  preprocessing_layer,
  tf.keras.layers.Dense(128, activation='relu'),
  tf.keras.layers.Dense(128, activation='relu'),
  tf.keras.layers.Dense(1),
])

model.compile(
    loss=tf.keras.losses.BinaryCrossentropy(from_logits=True),
    optimizer='adam',
    metrics=['accuracy'])

Addestra, valuta e prevedi

Ora il modello può essere istanziato e addestrato.

train_data = packed_train_data.shuffle(500)
test_data = packed_test_data
model.fit(train_data, epochs=20)
Epoch 1/20
WARNING:tensorflow:Layers in a Sequential model should only have a single input tensor, but we receive a <class 'collections.OrderedDict'> input: OrderedDict([('sex', <tf.Tensor 'ExpandDims_4:0' shape=(None, 1) dtype=string>), ('class', <tf.Tensor 'ExpandDims_1:0' shape=(None, 1) dtype=string>), ('deck', <tf.Tensor 'ExpandDims_2:0' shape=(None, 1) dtype=string>), ('embark_town', <tf.Tensor 'ExpandDims_3:0' shape=(None, 1) dtype=string>), ('alone', <tf.Tensor 'ExpandDims:0' shape=(None, 1) dtype=string>), ('numeric', <tf.Tensor 'IteratorGetNext:4' shape=(None, 4) dtype=float32>)])
Consider rewriting this model with the Functional API.
WARNING:tensorflow:Layers in a Sequential model should only have a single input tensor, but we receive a <class 'collections.OrderedDict'> input: OrderedDict([('sex', <tf.Tensor 'ExpandDims_4:0' shape=(None, 1) dtype=string>), ('class', <tf.Tensor 'ExpandDims_1:0' shape=(None, 1) dtype=string>), ('deck', <tf.Tensor 'ExpandDims_2:0' shape=(None, 1) dtype=string>), ('embark_town', <tf.Tensor 'ExpandDims_3:0' shape=(None, 1) dtype=string>), ('alone', <tf.Tensor 'ExpandDims:0' shape=(None, 1) dtype=string>), ('numeric', <tf.Tensor 'IteratorGetNext:4' shape=(None, 4) dtype=float32>)])
Consider rewriting this model with the Functional API.
126/126 [==============================] - 0s 3ms/step - loss: 0.5091 - accuracy: 0.7400
Epoch 2/20
126/126 [==============================] - 0s 3ms/step - loss: 0.4295 - accuracy: 0.8118
Epoch 3/20
126/126 [==============================] - 0s 3ms/step - loss: 0.4043 - accuracy: 0.8341
Epoch 4/20
126/126 [==============================] - 0s 3ms/step - loss: 0.3894 - accuracy: 0.8325
Epoch 5/20
126/126 [==============================] - 0s 3ms/step - loss: 0.3895 - accuracy: 0.8309
Epoch 6/20
126/126 [==============================] - 0s 3ms/step - loss: 0.3722 - accuracy: 0.8421
Epoch 7/20
126/126 [==============================] - 0s 3ms/step - loss: 0.3629 - accuracy: 0.8421
Epoch 8/20
126/126 [==============================] - 0s 3ms/step - loss: 0.3575 - accuracy: 0.8485
Epoch 9/20
126/126 [==============================] - 0s 3ms/step - loss: 0.3471 - accuracy: 0.8485
Epoch 10/20
126/126 [==============================] - 0s 3ms/step - loss: 0.3447 - accuracy: 0.8485
Epoch 11/20
126/126 [==============================] - 0s 3ms/step - loss: 0.3415 - accuracy: 0.8533
Epoch 12/20
126/126 [==============================] - 0s 3ms/step - loss: 0.3388 - accuracy: 0.8612
Epoch 13/20
126/126 [==============================] - 0s 3ms/step - loss: 0.3274 - accuracy: 0.8549
Epoch 14/20
126/126 [==============================] - 0s 3ms/step - loss: 0.3332 - accuracy: 0.8596
Epoch 15/20
126/126 [==============================] - 0s 3ms/step - loss: 0.3209 - accuracy: 0.8533
Epoch 16/20
126/126 [==============================] - 0s 3ms/step - loss: 0.3139 - accuracy: 0.8644
Epoch 17/20
126/126 [==============================] - 0s 3ms/step - loss: 0.3170 - accuracy: 0.8596
Epoch 18/20
126/126 [==============================] - 0s 3ms/step - loss: 0.3142 - accuracy: 0.8644
Epoch 19/20
126/126 [==============================] - 0s 3ms/step - loss: 0.3105 - accuracy: 0.8612
Epoch 20/20
126/126 [==============================] - 0s 3ms/step - loss: 0.3052 - accuracy: 0.8644

<tensorflow.python.keras.callbacks.History at 0x7f4f3829f550>

Una volta che il modello è stato addestrato, è possibile verificarne l'accuratezza sul set test_data .

test_loss, test_accuracy = model.evaluate(test_data)

print('\n\nTest Loss {}, Test Accuracy {}'.format(test_loss, test_accuracy))
WARNING:tensorflow:Layers in a Sequential model should only have a single input tensor, but we receive a <class 'collections.OrderedDict'> input: OrderedDict([('sex', <tf.Tensor 'ExpandDims_4:0' shape=(None, 1) dtype=string>), ('class', <tf.Tensor 'ExpandDims_1:0' shape=(None, 1) dtype=string>), ('deck', <tf.Tensor 'ExpandDims_2:0' shape=(None, 1) dtype=string>), ('embark_town', <tf.Tensor 'ExpandDims_3:0' shape=(None, 1) dtype=string>), ('alone', <tf.Tensor 'ExpandDims:0' shape=(None, 1) dtype=string>), ('numeric', <tf.Tensor 'IteratorGetNext:4' shape=(None, 4) dtype=float32>)])
Consider rewriting this model with the Functional API.
53/53 [==============================] - 0s 3ms/step - loss: 0.4821 - accuracy: 0.8409


Test Loss 0.4820583164691925, Test Accuracy 0.8409090638160706

Utilizza tf.keras.Model.predict per dedurre le etichette su un batch o un set di dati di batch.

predictions = model.predict(test_data)

# Show some results
for prediction, survived in zip(predictions[:10], list(test_data)[0][1][:10]):
  prediction = tf.sigmoid(prediction).numpy()
  print("Predicted survival: {:.2%}".format(prediction[0]),
        " | Actual outcome: ",
        ("SURVIVED" if bool(survived) else "DIED"))

WARNING:tensorflow:Layers in a Sequential model should only have a single input tensor, but we receive a <class 'collections.OrderedDict'> input: OrderedDict([('sex', <tf.Tensor 'ExpandDims_4:0' shape=(None, 1) dtype=string>), ('class', <tf.Tensor 'ExpandDims_1:0' shape=(None, 1) dtype=string>), ('deck', <tf.Tensor 'ExpandDims_2:0' shape=(None, 1) dtype=string>), ('embark_town', <tf.Tensor 'ExpandDims_3:0' shape=(None, 1) dtype=string>), ('alone', <tf.Tensor 'ExpandDims:0' shape=(None, 1) dtype=string>), ('numeric', <tf.Tensor 'IteratorGetNext:4' shape=(None, 4) dtype=float32>)])
Consider rewriting this model with the Functional API.
Predicted survival: 94.38%  | Actual outcome:  DIED
Predicted survival: 8.66%  | Actual outcome:  SURVIVED
Predicted survival: 99.36%  | Actual outcome:  DIED
Predicted survival: 77.46%  | Actual outcome:  DIED
Predicted survival: 84.20%  | Actual outcome:  DIED