Klasifikasikan data terstruktur dengan kolom fitur

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.