یک DataFrame پاندا را بارگیری کنید

مشاهده در TensorFlow.org در Google Colab اجرا شود مشاهده منبع در GitHub دانلود دفترچه یادداشت

این آموزش نمونه هایی از نحوه بارگذاری DataFrames پانداها در TensorFlow را ارائه می دهد.

شما از یک مجموعه داده کوچک بیماری قلبی ارائه شده توسط UCI Machine Learning Repository استفاده خواهید کرد. چند صد ردیف در CSV وجود دارد. هر ردیف یک بیمار را توصیف می کند و هر ستون یک ویژگی را توصیف می کند. شما از این اطلاعات برای پیش بینی اینکه آیا یک بیمار به بیماری قلبی مبتلا است یا خیر استفاده خواهید کرد، که یک کار طبقه بندی باینری است.

خواندن داده ها با استفاده از پانداها

import pandas as pd
import tensorflow as tf

SHUFFLE_BUFFER = 500
BATCH_SIZE = 2

دانلود فایل CSV حاوی مجموعه داده بیماری قلبی:

csv_file = tf.keras.utils.get_file('heart.csv', 'https://storage.googleapis.com/download.tensorflow.org/data/heart.csv')
Downloading data from https://storage.googleapis.com/download.tensorflow.org/data/heart.csv
16384/13273 [=====================================] - 0s 0us/step
24576/13273 [=======================================================] - 0s 0us/step

فایل CSV را با استفاده از پاندا بخوانید:

df = pd.read_csv(csv_file)

این چیزی است که داده ها به نظر می رسد:

df.head()
df.dtypes
age           int64
sex           int64
cp            int64
trestbps      int64
chol          int64
fbs           int64
restecg       int64
thalach       int64
exang         int64
oldpeak     float64
slope         int64
ca            int64
thal         object
target        int64
dtype: object

شما مدل هایی برای پیش بینی برچسب موجود در ستون target خواهید ساخت.

target = df.pop('target')

یک DataFrame به عنوان یک آرایه

اگر داده‌های شما یک نوع داده یکنواخت یا dtype ، می‌توانید در هر جایی که می‌توانید از آرایه NumPy استفاده کنید، از DataFrame pandas استفاده کنید. این کار به این دلیل کار می کند که کلاس pandas.DataFrame از پروتکل __array__ پشتیبانی می کند و تابع tf.convert_to_tensor اشیایی را می پذیرد که از پروتکل پشتیبانی می کنند.

ویژگی‌های عددی را از مجموعه داده بگیرید (فعلاً از ویژگی‌های دسته‌بندی صرفنظر کنید):

numeric_feature_names = ['age', 'thalach', 'trestbps',  'chol', 'oldpeak']
numeric_features = df[numeric_feature_names]
numeric_features.head()

DataFrame را می توان با استفاده از ویژگی DataFrame.values یا numpy.array(df) به آرایه NumPy تبدیل کرد. برای تبدیل آن به تانسور، از tf.convert_to_tensor استفاده کنید:

tf.convert_to_tensor(numeric_features)
<tf.Tensor: shape=(303, 5), dtype=float64, numpy=
array([[ 63. , 150. , 145. , 233. ,   2.3],
       [ 67. , 108. , 160. , 286. ,   1.5],
       [ 67. , 129. , 120. , 229. ,   2.6],
       ...,
       [ 65. , 127. , 135. , 254. ,   2.8],
       [ 48. , 150. , 130. , 256. ,   0. ],
       [ 63. , 154. , 150. , 407. ,   4. ]])>

به طور کلی، اگر یک شی را بتوان با tf.convert_to_tensor به یک تانسور تبدیل کرد، می‌توان آن را به هر جایی که یک tf.Tensor ارسال کرد ارسال کرد.

با Model.fit

یک DataFrame که به عنوان یک تانسور منفرد تفسیر می شود، می تواند مستقیماً به عنوان آرگومان برای روش Model.fit استفاده شود.

در زیر نمونه ای از آموزش یک مدل در مورد ویژگی های عددی مجموعه داده آورده شده است.

اولین قدم، عادی سازی محدوده های ورودی است. برای این کار از یک لایه tf.keras.layers.Normalization استفاده کنید.

برای تنظیم میانگین و انحراف استاندارد لایه قبل از اجرای آن، حتماً متد Normalization.adapt را فراخوانی کنید:

normalizer = tf.keras.layers.Normalization(axis=-1)
normalizer.adapt(numeric_features)

لایه روی سه ردیف اول DataFrame را فراخوانی کنید تا نمونه ای از خروجی این لایه را به تصویر بکشید:

