![]() |
![]() |
![]() |
![]() |
本教學課程示範如何分類結構化資料 (例如 CSV 中的表格資料)。我們將使用 Keras 定義模型,並使用 tf.feature_column
作為橋樑,將 CSV 中的欄位對應至用於訓練模型的特徵。本教學課程包含以下完整程式碼:
- 使用 Pandas 載入 CSV 檔案。
- 建構輸入管道,以使用 tf.data 批次處理和隨機排序資料列。
- 使用特徵欄位,將 CSV 中的欄位對應至用於訓練模型的特徵。
- 使用 Keras 建構、訓練及評估模型。
資料集
我們將使用 PetFinder 資料集的簡化版本。CSV 中有數千列。每一列描述一隻寵物,每一欄描述一個屬性。我們將使用這些資訊來預測寵物被領養的速度。
以下是此資料集的描述。請注意,其中同時包含數值和類別欄位。其中有一個自由文字欄位,我們在本教學課程中不會使用。
欄位 | 說明 | 特徵類型 | 資料類型 |
---|---|---|---|
類型 | 動物類型 (狗、貓) | 類別型 | 字串 |
年齡 | 寵物的年齡 | 數值型 | 整數 |
Breed1 | 寵物的主要品種 | 類別型 | 字串 |
Color1 | 寵物的顏色 1 | 類別型 | 字串 |
Color2 | 寵物的顏色 2 | 類別型 | 字串 |
MaturitySize | 成熟時的大小 | 類別型 | 字串 |
FurLength | 毛髮長度 | 類別型 | 字串 |
Vaccinated | 寵物已接種疫苗 | 類別型 | 字串 |
Sterilized | 寵物已絕育 | 類別型 | 字串 |
Health | 健康狀況 | 類別型 | 字串 |
Fee | 領養費用 | 數值型 | 整數 |
說明 | 個人檔案描述 | 文字 | 字串 |
PhotoAmt | 此寵物上傳的照片總數 | 數值型 | 整數 |
AdoptionSpeed | 領養速度 | 分類 | 整數 |
匯入 TensorFlow 和其他程式庫
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
2023-10-27 05:23:51.727166: E external/local_xla/xla/stream_executor/cuda/cuda_dnn.cc:9261] Unable to register cuDNN factory: Attempting to register factory for plugin cuDNN when one has already been registered 2023-10-27 05:23:51.727210: E external/local_xla/xla/stream_executor/cuda/cuda_fft.cc:607] Unable to register cuFFT factory: Attempting to register factory for plugin cuFFT when one has already been registered 2023-10-27 05:23:51.728742: E external/local_xla/xla/stream_executor/cuda/cuda_blas.cc:1515] Unable to register cuBLAS factory: Attempting to register factory for plugin cuBLAS when one has already been registered
使用 Pandas 建立資料框架
Pandas 是一個 Python 程式庫,其中包含許多實用的工具,可用於載入和處理結構化資料。我們將使用 Pandas 從網址下載資料集,並將其載入至資料框架中。
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 1668792/1668792 [==============================] - 0s 0us/step
dataframe.head()
建立目標變數
原始資料集中的任務是預測寵物被領養的速度 (例如,在第一週、第一個月、前三個月等等)。讓我們在本教學課程中簡化此任務。在此,我們將其轉換為二元分類問題,並簡單地預測寵物是否被領養。
修改標籤欄位後,0 表示寵物未被領養,1 表示寵物已被領養。
# 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'])
將資料框架分割為訓練集、驗證集和測試集
我們下載的資料集是一個 CSV 檔案。我們會將其分割為訓練集、驗證集和測試集。
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
使用 tf.data 建立輸入管道
接下來,我們將使用 tf.data 包裝資料框架。這會讓我們能夠使用特徵欄位作為橋樑,將 Pandas 資料框架中的欄位對應至用於訓練模型的特徵。如果我們使用的是非常大的 CSV 檔案 (大到無法放入記憶體),我們會使用 tf.data 直接從磁碟讀取。本教學課程未涵蓋此內容。
# 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)
瞭解輸入管道
現在我們已建立輸入管道,讓我們呼叫它以查看其傳回的資料格式。我們已使用小批次大小,以使輸出結果更容易閱讀。
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([ 2 24 1 4 2], shape=(5,), dtype=int64) A batch of targets: tf.Tensor([1 1 1 1 1], shape=(5,), dtype=int64)
我們可以看見資料集傳回欄位名稱 (來自資料框架) 字典,其對應至資料框架中資料列的欄位值。
示範幾種特徵欄位類型
TensorFlow 提供多種特徵欄位類型。在本節中,我們將建立幾種特徵欄位類型,並示範它們如何轉換資料框架中的欄位。
# 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())
數值欄位
特徵欄位的輸出會變成模型的輸入 (使用上方定義的示範函式,我們將能夠準確地看見資料框架中的每個欄位如何轉換)。數值欄位是最簡單的欄位類型。它用於表示實值特徵。使用此欄位時,您的模型將接收來自資料框架的欄位值,且欄位值保持不變。
photo_count = feature_column.numeric_column('PhotoAmt')
demo(photo_count)
WARNING:tensorflow:From /tmpfs/tmp/ipykernel_442856/2408317497.py:1: numeric_column (from tensorflow.python.feature_column.feature_column_v2) is deprecated and will be removed in a future version. Instructions for updating: Use Keras preprocessing layers instead, either directly or via the `tf.keras.utils.FeatureSpace` utility. Each of `tf.feature_column.*` has a functional equivalent in `tf.keras.layers` for feature preprocessing when training a Keras model. [[2.] [1.] [2.] [3.] [1.]]
在 PetFinder 資料集中,資料框架中的大多數欄位都是類別欄位。
分桶欄位
通常,您不希望直接將數字饋送至模型,而是根據數值範圍將其值分割成不同的類別。考量代表人員年齡的原始資料。我們可以使用分桶欄位,將年齡分割成數個分桶,而不是將年齡表示為數值欄位。請注意,下方的獨熱編碼值說明每個資料列符合哪個年齡範圍。
age = feature_column.numeric_column('Age')
age_buckets = feature_column.bucketized_column(age, boundaries=[1, 3, 5])
demo(age_buckets)
WARNING:tensorflow:From /tmpfs/tmp/ipykernel_442856/4134348679.py:2: bucketized_column (from tensorflow.python.feature_column.feature_column_v2) is deprecated and will be removed in a future version. Instructions for updating: Use Keras preprocessing layers instead, either directly or via the `tf.keras.utils.FeatureSpace` utility. Each of `tf.feature_column.*` has a functional equivalent in `tf.keras.layers` for feature preprocessing when training a Keras model. [[0. 0. 0. 1.] [0. 0. 0. 1.] [0. 0. 0. 1.] [0. 1. 0. 0.] [0. 0. 0. 1.]]
類別欄位
在此資料集中,「類型」表示為字串 (例如「狗」或「貓」)。我們無法將字串直接饋送至模型。相反地,我們必須先將其對應至數值。categorical_column_with_vocabulary_list 使用詞彙表類別欄位提供一種將字串表示為獨熱編碼向量的方式 (與您在上方看到的年齡分桶非常相似)。詞彙表可以使用 categorical_column_with_vocabulary_list 以清單形式傳遞,或使用 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)
WARNING:tensorflow:From /tmpfs/tmp/ipykernel_442856/1157957390.py:1: categorical_column_with_vocabulary_list (from tensorflow.python.feature_column.feature_column_v2) is deprecated and will be removed in a future version. Instructions for updating: Use Keras preprocessing layers instead, either directly or via the `tf.keras.utils.FeatureSpace` utility. Each of `tf.feature_column.*` has a functional equivalent in `tf.keras.layers` for feature preprocessing when training a Keras model. WARNING:tensorflow:From /tmpfs/tmp/ipykernel_442856/1157957390.py:4: indicator_column (from tensorflow.python.feature_column.feature_column_v2) is deprecated and will be removed in a future version. Instructions for updating: Use Keras preprocessing layers instead, either directly or via the `tf.keras.utils.FeatureSpace` utility. Each of `tf.feature_column.*` has a functional equivalent in `tf.keras.layers` for feature preprocessing when training a Keras model. [[0. 1.] [1. 0.] [1. 0.] [1. 0.] [1. 0.]]
嵌入欄位
假設我們擁有的不只是幾個可能的字串,而是每個類別數千個 (或更多) 值。由於許多原因,隨著類別數量增加,使用獨熱編碼訓練神經網路變得不可行。我們可以使用嵌入欄位來克服此限制。嵌入欄位不是將資料表示為多維度的獨熱編碼向量,而是將資料表示為低維度、密集向量,其中每個儲存格可以包含任何數字,而不僅僅是 0 或 1。嵌入的大小 (在以下範例中為 8) 是必須調整的參數。
# 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)
WARNING:tensorflow:From /tmpfs/tmp/ipykernel_442856/689811331.py:5: embedding_column (from tensorflow.python.feature_column.feature_column_v2) is deprecated and will be removed in a future version. Instructions for updating: Use Keras preprocessing layers instead, either directly or via the `tf.keras.utils.FeatureSpace` utility. Each of `tf.feature_column.*` has a functional equivalent in `tf.keras.layers` for feature preprocessing when training a Keras model. [[ 0.23340847 -0.22288084 0.41993982 0.48253137 0.14740573 -0.30386004 0.30413502 0.14656945] [-0.23076059 -0.13627627 -0.05317891 0.6952521 0.46279088 -0.5734566 -0.04382351 -0.5681491 ] [ 0.45319527 0.40937862 -0.21215594 0.4152906 -0.11821023 -0.20306908 0.31819987 -0.0359318 ] [-0.23076059 -0.13627627 -0.05317891 0.6952521 0.46279088 -0.5734566 -0.04382351 -0.5681491 ] [-0.23076059 -0.13627627 -0.05317891 0.6952521 0.46279088 -0.5734566 -0.04382351 -0.5681491 ]]
雜湊特徵欄位
表示具有大量值的類別欄位的另一種方式是使用 categorical_column_with_hash_bucket。此特徵欄位會計算輸入的雜湊值,然後選取 hash_bucket_size
分桶的其中一個來編碼字串。使用此欄位時,您不需要提供詞彙表,並且可以選擇將雜湊分桶的數量設定為遠小於實際類別的數量,以節省空間。
breed1_hashed = feature_column.categorical_column_with_hash_bucket(
'Breed1', hash_bucket_size=10)
demo(feature_column.indicator_column(breed1_hashed))
WARNING:tensorflow:From /tmpfs/tmp/ipykernel_442856/3606107843.py:1: categorical_column_with_hash_bucket (from tensorflow.python.feature_column.feature_column_v2) is deprecated and will be removed in a future version. Instructions for updating: Use Keras preprocessing layers instead, either directly or via the `tf.keras.utils.FeatureSpace` utility. Each of `tf.feature_column.*` has a functional equivalent in `tf.keras.layers` for feature preprocessing when training a Keras model. [[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. 0. 0. 1. 0.] [0. 0. 0. 0. 0. 0. 0. 0. 0. 1.] [0. 0. 0. 0. 0. 0. 0. 0. 0. 1.]]
交叉特徵欄位
將多個特徵合併為單一特徵 (更廣為人知的是特徵交叉),讓模型能夠為每個特徵組合學習不同的權重。在此,我們將建立一個新特徵,它是「年齡」和「類型」的交叉特徵。請注意,crossed_column
不會建構所有可能組合的完整表格 (可能會非常大)。相反地,它由 hashed_column
支援,因此您可以選擇表格的大小。
crossed_feature = feature_column.crossed_column([age_buckets, animal_type], hash_bucket_size=10)
demo(feature_column.indicator_column(crossed_feature))
WARNING:tensorflow:From /tmpfs/tmp/ipykernel_442856/3676267184.py:1: crossed_column (from tensorflow.python.feature_column.feature_column_v2) is deprecated and will be removed in a future version. Instructions for updating: Use `tf.keras.layers.experimental.preprocessing.HashedCrossing` instead for feature crossing when preprocessing data to train a Keras model. [[0. 0. 0. 0. 0. 0. 0. 0. 1. 0.] [1. 0. 0. 0. 0. 0. 0. 0. 0. 0.] [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.]]
選擇要使用的欄位
我們已了解如何使用幾種類型的特徵欄位。現在我們將使用它們來訓練模型。本教學課程的目標是向您展示使用特徵欄位所需的完整程式碼 (例如機制)。我們已在下方任意選取幾個欄位來訓練模型。
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))
建立特徵層
現在我們已定義特徵欄位,我們將使用 DenseFeatures 層將它們輸入至我們的 Keras 模型。
feature_layer = tf.keras.layers.DenseFeatures(feature_columns)
稍早,我們使用小批次大小來示範特徵欄位如何運作。我們建立具有較大批次大小的新輸入管道。
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)
建立、編譯及訓練模型
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: All log messages before absl::InitializeLog() is called are written to STDERR I0000 00:00:1698384239.823402 443010 device_compiler.h:186] Compiled cluster using XLA! This line is logged at most once for the lifetime of the process. 231/231 [==============================] - 8s 18ms/step - loss: 0.7295 - accuracy: 0.6794 - val_loss: 0.5710 - val_accuracy: 0.7443 Epoch 2/10 231/231 [==============================] - 2s 8ms/step - loss: 0.5687 - accuracy: 0.7081 - val_loss: 0.6360 - val_accuracy: 0.7329 Epoch 3/10 231/231 [==============================] - 2s 8ms/step - loss: 0.5303 - accuracy: 0.7181 - val_loss: 0.5047 - val_accuracy: 0.7275 Epoch 4/10 231/231 [==============================] - 2s 8ms/step - loss: 0.5037 - accuracy: 0.7303 - val_loss: 0.4990 - val_accuracy: 0.7514 Epoch 5/10 231/231 [==============================] - 2s 8ms/step - loss: 0.4980 - accuracy: 0.7320 - val_loss: 0.5052 - val_accuracy: 0.6777 Epoch 6/10 231/231 [==============================] - 2s 8ms/step - loss: 0.4927 - accuracy: 0.7378 - val_loss: 0.4964 - val_accuracy: 0.7210 Epoch 7/10 231/231 [==============================] - 2s 8ms/step - loss: 0.4835 - accuracy: 0.7399 - val_loss: 0.4912 - val_accuracy: 0.7438 Epoch 8/10 231/231 [==============================] - 2s 7ms/step - loss: 0.4775 - accuracy: 0.7417 - val_loss: 0.4991 - val_accuracy: 0.7178 Epoch 9/10 231/231 [==============================] - 2s 7ms/step - loss: 0.4719 - accuracy: 0.7440 - val_loss: 0.4956 - val_accuracy: 0.7205 Epoch 10/10 231/231 [==============================] - 2s 7ms/step - loss: 0.4669 - accuracy: 0.7519 - val_loss: 0.5177 - val_accuracy: 0.6907 <keras.src.callbacks.History at 0x7febf88ba1c0>
loss, accuracy = model.evaluate(test_ds)
print("Accuracy", accuracy)
73/73 [==============================] - 0s 5ms/step - loss: 0.5207 - accuracy: 0.7015 Accuracy 0.7014731168746948
後續步驟
深入瞭解如何分類結構化資料的最佳方式是親自嘗試。我們建議您尋找另一個要處理的資料集,並使用類似於上述程式碼的程式碼訓練模型以分類該資料集。若要提高準確性,請仔細思考要在模型中納入哪些特徵,以及應如何表示這些特徵。