Lihat di TensorFlow.org | Jalankan di Google Colab | Lihat sumber di GitHub | Unduh buku catatan |
Tutorial ini menunjukkan bagaimana mengklasifikasikan data terstruktur (misalnya data tabular dalam CSV). Kami akan menggunakan Keras untuk mendefinisikan model, dan tf.feature_column
sebagai jembatan untuk memetakan dari kolom dalam CSV ke fitur yang digunakan untuk melatih model. Tutorial ini berisi kode lengkap untuk:
- Muat file CSV menggunakan Pandas .
- Bangun saluran input untuk mengelompokkan dan mengacak baris menggunakan tf.data .
- Petakan dari kolom di CSV ke fitur yang digunakan untuk melatih model menggunakan kolom fitur.
- Bangun, latih, dan evaluasi model menggunakan Keras.
Kumpulan Data
Kami akan menggunakan versi sederhana dari kumpulan data PetFinder . Ada beberapa ribu baris di CSV. Setiap baris menggambarkan hewan peliharaan, dan setiap kolom menggambarkan atribut. Kami akan menggunakan informasi ini untuk memprediksi kecepatan adopsi hewan peliharaan.
Berikut adalah deskripsi dari dataset ini. Perhatikan ada kolom numerik dan kategorikal. Ada kolom teks gratis yang tidak akan kita gunakan dalam tutorial ini.
Kolom | Keterangan | Tipe Fitur | Tipe data |
---|---|---|---|
Jenis | Jenis Hewan (Anjing, Kucing) | kategoris | rangkaian |
Usia | Usia hewan peliharaan | numerik | bilangan bulat |
Breed1 | Trah utama hewan peliharaan | kategoris | rangkaian |
warna1 | Warna 1 hewan peliharaan | kategoris | rangkaian |
warna2 | Warna 2 hewan peliharaan | kategoris | rangkaian |
KedewasaanUkuran | Ukuran saat jatuh tempo | kategoris | rangkaian |
panjang bulu | panjang bulu | kategoris | rangkaian |
Divaksinasi | Hewan peliharaan telah divaksinasi | kategoris | rangkaian |
disterilkan | Hewan peliharaan telah disterilkan | kategoris | rangkaian |
Kesehatan | Kondisi kesehatan | kategoris | rangkaian |
Biaya | Biaya Adopsi | numerik | bilangan bulat |
Keterangan | Penulisan profil untuk hewan peliharaan ini | Teks | rangkaian |
FotoAmt | Total foto yang diunggah untuk hewan peliharaan ini | numerik | bilangan bulat |
Kecepatan Adopsi | Kecepatan adopsi | Klasifikasi | bilangan bulat |
Impor TensorFlow dan perpustakaan lainnya
pip install sklearn
import numpy as np
import pandas as pd
import tensorflow as tf
from tensorflow import feature_column
from tensorflow.keras import layers
from sklearn.model_selection import train_test_split
Gunakan Pandas untuk membuat kerangka data
Pandas adalah pustaka Python dengan banyak utilitas bermanfaat untuk memuat dan bekerja dengan data terstruktur. Kami akan menggunakan Pandas untuk mengunduh kumpulan data dari URL, dan memuatnya ke dalam kerangka data.
import pathlib
dataset_url = 'http://storage.googleapis.com/download.tensorflow.org/data/petfinder-mini.zip'
csv_file = 'datasets/petfinder-mini/petfinder-mini.csv'
tf.keras.utils.get_file('petfinder_mini.zip', dataset_url,
extract=True, cache_dir='.')
dataframe = pd.read_csv(csv_file)
Downloading data from http://storage.googleapis.com/download.tensorflow.org/data/petfinder-mini.zip 1671168/1668792 [==============================] - 0s 0us/step 1679360/1668792 [==============================] - 0s 0us/step
dataframe.head()
Buat variabel target
Tugas dalam kumpulan data asli adalah memprediksi kecepatan adopsi hewan peliharaan (misalnya, dalam minggu pertama, bulan pertama, tiga bulan pertama, dan seterusnya). Mari kita sederhanakan ini untuk tutorial kita. Di sini, kami akan mengubah ini menjadi masalah klasifikasi biner, dan hanya memprediksi apakah hewan peliharaan itu diadopsi, atau tidak.
Setelah memodifikasi kolom label, 0 akan menunjukkan hewan peliharaan tidak diadopsi, dan 1 akan menunjukkan itu.
# In the original dataset "4" indicates the pet was not adopted.
dataframe['target'] = np.where(dataframe['AdoptionSpeed']==4, 0, 1)
# Drop un-used columns.
dataframe = dataframe.drop(columns=['AdoptionSpeed', 'Description'])
Pisahkan kerangka data menjadi kereta, validasi, dan pengujian
Kumpulan data yang kami unduh adalah satu file CSV. Kami akan membagi ini menjadi rangkaian pelatihan, validasi, dan pengujian.
train, test = train_test_split(dataframe, test_size=0.2)
train, val = train_test_split(train, test_size=0.2)
print(len(train), 'train examples')
print(len(val), 'validation examples')
print(len(test), 'test examples')
7383 train examples 1846 validation examples 2308 test examples
Buat saluran input menggunakan tf.data
Selanjutnya, kita akan membungkus dataframe dengan tf.data . Ini akan memungkinkan kita untuk menggunakan kolom fitur sebagai jembatan untuk memetakan dari kolom dalam kerangka data Pandas ke fitur yang digunakan untuk melatih model. Jika kita bekerja dengan file CSV yang sangat besar (sangat besar sehingga tidak muat ke dalam memori), kita akan menggunakan tf.data untuk membacanya dari disk secara langsung. Itu tidak tercakup dalam tutorial ini.
# A utility method to create a tf.data dataset from a Pandas Dataframe
def df_to_dataset(dataframe, shuffle=True, batch_size=32):
dataframe = dataframe.copy()
labels = dataframe.pop('target')
ds = tf.data.Dataset.from_tensor_slices((dict(dataframe), labels))
if shuffle:
ds = ds.shuffle(buffer_size=len(dataframe))
ds = ds.batch(batch_size)
return ds
batch_size = 5 # A small batch sized is used for demonstration purposes
train_ds = df_to_dataset(train, batch_size=batch_size)
val_ds = df_to_dataset(val, shuffle=False, batch_size=batch_size)
test_ds = df_to_dataset(test, shuffle=False, batch_size=batch_size)
Pahami pipa input
Sekarang kita telah membuat pipa input, sebut saja untuk melihat format data yang dikembalikannya. Kami telah menggunakan ukuran batch kecil untuk menjaga output dapat dibaca.
for feature_batch, label_batch in train_ds.take(1):
print('Every feature:', list(feature_batch.keys()))
print('A batch of ages:', feature_batch['Age'])
print('A batch of targets:', label_batch )
Every feature: ['Type', 'Age', 'Breed1', 'Gender', 'Color1', 'Color2', 'MaturitySize', 'FurLength', 'Vaccinated', 'Sterilized', 'Health', 'Fee', 'PhotoAmt'] A batch of ages: tf.Tensor([ 6 2 36 2 2], shape=(5,), dtype=int64) A batch of targets: tf.Tensor([1 1 1 1 1], shape=(5,), dtype=int64)
Kita dapat melihat bahwa kumpulan data mengembalikan kamus nama kolom (dari kerangka data) yang memetakan ke nilai kolom dari baris dalam kerangka data.
Peragakan beberapa jenis kolom fitur
TensorFlow menyediakan banyak jenis kolom fitur. Di bagian ini, kami akan membuat beberapa jenis kolom fitur, dan mendemonstrasikan bagaimana mereka mengubah kolom dari kerangka data.
# We will use this batch to demonstrate several types of feature columns
example_batch = next(iter(train_ds))[0]
# A utility method to create a feature column
# and to transform a batch of data
def demo(feature_column):
feature_layer = layers.DenseFeatures(feature_column)
print(feature_layer(example_batch).numpy())
Kolom numerik
Output dari kolom fitur menjadi input ke model (menggunakan fungsi demo yang didefinisikan di atas, kita akan dapat melihat dengan tepat bagaimana setiap kolom dari kerangka data ditransformasikan). Kolom numerik adalah jenis kolom yang paling sederhana. Ini digunakan untuk merepresentasikan fitur yang bernilai nyata. Saat menggunakan kolom ini, model Anda akan menerima nilai kolom dari kerangka data tidak berubah.
photo_count = feature_column.numeric_column('PhotoAmt')
demo(photo_count)
[[2.] [4.] [4.] [1.] [2.]]
Dalam kumpulan data PetFinder, sebagian besar kolom dari kerangka data bersifat kategoris.
Kolom yang di-bucket
Seringkali, Anda tidak ingin memasukkan angka secara langsung ke dalam model, tetapi membagi nilainya ke dalam kategori yang berbeda berdasarkan rentang numerik. Pertimbangkan data mentah yang mewakili usia seseorang. Alih-alih merepresentasikan usia sebagai kolom numerik, kita dapat membagi usia menjadi beberapa ember menggunakan kolom ember . Perhatikan nilai one-hot di bawah ini yang menjelaskan rentang usia mana yang cocok dengan setiap baris.
age = feature_column.numeric_column('Age')
age_buckets = feature_column.bucketized_column(age, boundaries=[1, 3, 5])
demo(age_buckets)
[[0. 0. 0. 1.] [0. 1. 0. 0.] [0. 0. 0. 1.] [0. 0. 1. 0.] [0. 1. 0. 0.]]
Kolom kategoris
Dalam kumpulan data ini, Jenis direpresentasikan sebagai string (misalnya 'Anjing', atau 'Kucing'). Kami tidak dapat memasukkan string langsung ke model. Sebagai gantinya, pertama-tama kita harus memetakannya ke nilai numerik. Kolom kosakata kategoris menyediakan cara untuk mewakili string sebagai vektor satu-panas (seperti yang telah Anda lihat di atas dengan ember usia). Kosakata dapat diteruskan sebagai daftar menggunakan categorical_column_with_vocabulary_list , atau dimuat dari file menggunakan categorical_column_with_vocabulary_file .
animal_type = feature_column.categorical_column_with_vocabulary_list(
'Type', ['Cat', 'Dog'])
animal_type_one_hot = feature_column.indicator_column(animal_type)
demo(animal_type_one_hot)
[[1. 0.] [1. 0.] [1. 0.] [1. 0.] [0. 1.]]
Menyematkan kolom
Misalkan daripada hanya memiliki beberapa kemungkinan string, kita memiliki ribuan (atau lebih) nilai per kategori. Untuk sejumlah alasan, karena jumlah kategori bertambah besar, menjadi tidak mungkin untuk melatih jaringan saraf menggunakan penyandian satu-panas. Kita dapat menggunakan kolom embedding untuk mengatasi keterbatasan ini. Alih-alih mewakili data sebagai vektor satu-panas dari banyak dimensi, kolom penyematan mewakili data tersebut sebagai vektor padat berdimensi lebih rendah di mana setiap sel dapat berisi angka apa pun, bukan hanya 0 atau 1. Ukuran penyematan ( 8, pada contoh di bawah) adalah parameter yang harus disetel.
# Notice the input to the embedding column is the categorical column
# we previously created
breed1 = feature_column.categorical_column_with_vocabulary_list(
'Breed1', dataframe.Breed1.unique())
breed1_embedding = feature_column.embedding_column(breed1, dimension=8)
demo(breed1_embedding)
[[-0.22380038 -0.09379731 0.21349265 0.33451992 -0.49730566 0.05174963 0.2668497 0.27391028] [-0.5484653 -0.03492585 0.05648395 -0.09792244 0.02530896 -0.15477926 -0.10695003 -0.45474145] [-0.22380038 -0.09379731 0.21349265 0.33451992 -0.49730566 0.05174963 0.2668497 0.27391028] [ 0.10050306 0.43513173 0.375823 0.5652766 0.40925583 -0.03928828 0.4901914 0.20637617] [-0.2319875 -0.21874283 0.12272807 0.33345345 -0.4563055 0.21609035 -0.2410521 0.4736915 ]]
Kolom fitur hash
Cara lain untuk mewakili kolom kategoris dengan sejumlah besar nilai adalah dengan menggunakan categorical_column_with_hash_bucket . Kolom fitur ini menghitung nilai hash dari input, lalu memilih salah satu bucket hash_bucket_size
untuk menyandikan string. Saat menggunakan kolom ini, Anda tidak perlu menyediakan kosakata, dan Anda dapat memilih untuk membuat jumlah hash_buckets secara signifikan lebih kecil daripada jumlah kategori sebenarnya untuk menghemat ruang.
breed1_hashed = feature_column.categorical_column_with_hash_bucket(
'Breed1', hash_bucket_size=10)
demo(feature_column.indicator_column(breed1_hashed))
[[0. 0. 0. 0. 0. 0. 0. 0. 0. 1.] [0. 0. 0. 0. 0. 0. 0. 1. 0. 0.] [0. 0. 0. 0. 0. 0. 0. 0. 0. 1.] [0. 0. 0. 0. 0. 0. 1. 0. 0. 0.] [0. 0. 0. 0. 0. 0. 0. 1. 0. 0.]]
Kolom fitur bersilangan
Menggabungkan fitur menjadi satu fitur, lebih dikenal sebagai persilangan fitur , memungkinkan model mempelajari bobot terpisah untuk setiap kombinasi fitur. Disini kita akan membuat sebuah fitur baru yaitu persilangan Age dan Type. Perhatikan bahwa crossed_column
tidak membuat tabel lengkap dari semua kemungkinan kombinasi (yang bisa sangat besar). Sebaliknya, ini didukung oleh hashed_column
, sehingga Anda dapat memilih seberapa besar tabelnya.
crossed_feature = feature_column.crossed_column([age_buckets, animal_type], hash_bucket_size=10)
demo(feature_column.indicator_column(crossed_feature))
[[1. 0. 0. 0. 0. 0. 0. 0. 0. 0.] [0. 0. 0. 1. 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. 1. 0. 0. 0. 0. 0. 0. 0. 0.]]
Pilih kolom mana yang akan digunakan
Kita telah melihat bagaimana menggunakan beberapa jenis kolom fitur. Sekarang kita akan menggunakannya untuk melatih model. Tujuan dari tutorial ini adalah untuk menunjukkan kepada Anda kode lengkap (misalnya mekanik) yang diperlukan untuk bekerja dengan kolom fitur. Kami telah memilih beberapa kolom untuk melatih model kami di bawah ini secara sewenang-wenang.
feature_columns = []
# numeric cols
for header in ['PhotoAmt', 'Fee', 'Age']:
feature_columns.append(feature_column.numeric_column(header))
# bucketized cols
age = feature_column.numeric_column('Age')
age_buckets = feature_column.bucketized_column(age, boundaries=[1, 2, 3, 4, 5])
feature_columns.append(age_buckets)
# indicator_columns
indicator_column_names = ['Type', 'Color1', 'Color2', 'Gender', 'MaturitySize',
'FurLength', 'Vaccinated', 'Sterilized', 'Health']
for col_name in indicator_column_names:
categorical_column = feature_column.categorical_column_with_vocabulary_list(
col_name, dataframe[col_name].unique())
indicator_column = feature_column.indicator_column(categorical_column)
feature_columns.append(indicator_column)
# embedding columns
breed1 = feature_column.categorical_column_with_vocabulary_list(
'Breed1', dataframe.Breed1.unique())
breed1_embedding = feature_column.embedding_column(breed1, dimension=8)
feature_columns.append(breed1_embedding)
# crossed columns
age_type_feature = feature_column.crossed_column([age_buckets, animal_type], hash_bucket_size=100)
feature_columns.append(feature_column.indicator_column(age_type_feature))
Buat lapisan fitur
Sekarang kita telah mendefinisikan kolom fitur kita, kita akan menggunakan layer DenseFeatures untuk memasukkannya ke model Keras kita.
feature_layer = tf.keras.layers.DenseFeatures(feature_columns)
Sebelumnya, kami menggunakan ukuran batch kecil untuk mendemonstrasikan cara kerja kolom fitur. Kami membuat saluran input baru dengan ukuran batch yang lebih besar.
batch_size = 32
train_ds = df_to_dataset(train, batch_size=batch_size)
val_ds = df_to_dataset(val, shuffle=False, batch_size=batch_size)
test_ds = df_to_dataset(test, shuffle=False, batch_size=batch_size)
Buat, kompilasi, dan latih model
model = tf.keras.Sequential([
feature_layer,
layers.Dense(128, activation='relu'),
layers.Dense(128, activation='relu'),
layers.Dropout(.1),
layers.Dense(1)
])
model.compile(optimizer='adam',
loss=tf.keras.losses.BinaryCrossentropy(from_logits=True),
metrics=['accuracy'])
model.fit(train_ds,
validation_data=val_ds,
epochs=10)
Epoch 1/10 WARNING:tensorflow:Layers in a Sequential model should only have a single input tensor. Received: inputs={'Type': <tf.Tensor 'IteratorGetNext:11' shape=(None,) dtype=string>, 'Age': <tf.Tensor 'IteratorGetNext:0' shape=(None,) dtype=int64>, 'Breed1': <tf.Tensor 'IteratorGetNext:1' shape=(None,) dtype=string>, 'Gender': <tf.Tensor 'IteratorGetNext:6' shape=(None,) dtype=string>, 'Color1': <tf.Tensor 'IteratorGetNext:2' shape=(None,) dtype=string>, 'Color2': <tf.Tensor 'IteratorGetNext:3' shape=(None,) dtype=string>, 'MaturitySize': <tf.Tensor 'IteratorGetNext:8' shape=(None,) dtype=string>, 'FurLength': <tf.Tensor 'IteratorGetNext:5' shape=(None,) dtype=string>, 'Vaccinated': <tf.Tensor 'IteratorGetNext:12' shape=(None,) dtype=string>, 'Sterilized': <tf.Tensor 'IteratorGetNext:10' shape=(None,) dtype=string>, 'Health': <tf.Tensor 'IteratorGetNext:7' shape=(None,) dtype=string>, 'Fee': <tf.Tensor 'IteratorGetNext:4' shape=(None,) dtype=int64>, 'PhotoAmt': <tf.Tensor 'IteratorGetNext:9' shape=(None,) dtype=int64>}. Consider rewriting this model with the Functional API. WARNING:tensorflow:Layers in a Sequential model should only have a single input tensor. Received: inputs={'Type': <tf.Tensor 'IteratorGetNext:11' shape=(None,) dtype=string>, 'Age': <tf.Tensor 'IteratorGetNext:0' shape=(None,) dtype=int64>, 'Breed1': <tf.Tensor 'IteratorGetNext:1' shape=(None,) dtype=string>, 'Gender': <tf.Tensor 'IteratorGetNext:6' shape=(None,) dtype=string>, 'Color1': <tf.Tensor 'IteratorGetNext:2' shape=(None,) dtype=string>, 'Color2': <tf.Tensor 'IteratorGetNext:3' shape=(None,) dtype=string>, 'MaturitySize': <tf.Tensor 'IteratorGetNext:8' shape=(None,) dtype=string>, 'FurLength': <tf.Tensor 'IteratorGetNext:5' shape=(None,) dtype=string>, 'Vaccinated': <tf.Tensor 'IteratorGetNext:12' shape=(None,) dtype=string>, 'Sterilized': <tf.Tensor 'IteratorGetNext:10' shape=(None,) dtype=string>, 'Health': <tf.Tensor 'IteratorGetNext:7' shape=(None,) dtype=string>, 'Fee': <tf.Tensor 'IteratorGetNext:4' shape=(None,) dtype=int64>, 'PhotoAmt': <tf.Tensor 'IteratorGetNext:9' shape=(None,) dtype=int64>}. Consider rewriting this model with the Functional API. 231/231 [==============================] - ETA: 0s - loss: 0.6759 - accuracy: 0.6802WARNING:tensorflow:Layers in a Sequential model should only have a single input tensor. Received: inputs={'Type': <tf.Tensor 'IteratorGetNext:11' shape=(None,) dtype=string>, 'Age': <tf.Tensor 'IteratorGetNext:0' shape=(None,) dtype=int64>, 'Breed1': <tf.Tensor 'IteratorGetNext:1' shape=(None,) dtype=string>, 'Gender': <tf.Tensor 'IteratorGetNext:6' shape=(None,) dtype=string>, 'Color1': <tf.Tensor 'IteratorGetNext:2' shape=(None,) dtype=string>, 'Color2': <tf.Tensor 'IteratorGetNext:3' shape=(None,) dtype=string>, 'MaturitySize': <tf.Tensor 'IteratorGetNext:8' shape=(None,) dtype=string>, 'FurLength': <tf.Tensor 'IteratorGetNext:5' shape=(None,) dtype=string>, 'Vaccinated': <tf.Tensor 'IteratorGetNext:12' shape=(None,) dtype=string>, 'Sterilized': <tf.Tensor 'IteratorGetNext:10' shape=(None,) dtype=string>, 'Health': <tf.Tensor 'IteratorGetNext:7' shape=(None,) dtype=string>, 'Fee': <tf.Tensor 'IteratorGetNext:4' shape=(None,) dtype=int64>, 'PhotoAmt': <tf.Tensor 'IteratorGetNext:9' shape=(None,) dtype=int64>}. Consider rewriting this model with the Functional API. 231/231 [==============================] - 4s 10ms/step - loss: 0.6759 - accuracy: 0.6802 - val_loss: 0.5361 - val_accuracy: 0.7351 Epoch 2/10 231/231 [==============================] - 2s 9ms/step - loss: 0.5742 - accuracy: 0.7054 - val_loss: 0.5178 - val_accuracy: 0.7411 Epoch 3/10 231/231 [==============================] - 2s 9ms/step - loss: 0.5369 - accuracy: 0.7231 - val_loss: 0.5031 - val_accuracy: 0.7438 Epoch 4/10 231/231 [==============================] - 2s 9ms/step - loss: 0.5161 - accuracy: 0.7214 - val_loss: 0.5115 - val_accuracy: 0.7259 Epoch 5/10 231/231 [==============================] - 2s 9ms/step - loss: 0.5034 - accuracy: 0.7296 - val_loss: 0.5173 - val_accuracy: 0.7237 Epoch 6/10 231/231 [==============================] - 2s 8ms/step - loss: 0.4983 - accuracy: 0.7301 - val_loss: 0.5153 - val_accuracy: 0.7254 Epoch 7/10 231/231 [==============================] - 2s 9ms/step - loss: 0.4912 - accuracy: 0.7412 - val_loss: 0.5258 - val_accuracy: 0.7010 Epoch 8/10 231/231 [==============================] - 2s 9ms/step - loss: 0.4890 - accuracy: 0.7360 - val_loss: 0.5066 - val_accuracy: 0.7221 Epoch 9/10 231/231 [==============================] - 2s 9ms/step - loss: 0.4824 - accuracy: 0.7443 - val_loss: 0.5091 - val_accuracy: 0.7481 Epoch 10/10 231/231 [==============================] - 2s 9ms/step - loss: 0.4758 - accuracy: 0.7466 - val_loss: 0.5159 - val_accuracy: 0.7492 <keras.callbacks.History at 0x7f06b52a1810>
loss, accuracy = model.evaluate(test_ds)
print("Accuracy", accuracy)
73/73 [==============================] - 0s 6ms/step - loss: 0.4812 - accuracy: 0.7543 Accuracy 0.7543327808380127
Langkah selanjutnya
Cara terbaik untuk mempelajari lebih lanjut tentang mengklasifikasikan data terstruktur adalah dengan mencobanya sendiri. Kami menyarankan untuk mencari kumpulan data lain untuk digunakan, dan melatih model untuk mengklasifikasikannya menggunakan kode yang mirip dengan di atas. Untuk meningkatkan akurasi, pikirkan baik-baik fitur mana yang akan disertakan dalam model Anda, dan bagaimana fitur tersebut harus ditampilkan.