BP神经网络做kaggle房价预测-Top20%

BP神经网络做房价预测-Top20%

  • 一.数据预处理
    • 1.数据清洗(Data Cleaning)
    • 2.特征工程(Feature Engineering)
    • 3.PCA降维
  • 二.网络搭建
  • 三.结果展示
  • 四.总结

一直在学习图像分类任务,预测方面较为薄弱。本次参考网上的数据预处理代码,用BP神经网络整合实现预测,特此记录。

比赛页面:https://www.kaggle.com/c/house-prices-advanced-regression-techniques
数据预处理:https://www.cnblogs.com/massquantity/p/8640991.html
完整代码整合:https://github.com/wulewule/neural/blob/master/house.py

一.数据预处理

1.数据清洗(Data Cleaning)

清洗掉NaN值,用其他的值补全,补全方式如下:
用0填补:特征为数字,0有实际意义时。如地下室面积,0代表没有地下室。
用None填补:特征为抽象,None有实际意义时。如游泳池质量,None代表没有游泳池。
用众数填补:特征为分类,如住宅类型(学区房)等。
剩余特征视具体情况而定,如根据其他特征进行分组后,用中位数填补。

# 用None填补,特征多为抽象
N_list = ["PoolQC" , "MiscFeature", "Alley", "Fence", "FireplaceQu", "GarageQual", "GarageCond", "GarageFinish", 
          "GarageYrBlt", "GarageType","BsmtExposure", "BsmtCond", "BsmtQual", "BsmtFinType2", "BsmtFinType1", "MasVnrType"]
for n in N_list:
    data[n].fillna("None", inplace=True)
    
# 用0填补,特征多为数字
Z_list=["MasVnrArea", "BsmtUnfSF", "TotalBsmtSF", "GarageCars", "BsmtFinSF2", "BsmtFinSF1", "GarageArea"]
for z in Z_list:
    data[z].fillna(0, inplace=True)

# 其它特征用众数填补,[0]为取多个众数的第一个
M_list = ["MSZoning", "BsmtHalfBath", "BsmtFullBath", "Utilities", "Functional", "Electrical", "KitchenQual", "SaleType","Exterior1st", "Exterior2nd"]
for m in M_list:
    data[m].fillna(data[m].mode()[0], inplace=True)

# 按照数字大小,十个为一组将特征划分,目的是防止下面取中位数后仍为NaN
data['LotAreaCut'] = pd.qcut(data['LotArea'], 10)
    
# 按照LotAreaCut和Neighborhood分组后的中位数进行填补NaN
data['LotFrontage'] = data.groupby(['LotAreaCut', 'Neighborhood'])['LotFrontage'].transform(lambda x: x.fillna(x.median()))
data['LotFrontage'] = data.groupby(['LotAreaCut'])['LotFrontage'].transform(lambda x:x.fillna(x.median()))

2.特征工程(Feature Engineering)

从原始数据中提取特征以供使用:
将一部分离散型的数字特征转为字符串,筛选条件是该特征数值无具体数量含义,或与房价没有很强烈的正相关关系。
手动分类不适合用LabelEncoder处理的特征,比如特征的每个值对应的价格平均数相差很大,则适合手动分类。
LabelEncoder处理特征,比如年份,越老的房子相对越便宜,价格曲线波动较小。
特征组合,先用Lasso进行特征筛选,选出较重要的特征,再进行组合测试
(②③④可以根据最终效果进行更改)
数据平滑处理,增添虚拟变量。平滑处理指的是使特征的峰度更符合高斯分布,虚拟变量指的是通过get_dummies使所有特征转为数值变量,也就是one-hot特征。

# 将一部分离散的数字特征转为字符串
NumStr = ["MSSubClass", "BsmtFullBath", "BsmtHalfBath", "HalfBath", "BedroomAbvGr", "KitchenAbvGr", "MoSold", 
          "YrSold", "YearBuilt", "YearRemodAdd", "LowQualFinSF", "GarageYrBlt"]
for col in NumStr:
    data[col] = data[col].astype(str)
    
