深度学习模型实例及数据处理和分类嵌入
与其他机器学习算法一样,在构建深度学习网络时,理解数据非常重要。让我们使用一个简单的数据集来可视化数据,得出结论,以及如何使用不同的处理技术提高深度学习模型的性能。
在 King County House Prices数据集(https://www.kaggle.com/harlfoxem/housesalesprediction)提供有关在King County房屋销售价格21613个数据点。它有大约19个特征列,如下所示。它混合了日期,数字和分类数据。
数据可视化
让我们深入研究数据,看看在构建模型之前我们是否可以对数据有所了解。我们将使用Python统计可视化库Seaborn,它建立在matplotlib之上。以下是每个特征的价格分布。
- 销售年度数据为双峰,数据来自两年:2014年和2015年
- no of bedrooms, no of bathrooms, Sqft living room, Sqft above, Sqft basement,销售价格都是单峰的,我们已经可以看出,对于这些特征值较高的房屋,模型可能具有较高的平均误差。
让我们看一下标签栏的特征相关性,即房屋的售价。
构建深度学习模型
我将使用keras 2.0库来构建一个序列神经网络,以学习用于预测房价的回归模型。
导入数据集,然后将其划分为训练,验证和测试集。Python代码如下:
import os import numpy as np import pandas as pd import matplotlib.pyplot as plt from scipy import stats from scipy.stats import zscore from math import radians, cos, sin, asin, sqrt import pydot import seaborn as sns import keras from keras import metrics from keras import regularizers from keras.models import Sequential, load_model from keras.layers import Dense, Dropout, Flatten, Activation from keras.optimizers import Adam, RMSprop from keras.callbacks import TensorBoard, EarlyStopping, ModelCheckpoint from keras.utils import plot_model label_column = 'price' kc_raw_data = pd.read_csv('../data/kc_house_data.csv') kc_raw_data['sale_yr'] = pd.to_numeric(kc_raw_data.date.str.slice(0,4)) kc_raw_data['sale_month'] = pd.to_numeric(kc_raw_data.date.str.slice(4,6)) kc_raw_data['sale_day'] = pd.to_numeric(kc_raw_data.date.str.slice(6,8)) kc_data = pd.DataFrame(kc_raw_data, columns=[ 'sale_yr','sale_month','sale_day', 'view', 'waterfront', 'lat', 'long', 'bedrooms','bathrooms','sqft_living','sqft_lot','floors', 'condition','grade','sqft_above','sqft_basement','yr_built','yr_renovated', 'zipcode','sqft_living15','sqft_lot15','price']) kc_data = kc_data.sample(frac=1) train = kc_data.sample(frac=0.8) 'Train:' + str(train.shape) validate = kc_data.sample(frac=0.1) 'Validate:' + str(validate.shape) test = kc_data.sample(frac=0.1) 'Test:' + str(test.shape)
该模型有两个隐藏的dense 层和一个最终的linear combination层,产生回归输出。我们将使用均方误差作为损失函数。
t_model = Sequential() t_model.add(Dense(100, activation="relu", input_shape=(xsize,))) t_model.add(Dense(50, activation="relu")) t_model.add(Dense(ysize)) t_model.compile( loss="mean_squared_error", optimizer=Adam(lr=0.001), metrics=[metrics.mae])
epochs = 500 batch = 128 cols = list(train.columns) cols.remove(label_column) history = model.fit( train[cols], train[label_column], batch_size=batch, epochs=epochs, shuffle=True, verbose=1, validation_data=(validate[cols],validate[label_column]), callbacks=keras_callbacks ) score = model.evaluate(test[cols], test[label_column], verbose=0)
使用开箱即用的数据给我们MAE为149167.61。现在让我们看一些数据处理技术以及它们如何帮助提高深度学习模型性能。
白化数据(Whitening the data)
我们的一些特征是0.1的数量级,一些数量级为10,有些数量级为100,有些数量为10000.这种不同数值顺序的差异会导致高阶数值主导其他数值。白化数据有助于归一化不同值的顺序。
白化操作采用特征基础中的数据并将每个维度除以特征值以归一化比例。这种变换的几何解释是,如果输入数据是多变量高斯,那么白化数据将是具有零均值和同一性协方差矩阵的高斯。假设我们的数据应该是高斯分布,我们将计算每一列的z分数。
关于预处理的重要一点是,任何预处理统计数据(例如数据均值)必须仅在训练数据上计算,然后应用于验证/测试数据。
train_mean = train[cols].mean(axis=0) train_std = train[cols].std(axis=0) train[cols] = (train[cols] - train_mean) / train_std validate[cols] = (validate[cols] - train_mean) / train_std test[cols] = (test[cols] - train_mean) / train_std
一旦我们用归一化数据重新运行模型,我们的MAE就会下降到 99622.24。与使用数据相比,这是一个巨大的进步。
将'long'和'lat'转换为距离
虽然可以按原样使用经度和纬度,但我们可以通过将经度和纬度转换为房屋与固定位置的距离以及表示房屋相对于固定位置的方向的布尔值来获得更多洞察力。Python代码如下:
def haversine(lon1, lat1, lon2, lat2): """ Calculate the great circle distance between two points on the earth (specified in decimal degrees) """ # convert decimal degrees to radians lon1, lat1, lon2, lat2 = map(radians, [lon1, lat1, lon2, lat2]) # haversine formula dlon = lon2 - lon1 dlat = lat2 - lat1 a = sin(dlat/2)**2 + cos(lat1) * cos(lat2) * sin(dlon/2)**2 c = 2 * asin(sqrt(a)) r = 6371 # Radius of earth in kilometers. Use 3956 for miles return c * r FIXED_LONG = -122.213896 FIXED_LAT = 47.560053 kc_raw_data['distance'] = kc_raw_data.apply(lambda row: haversine(FIXED_LONG, FIXED_LAT, row['long'], row['lat']), axis=1) kc_raw_data['greater_long'] = (kc_raw_data['long'] >= FIXED_LONG).astype(int) kc_raw_data['less_long'] = (kc_raw_data['long'] < FIXED_LONG).astype(int) kc_raw_data['greater_lat'] = (kc_raw_data['lat'] >= FIXED_LAT).astype(int) kc_raw_data['less_lat'] = (kc_raw_data['lat'] < FIXED_LAT).astype(int)
使用新特征'distance','greater_long','less_long','greater_lat'和'less_lat',我们再次在数据集上训练深度学习模型。由此产生的训练集上的MAE进一步下降到87231.59。
使用分类数据
Zipcode是数据中的特征列。我们一直将其视为正常数值,但不同的邮政编码值不具有顺序关系。此外,他们编码了一些更深层次的关系,例如,一些邮政编码有更昂贵的房子,因为他们更接近学校或交通等。
借助嵌入可以丰富地表达分类数据。
为了在Keras 2.0中使用嵌入,我们必须使用API函数。其中一个输入将是zipcode数据,我们将其转换为嵌入。另一个输入是其他特征的向量。
data_zipcode = train_zipcode_x data_main = train_otherfeatures_x data_y = train_y zipcode_input = Input(shape=(1,), dtype='int32', name='zipcode_input') x = Embedding(output_dim=5, input_dim=200, input_length=1)(zipcode_input) zipcode_out = Flatten()(x) zipcode_output = Dense(1, activation='relu', name='zipcode_model_out')(zipcode_out) main_input = Input(shape=(data_main.shape[1],), name='main_input') lyr = keras.layers.concatenate([main_input, zipcode_out]) lyr = Dense(100, activation="relu")(lyr) lyr = Dense(50, activation="relu")(lyr) main_output = Dense(1, name='main_output')(lyr) t_model = Model( inputs=[main_input, zipcode_input], outputs=[main_output, zipcode_output] ) t_model.compile( loss="mean_squared_error", optimizer=Adam(lr=0.001), metrics=[metrics.mae], loss_weights=[1.0, 0.5] )
如果我们打印出模型并将其可视化,则该模型更容易理解。
训练此模型并在测试数据集上运行它,MAE急剧下降到69471.41。
让我们使用TSNE库可视化zipcode嵌入,Python代码如下所示:
from sklearn.manifold import TSNE import seaborn as sns zipcode_embeddings = model.layers[1].get_weights()[0] labels = train_zipcode_x zipcode_embeddings.shape tsne_model = TSNE(perplexity=200, n_components=2, init='pca', n_iter=2500, random_state=23) new_values = tsne_model.fit_transform(zipcode_embeddings) x1 = [] y1 = [] avg_price1 = [] for index, value in enumerate(train_zipcode_x): zipcode = train_zipcode_x.iloc[index] price = train_y.iloc[index] avg_price1.append(price) x1.append(new_values[zipcode][0]) y1.append(new_values[zipcode][1]) f, ax = plt.subplots(2, 1) cmap = sns.cubehelix_palette(n_colors=10, start=0.3, rot=0.4, gamma=1.0, hue=1.0, light=0.9, dark=0.1, as_cmap=True) axs0 = ax[0].scatter(x1, y1, s=20, c=avg_price1, cmap=cmap) f.colorbar(axs0, ax=ax[0], orientation='vertical') f
我们看到左侧有一组zipcode ,其房屋的销售价格较高。
结论
因此,当我们开始使用149167.61的MAE时,在对数据进行白化并使用分类嵌入处理它之后,我们将MAE降低到69471.41。