normalizer(numeric_features.iloc[:3])
<tf.Tensor: shape=(3, 5), dtype=float32, numpy=
array([[ 0.93383914,  0.03480718,  0.74578077, -0.26008663,  1.0680453 ],
       [ 1.3782105 , -1.7806165 ,  1.5923285 ,  0.7573877 ,  0.38022864],
       [ 1.3782105 , -0.87290466, -0.6651321 , -0.33687714,  1.3259765 ]],
      dtype=float32)>

از لایه نرمال سازی به عنوان اولین لایه یک مدل ساده استفاده کنید:

def get_basic_model():
  model = tf.keras.Sequential([
    normalizer,
    tf.keras.layers.Dense(10, activation='relu'),
    tf.keras.layers.Dense(10, activation='relu'),
    tf.keras.layers.Dense(1)
  ])

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

هنگامی که DataFrame را به عنوان آرگومان x به Model.fit می کنید، Keras با DataFrame مانند آرایه NumPy رفتار می کند:

model = get_basic_model()
model.fit(numeric_features, target, epochs=15, batch_size=BATCH_SIZE)
Epoch 1/15
152/152 [==============================] - 1s 2ms/step - loss: 0.6839 - accuracy: 0.7690
Epoch 2/15
152/152 [==============================] - 0s 2ms/step - loss: 0.5789 - accuracy: 0.7789
Epoch 3/15
152/152 [==============================] - 0s 2ms/step - loss: 0.5195 - accuracy: 0.7723
Epoch 4/15
152/152 [==============================] - 0s 2ms/step - loss: 0.4814 - accuracy: 0.7855
Epoch 5/15
152/152 [==============================] - 0s 2ms/step - loss: 0.4566 - accuracy: 0.7789
Epoch 6/15
152/152 [==============================] - 0s 2ms/step - loss: 0.4427 - accuracy: 0.7888
Epoch 7/15
152/152 [==============================] - 0s 2ms/step - loss: 0.4342 - accuracy: 0.7921
Epoch 8/15
152/152 [==============================] - 0s 2ms/step - loss: 0.4290 - accuracy: 0.7855
Epoch 9/15
152/152 [==============================] - 0s 2ms/step - loss: 0.4240 - accuracy: 0.7987
Epoch 10/15
152/152 [==============================] - 0s 2ms/step - loss: 0.4232 - accuracy: 0.7987
Epoch 11/15
152/152 [==============================] - 0s 2ms/step - loss: 0.4208 - accuracy: 0.7987
Epoch 12/15
152/152 [==============================] - 0s 2ms/step - loss: 0.4186 - accuracy: 0.7954
Epoch 13/15
152/152 [==============================] - 0s 2ms/step - loss: 0.4172 - accuracy: 0.8020
Epoch 14/15
152/152 [==============================] - 0s 2ms/step - loss: 0.4156 - accuracy: 0.8020
Epoch 15/15
152/152 [==============================] - 0s 2ms/step - loss: 0.4138 - accuracy: 0.8020
<keras.callbacks.History at 0x7f1ddc27b110>

با tf.data

اگر می‌خواهید tf.data را در یک DataFrame با dtype یکنواخت اعمال کنید، متد Dataset.from_tensor_slices یک مجموعه داده ایجاد می‌کند که روی ردیف‌های DataFrame تکرار می‌شود. هر ردیف در ابتدا یک بردار از مقادیر است. برای آموزش یک مدل، به جفت (inputs, labels) نیاز دارید، بنابراین pass (features, labels) و Dataset.from_tensor_slices جفت‌های مورد نیاز را برمی‌گرداند:

numeric_dataset = tf.data.Dataset.from_tensor_slices((numeric_features, target))

for row in numeric_dataset.take(3):
  print(row)
(<tf.Tensor: shape=(5,), dtype=float64, numpy=array([ 63. , 150. , 145. , 233. ,   2.3])>, <tf.Tensor: shape=(), dtype=int64, numpy=0>)
(<tf.Tensor: shape=(5,), dtype=float64, numpy=array([ 67. , 108. , 160. , 286. ,   1.5])>, <tf.Tensor: shape=(), dtype=int64, numpy=1>)
(<tf.Tensor: shape=(5,), dtype=float64, numpy=array([ 67. , 129. , 120. , 229. ,   2.6])>, <tf.Tensor: shape=(), dtype=int64, numpy=0>)
numeric_batches = numeric_dataset.shuffle(1000).batch(BATCH_SIZE)

