前言:
线性回归是机器学习中最基础的一个算法。虽然线性回归是最简单的机器学习算法之一,但是其包含了几乎所有的机器学习算法中需要的步骤:数据预处理,假设函数,代价函数,优化方法,模型测试。也可谓是麻雀虽小,五脏俱全。
算法的由来,
都求过一元一次方程,y=ax+b,求这个方程只需要
两个点即可。问题往往不会那么简单!如果给了
三个点怎么办?
简单的情况:当然三个点都在一条直线上,那就简单了,直接用其中两个点求出来[a,b]即可。
复杂点的情况:那如果这三个点不在一条直线上呐?
更复杂的情况:有很多个点,也不在一条直线上呐?
还有更复杂的情况:有很多个点,不知道是在一条直线附近,还是在一个圆附近,还是在某个未知形状的曲线附近?
在对数据处理前,我们要花很多时间去理解数据,使用什么假设函数才能更好的拟合数据。
当然今天接触的是线性规划,拟合的是一条直线。
算法要涉及的知识:
代价函数,梯度下降,归一化,正则化,L1,L2
算法过程:
线性回归可以分为单变量和多变量,先从简单的单变量开始:
举个例子:
这个例子是吴恩达机器学习课程中给出的,也比较简单,因为只有单个变量x,所有我们可以假设一条这样的直线:
去拟合图中给出的数据。
下一个任务:如何找到一条最合适的直线来拟合这些数据呐?换句话说就是如何确定参数
和
来更好的拟合这些数据?
所以要找到一个评判标准来说明到底哪条直线能够更好的拟合数据,这个评判标准就是代价函数。
代价函数(cost function)就是为此而生。在回归问题中,我们一般采用误差平方代价函数。当然在其他问题中,还有其他很多种代价函数。
下面问题就简单了,找到能够使代价函数最小的
和
。
可以看出在三维空间中存在一个使得
最小的点。
在没有学习机器学习之前,我相信都能解决这个问题,不就是二次二元方程求最小值吗?我们只要干什么?找到即可啊。
很简单呀。(高数中很简单的问题)
这里只是一个小插曲,这个方法先按住不表,我们看看机器学习通常来怎么解决这个问题。
梯度下降:梯度下降是求函数最小值的一种算法,也是现在最流行的一种求最小值的一种方法了。
其思想是:我们随机选择一组参数组合,计算代价函数,然后我们寻找下一个能让代价函数下降最多的参数组合。一直这样做,直到找到一个局部最小值。
即使只有两个参数我们也不可能尝试所有的参数组合,所以,我们并不能确定得到局部最小值是否是全局最小值。
用算法来表述上面那一大堆话就是:
其中learning rate决定了我们沿着能让代价函数下降程度最大的方向迈出的步子有多大。
方法
:
(1)先确定向下一步的步伐大小,我们称为Learning rate;
(2)任意给定一个初始值:
;
(3)确定一个向下的方向,并向下走预先规定的步伐,并更新
;
(4)当下降的高度小于某个定义的值,则停止下降;
算法缺点:
1,上文说了,算法找到的只是局部最小值,而且初始点不同,局部最小值还会改变。
2,算法越接近局部最小值的时候,速度越慢。从中会引出很多故事,以后有机会还要慢慢讲。
调参技巧:
现在我们有参数了,learning rate,我们不能让算法一直迭代下去,所以还要有迭代次数num_iters
1,learning rate,我们起初可以给个很小的值。我当时就突然冒个想法,能不能把它弄成个越来越小的变化的值,这样不就能更好的接近局部最小值吗?
其实是我想多了,learning rate 后面乘上的梯度,本来就是在逐渐变下的啊,而且还是有方向的呐!
2,num_iters,这个值可以说越大越好,最理想的情况就是在这个迭代范围内,梯度下降到了最小值,不动了,那我们找到了最小值咯。
另外不知道吴恩达老师为什么单拿出来一个初始点就在局部最小值的情况给大家解释一下,如果初始点在局部最小上,我们迭代一次就够了!对吧。我们给一个很大的迭代次数的理由就是,当来到局部最小之后,参数就不变化了呀。
当然梯度下降涉及的问题还有很多,在局部最小值周围震荡啊,等等有兴趣可以查阅更详细的资料。
单变量到这就结束了。
多变量线性回归
我们都知道,参数多了,必定会带来更多的问题。
归一化:
面对多维特征问题时,要保证这些特征都具有更相近的尺度,这将帮助梯度下降算法更快的收敛。
最直观的就是看上面两张图的对比。
归一化最简单的方法就是
当然还有:
这些都比较简单的方法,目的都是一样。
数据预处理完成后,下面基本和单变量相似了。
多变量线性回归的模型:
代价函数(cost function):
梯度下降算法:
当然光说不练肯定是假把式,以下是python代码实现:
#coding:utf-8
import numpy as np
from matplotlib import pyplot as plt
from matplotlib.font_manager import FontProperties
font = FontProperties(fname=r"c:\windows\fonts\simsun.ttc", size=14)
def linearRegression():
#初始化参数
#学习率
lr=0.01
#迭代次数
num_iters=400
#第一步:读取数据并返回想要的数据格式
data=loadData("data.csv",",",np.float64)
theta_num=data.shape[1]
#第二步处理数据
X,Y,mean,std= handleData(data)
m=len(Y)
theta=np.zeros((theta_num,1))#theta初始化为0矩阵
X = np.hstack((np.ones((m,1)),X))
#第三步梯度下降算法
theta,cost_history=gradientDecent(X,Y,theta,lr,num_iters)
print theta
plot(cost_history, num_iters)
pre=predict(mean,std,theta)
print pre
def loadData(fileName,split,dataType):
return np.loadtxt(fileName,delimiter=split,dtype=dataType)
def handleData(data):
"""数据统一处理
"""
X=data[:,0:-1]
Y=data[:,-1]
X_norm,X_mean,X_std=normalFeature(X)
Y=Y.reshape(-1,1)
return X_norm,Y,X_mean,X_std
def normalFeature(X):
"""数据归一化,公式是x=(x-mean)/std
可以获得数据的均值和标准差
"""
X_norm=np.array(X)
X_mean=np.mean(X,0)
X_std=np.std(X,0)
for i in range(X.shape[1]):
X_norm[:,i]=(X[:,i]-X_mean[i])/X_std[i]
return X_norm,X_mean,X_std
def CostFuction(X,Y,theta):
"""计算代价函数"""
m=len(Y)
#print X.shape
#print theta.shape
cost=(np.transpose(X*theta-Y))*(X*theta-Y)/(2*m)
return cost
def gradientDecent(X,Y,theta,lr,num_iters):
cost_history=np.zeros((num_iters,1))
temp = np.matrix(np.zeros((len(theta),num_iters)))
for i in range(num_iters):
h_theta=np.dot(X,theta)
temp[:,i]=theta-(lr/len(Y))*(np.dot(np.transpose(X),h_theta-Y))
theta=temp[:,i]
cost_history[i]=CostFuction(X,Y,theta)
return theta,cost_history
def plot(cost_history,num_iters):
x = np.arange(1,num_iters+1)
plt.plot(x,cost_history)
plt.xlabel(u"迭代次数",fontproperties=font) # 注意指定字体,要不然出现乱码问题
plt.ylabel(u"代价值",fontproperties=font)
plt.title(u"代价随迭代次数的变化",fontproperties=font)
plt.show()
def predict(mean,std,theta):
result=0
num=np.array([3000,4])
num_normal=(num-mean)/std
num_1=np.hstack((np.ones((1)),num_normal))
result=np.dot(num_1,theta)
return result
if __name__=="__main__":
linearRegression()
其中data.csv在这里:http://download.csdn.net/download/u010725283/10135960
是不是忘了一件事,正则化,L1,L2呐?且听下次分解。