# 手动分类,用于处理不能直接用LabelEncoder的特征
data.groupby(['MSSubClass'])[['SalePrice']].agg(['mean','median','count'])
data = map_values(data)
print('after map_value:', data.shape)
    
# 删掉无作用的两个特征
data.drop("LotAreaCut", axis=1, inplace=True)
data.drop(['SalePrice'], axis=1, inplace=True)
    
# 封装处理步骤,并处理数据 (1.标准化标签 2.数据平滑处理,增填虚拟变量)
pipe = Pipeline([('labenc', labelenc()), ('skew_dummies', skew_dummies(skew=1))])
copy = data.copy()
data_pipe = pipe.fit_transform(copy)
print('after pipe1:', data_pipe.shape)

3.PCA降维

在以前的博客已有介绍,这里的主要目的是,降低新增加的特征和以前特征的相关性,而不是降维加快运算。(基于Tensorflow实现BP神经网络+PCA降维)

二.网络搭建

网络整体结构和跑MNIST时大致相同,改动如下:
1. 去掉了dropout,选择L2正则化。
2. loss函数选择了均方根误差来进行训练。
训练代码如下:

# 网络搭建
input_size = 410
num_classes = 1
weight_decay = 0.05 # 权重衰减系数
hidden_units_size = 2*input_size + 1
X = tf.placeholder(tf.float32, shape = [None, input_size], name='x')
Y = tf.placeholder(tf.float32, shape = [None, num_classes], name='y')

W1 = tf.get_variable("W1", shape=[input_size, hidden_units_size], initializer=tf.contrib.layers.xavier_initializer())
B1 = tf.Variable(tf.constant (0.1), [hidden_units_size])
W2 = tf.get_variable("W2", shape=[hidden_units_size, num_classes], initializer=tf.contrib.layers.xavier_initializer())
B2 = tf.Variable(tf.constant (0.1), [num_classes])

hidden_opt = tf.matmul(X, W1) + B1  # 输入层到隐藏层正向传播
hidden_opt = tf.nn.relu(hidden_opt)  # 激活函数,用于计算节点输出值
final_opt = tf.matmul(hidden_opt, W2) + B2  # 隐藏层到输出层正向传播
tf.add_to_collection('pred_network', final_opt)

loss = tf.reduce_mean(tf.losses.mean_squared_error(Y, final_opt))
l2_loss = weight_decay * tf.add_n([tf.nn.l2_loss(tf.cast(v, tf.float32)) for v in tf.trainable_variables()])
tf.summary.scalar('l2_loss', l2_loss)
loss = loss + l2_loss

train_step = tf.train.AdamOptimizer(learning_rate=0.01).minimize(loss)

sess = tf.Session()
sess.run(tf.global_variables_initializer())
NEPOCH = 10000
for i in range(NEPOCH):
    train_loss = sess.run([final_opt, train_step], feed_dict={X: train_x_data, Y: train_y_data, keep_prob:0.1})
    test_loss = sess.run(final_opt, feed_dict={X: test_x_data, keep_prob:1})
    if i%100 == 0:
            print('step:', i, 'train_mean_squared_error:', mean_squared_error(train_loss[0], train_y_data), 'test_mean_squared_error:', mean_squared_error(test_loss, test_y_data))
    if mean_squared_error(test_loss, test_y_data) < 0.01:
            break

三.结果展示

数据shape变化:
在这里插入图片描述
训练结果:
BP神经网络做kaggle房价预测-Top20%_第1张图片
kaggle提交评分:
在这里插入图片描述

四.总结

大部分学习遇到的困难不是网络搭建,而是数据处理。好的数据代表着好的结果,这需要大量的经验和耐心,这次是预测任务的一个开端,接下来会尝试自己处理数据集来训练,来日方长,加油。

参考博客如下:

https://www.cnblogs.com/massquantity/p/8640991.html
https://blog.csdn.net/ningyanggege/article/details/82690766

你可能感兴趣的:(神经网络,机器学习,tensorflow)