最近,看了一篇用机器学习来预测房屋价格的文章:
httphttps://github.com/TomorrowIsBetter/crawler/blob/master/price_prediction/README.md://
于是我就想着能不能把我手头的某品牌设备的价格也进行评估预测,算法用的是SVR回归分析。
整个过程的思路其实很简单。
1.数据获取。在我参考的博客中,原作者是从58同城上爬下来的一系列数据,他的文件是csv格式,而我手头的数据是ms sql中的,首先就是先把影响价格的因素提取出来,这里我用到的是三个因素。第一个是工作小时数,第二个是设备的寿龄(按天数计算的),第三个就是不同的型号,因为不同型号的设备对最终的售价还是影响很大的。然后将这些数据保存到csv文件中。
2.数据清洗。这里需要先对原始数据进行描述性统计分析。对第一个变量工作小时数来说,有些数据的工作小时数是明显偏低的,有些小时数极度偏高,这都可以从箱线图中看出来,从而把离群值剔除掉。并且要将清洗后的数据进行归一化处理。
3.建立模型,这里我用到的是svr算法,
# edit by mengqi 2018-07-14
# input source filename :longgong.csv
# output filename:model.m
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn import preprocessing
from sklearn.kernel_ridge import KernelRidge
from sklearn.model_selection import GridSearchCV
from sklearn.svm import SVR
from sklearn.svm import SVC
from sklearn.linear_model import LogisticRegression
from sklearn.externals import joblib
from sklearn.utils import shuffle
# 首先创建一个函数用来将数据进行归一化处理
def normalization(data,tag=""): # 需要输入的形参为np.ndarray格式的数据
mean = data.mean() # 求均值
maximum = data.max() # 求最大值
minimum = data.min() # 求最小值
print(tag,'数据的均值,最大值,最小值分别为:',mean,maximum,minimum)
return (data - mean) / (maximum - minimum)
# 创建一个函数用来对某一列进行统计分析.
def summary_data(data1,tag="",order=1):
print('next print summary of {}:'.format(tag))
plt.figure(order)
plt.boxplot(data1)
# 第一步导入数据:
df = pd.read_csv("longgong.csv",encoding='gbk') # 1.载入数据
pd.set_option('display.width',None) # 这行代码可以解决输出的时候中间省略号的问题
# 第二步数据预处理
df = shuffle(df)
df = shuffle(df) # 打乱数据
work_hours = df['work_hours'].values # 第一个自变量 工作小时数
# print('type of work_hours is: {}'.format(type(work_hours)))
summary_data(work_hours,tag='work_hours',order=1)
work_hours = normalization(work_hours,tag='work_hours') # 对第一个变量做归一化处理
age_day = df['age_day'].values # 第二个变量 设备的寿龄,用天数来表示
summary_data(age_day,tag='age_day',order=2)
age_day = normalization(age_day,tag='age_day') # 对第二个变量做归一化处理
model_num = df['model_num'].values / 56 # 第三个变量 设备的不同型号作为变量,
sale_price = df['sale_price'].values # 我们要预测的值,售价
print(work_hours.shape,age_day.shape,model_num.shape,sale_price.shape)
data = np.array([work_hours,age_day,model_num])
data = data.T # 数组转置
# 划分训练集和测试集
train_fraction = .8
train_number = int(df.shape[0] * train_fraction)
X_train = data[:train_number] # x训练集
X_test = data[train_number:] # x测试集
y_train = sale_price[:train_number] # y训练集
y_test = sale_price[train_number:] # y测试集
print('输出所有型号的售价最大值',np.max(sale_price)) # 输出最大值
# model
clf = GridSearchCV(SVR(kernel='rbf', gamma=0.1),{"C": [1e0, 1e1, 1e2, 1e3], "gamma": np.logspace(-2, 2, 5)},cv=5)
# clf = GridSearchCV(LogisticRegression(),{"C":[1e0,1e1,1e2,1e3],"random_state":list(range(10))},cv=5)
# clf = GridSearchCV(KernelRidge(kernel='rbf', gamma=0.1), {"alpha": [1e0, 1e1, 1e2, 1e3], "gamma": np.logspace(-2, 2, 5)},cv=5)
clf.fit(X_train,y_train)
result = clf.score(X_train,y_train)
print('结果的评分函数',result)
test = clf.score(X_test,y_test)
print('测试集的评分函数',test)
c = clf.best_params_ # 最佳参数
y = clf.predict(X_test) # 对x的测试集进行预测,y保存预测结果
x = list(range(len(y))) #
plt.figure(3)
plt.subplot(2,1,1) # 画第一张散点图,表示实际数据和测试数据进行比较
plt.scatter(x=x,y=y,color='r')
plt.scatter(x=x,y=y_test,color='g')
print('估价误差的平均值',np.average((y-y_test)/y_test))
print('最佳参数c gamma','结果集','测试集\n')
print(clf.best_params_,result,test)
#
deviation = y - y_test
deviation = deviation.flatten()
deviation = abs(deviation)
print('误差的median:',np.median(deviation))
print('误差的最大值',np.max(deviation))
plt.subplot(2,1,2)
plt.hist(deviation,10)
joblib.dump(clf,"model.m")
plt.show()
# 使用方法:
# 在cmd中输入:curl -d "work_hours=0&age_day=100&model_num=0" http://127.0.0.1:3000/predict
# 需要首先安装 curl (教程:https://jingyan.baidu.com/article/a681b0dec4c67a3b1943467c.html)
from flask import Flask
from flask import request
from sklearn.externals import joblib
import numpy as np
app = Flask(__name__)
clf = joblib.load("model.m")
# need to revise if model was updated
mean_work_hours = 5673.1785536159605
maximum_work_hours = 72000
minimum_work_hours = 80
mean_age_day = 2652.024487756
maximum_age_day = 5944
minimum_age_day = 100
@app.route("/")
def hello():
return "Hello ,I'm Mengqi!"
@app.route("/predict", methods=["POST"])
def predict():
work_hours = request.values.get("work_hours", None)
age_day = request.values.get("age_day", None)
model_num = request.values.get("model_num", None)
if None in [work_hours, age_day, model_num]:
return "{price:0}"
else:
work_hours = (int(work_hours) - mean_work_hours) / (maximum_work_hours - minimum_work_hours)
age_day = (int(age_day) - mean_age_day) / (maximum_age_day - minimum_age_day)
model_num = int(model_num) / 56
x = np.array([work_hours, age_day, model_num]).reshape(1, -1)
r = clf.predict(x)[0]
return "{price:" + str(r) + "}"
if __name__ == "__main__":
app.run(host='127.0.0.1', port=3000, debug=True)
# curl -d "work_hours=8000&age_day=3391&model_num=1" http://127.0.0.1:3000/predict