model = get_basic_model()
model.fit(numeric_batches, epochs=15)
Epoch 1/15
152/152 [==============================] - 1s 2ms/step - loss: 0.7677 - accuracy: 0.6865
Epoch 2/15
152/152 [==============================] - 0s 2ms/step - loss: 0.6319 - accuracy: 0.7591
Epoch 3/15
152/152 [==============================] - 0s 2ms/step - loss: 0.5717 - accuracy: 0.7459
Epoch 4/15
152/152 [==============================] - 0s 2ms/step - loss: 0.5228 - accuracy: 0.7558
Epoch 5/15
152/152 [==============================] - 0s 2ms/step - loss: 0.4820 - accuracy: 0.7624
Epoch 6/15
152/152 [==============================] - 0s 2ms/step - loss: 0.4584 - accuracy: 0.7657
Epoch 7/15
152/152 [==============================] - 0s 2ms/step - loss: 0.4454 - accuracy: 0.7657
Epoch 8/15
152/152 [==============================] - 0s 2ms/step - loss: 0.4379 - accuracy: 0.7789
Epoch 9/15
152/152 [==============================] - 0s 2ms/step - loss: 0.4324 - accuracy: 0.7789
Epoch 10/15
152/152 [==============================] - 0s 2ms/step - loss: 0.4282 - accuracy: 0.7756
Epoch 11/15
152/152 [==============================] - 0s 2ms/step - loss: 0.4273 - accuracy: 0.7789
Epoch 12/15
152/152 [==============================] - 0s 2ms/step - loss: 0.4268 - accuracy: 0.7756
Epoch 13/15
152/152 [==============================] - 0s 2ms/step - loss: 0.4248 - accuracy: 0.7789
Epoch 14/15
152/152 [==============================] - 0s 2ms/step - loss: 0.4235 - accuracy: 0.7855
Epoch 15/15
152/152 [==============================] - 0s 2ms/step - loss: 0.4223 - accuracy: 0.7888
<keras.callbacks.History at 0x7f1ddc406510>

یک DataFrame به عنوان یک فرهنگ لغت

وقتی شروع به کار با داده های ناهمگن می کنید، دیگر نمی توان با DataFrame به گونه ای رفتار کرد که گویی یک آرایه واحد است. تانسورهای TensorFlow نیاز دارند که همه عناصر دارای dtype یکسان باشند.

بنابراین، در این مورد، باید آن را به عنوان یک فرهنگ لغت از ستون ها در نظر بگیرید، که در آن هر ستون دارای dtype یکنواخت است. یک DataFrame بسیار شبیه به فرهنگ لغت آرایه‌ها است، بنابراین معمولاً تنها کاری که باید انجام دهید این است که DataFrame را به یک دستور Python ارسال کنید. بسیاری از API های مهم TensorFlow از فرهنگ لغت (تودرتو) آرایه ها به عنوان ورودی پشتیبانی می کنند.

خطوط لوله ورودی tf.data به خوبی از عهده این کار بر می آیند. همه عملیات tf.data دیکشنری ها و تاپل ها را به طور خودکار مدیریت می کنند. بنابراین، برای ایجاد مجموعه داده‌ای از نمونه‌های فرهنگ لغت از یک DataFrame، کافی است قبل از برش دادن آن با Dataset.from_tensor_slices ، آن را به یک دیکته ارسال کنید:

numeric_dict_ds = tf.data.Dataset.from_tensor_slices((dict(numeric_features), target))

در اینجا سه ​​نمونه اول از آن مجموعه داده آمده است:

for row in numeric_dict_ds.take(3):
  print(row)
({'age': <tf.Tensor: shape=(), dtype=int64, numpy=63>, 'thalach': <tf.Tensor: shape=(), dtype=int64, numpy=150>, 'trestbps': <tf.Tensor: shape=(), dtype=int64, numpy=145>, 'chol': <tf.Tensor: shape=(), dtype=int64, numpy=233>, 'oldpeak': <tf.Tensor: shape=(), dtype=float64, numpy=2.3>}, <tf.Tensor: shape=(), dtype=int64, numpy=0>)
({'age': <tf.Tensor: shape=(), dtype=int64, numpy=67>, 'thalach': <tf.Tensor: shape=(), dtype=int64, numpy=108>, 'trestbps': <tf.Tensor: shape=(), dtype=int64, numpy=160>, 'chol': <tf.Tensor: shape=(), dtype=int64, numpy=286>, 'oldpeak': <tf.Tensor: shape=(), dtype=float64, numpy=1.5>}, <tf.Tensor: shape=(), dtype=int64, numpy=1>)
({'age': <tf.Tensor: shape=(), dtype=int64, numpy=67>, 'thalach': <tf.Tensor: shape=(), dtype=int64, numpy=129>, 'trestbps': <tf.Tensor: shape=(), dtype=int64, numpy=120>, 'chol': <tf.Tensor: shape=(), dtype=int64, numpy=229>, 'oldpeak': <tf.Tensor: shape=(), dtype=float64, numpy=2.6>}, <tf.Tensor: shape=(), dtype=int64, numpy=0>)

فرهنگ لغت با Keras

