在这部分中,你将使用多变量线性回归去预测房屋价格,假设你要卖掉房子而且你想知什么是一个好的市场价格,去做的一个方式就是首先收集最近出售的房子信息并制作房屋价格的模型,文件ex1data2/txt包含了一个房屋价格在Portland的训练集,第一列是房子大小,第二列是卧室的数量,第三列是房屋价格,ex1_multi.m脚步已经给你写好了你只需要填空,
发现数据集中房屋大小大约是卧室数量的1000倍,当特征相差了几个数量级时,首先进行特征缩放会使使用梯度下降收敛变得更快,你的任务要完成把数据集中所有数据减去减取均值后在除以标准差。
注:这里吴恩达只对X 没对预测价格Y做标准化(从下面的图4:适当学习率下梯度下降收敛过程
就能看出来) 我个人感觉这样做出来的误差会很大 当然初学阶段也就将就了
标准差是一种测量变化量的方法 在特定值的范围内 (大多数数据点将位于正负2个标准差之中)当然还有另外一种方式来确定取值范围 那就是通过最大值MAX-最小值MIN
请注意这些矩阵X的列对应于一个特征
实现注意:在标准化特征时,去存储用于标准化的值——用于计算的均值和标偏差是很重要的。在从模型中学习参数之后我们经常想预测我们之前从来没有见过的房加,给定一个新的X值(客厅面积和寝室数量)我们必须首先使用之前从训练集中计算出来的均值和标准差去归一化X
以前,你在一元回归上使用了梯度下降,现在唯一的不同是矩阵X多了一个特征,假设假设函数和批量更新的梯度下降规则保持不变。你应该在computeCostMulti和gradientDescentMulti中完成代码实现多元线性回归的代价函数和梯度下降。如果你已经完成,为了确保你的代码支持所有数量的特征而且能很好的向量化,你可以使用size(X,2)去找出数据集中有多少特征。
执行注意事项:在多元的情况下,代价函数也可以写成如下向量化的形式:
当你使用像Octave / MATLAB(Python.numpy)这样的数字计算工具时,向量化版本是非常给力的,如果你是操作矩阵的专家,你可以向自己证明这两种形式是等价的。
可选练习:寻找学习率
在这部分练习中,你将为数据集试测不同的学习率并找出那个收敛速度更快的。
下一阶段ex1将在选中的学习率中调用你的gradientDescent函数进行大约50次迭代,这个函数应该能返回向量J中每一次J(θ)值的历史记录,在最后一次迭代后,ex1.multi脚本将绘制迭代次数与J(θ)值的图像
如果你是在一个很好的范围里选择学习率的,你绘制出的图会很像图4,如果你的图表看上去完全不一样,尤其是你的J(θ)呈爆炸型增长时,调整你的学习率然后重试一次。我们推荐你尝试的学习率的刻度是:对上一个学习率乘以3,即(0.3、0.1、0.03、0.01等等)你可能还需要调整运行的迭代次数以帮助你看到曲线的整体走势。
图4:适当学习率下梯度下降收敛过程
执行注意事项:如果你选的学习率过大,J(θ)可能会爆炸性增长然后发散,导致计算机计算代价太大,在这种情况下,Octave/MATLAB会返回结果NaNs。NaN代表不是一个数字而且总是导致未定义的-1和+1的操作(看不懂这段)
Octave/MATLAB小贴士:为比较不同学习率对收敛的影响,把多个学习率跟J(θ)画在同一幅图中是很有帮助的,在OCTAVE/MATLAB中可以通过使用hold on命令在之间执行多次梯度下降来绘制,具体而言,如果你尝试3个不同的α(你应该尝试使用更多的α值)并将代价值存储在J1 J2 J3上,你可以使用下面的命令把他们绘制在同一张图上:plot()……
函数中的brk代表不同的颜色。
注意收敛曲线随着学习率的变化而变化,采用一个很小的学习率你会发现梯度下降法将花费大量时间去收敛到最优值,反之大的学习率可能会不收敛甚至发散!在你发现最好的学习率后运行它,去预测一个1650平米,3个卧室的房子的价格,随后你将使用值去检查你的执行的正规方程。别忘了在预测过程中去做标准化处理!
在教学视频中,你已经学到了线性回归的封闭解(closed-form solution)是
使用这个公式不需要进行任何特征缩放,你就会在计算中得到一个精确解,不会像梯度下降那样在收敛前进行循环迭代,完成标准方程的代码,使用上面公式计算θ,记住尽管你不需要缩放特征,我们仍然需要添加“全是1”的这列作为X的第一列。
可选择的练习:现在一旦你用这个方法找到了θ,用它来预测3间卧室1650平米的房子,你应该会发现预测出的价格和之前梯度下降法预测出的一样。
注意:本人代码中通过梯度下降法得到的参数θ2<0说明随着卧室数量增加价格反而减小 可能有点问题。-0-
运行结果:
代码:
import numpy as np
import matplotlib.pyplot as plt
def featureNormalization(X):
AVGmu = np.mean(X, axis=0)
SDsigma = np.std(X, axis=0, ddof=0) # axis=0代表对列做 ddof=0代表是有偏的 (数理统计对样本标准差的定义是ddof=1是无偏的即默认情况下分母是n-1,若是想除以n则加上ddof=0)
xxnormal = (X - AVGmu) / SDsigma #每个样本减去均值除以有偏标准差
#print(AVGmu)
# print(SDsigma)
# print(xxnormal)
return AVGmu,SDsigma,xxnormal
def featureNormalization2(X):#把数据映射到0~1
max = np.max(X, axis=0)
min = np.min(X, axis=0) # axis=0代表对列做 ddof=0代表是有偏的 (数理统计对样本标准差的定义是ddof=1是无偏的即默认情况下分母是n-1,若是想除以n则加上ddof=0)
xxnormal = (X - min) / (max-min) #每个样本减去均值除以有偏标准差
print(max)
print(min)
print(xxnormal)
return max,min,xxnormal
def gradientDescent(X,y,theta,num,studyrate,iterations):
m=num
J_every=np.zeros((iterations,1))#用于存储每次迭代计算出的costfunction值
theta_every=np.zeros((interations,2))
XT=X.T#为保证矩阵乘法行列要求 接下来计算会用到X的转置
for i in range(interations):
dJdivdtheta = (np.dot(XT,((np.dot(X, theta) - y))/m ))
theta = theta - studyrate * dJdivdtheta
theta_every[i][0]=theta[0][0]
theta_every[i][1]=theta[1][0]
J_every[i] = computeCost(X, y, theta,num)
return theta,J_every,theta_every
def computeCost(X,y,theta,num):
m = num
result = (np.sum((np.dot(X, theta) - y) ** 2)) / (2 * m)
return result
def showCostfunction(interations):
for i in range(interations):
print('第',i+1,'次迭代的代价函数值为',costhistory[i],'theta0和theta1分别是',thetahistory[i])
def showJValueWithInterations(costhistory1,costhistory2,costhistory3):#绘制不同学习率下代价值与迭代次数的关系图
plt.xlabel('Number of Iterations')
plt.ylabel('Value of Cost')
plt.plot(np.arange(np.size(costhistory1, 0)), costhistory1, '-b', lw=2)
plt.plot(np.arange(np.size(costhistory2, 0)), costhistory2, '-g', lw=2)
plt.plot(np.arange(np.size(costhistory3, 0)), costhistory3, '-r', lw=2)
plt.show()
def predictProfitByGradientDescent(x1,x2,AVGmu,SDsgm,thetai):
Xtest=( np.array(([x1, x2])-AVGmu)/SDsgm)
print("样本均值是",AVGmu)
print("样本标准差是",SDsgm)
print(Xtest)
Xtest = np.hstack((1, Xtest)) # 这是矩阵拼接的另外一个方法
predict=np.dot(Xtest,thetai)#预测
print("通过梯度下降法:",x1,'占地面积',x2,'个卧室的房子预测价格是',(predict[0]))
def normalEquations(x,y):
theta=np.dot(np.dot((np.linalg.inv(np.dot(np.transpose(x),x))),np.transpose(x)),y)
return theta
def predictProfitBynormalEquations(x1,x2,thetai):
Xtest = np.array([x1, x2])
Xtest = np.hstack((1, Xtest)) # 这是矩阵拼接的另外一个方法
predict = np.dot(Xtest, thetai) # 预测
print("通过正规方程法",x1, '占地面积', x2, '个卧室的房子预测价格是', (predict[0]))
#####下面都是主函数######
#####这里都是读取文本######
dataset = np.loadtxt('ex1data2.txt', delimiter=',') # 读取数据集文本
xx = dataset[:, 0:2] # 取出文本的1 2列(房子面积、卧室数量)
yy = dataset[:, 2] # 取出文本的第3列(钱)
num = len(xx)
#print(num) #看看有多少个数据 (有47个数据)
x = xx.reshape(num, 2) # 转成num行的列向量
y = yy.reshape(num, 1) # 同上
#print(featureNormalization(x))#用于检测
AVGmu,SDsigma,XX= featureNormalization(x)#AVGmu代表均值 SDsigma代表标准差 XX代表归一化后的矩阵
print(AVGmu)#用于检测
print(SDsigma)#用于检测
#print(XX)#用于检测标准化后的矩阵
#max,min,XX= featureNormalization2(x) #代表用最大值最小值那个方法进行归一化
X0=np.ones((len(x), 1))#因为假设函数有常数项theta0所以考虑给实际运算的矩阵多加一列111……
juzhenXX=np.array(XX).reshape(len(XX),2)#数据集中属性x转换成一个n行1列的矩阵 (这行代码的转换好像有点累赘)
X = np.c_[X0, juzhenXX]#把归一化后的juzhenXX(47行2列)拼在X0(47行1列)右边 形成一个97行3列的矩阵X
#print(X)#看看原始数据
thetainit=np.zeros((3,1))#由题设theta包含三个参数常数项theta0、一阶系数theta1和theta2 后面会更新theta所以初始化是一个空矩阵 是3行1列的矩阵
print("Costfunction的初始值是",computeCost(X,y,thetainit,num))#查看还未更新的代价函数值
studyrate=0.1#根据试探 0.01 0.03 0.1发现最好
studyrate2=0.03
studyrate3=0.01
interations=50
thetai,costhistory,thetahistory=(gradientDescent(X,y,thetainit,num,studyrate,interations))
thetai2,costhistory2,thetahistory2=(gradientDescent(X,y,thetainit,num,studyrate2,interations))
thetai3,costhistory3,thetahistory3=(gradientDescent(X,y,thetainit,num,studyrate3,interations))
#showCostfunction(interations)
print("梯度下降出来参数分别是",thetai)
showJValueWithInterations(costhistory,costhistory2,costhistory3)
predictProfitByGradientDescent(1650,3,AVGmu,SDsigma,thetai)
#下面是normal equations方法的代码
normalequationsjuzhenXX=np.array(x).reshape(len(x),2)
normalequationsX = np.c_[X0, normalequationsjuzhenXX]
normalequationtheta=normalEquations(normalequationsX,y)
print("正规方程出来的参数分别是",normalequationtheta)
predictProfitBynormalEquations(1650,3,normalequationtheta)