YOLO813

机器学习(5)- 综合实战训练

    以下数据源来自于互联网公开的北京二手房成交数据,仅作个人学习使用。

数据预处理

    合并数据如下

data.head()

data = data.dropna(how='all')
data.info()

    考虑分析时间和成交单价的关联性,并对某个小区的单价进行预测

    先清洗成交单价字段

data.cjdanjia = np.round((data.cjdanjia.str.replace("元/平","").\
                          astype('float'))/10000,2)
data.cjdanjia

    将其整理成时间序列

data.cjshijian.str.replace("签约时间:","")

pd.to_datetime(data.cjshijian.str.replace("签约时间:",""))
data.cjshijian = pd.to_datetime(data.cjshijian.str.replace("签约时间:",""))

data.set_index("cjshijian",inplace=True)

data.index

    取得某个小区的数据,并将其排序

data[data.cjxiaoqu.str.contains('远洋山水')]
data = data[data.cjxiaoqu.str.contains('远洋山水')]

data.sort_values(by='cjshijian')
data = data.sort_values(by='cjshijian')

    取出2012年以后的数据(对于时间序列的取值)

data= data["2012":]
data


    在建模之前,我们可以先绘图来看下情况,注意,由于cjshijian已经是时间索引了,所以如果使用data.cjshijian是取不到时间值的,我们必须使用index.values来获取其时间数组

plt.figure(figsize=(12,8))
plt.scatter(data.index.values, data.cjdanjia)

    存在单价为0的数据,我们也一并去掉

data = data[data.cjdanjia>1]
plt.figure(figsize=(12,8))
plt.scatter(data.index.values, data.cjdanjia)

 

建模测试

    先假设我们不考虑分离训练数据和测试数据,将全部数据用于建模。

    我们可以考虑将日期转换为天数,更方便运算。例如,以2012年1月1日为起点开始计算

data.index - pd.to_datetime("2012-01-01")

(data.index - pd.to_datetime("2012-01-01")).days

    此时如果直接赋值,如下面这种方法,可能会有警告

data['time'] = (data.index.copy() - pd.to_datetime("2012-01-01")).days

    建议使用assign方法

data = data.assign(time = (data.index - pd.to_datetime("2012-01-01")).days)

    取出需要的值

data = data[['cjdanjia','time']]
data

plt.figure(figsize=(12,8))
plt.scatter(data.time, data.cjdanjia)


    先尝试一元建模

from sklearn.linear_model import LinearRegression
model1 = LinearRegression()
model1.fit(data.time, data.cjdanjia)

    这时会报错,因为data.time的形状不符合要求,我们来看下data.time,它是一个Series,并没有reshape方法,我们可以将其转为数组类型

data.time

data.time.values

model1.fit(data.time.values.reshape(-1,1), data.cjdanjia)
# 也可以直接将data.time转为DataFrame
model1.fit(pd.DataFrame(data.time), data.cjdanjia)

    绘图查看情况

#制作x轴数据来看下曲线情况
x1 = np.linspace(0,1900,num=100)
y1 = model1.predict(x1.reshape(-1,1))
plt.figure(figsize=(12,8))
plt.scatter(data.time, data.cjdanjia)
plt.plot(x1,y1,'r')

    可以看到,效果很差。

 

多项式回归

    形如f(x)=an·x^n+an-1·x^(n-1)+…+a2·x^2+a1·x+a0的函数,叫做多项式函数,它是由常数与自变量x经过有限次乘法与加法运算得到的。显然,当n=1时,其为一次函数y=kx+b,当n=2时,其为二次函数。

    一般地,形如y=ax^2+bx+c的函数叫做二次函数(quadratic function)。其图像在平面直角坐标系中呈一条抛物线。

    形如 y=ax^3+bx^2+cx+d (a≠0,b,c,d为常数)的函数叫做三次函数(cubics function)。三次函数的图像是一条曲线——回归式抛物线(不同于普通抛物线),具有比较特殊的性质。


    由于绘制的散点图形状,所以考虑多项式回归模型。

    根据公式y=ax^2+bx+c,所以这次的X轴需要将x^2和x一同输入进去

#将所有数据按照公式丢入进来
X = pd.DataFrame({"x1":data.time**2,
           'x2':data.time})
Y = data.cjdanjia
X[:5]

model2 = LinearRegression()
model2.fit(X,Y)
#为什么自制x轴坐标?
#可以想象以下,如果使用原始数据的X
#他有两个点,根本无法确定
x2 = np.linspace(0,1900,num=100)
#这里面预测的点就使用上面的x2坐标
y2 = model2.predict(pd.DataFrame({"x1":x2**2,
           'x2':x2}))
plt.figure(figsize=(12,8))
plt.scatter(data.time, data.cjdanjia)
plt.plot(x2,y2,'r')


    二次回归的效果稍微强点,但也不是特别符合,可以考虑使用三次函数来建模。

    我们可以继续使用前面的方法来构造方程式,但是挺麻烦的,sklearn中有一个preprocessing.PolynomialFeatures可以快速帮我们构造多项式,

from sklearn.preprocessing import PolynomialFeatures
#初始化几次函数
q3 = PolynomialFeatures(degree=3)

X3 = q3.fit_transform(pd.DataFrame(data.time))
X3

model3= LinearRegression()
model3.fit(X3, Y)
x3 = np.linspace(0,1900,num=100)
#我们需要把待预测的x3也变成多项式
x_ = q3.fit_transform(pd.DataFrame(x3))
# y2 = model3.predict(pd.DataFrame({"x1":x3**2,
#            'x2':x2}))
y3 = model3.predict(x_)
plt.figure(figsize=(12,8))
plt.scatter(data.time, data.cjdanjia)
plt.plot(x3,y3,'r')


    同理,我们可以快速的使用4次函数建模

q4 = PolynomialFeatures(degree=4)
X4 = q4.fit_transform(pd.DataFrame(data.time))
model4= LinearRegression()
model4.fit(X4, Y)
x4 = np.linspace(0,1900,num=100)
#我们需要把x3也变成多项式
x_ = q4.fit_transform(pd.DataFrame(x4))
y4 = model4.predict(x_)
plt.figure(figsize=(12,8))
plt.scatter(data.time, data.cjdanjia)
plt.plot(x3,y3,'g')
plt.plot(x4,y4,'r')


    到这里,你会发现似乎没有一个好的办法去评估自己的模型,因为所有数据都用于建模训练了,所以,对于线性回归,最好还是分成训练数据和测试数据。

    需要注意的是,因为这些数据具有先后时间关系,就无法使用之前那种乱序划分 train_test_split方法了。

x_train,x_test = data[:"2016-05"].time,data["2016-05":].time
x_train[:5]

y_train,y_test = data[:"2016-05"].cjdanjia,data["2016-05":].cjdanjia
y_train[:5]

q3 = PolynomialFeatures(degree=3)
x3 = q3.fit_transform(pd.DataFrame(x_train))
model3 = LinearRegression()
model3.fit(x3, y_train)
#使用模型预测
x_ = q3.fit_transform(pd.DataFrame(x_test))
y_pre = model3.predict(x_)
y_pre

#导入函数计算差均值
from sklearn.metrics import mean_squared_error
mean_squared_error(y_test,y_pre)

#四项函数
q4 = PolynomialFeatures(degree=4)
x4 = q4.fit_transform(pd.DataFrame(x_train))
model4 = LinearRegression()
model4.fit(x4, y_train)
x_ = q4.fit_transform(pd.DataFrame(x_test))
y_pre = model4.predict(x_)
y_pre

mean_squared_error(y_test,y_pre)


    可以看到,四次函数的拟合度更好。