به طور معمول، مدل‌ها و لایه‌های Keras انتظار یک تانسور ورودی را دارند، اما این کلاس‌ها می‌توانند ساختارهای تودرتو از دیکشنری‌ها، تاپل‌ها و تانسورها را بپذیرند و برگردانند. این ساختارها به عنوان "nest" شناخته می شوند (برای جزئیات به ماژول tf.nest مراجعه کنید).

دو روش معادل برای نوشتن یک مدل keras وجود دارد که یک فرهنگ لغت را به عنوان ورودی می پذیرد.

1. سبک Model-subclass

شما یک زیر کلاس از tf.keras.Model (یا tf.keras.Layer ) می نویسید. شما مستقیماً ورودی ها را مدیریت می کنید و خروجی ها را ایجاد می کنید:

def stack_dict(inputs, fun=tf.stack):
    values = []
    for key in sorted(inputs.keys()):
      values.append(tf.cast(inputs[key], tf.float32))

    return fun(values, axis=-1)

این مدل می‌تواند فرهنگ لغت ستون‌ها یا مجموعه داده‌ای از عناصر فرهنگ لغت را برای آموزش بپذیرد:

model.fit(dict(numeric_features), target, epochs=5, batch_size=BATCH_SIZE)
Epoch 1/5
152/152 [==============================] - 3s 17ms/step - loss: 0.6736 - accuracy: 0.7063
Epoch 2/5
152/152 [==============================] - 3s 17ms/step - loss: 0.5577 - accuracy: 0.7294
Epoch 3/5
152/152 [==============================] - 2s 16ms/step - loss: 0.4869 - accuracy: 0.7591
Epoch 4/5
152/152 [==============================] - 2s 16ms/step - loss: 0.4525 - accuracy: 0.7690
Epoch 5/5
152/152 [==============================] - 2s 16ms/step - loss: 0.4403 - accuracy: 0.7624
<keras.callbacks.History at 0x7f1de4fa9390>
numeric_dict_batches = numeric_dict_ds.shuffle(SHUFFLE_BUFFER).batch(BATCH_SIZE)
model.fit(numeric_dict_batches, epochs=5)
Epoch 1/5
152/152 [==============================] - 2s 15ms/step - loss: 0.4328 - accuracy: 0.7756
Epoch 2/5
152/152 [==============================] - 2s 14ms/step - loss: 0.4297 - accuracy: 0.7888
Epoch 3/5
152/152 [==============================] - 2s 15ms/step - loss: 0.4270 - accuracy: 0.7888
Epoch 4/5
152/152 [==============================] - 2s 15ms/step - loss: 0.4245 - accuracy: 0.8020
Epoch 5/5
152/152 [==============================] - 2s 15ms/step - loss: 0.4240 - accuracy: 0.7921
<keras.callbacks.History at 0x7f1ddc0dba90>

در اینجا پیش‌بینی‌های سه مثال اول آمده است:

model.predict(dict(numeric_features.iloc[:3]))
array([[[0.00565109]],

       [[0.60601974]],

       [[0.03647463]]], dtype=float32)

2. سبک کاربردی Keras

inputs = {}
for name, column in numeric_features.items():
  inputs[name] = tf.keras.Input(
      shape=(1,), name=name, dtype=tf.float32)

inputs
{'age': <KerasTensor: shape=(None, 1) dtype=float32 (created by layer 'age')>,
 'thalach': <KerasTensor: shape=(None, 1) dtype=float32 (created by layer 'thalach')>,
 'trestbps': <KerasTensor: shape=(None, 1) dtype=float32 (created by layer 'trestbps')>,
 'chol': <KerasTensor: shape=(None, 1) dtype=float32 (created by layer 'chol')>,
 'oldpeak': <KerasTensor: shape=(None, 1) dtype=float32 (created by layer 'oldpeak')>}
x = stack_dict(inputs, fun=tf.concat)

normalizer = tf.keras.layers.Normalization(axis=-1)
normalizer.adapt(stack_dict(dict(numeric_features)))

x = normalizer(x)
x = tf.keras.layers.Dense(10, activation='relu')(x)
x = tf.keras.layers.Dense(10, activation='relu')(x)
x = tf.keras.layers.Dense(1)(x)

model = tf.keras.Model(inputs, x)

model.compile(optimizer='adam',
              loss=tf.keras.losses.BinaryCrossentropy(from_logits=True),
              metrics=['accuracy'],
              run_eagerly=True)
tf.keras.utils.plot_model(model, rankdir="LR", show_shapes=True)

png

می توانید مدل عملکردی را به همان روش زیر کلاس مدل آموزش دهید:

