import numpy as np
import matplotlib.pyplot as plt
#读取数据源: 面积、房价
filename = 'ex1data2.txt'
content = np.loadtxt(filename, delimiter=',', usecols=(0, 2))
#数据归一化
def nomalization(arr):
range = np.max(arr) - np.min(arr)
return (arr - np.min(arr)) / range
#选择第一列数据作为x轴
x = content[:, :1]
#选择第二列数据作为y轴
y = content[:, 1:]
x = nomalization(x)
y = nomalization(y)
plt.scatter(x, y)
<matplotlib.collections.PathCollection at 0x1138637b8>
#线性函数公式
def formula(a, b, x):
return a*x + b
#优化函数
def optimifunc(a, b, x, y, times):
rate = 0.01
n = x.size
yhat = y
for i in range(times):
yhat = formula(a, b, x)
da = np.sum((yhat - y) * x) / n
db = np.sum(yhat - y) /n
a = a - rate * da
b = b - rate * db
plt.scatter(x,y)
plt.plot(x, yhat)
return a, b
#初始化参数
a, b = 0, 0
#学习、训练参数
a, b = optimifunc(a, b, x, y, 1)
a, b = optimifunc(a, b, x, y, 50)
a, b = optimifunc(a, b, x, y, 100)
a, b = optimifunc(a, b, x, y, 500)
a, b = optimifunc(a, b, x, y, 10000)
先看下房子面积与价格的趋势图:
plt.scatter(content[:, :1], content[:, 1:])
<matplotlib.collections.PathCollection at 0x113e3a940>
根据上图可以看出,房子的面积与房价之间的关系是线性的,也就是房子面积越大价格越高。现在要根据已有数据,根据新给的房子面积,预测出最合理的价格。
线性关系,可以用线性函数来表示:y = ax + b
现在x(房子的面积)和y(房子的价格)已经有了,因此,主要是根据历史数据得出a、b的解。例如2014 * a + b = 399900
,可以看到因为有两个参数,所以无法直接得出a和b的解。
这就是机器学习的特殊的地方,一个是历史数据多,而且数据不太规则;另一个就是无法直接套用公式得出解。那怎么办呢?采用逼近法。就是先假设a和b的值,然后套用公式得出y的值和历史的y值进行比较, 根据y值的接近程度来调整a和b,直到a、b带入到整个历史数据中得出y的值和历史的y值最接近,就称为公式的最优解。
假设a、b的初始值为0,带入公式:2014 * 0 + 0 = 0
,结果为0(我们将计算出来的y值称为yhat,用于真实的y值做区分),而真实y的值为399900
,因此0不是a、b的最优解。如何评判是不是最优解呢?
一般通过yhat与y值进行比较。yhat与y进行比较的函数我们叫做损失函数(Loss Function)或代价函数(Cast Function)。
损失函数是单个样本上的误差,如上例中的yhat计算结果为0,而实际y值为399900,两者的误差为y-yhat=399900。y-yhat就是损失函数。而代价函数指的是整个训练集上所有样本的误差。
代价函数的作用就是来评价参数a、b与预期结果的拟合程度。
上面的示例中,我们采用的代价函数是12mm∑i=1(h(xi)−yi)2
yhat-y就是误差值,通过这个意义就可以看出代价函数是用来计算误差的,误差越小说明越接近目标。对误差值平方再求和,一看就知道是方差公式(方差定义参见另一篇文章)。也就是说这里用方差作为代价函数。
只要我们不停变换参数a、b的值带入训练集,然后通过代价函数来评判哪个更优,将a、b所有的可能性遍历完后,就可以得出最优a和b。
通过代价函数可以计算出来不同的参数的优劣,然而我们不可能真的将所有a、b遍历计算。因此需要找一种好的方法,用最快的速度找出a和b,也就是最短路径。
梯度下降就是找出最短路径的一种方法。其原理类似你站在一个山坡上,360度观察四周,朝哪个方向走可以快速下山。转换成数学方式,就是求导。
因为我们的代价函数是二阶函数,二阶导数的意义是凹凸性,通过凹凸性来判断是上坡还是下坡,让我们朝坡下快速行进。需要注意的是,因为函数可能存在多个凹点,因此最终得出的a、b只是局部最优解,而不是全局最优解。
最后一点是rate,就是下山的方向每次迈出的步子有多大,不能太大也不能太小。对代价函数求导后的函数,我们一般称之为优化函数。
对a求导:∂J∂a=1mm∑i=1x(h(xi)−yi)
对b求导:∂J∂b=1mm∑i=1(h(xi)−yi)
更新a: a=a−α∂J∂a
更新b: b=b−α∂J∂b
其中α就是rate。
首先确定一点:过拟合和欠拟合都是不好的,预测的准确度低。
在做机器学习时,会将历史数据分为两部分:一部分是训练集,另一部分是测试集。用训练集得出最优函数,再用测试集去验证这个函数是否符合实际需求。
欠拟合就是训练集上表现差,测试集上预测准确度低。过拟合是在训练集上表现过于良好,但在测试集上表现差。
机器学习涉及到很多方面的知识,跟以往我们解决问题的方式有很大区别,因此要先从思维上做些转换,再根据自身的目的,对涉及面做些取舍,毕竟我们是为了解决问题,而不是要成为这方面的专家。