tensorflow處理結構化資料
一、泰坦尼克資料集
首先從csv讀取資料
import numpy as np import pandas as pd from matplotlib import pyplot as plt import tensorflow as tf from tensorflow.keras import layers,models ''' #================================================================== # 一,構建資料管道 #================================================================== ''' dftrain_raw = pd.read_csv("./data/titanic/train.csv") dftest_raw = pd.read_csv("./data/titanic/test.csv") dfraw = pd.concat([dftrain_raw,dftest_raw],axis=0) def prepare_dfdata(dfraw): dfdata = dfraw.copy() dfdata.columns = [x.lower() for x in dfdata.columns] dfdata = dfdata.rename(columns={'survived':'label'}) dfdata = dfdata.drop(['passengerid','name'],axis = 1) for col,dtype in dict(dfdata.dtypes).items(): # 判斷是否包含缺失值 if dfdata[col].hasnans: # 新增標識是否缺失列 dfdata[col + '_nan'] = pd.isna(dfdata[col]).astype('int32') # 填充,如果是數字,那麼就新增這一列的平均值,否則空著 if dtype not in [np.object,np.str,np.unicode]: dfdata[col].fillna(dfdata[col].mean(),inplace = True) else: dfdata[col].fillna('',inplace = True) return(dfdata) dfdata = prepare_dfdata(dfraw) dftrain = dfdata.iloc[0:len(dftrain_raw),:] dftest = dfdata.iloc[len(dftrain_raw):,:] # 從 dataframe 匯入資料 def df_to_dataset(df, shuffle=True, batch_size=4): dfdata = df.copy() if 'label' not in dfdata.columns: ds = tf.data.Dataset.from_tensor_slices(dfdata.to_dict(orient = 'list')) else: labels = dfdata.pop('label') ds = tf.data.Dataset.from_tensor_slices((dfdata.to_dict(orient = 'list'), labels)) if shuffle: ds = ds.shuffle(buffer_size=len(dfdata)) ds = ds.batch(batch_size) return ds ds_train = df_to_dataset(dftrain) ds_test = df_to_dataset(dftest)
tensorflow只能處理數值型別的資料,如何將原始資料轉換為神經網路的輸入格式:使用特徵列模組 tf.feature_column,在輸入資料和模型之間搭建橋樑
特徵列完成以下等功能:
- 類別特徵轉換為ont-hot編碼特徵
- 連續特徵轉換為分桶特徵
- 特徵組合
二、定義特徵列
2.1 數值特徵使用 tf.feature_column.numeric_column得到數值列。
feature_columns = [] for col in ['age','fare','parch','sibsp'] + [ c for c in dfdata.columns if c.endswith('_nan')]: feature_columns.append(tf.feature_column.numeric_column(col))
2.2 比如年齡資料,按區間進行劃分,使用tf.feature_column.bucketized_column 得到分桶列。
不直接將一個數值直接傳給模型,而是根據數值範圍將其值分為不同的 categories。
此時,10個年齡間隔得到ont-hot列表長度為11,小於18歲的轉換為[1,0,0,0,0,0,0,0,0,0,0]
age = tf.feature_column.numeric_column('age') age_buckets = tf.feature_column.bucketized_column(age, boundaries=[18, 25, 30, 35, 40, 45, 50, 55, 60, 65]) feature_columns.append(age_buckets)
2.3 類別特徵,使用tf.feature_column.categorical_column_with_vocabulary_list 轉換為 one-hot編碼
sex = tf.feature_column.indicator_column(
tf.feature_column.categorical_column_with_vocabulary_list(
key='sex',vocabulary_list=["male", "female"]))
feature_columns.append(sex)
2.4 當類別很多或者我們不知道有多少類的時候,我們不能一個一個的列出來,這時候就可以使用hash_bucket,第二個引數是我們想把這些資料分成多少類,
這個類別數和真實的類別數不一定是一樣的,我們自己設定劃分為多少類即可。
使用tf.feature_column.categorical_column_with_has_bucket 對 ticket列進行轉換。
ticket = tf.feature_column.indicator_column(
tf.feature_column.categorical_column_with_hash_bucket('ticket',3))
feature_columns.append(ticket)
2.5 當類別很多的時候,藉由lookup table的方式找尋對應的feature vector來表示。tf.feature_column.embedding_column
嵌入列可以看成keras.layers.Embedding層
cabin = tf.feature_column.embedding_column(
tf.feature_column.categorical_column_with_hash_bucket('cabin',32),2)
feature_columns.append(cabin)
2.6 多個特徵組合為一個特徵,組合列。tf.feature_column.crossed_column
pclass_cate = tf.feature_column.categorical_column_with_vocabulary_list(
key='pclass',vocabulary_list=[1,2,3])
crossed_feature = tf.feature_column.indicator_column(
tf.feature_column.crossed_column([age_buckets, pclass_cate],hash_bucket_size=15))
feature_columns.append(crossed_feature)
ps:此時 feature_columns 僅僅儲存了一些特徵列,需要在定義模型的時候把這些特徵列作為輸入層放到 tf.keras.layers.DenseFeatures
三、定義&訓練模型
通過 layers.DenseFeatures(feature_columns) 完成了原始特徵到模型輸入特徵的轉換。
fit 階段 之間輸入 tf.data.Dataset 資料。
tf.keras.backend.clear_session()
model = tf.keras.Sequential([
layers.DenseFeatures(feature_columns), #將特徵列放入到tf.keras.layers.DenseFeatures中!!!
layers.Dense(64, activation='relu'),
layers.Dense(64, activation='relu'),
layers.Dense(1, activation='sigmoid')
])
model.compile(optimizer='adam',
loss='binary_crossentropy',
metrics=['accuracy'])
history = model.fit(ds_train,
validation_data=ds_test,
epochs=10)