model.fit(dict(numeric_features), target, epochs=5, batch_size=BATCH_SIZE)
Epoch 1/5
152/152 [==============================] - 2s 15ms/step - loss: 0.6529 - accuracy: 0.7492
Epoch 2/5
152/152 [==============================] - 2s 15ms/step - loss: 0.5448 - accuracy: 0.7624
Epoch 3/5
152/152 [==============================] - 2s 15ms/step - loss: 0.4935 - accuracy: 0.7756
Epoch 4/5
152/152 [==============================] - 2s 15ms/step - loss: 0.4650 - accuracy: 0.7789
Epoch 5/5
152/152 [==============================] - 2s 15ms/step - loss: 0.4486 - accuracy: 0.7855
<keras.callbacks.History at 0x7f1ddc0d0f90>
numeric_dict_batches = numeric_dict_ds.shuffle(SHUFFLE_BUFFER).batch(BATCH_SIZE)
model.fit(numeric_dict_batches, epochs=5)
Epoch 1/5
152/152 [==============================] - 2s 15ms/step - loss: 0.4398 - accuracy: 0.7855
Epoch 2/5
152/152 [==============================] - 2s 15ms/step - loss: 0.4330 - accuracy: 0.7855
Epoch 3/5
152/152 [==============================] - 2s 16ms/step - loss: 0.4294 - accuracy: 0.7921
Epoch 4/5
152/152 [==============================] - 2s 16ms/step - loss: 0.4271 - accuracy: 0.7888
Epoch 5/5
152/152 [==============================] - 2s 16ms/step - loss: 0.4231 - accuracy: 0.7855
<keras.callbacks.History at 0x7f1d7c5d5d10>

مثال کامل

اگر یک DataFrame ناهمگن را به Keras ارسال کنید، هر ستون ممکن است نیاز به پیش پردازش منحصر به فردی داشته باشد. می‌توانید این پیش‌پردازش را مستقیماً در DataFrame انجام دهید، اما برای اینکه یک مدل به درستی کار کند، ورودی‌ها همیشه باید به همان روش پیش پردازش شوند. بنابراین، بهترین رویکرد، ایجاد پیش پردازش در مدل است. لایه های پیش پردازش Keras بسیاری از وظایف رایج را پوشش می دهند.

سر پیش پردازش را بسازید

در این مجموعه داده، برخی از ویژگی‌های «عدد صحیح» در داده‌های خام در واقع شاخص‌های دسته‌بندی هستند. این شاخص ها واقعاً مقادیر عددی مرتب نیستند (برای جزئیات به توضیحات مجموعه داده مراجعه کنید). از آنجایی که اینها مرتب نیستند، برای تغذیه مستقیم به مدل مناسب نیستند. مدل آنها را به عنوان سفارش شده تفسیر می کند. برای استفاده از این ورودی ها باید آنها را به صورت بردارهای تک داغ یا بردارهای جاسازی شده رمزگذاری کنید. همین امر در مورد ویژگی های رشته ای نیز صدق می کند.

از طرف دیگر ویژگی های باینری معمولاً نیازی به کدگذاری یا عادی سازی ندارند.

با ایجاد لیستی از ویژگی هایی که در هر گروه قرار می گیرند شروع کنید:

binary_feature_names = ['sex', 'fbs', 'exang']
categorical_feature_names = ['cp', 'restecg', 'slope', 'thal', 'ca']

گام بعدی ساختن یک مدل پیش پردازش است که پیش پردازش مناسبی را برای هر یک در هر ورودی اعمال می کند و نتایج را به هم متصل می کند.

این بخش از Keras Functional API برای پیاده سازی پیش پردازش استفاده می کند. شما با ایجاد یک tf.keras.Input برای هر ستون از dataframe شروع می کنید:

inputs = {}
for name, column in df.items():
  if type(column[0]) == str:
    dtype = tf.string
  elif (name in categorical_feature_names or
        name in binary_feature_names):
    dtype = tf.int64
  else:
    dtype = tf.float32

  inputs[name] = tf.keras.Input(shape=(), name=name, dtype=dtype)
inputs
{'age': <KerasTensor: shape=(None,) dtype=float32 (created by layer 'age')>,
 'sex': <KerasTensor: shape=(None,) dtype=int64 (created by layer 'sex')>,
 'cp': <KerasTensor: shape=(None,) dtype=int64 (created by layer 'cp')>,
 'trestbps': <KerasTensor: shape=(None,) dtype=float32 (created by layer 'trestbps')>,
 'chol': <KerasTensor: shape=(None,) dtype=float32 (created by layer 'chol')>,
 'fbs': <KerasTensor: shape=(None,) dtype=int64 (created by layer 'fbs')>,
 'restecg': <KerasTensor: shape=(None,) dtype=int64 (created by layer 'restecg')>,
 'thalach': <KerasTensor: shape=(None,) dtype=float32 (created by layer 'thalach')>,
 'exang': <KerasTensor: shape=(None,) dtype=int64 (created by layer 'exang')>,
 'oldpeak': <KerasTensor: shape=(None,) dtype=float32 (created by layer 'oldpeak')>,
 'slope': <KerasTensor: shape=(None,) dtype=int64 (created by layer 'slope')>,
 'ca': <KerasTensor: shape=(None,) dtype=int64 (created by layer 'ca')>,
 'thal': <KerasTensor: shape=(None,) dtype=string (created by layer 'thal')>}

