定义:
线性回归:用一条直线较为准备的描述数据 之间的关系(注:通过属性的线性组合来进行预测的线性模型,找到一条直线或者一个 平面,使得预测值与真实值之间的误差最小,常见于房价的预测)
特点:
计算熵不复杂,但是对非线性的拟合并不好注:(建模速度快,不需要很复杂的计算,在数据量大的情况下依然运行速度很快。可以根据系数给出每个变量的理解和解释。对异常值很敏感。)
问题:
假定现有一个房价数据集,怎末根据已有的数据集推测未来的房价走向
首先这是一个回归问题,而回归问题分为两个过程:学习和预测
采用github现有的数据集,采用之前看过的一个博客的求解方式进行求解
https://github.com/rieuse/Machine_Learning/blob/master/House_Regression/house_price.csv
假定变量如下:
m代表训练集中样本的数量
x代表输入变量
y代表输出变量
(x,y)代表训练集中的样本
代表第i个样本,如上述房价中的一个数据,输入x(1)表示:(rooms:2,halls:1,size:50),输出y(0)表示:price:170
代表第i个样本的第j个分量,举房价数据为参考,表示第一个数据样本中的halls字段,即=1
房价预测问题,实际上就是通过大量的训练数据来训练模型,最终得到预测函数Y=f(X)。然后我们将要预测的房子的rooms、halls、size作为输入变量,然后通过学习得到的预测函数f(X)得到输出变量为结果。这里我们假设放假的预测函数为:分别代表rooms、halls和size三个变量,所以这里的问题就变成了求解四个参数,找到符合的预测函数。
此时我们已经假定了预测函数为,那么我们该如何判定函数解出的参数解是正确的呢?
这里我们就需要引入代价函数:
1>代价函数:
定义在整个训练集上的,是所有样本误差的平均,也就是损失函数的平均。
代价函数越小,并表示这份数据拟合的越好
注:损失函数:是定义在单个样本上的,算的是一个样本的误差。
通过预测函数得到的预测值f(x)和实际的值y是可能存在一定误差的,而我们要做的是就是缩小这些误差。下面我们构建一个代价函数,这个函数是所有建模误差的平方和,即:
其中。所以,我们的目标就是找出使得代价函数最小的一系列参数变量,代价函数返回的值越小,说明预测函数越拟合数据,当然也可能出现过拟合的情况。,为何得到这个代价函数最小的参数变量,我们就需要再次引入梯度下降算法。
2>梯度下降:
可以将代价函数最小化的算法,梯度下降算法。相应地梯度上升算法是用来求函数局部最大值的算法
上式的代价函数展开,即:
求导后得到:
这里,对求导后,分别为:
下面,我们对梯度下降算法做个整理:
在上式中α称为学习率,也叫步长,它决定了在梯度下降的迭代过程中,每一步沿梯度负方向前进的长度。以上图的例子,学习率就是这一步所在位置沿着最陡峭的最易下山的位置走的那一步的长度。学习率如果取值太小,会导致收敛变慢,迭代次数变多;取值太大,则会导致波动较大,导致无法收敛。同时,该算法要对所有的θ参数变量进行求导过程。
用更简洁的矩阵方式来描述梯度下降算法:
首先约定如下几个矩阵形式:
令:
综合起来:
所以,采用矩阵形式表示梯度下降后,θ更新步骤如下,通过这个公式,我们就可以通过pandas和numpy更简洁地实现代码。
备注:这里θ是nx1矩阵,x是mxn矩阵,y是mx1矩阵
3>代码实现:
1:预测函数:
解析:
def model(theta(参数矩阵), X(输入变量矩阵)):
return X.dot(theta)(输出变量)
备注:上述公式x是nx1矩阵,θ是nx1矩阵,即代表一个数据实例的计算结果
上式是对一个数据实例的计算结果,如果要对所有m个训练集实例进行矩阵运算,可以采用下述公式:
备注:上述公式x是mxn矩阵,θ是nx1矩阵,即对所有训练集的数据实例的计算结果
(2)代价函数
def cost(m, theta, X, y):
"""
代价函数
:param m: 训练集个数
:param theta: 参数矩阵(mx1)
:param X: 输入变量矩阵(mx1)
:param y: 输出变量矩阵(mx1)
:return:
"""
ele = model(theta, X) - y
item = ele ** 2
item_sum = np.sum(item)
return item_sum / (2 * m)
(3)梯度下降和θ参数更新
在前几节中,我们推到了上述公式,如下:
def derivative(m, theta, X, y, n):
"""
对各个theta参数求导
:param m: 训练集个数
:param theta: 参数矩阵(nx1)
:param X: 输入变量矩阵(mxn)
:param y: 输出变量矩阵(mx1)
:param n: ?变量个数?0, ?1, ?2, ..., ?n-1
:return: nx1 矩阵
"""
grad_theta = []
for j in range(n):
# 对所有?j变量求导
grad = (model(theta, X) - y).T.dot(X[:, j])
grad_sum = np.sum(grad)
grad_theta.append(grad_sum / m)
return np.array(grad_theta).reshape(n, 1)
当然如果采用向量形式,代码会更简洁,在上面的章节中,我们推导出了如下的向量表达形式:
def derivative(m, theta, X, y, n):
"""
对各个theta参数求导(向量形式)
:param m: 训练集个数
:param theta: 参数矩阵(nx1)
:param X: 输入变量矩阵(mxn)
:param y: 输出变量矩阵(mx1)
:param n: ?变量个数?0, ?1, ?2, ..., ?n-1
:return: nx1 矩阵
"""
grad_sum = X.T.dot(model(theta, X) - y)
return grad_sum / m
对比下两个代码,明显向量形式的更简洁、更容易理解。
def gradient(grade_theta, theta, alpha):
"""
?更新
:param grade_theta:求导后的?矩阵(nx1)
:param theta: 更新后的?矩阵(nx1)
:param alpha: 学习率
:return: 返回更新后的?矩阵(nx1)
"""
return theta - alpha * grade_theta
(4)停止迭代策略(代价函数小于阈值或设定迭代次数)
def stop_strage(cost, cost_update, threshold):
"""
停止迭代条件
:param cost:
:param cost_update:
:param threshold:
:return:
"""
return (cost >= cost_update) and (cost - cost_update < threshold)
(5)线性回归
def linear_regression(X, y):
"""
线性回归模型
:param X: 输入变量矩阵(mxn)
:param y: 输出变量矩阵(mx1)
:param threshold:
:return:
"""
start = time.clock()
m = X.shape[0] # 样本个数
n = X.shape[1]
theta = np.zeros(n).reshape(n, 1) # 设置权重参数的初始值
y = y.reshape(m, 1)
print "theta:", theta.shape, ", X: ", X.shape, "y:", y.shape
cost_record = [] # 记录代价函数的值
alpha = 0.0001 # 学习率
threshold = 0.01
cost_val = cost(m, theta, X, y)
cost_record.append(cost_val)
iters = 0
while True:
grad = derivative(m, theta, X, y, n)
# 权重参数更新
theta = gradient(grad, theta, alpha)
cost_update = cost(m, theta, X, y)
if stop_strage(cost_val, cost_update, threshold):
break
cost_val = cost_update
cost_record.append(cost_val)
iters += 1
end = time.clock()
print("cost time: %f s" % (end - start))
return cost_record, theta, iters
(6)使用训练线性回归模型预测房价
df = pd.read_csv('house_price.csv')
print df['rooms'].unique()
print df['halls'].unique()
# 去除脏数据
keep_index = (df['rooms'] != '多') & (df['halls'] != '多')
df = df[keep_index]
# 转换数据类型
df['rooms'] = df['rooms'].astype('int')
df['halls'] = df['halls'].astype('int')
# 截取rooms、halls、size和price
X = df[['rooms', 'halls', 'size']]
y = df['price']
cost_record, theta, iters = linear_regression(X.values, y.values)
print iters
print theta
print cost_record
# 预测数据
# rooms,halls,size,price
# 1,1,49,326
# 2,1,56.45,315
# 2,1,58.3,466
# 3,1,92.33,1061
# 2,1,76.88,408
print model(theta, np.array([1, 1, 49]))
print model(theta, np.array([2, 1, 56.45]))
print model(theta, np.array([2, 1, 58.3]))
print model(theta, np.array([3, 1, 92.33]))
print model(theta, np.array([2, 1, 76.88]))
再来看下代价函数返回的值的收敛趋势图:
# 第一个数据太大,剔除,方便观察对比
plt.plot(np.arange(len(cost_record)-1), cost_record[1:], 'r')
plt.show()
注:以上内容参考他人博客太多,个人见解还需后续补充修改