ex I-代码实现
单变量线性回归
在本部分的练习中,您将使用一个变量实现线性回归,以预测食品卡车的利润。假设你是一家餐馆的首席执行官,正在考虑不同的城市开设一个新的分店。该连锁店已经在各个城市拥有卡车,而且你有来自城市的利润和人口数据。
您希望通过使用这些数据来帮助您扩展到下一个城市;
Step1: Prepare datasets
按照吴老师上课时候所说的来准备数据,取最后一列为目标向量,剩余列为输入矩阵X,最重要的是记得在第一列加入新的一列,数值全部为1
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
'''
单变量线性回归
1.Prepare datasets
'''
path = 'ex1data1.txt'
data = pd.read_csv(path, header=None, names=['Population', 'Profit']) # names添加列名,header用指定的行来作为标题,若原无标题且指定标题则设为None
data.head() # head()查看前5行,若为-1,则查看至倒数第二行
# print(data.head())
data.describe() # describe快速统计汇总数据内容
# print(data.describe())
# 展示散点图,可视化理解数据
# data.plot(kind='scatter', x='Population', y='Profit', figsize=(8, 5))
# plt.show()
data.insert(0, 'Ones', 1) # 加入至第一列,全部数值为1
# print(data)
# 变量初始化:set X (training data) and y (target variable)
cols = data.shape[1] # 列数
X = data.iloc[:, 0:cols - 1] # iloc根据位置索引选取数据,先行后列,取前cols-1列作为输入向量
y = data.iloc[:, cols - 1:cols] # 取最后一列作为目标向量
# print(X.head())
# print(y.head())
X = np.matrix(X.values)
y = np.matrix(y.values)
theta = np.matrix([0, 0])
print(X.shape, y.shape, theta.shape) # 查看各自的行列数
Step2: Design model using Gradient Descent
首先, 我们将创建一个以参数为特征函数的代价函数
其中:
计算代价函数
'''
2.Design model using Gradient Descent
'''
def computeCost(X, y, theta):
'''
作用:计算代价函数,向量化来计算参数
:param X: 输入矩阵
:param y: 输出目标
:param theta: parameters
:return:
'''
inner = np.power(((X * theta.T) - y), 2)
# print(inner)
return sum(inner) / (2 * len(X))
# testing
# computeCost(X, y, theta) # 32.07273388
注意:这里我使用的是matix而不是array,两者基本通用。
但是matrix的优势就是相对简单的运算符号,比如两个矩阵相乘,就是用符号*,但是array相乘不能这么用,得用方法.dot()
array的优势就是不仅仅表示二维,还能表示3、4、5…维,而且在大部分Python程序里,array也是更常用的。
两者区别:
对应元素相乘:matrix可以用np.multiply(X2,X1),array直接X1X2
点乘:matrix直接X1X2,array可以 X1@X2 或 X1.dot(X2) 或 np.dot(X1, X2)
代价函数是应该是numpy矩阵,所以我们需要转换X和Y,然后才能使用它们。 我们还需要初始化theta。
优化:
使用 vectorization同时更新所有的 , 可以大大提高效率
def gradientDescent(X, y, theta, alpha, epoch):
'''
作用:获得最终梯度下降后的theta值以及cost
:param X:
:param y:
:param theta:
:param alpha:
:param epoch:
:return:
'''
# 变量初始化,储存数据
temp = np.matrix(np.zeros(theta.shape)) # 初始化一个临时矩阵(1, 2)
# flatten()即返回一个折叠成一维的数组。但是该函数只能适用于numpy对象,即array或者mat,普通的list列表是不行的。
parameters = int(theta.flatten().shape[1]) # 参数theta的数量
cost = np.zeros(epoch) # 初始化一个ndarray, 包含每次训练后的cost
counterTheta = np.zeros((epoch, 2))
m = X.shape[0] # 样本参数
for i in range(epoch):
'''
使用 vectorization同时更新所有的θ,可以大大提高效率,此处都是相对应的进行计算
X.shape, theta.shape, y.shape, X.shape[0]
((97, 2), (1, 2), (97, 1), 97)
'''
temp = theta - (alpha / m) * (X * theta.T - y).T * X
# 以下是不用Vectorization求解梯度下降
# error = (X * theta.T) - y # (97, 1)
# for j in range(parameters):
# term = np.multiply(error, X[:,j]) # (97, 1)
# temp[0,j] = theta[0,j] - ((alpha / m) * np.sum(term)) # (1,1)
theta = temp
counterTheta[i] = theta
cost[i] = computeCost(X, y, theta)
pass
return counterTheta, theta, cost
Step3: Run model and Plot
最后一步就是将准备好的数据输入到相应的模型,得出两个图,第一个图是拟合数据图,第二个图是代价图
'''
3.Run model and Plot
'''
alpha = 0.01
epoch = 3800
counterTheta, final_theta, cost = gradientDescent(X, y, theta, alpha, epoch)
computeCost(X, y, final_theta)
x = np.linspace(data.Population.min(), data.Population.max(), 100) # xlabel
f = final_theta[0, 0] + (final_theta[0, 1] * x) # ylabel profit
fig1, ax = plt.subplots(figsize=(6, 4))
ax.plot(x, f, 'r', label='Prediction')
ax.scatter(data.Population, data.Profit, label='Training Data')
ax.legend(loc=2)
ax.set_xlabel('Population')
ax.set_ylabel('Profit')
ax.set_title('Predicted Profit vs. Population Size')
fig2, ax = plt.subplots(figsize=(8, 4))
ax.plot(np.arange(epoch), cost, 'r')
ax.set_xlabel('Iteration')
ax.set_ylabel('Cost')
ax.set_title('Error vs. Training Epoch')
plt.show()
可以看出来拟合的相当不错
最后大概是收敛到4.47左右,如以下图
使用别的方法同样可以达到以上成果
1.normal equation(正规方程)
梯度下降与正规方程的比较:
梯度下降:需要选择学习率α,需要多次迭代,当特征数量n大时也能较好适用,适用于各种类型的模型
正规方程:不需要选择学习率 , 一次计算得出, 需要计算 , 如果特征数量n较大则运算代 价大,因为矩阵逆的计算时间复杂度为 , 通常来说当
def normalEqu(X, y):
theta = np.linalg.inv(X.T@X)@X.T@y # X.T@X等价于X.T.dot(X)
return theta
final_theta2 = normalEqu(X, y)
x = np.linspace(data.Population.min(), data.Population.max(), 100) # xlabel
f = final_theta[0, 0] + (final_theta[0, 1] * x) # ylabel profit
fig3, ax = plt.subplots(figsize=(6, 4))
ax.plot(x, f, 'r', label='Prediction')
ax.scatter(data.Population, data.Profit, label='Training Data')
ax.legend(loc=2)
ax.set_xlabel('Population')
ax.set_ylabel('Profit')
ax.set_title('Predicted Profit vs. Population Size')
plt.show()
调用sklearn库来进行拟合
接着上面代码来
from sklearn import linear_model
'''
2.Design model using sklearn
'''
model = linear_model.LinearRegression()
model.fit(X, y)
# print(X)
# print(X[:, 1].A1.shape)
x = np.array(X[:, 1].A1) # numpy.matrix[:, 1].A1-->取矩阵的第二列 转换成一维的
f = model.predict(X).flatten() # 预测之后也转换成一维的
fig, ax = plt.subplots(figsize=(8, 5))
ax.plot(x, f, 'r', label='Prediction')
ax.scatter(data.Population, data.Profit, label='Traning Data')
ax.legend(loc=2)
ax.set_xlabel('Population')
ax.set_ylabel('Profit')
ax.set_title('Predicted Profit vs. Population Size')
plt.show()
多向量线性回归
这是ex1中另外一组数据,是多维的数据,其中包括房子的大小,以及卧室的多少,这个时候可以运用到一个小技巧就是特征值归一化
具体的不多说,看代码和图,可直接复制并且运行.
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
'''
多变量线性回归
1.Prepare datasets
'''
path = 'ex1data2.txt'
data = pd.read_csv(path, header=None, names=['Size', 'Bedroom', 'Price']) # names添加列名,header用指定的行来作为标题,若原无标题且指定标题则设为None
data.head() # head()查看前5行,若为-1,则查看至倒数第二行
# print(data.head)
# 预处理-特征值归一化
data = (data - data.mean())/data.std() # std为标准差
data.head()
# print(data.head)
# add ones column
data.insert(0, 'Ones', 1)
# set X (training data) and y (target variable)
cols = data.shape[1]
X = data.iloc[:, 0:cols - 1]
y = data.iloc[:, cols - 1:cols]
# convert to matrices and initialize theta
X = np.matrix(X.values)
y = np.matrix(y.values)
theta = np.matrix(np.array([0, 0, 0]))
'''
2.Design model using Gradient Descent
'''
def computeCost(X, y, theta):
'''
作用:计算代价函数,向量化来计算参数
:param X: 输入矩阵
:param y: 输出目标
:param theta: parameters
:return:
'''
inner = np.power(((X * theta.T) - y), 2)
# print(inner)
return sum(inner) / (2 * len(X))
# testing
# computeCost(X, y, theta) # 32.07273388
def gradientDescent(X, y, theta, alpha, epoch):
'''
作用:获得最终梯度下降后的theta值以及cost
:param X:
:param y:
:param theta:
:param alpha:
:param epoch:
:return:
'''
# 变量初始化,储存数据
temp = np.matrix(np.zeros(theta.shape)) # 初始化一个临时矩阵(1, 2)
# flatten()即返回一个折叠成一维的数组。但是该函数只能适用于numpy对象,即array或者mat,普通的list列表是不行的。
parameters = int(theta.flatten().shape[1]) # 参数theta的数量
cost = np.zeros(epoch) # 初始化一个ndarray, 包含每次训练后的cost
counterTheta = np.zeros((epoch, 3))
m = X.shape[0] # 样本参数
for i in range(epoch):
'''
使用 vectorization同时更新所有的θ,可以大大提高效率,此处都是相对应的进行计算
X.shape, theta.shape, y.shape, X.shape[0]
((97, 2), (1, 2), (97, 1), 97)
'''
temp = theta - (alpha / m) * (X * theta.T - y).T * X
# 以下是不用Vectorization求解梯度下降
# error = (X * theta.T) - y # (97, 1)
# for j in range(parameters):
# term = np.multiply(error, X[:,j]) # (97, 1)
# temp[0,j] = theta[0,j] - ((alpha / m) * np.sum(term)) # (1,1)
theta = temp
counterTheta[i] = theta
cost[i] = computeCost(X, y, theta)
pass
return counterTheta, theta, cost
'''
3.Run model and Plot
'''
alpha = 0.01
epoch = 3800
counterTheta, final_theta, cost = gradientDescent(X, y, theta, alpha, epoch)
computeCost(X, y, final_theta)
fig2, ax = plt.subplots(figsize=(8, 4))
ax.plot(np.arange(epoch), cost, 'r')
ax.set_xlabel('Iteration')
ax.set_ylabel('Cost')
ax.set_title('Error vs. Training Epoch')
plt.show()