برای هر ورودی، با استفاده از لایه‌های Keras و عملیات TensorFlow، تغییراتی را اعمال خواهید کرد. هر ویژگی به‌عنوان دسته‌ای از اسکالرها شروع می‌شود ( shape=(batch,) ). خروجی برای هر یک باید دسته ای از بردارهای tf.float32 باشد ( shape=(batch, n) ). مرحله آخر تمام آن بردارها را به هم متصل می کند.

ورودی های باینری

از آنجایی که ورودی های باینری نیازی به پیش پردازش ندارند، فقط محور برداری را اضافه کنید، آنها را به float32 و به لیست ورودی های از پیش پردازش شده اضافه کنید:

preprocessed = []

for name in binary_feature_names:
  inp = inputs[name]
  inp = inp[:, tf.newaxis]
  float_value = tf.cast(inp, tf.float32)
  preprocessed.append(float_value)

preprocessed
[<KerasTensor: shape=(None, 1) dtype=float32 (created by layer 'tf.cast_5')>,
 <KerasTensor: shape=(None, 1) dtype=float32 (created by layer 'tf.cast_6')>,
 <KerasTensor: shape=(None, 1) dtype=float32 (created by layer 'tf.cast_7')>]

ورودی های عددی

مانند بخش قبل، می‌خواهید این ورودی‌های عددی را قبل از استفاده از یک لایه tf.keras.layers.Normalization کنید. تفاوت این است که این بار آنها به عنوان یک دیکته وارد می شوند. کد زیر ویژگی‌های عددی را از DataFrame جمع‌آوری می‌کند، آن‌ها را در کنار هم قرار می‌دهد و آن‌ها را به روش Normalization.adapt ارسال می‌کند.

normalizer = tf.keras.layers.Normalization(axis=-1)
normalizer.adapt(stack_dict(dict(numeric_features)))

کد زیر ویژگی های عددی را روی هم قرار می دهد و آنها را در لایه نرمال سازی اجرا می کند.

numeric_inputs = {}
for name in numeric_feature_names:
  numeric_inputs[name]=inputs[name]

numeric_inputs = stack_dict(numeric_inputs)
numeric_normalized = normalizer(numeric_inputs)

preprocessed.append(numeric_normalized)

preprocessed
[<KerasTensor: shape=(None, 1) dtype=float32 (created by layer 'tf.cast_5')>,
 <KerasTensor: shape=(None, 1) dtype=float32 (created by layer 'tf.cast_6')>,
 <KerasTensor: shape=(None, 1) dtype=float32 (created by layer 'tf.cast_7')>,
 <KerasTensor: shape=(None, 5) dtype=float32 (created by layer 'normalization_3')>]

ویژگی های دسته بندی

برای استفاده از ویژگی های طبقه بندی شده، ابتدا باید آنها را در بردارهای باینری یا جاسازی ها رمزگذاری کنید. از آنجایی که این ویژگی‌ها فقط شامل تعداد کمی از دسته‌ها هستند، ورودی‌ها را مستقیماً با استفاده از output_mode='one_hot' که توسط لایه‌های tf.keras.layers.StringLookup و tf.keras.layers.IntegerLookup پشتیبانی می‌شود، به بردارهای تک داغ تبدیل کنید.

در اینجا مثالی از نحوه عملکرد این لایه ها آورده شده است:

vocab = ['a','b','c']
lookup = tf.keras.layers.StringLookup(vocabulary=vocab, output_mode='one_hot')
lookup(['c','a','a','b','zzz'])
<tf.Tensor: shape=(5, 4), dtype=float32, numpy=
array([[0., 0., 0., 1.],
       [0., 1., 0., 0.],
       [0., 1., 0., 0.],
       [0., 0., 1., 0.],
       [1., 0., 0., 0.]], dtype=float32)>
vocab = [1,4,7,99]
lookup = tf.keras.layers.IntegerLookup(vocabulary=vocab, output_mode='one_hot')

lookup([-1,4,1])
<tf.Tensor: shape=(3, 5), dtype=float32, numpy=
array([[1., 0., 0., 0., 0.],
       [0., 0., 1., 0., 0.],
       [0., 1., 0., 0., 0.]], dtype=float32)>

برای تعیین واژگان برای هر ورودی، یک لایه ایجاد کنید تا آن واژگان را به یک بردار یک داغ تبدیل کنید:

