在TensorFlow中使用KNN预测房价

最近在看《Python机器学习实践 测试驱动的开发方法》。里面的第一个例子就是使用sklearn去实现房价的预测。我想使用TensorFlow去完成该例题。但TensorFlow(目前版本1.8)中并未整合KNN算法,网上也有很多文章讲到TensorFlow KNN的实例,可大都是互相抄袭MINST的例子,而且实现的很不合理。于是我自己摸索着实现了一个,分享出来供同是入门者的朋友参考。本文所用数据集上传到了百度云,点击下载

问题描述

这个数据集中包含了好几十列数据,是西雅图一个县的房产数据,包含面积,位置,环境,价格等各个属性。本次简化了问题:仅根据 面积SqFtLot,位置(经度lat、维度long),去预测房价AppraisedValue

导入依赖

本次需要用到的包如下

1
2
3
import numpy as np
import tensorflow as tf
import pandas as pd

数据处理

1
2
3
4
5
6
7
8
9
10
11
12
13
# 从csv里读取数据到dataframe里去,告诉pandas第一行是标题,另外只要限定的4列
data = pd.read_csv(DATA_PATH, header=0)[['AppraisedValue','SqFtLot','lat','long']]
# 构建样本数据和测试数据
train_data = data[0:50000]
test_data = data[50000:51000]
# pop的含义是将指定列从数据集中抽出来
train_x, train_y = train_data, train_data.pop("AppraisedValue")
test_x, test_y = test_data, test_data.pop("AppraisedValue")
# 归一化,经过调试发现z-score的效果更好。min-max差一点
# train_x = (train_x - train_x.min()) / (train_x.max() - train_x.min())
# test_x = (test_x - test_x.min()) / (test_x.max() - test_x.min())
train_x = (train_x - train_x.mean()) / (train_x.std())
test_x = (test_x - test_x.mean()) / (test_x.std())

构建运行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 定义占位符,tensorflow run的时候用到
xtr = tf.placeholder("float", [None, 3])
xte = tf.placeholder("float", [3])
# 使用曼哈顿距离,测试欧氏距离效果差一点
# reduce_sum是降维求和的方法,reduction_indices=1 代表按行求和
distance = tf.reduce_sum(tf.abs(tf.add(xtr, tf.negative(xte))), reduction_indices=1)
#distance = tf.sqrt(tf.reduce_sum(tf.pow(tf.add(xtr,tf.negative(xte)),2),reduction_indices=1))
# 取出距离最近的100个点
pred = tf.nn.top_k(tf.negative(distance),50)
accuracy = 0.
# tensorflow需要的初始化变量
init = tf.global_variables_initializer()
with tf.Session() as sess:
sess.run(init)
# 循环,每次训练集全取,测试集取一行
for i in range(len(test_x)):
nn_index = sess.run(pred, feed_dict={xtr: train_x, xte: test_x.iloc[i]})
# 最近的几个点求均值作为预测值
pre_value = np.mean(train_y[nn_index.indices])
print("Test", i, "预测值:", pre_value,"真实值:", test_y.iloc[i])
# 偏差10%以内认为可以接受
if abs(pre_value / test_y.iloc[i]-1)<=0.1:
accuracy += 1. / len(test_x)
print("结束!")
print("准确率:", accuracy)

END

以上代码没有省略,直接拼一块就是完整代码。准确率很低,才24% - -# !我能想到的改进点是将经纬度合成一个特征以及引入更多的属性特征。

参考资料