我们之前介绍了几种机器学习算法,这些机器学习算法都是用来进行分类的。今天换换口味,我们来了解一下如何进行回归,回归是基于已有的数据对新的数据进行预测,比如预测产品销量。
我们来看看最简单的线性回归,基于标准的线性回归,可以扩展出更多的线性回归算法,比如基于核函数的局部加权线性回归,lasso等。希望了解的可以查阅相关的资料。下面来看看最基本的线性回归的原理。
根据线性代数,我们可以定义线性方程组Xw=y,在线性回归问题中,X是我们的样本数据矩阵,y是我们的期望值向量,也就是说,对于线性回归问题,我们的X和y是已知的,我们要解决的问题是,求取最合适的一个向量w,使得线性方程组能够尽可能的满足样本点的线性分布。之后我们就可以利用求得的w,对新的数据点进行预测。
这里我们使用平方误差来评估实际y值和预测值之间的误差:
修改为矩阵形式:
我们要使平方误差为最小,根据微积分的内容,我们可以对上面的式子相对w求导:
令上式等于0,然后求得:
等式右边都是我们的已知数据,所以可以求得w的最佳估计。
可以看到,线性回归的原理比较简单,但是,如果注意上面的式子会发现,我们需要求逆矩阵,但是如果矩阵不可逆怎么办?这里有两个思路,一个是采用岭回归的思路,引入参数lambda:
这样,按照线性代数的理论,对于lambda不为0,逆矩阵是一定存在的。下面看看代码:
def linear_regression(x_arr, y_arr, lam=0.2):
x_mat = np.mat(x_arr).T
y_mat = np.mat(y_arr).T
x_tx = x_mat.T * x_mat
denom = x_tx + np.eye(np.shape(x_mat)[1]) * lam
# if lam == 0.0
if np.linalg.det(denom) == 0.0:
print('This matrix is singular, cannot do inverse')
return
ws = denom.I * (x_mat.T * y_mat)
return ws
再看一下调用的demo:
if __name__ == '__main__':
x_vals = np.linspace(0, 1, 1000)
y_vals = x_vals + np.random.normal(0, 1, 1000)
ws = linear_regression(x_vals, y_vals)
predict = 20 * ws
print(predict.A[0][0])
我们构造了x和y使其尽可能满足x=y,不过在其中加入了标准正态分布的噪声,求出ws之后,我们预测了x=20的y值。下面是我运行一次的结果,预测效果还不错:
19.690649736617942
另一种思路是我们直接使用梯度下降法求取平方误差的最小值,这里我们使用tensorflow实现。首先导入需要的包并准备数据:
import numpy as np
import tensorflow as tf
learning_rate = 0.05
batch_size = 50
x_vals = np.linspace(0, 1, 1000)
y_vals = x_vals + np.random.normal(0, 1, 1000)
x_vals.resize((x_vals.shape[0], 1))
y_vals.resize((y_vals.shape[0], 1))
然后构造模型,x_data和y_target是占位符,在训练模型时传入,w是我们训练模型希望得到的目标变量:
sess = tf.Session()
x_data = tf.placeholder(shape=[None, 1], dtype=tf.float32)
y_target = tf.placeholder(shape=[None, 1], dtype=tf.float32)
w = tf.Variable(tf.random_normal([1, 1]))
model_output = tf.matmul(x_data, w)
定义均方误差,然后使用梯度下降法进行优化,求取最小值
loss = tf.reduce_mean(tf.square(y_target - model_output))
init = tf.global_variables_initializer()
sess.run(init)
my_opt = tf.train.GradientDescentOptimizer(learning_rate)
train_step = my_opt.minimize(loss)
最后,使用随机梯度下降法进行训练,并输出测试结果
for i in range(500):
rand_index = np.random.choice(len(x_vals), size=batch_size)
rand_x = x_vals[rand_index]
rand_y = y_vals[rand_index]
sess.run(train_step, feed_dict={x_data: rand_x, y_target: rand_y})
[k] = sess.run(w)
predict = 20 * k
print(predict[0])
一次运行结果:
19.260855
至此,我们使用两种方式实现了线性回归,第一种方式比较直接,直接实现算法,第二种方法借助于tensorflow通过梯度下降算法求取了最优值。