for name in categorical_feature_names:
  vocab = sorted(set(df[name]))
  print(f'name: {name}')
  print(f'vocab: {vocab}\n')

  if type(vocab[0]) is str:
    lookup = tf.keras.layers.StringLookup(vocabulary=vocab, output_mode='one_hot')
  else:
    lookup = tf.keras.layers.IntegerLookup(vocabulary=vocab, output_mode='one_hot')

  x = inputs[name][:, tf.newaxis]
  x = lookup(x)
  preprocessed.append(x)
name: cp
vocab: [0, 1, 2, 3, 4]

name: restecg
vocab: [0, 1, 2]

name: slope
vocab: [1, 2, 3]

name: thal
vocab: ['1', '2', 'fixed', 'normal', 'reversible']

name: ca
vocab: [0, 1, 2, 3]

سر پیش پردازش را مونتاژ کنید

در این مرحله از preprocessed شده فقط یک لیست پایتون از تمام نتایج پیش پردازش است، هر نتیجه شکلی از (batch_size, depth) :

preprocessed
[<KerasTensor: shape=(None, 1) dtype=float32 (created by layer 'tf.cast_5')>,
 <KerasTensor: shape=(None, 1) dtype=float32 (created by layer 'tf.cast_6')>,
 <KerasTensor: shape=(None, 1) dtype=float32 (created by layer 'tf.cast_7')>,
 <KerasTensor: shape=(None, 5) dtype=float32 (created by layer 'normalization_3')>,
 <KerasTensor: shape=(None, 6) dtype=float32 (created by layer 'integer_lookup_1')>,
 <KerasTensor: shape=(None, 4) dtype=float32 (created by layer 'integer_lookup_2')>,
 <KerasTensor: shape=(None, 4) dtype=float32 (created by layer 'integer_lookup_3')>,
 <KerasTensor: shape=(None, 6) dtype=float32 (created by layer 'string_lookup_1')>,
 <KerasTensor: shape=(None, 5) dtype=float32 (created by layer 'integer_lookup_4')>]

تمام ویژگی های از پیش پردازش شده را در امتداد محور depth به هم ادغام کنید، بنابراین هر نمونه فرهنگ لغت به یک بردار تبدیل می شود. این بردار شامل ویژگی‌های طبقه‌بندی، ویژگی‌های عددی و ویژگی‌های دسته‌بندی تک داغ است:

preprocesssed_result = tf.concat(preprocessed, axis=-1)
preprocesssed_result
<KerasTensor: shape=(None, 33) dtype=float32 (created by layer 'tf.concat_1')>

حالا یک مدل از آن محاسبات ایجاد کنید تا بتوان از آن دوباره استفاده کرد:

preprocessor = tf.keras.Model(inputs, preprocesssed_result)
tf.keras.utils.plot_model(preprocessor, rankdir="LR", show_shapes=True)

png

برای آزمایش پیش پردازنده، از Accessor DataFrame.iloc استفاده کنید تا اولین نمونه را از DataFrame جدا کنید. سپس آن را به دیکشنری تبدیل کنید و دیکشنری را به پیش پردازنده منتقل کنید. نتیجه یک بردار منفرد حاوی ویژگی‌های باینری، ویژگی‌های عددی نرمال‌شده و ویژگی‌های دسته‌بندی یک داغ است، به ترتیب:

preprocessor(dict(df.iloc[:1]))
<tf.Tensor: shape=(1, 33), dtype=float32, numpy=
array([[ 1.        ,  1.        ,  0.        ,  0.93383914, -0.26008663,
         1.0680453 ,  0.03480718,  0.74578077,  0.        ,  0.        ,

         1.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  0.        ,  1.        ,  0.        ,  0.        ,
         0.        ,  1.        ,  0.        ,  0.        ,  0.        ,
         1.        ,  0.        ,  0.        ,  0.        ,  1.        ,
         0.        ,  0.        ,  0.        ]], dtype=float32)>

ایجاد و آموزش یک مدل

حالا بدنه اصلی مدل را بسازید. از همان پیکربندی مثال قبلی استفاده کنید: چند لایه خطی اصلاح شده Dense و یک لایه خروجی Dense(1) برای طبقه بندی.

body = tf.keras.Sequential([
  tf.keras.layers.Dense(10, activation='relu'),
  tf.keras.layers.Dense(10, activation='relu'),
  tf.keras.layers.Dense(1)
])

حالا دو قطعه را با استفاده از API عملکردی Keras کنار هم قرار دهید.

inputs
{'age': <KerasTensor: shape=(None,) dtype=float32 (created by layer 'age')>,
 'sex': <KerasTensor: shape=(None,) dtype=int64 (created by layer 'sex')>,
 'cp': <KerasTensor: shape=(None,) dtype=int64 (created by layer 'cp')>,
 'trestbps': <KerasTensor: shape=(None,) dtype=float32 (created by layer 'trestbps')>,
 'chol': <KerasTensor: shape=(None,) dtype=float32 (created by layer 'chol')>,
 'fbs': <KerasTensor: shape=(None,) dtype=int64 (created by layer 'fbs')>,
 'restecg': <KerasTensor: shape=(None,) dtype=int64 (created by layer 'restecg')>,
 'thalach': <KerasTensor: shape=(None,) dtype=float32 (created by layer 'thalach')>,
 'exang': <KerasTensor: shape=(None,) dtype=int64 (created by layer 'exang')>,
 'oldpeak': <KerasTensor: shape=(None,) dtype=float32 (created by layer 'oldpeak')>,
 'slope': <KerasTensor: shape=(None,) dtype=int64 (created by layer 'slope')>,
 'ca': <KerasTensor: shape=(None,) dtype=int64 (created by layer 'ca')>,
 'thal': <KerasTensor: shape=(None,) dtype=string (created by layer 'thal')>}
x = preprocessor(inputs)
x
<KerasTensor: shape=(None, 33) dtype=float32 (created by layer 'model_1')>
result = body(x)
result
<KerasTensor: shape=(None, 1) dtype=float32 (created by layer 'sequential_3')>
model = tf.keras.Model(inputs, result)

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

این مدل انتظار یک فرهنگ لغت از ورودی ها را دارد. ساده ترین راه برای انتقال داده ها این است که DataFrame را به یک dict تبدیل کنید و آن dict را به عنوان آرگومان x به Model.fit :

history = model.fit(dict(df), target, epochs=5, batch_size=BATCH_SIZE)
Epoch 1/5
152/152 [==============================] - 1s 4ms/step - loss: 0.6911 - accuracy: 0.6997
Epoch 2/5
152/152 [==============================] - 1s 4ms/step - loss: 0.5073 - accuracy: 0.7393
Epoch 3/5
152/152 [==============================] - 1s 4ms/step - loss: 0.4129 - accuracy: 0.7888
Epoch 4/5
152/152 [==============================] - 1s 4ms/step - loss: 0.3663 - accuracy: 0.7921
Epoch 5/5
152/152 [==============================] - 1s 4ms/step - loss: 0.3363 - accuracy: 0.8152

استفاده از tf.data نیز کار می کند:

ds = tf.data.Dataset.from_tensor_slices((
    dict(df),
    target
))

ds = ds.batch(BATCH_SIZE)
import pprint

for x, y in ds.take(1):
  pprint.pprint(x)
  print()
  print(y)
{'age': <tf.Tensor: shape=(2,), dtype=int64, numpy=array([63, 67])>,
 'ca': <tf.Tensor: shape=(2,), dtype=int64, numpy=array([0, 3])>,
 'chol': <tf.Tensor: shape=(2,), dtype=int64, numpy=array([233, 286])>,
 'cp': <tf.Tensor: shape=(2,), dtype=int64, numpy=array([1, 4])>,
 'exang': <tf.Tensor: shape=(2,), dtype=int64, numpy=array([0, 1])>,
 'fbs': <tf.Tensor: shape=(2,), dtype=int64, numpy=array([1, 0])>,
 'oldpeak': <tf.Tensor: shape=(2,), dtype=float64, numpy=array([2.3, 1.5])>,
 'restecg': <tf.Tensor: shape=(2,), dtype=int64, numpy=array([2, 2])>,
 'sex': <tf.Tensor: shape=(2,), dtype=int64, numpy=array([1, 1])>,
 'slope': <tf.Tensor: shape=(2,), dtype=int64, numpy=array([3, 2])>,
 'thal': <tf.Tensor: shape=(2,), dtype=string, numpy=array([b'fixed', b'normal'], dtype=object)>,
 'thalach': <tf.Tensor: shape=(2,), dtype=int64, numpy=array([150, 108])>,
 'trestbps': <tf.Tensor: shape=(2,), dtype=int64, numpy=array([145, 160])>}

tf.Tensor([0 1], shape=(2,), dtype=int64)
history = model.fit(ds, epochs=5)
Epoch 1/5
152/152 [==============================] - 1s 5ms/step - loss: 0.3150 - accuracy: 0.8284
Epoch 2/5
152/152 [==============================] - 1s 5ms/step - loss: 0.2989 - accuracy: 0.8449
Epoch 3/5
152/152 [==============================] - 1s 5ms/step - loss: 0.2870 - accuracy: 0.8449
Epoch 4/5
152/152 [==============================] - 1s 5ms/step - loss: 0.2782 - accuracy: 0.8482
Epoch 5/5
152/152 [==============================] - 1s 5ms/step - loss: 0.2712 - accuracy: 0.8482