一、单变量线性回归
1.假设函数:
2.代价函数:
Python实现:
3.利用梯度下降的思想去迭代地改变theta的值,以求理想的theta的值使得代价函数取值最小,思路如下:
Python代码实现:
疑惑解答:parameter获取到的是θ的值的个数,循环遍历parameter可以实现对每个θ的值下降一次。
最后的图绘结果如下图所示:
完整实现过程如下:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
path = 'C:/Users/nydcomputer/Desktop/机器学习/数据集/ex1/ex1dta.txt'
# 读取csv文件
# header=0时是默认情况,表示以数据的第一行为列索引,若改names则第一行数据会丢失
# header=None时,添加names第一行数据不会丢失
# names为横向索引header的名字,可以是数字
data = pd.read_csv(path, header=None,names = ['Population', 'Profit'])
# 读取csv文件
# header = 0是默认情况(即不标明,默认就是header = 0),表示以数据的第一行为列索引,若改names,则第一行数据会丢失(直接修改第一行数据)。
# header=None时,显示每一行数据,添加names,第一行数据不会丢失
# names为横向索引header的名字,可以是数字,如names=range(2,6)
data.head() # 检验数据,可检验5行
data = pd.DataFrame(data) # 生成图表,pandas中方法,也可以直接用data
print(data.head()) # head函数默认输出五行
# 特征归一化(为了使梯度下降得更方
# 便)
data = (data - data.mean()) / data.std() # (原始数据 - 平均值)/ 标准差
data.head()
# 定义代价函数
def computeCost(X, y, theta):
inner = np.power(((X * theta.T) - y), 2) # X为输入矩阵。*theta的转置为假设函数,-y后整体平方;power函数计算幂
return np.sum(inner) / (2 * len(X))
# 在原始数据集表上增加第0列,总共数据集为三列
data.insert(0, 'Ones', 1)
cols = data.shape[1] # shape函数读取data中的二维的长度,即为数据的列数,此时共有三列,clos=3;shape[0]为行数
X = data.iloc[:, :-1] # X为数据中的所有行,以及除了最后一列,此时X中有ones列与population列,X是72*2的数据,列数等同于[0:2]
y = data.iloc[:, cols - 1:cols] # y为最后一列数据,等同于[2:3]
X = np.matrix(X.values) # 将X转换为矩阵,72*2
y = np.matrix(y.values) # 将y转换为矩阵,72*1
theta = np.matrix(np.array([0, 0])) # theta向量是两个值都初始化为0的一维向量,1*2,转置后为2*1
print("初始theta值的代价为:")
print(computeCost(X, y, theta)) # 此时theta为初始自定义的值(0,0),计算出了此时输入的代价
# 定义梯度下降函数
def gradientDecent(X, y, theta, alpha, iters): # alpha为学习率,iters为设定迭代次数
tempt = np.matrix(np.zeros(theta.shape)) # theta的维度的所有数据全部初始化为0
parameters = int(theta.ravel().shape[1]) # ravel函数将theta的维度降为一维,shape[1]为列数
cost = np.zeros(iters) # 初始化代价,值为0的有iters个值的矩阵
for i in range(iters):
error = (X * theta.T) - y # 预测值与实际值的误差,为72*1矩阵,放在大循环内小循环外,每次迭代后的theta进行了更新,error值随之变换。
for j in range(parameters): # 梯度下降重要步骤,根据公式将每个theta[j]的值下降一次
term = np.multiply(error, X[:, j]) # error与第j列的向量对应位置相乘并最终求和,之前增加ones列用于与1相乘
tempt[0, j] = theta[0, j] - ((alpha / len(X)) * (np.sum(term)))
cost[i] = computeCost(X, y, tempt) # 计算第i此迭代时此theta值的代价
theta = tempt # 将theta向量更新,进行下次迭代循环继续处理theta
return theta, cost
# 赋值
alpha = 0.01
iters = 1500
g, cost = gradientDecent(X, y, theta, alpha, iters)
print("参数theta向量:")
print(g)
print(cost)
# 预测70000人口的时候,根据公式h= theta0 + theta1*X
predict1 = (1, 7) * g.T # g.T为g的转置,g为1*2的参数向量 ,1*theta[0],7为population,7*参数theta[1]得到预测值profit
print("预测值1:")
print(predict1)
# 作图
x = np.linspace(data.Population.min(), data.Population.max(), 100) # 生成等差数列,100个等差点
f = g[0, 0] + (g[0, 1] * x) # f为假设函数,theta0+theta1*x
fig, ax = plt.subplots(figsize=(8, 6)) # 创建作图画布
ax.plot(x, f, 'r', label='Prediction') # 画出线,红色,名为Prediction
ax.scatter(data.Population, data.Profit, label='training data') # scatter为散点图
ax.legend(loc=2) # 在图上标明一个图例,用于说明每条曲线的文字显示,loc为第二象限
ax.set_xlabel('Population')
ax.set_ylabel('Profit')
ax.set_title('Predicted Profit vs. Population Size')
plt.show()
二、多变量线性回归
多变量的意思是指假设函数中的θ可能不止有两个,可能有多个,但仍然是线性函数。
1.假设函数
2.代价函数
3.计算梯度
Python实现的过程与单变量线性回归大差不差,只是theta变量在初始赋值的时候以及在对每一个theta变量下降时有所区别。
最后的图绘结果如下图所示:
完整实现过程如下:
import numpy as np
import pandas as pd
# pyplot是常用的绘图模块,能很方便让用户绘制2D图表
import matplotlib.pyplot as plt
# 通过从mpl_toolkits.mplot3d引入axes3d来创建3d图现象
from mpl_toolkits.mplot3d import Axes3D
path = 'C:/Users/nydcomputer/Desktop/机器学习/数据集/ex1/ex1dta2.txt'
data = pd.read_csv(path, header=None, names=['Sizes', 'Bedrooms', 'Price'])
# 多个特征相差过大,容易震荡,故需要归一化操作
data = (data-data.mean())/data.std()
print(data.head())
data.insert(0, 'ones', 1)
cols = data.shape[1]
X = data.iloc[:, 0: cols-1]
y = data.iloc[:, cols-1:cols]
X = np.matrix(X.values)
y = np.matrix(y.values)
theta = np.matrix(np.array([0, 0, 0])) # 多变量梯度需要三个theta,初始化为0
def computeCost(X, y, theta):
inner = np.power(((X*theta.T)-y), 2)
return np.sum(inner) / (2*len(X))
def gredientDecent(X, y, theta, alpha, iters): # alpha为学习率,iters为迭代次数
tempt = np.matrix(np.zeros(theta.shape))
parameters = int(theta.ravel().shape[1])
cost = np.zeros(iters) # cost为iters个值的一维矩阵,仅有一行,iters列
for i in range(iters):
error = (X * theta.T) - y
for j in range(parameters):
term = np.multiply(error, X[:, j])
tempt[0, j] = theta[0, j] - ((alpha/len(X))*(np.sum(term)))
theta = tempt
cost[i] = computeCost(X, y, theta)
return theta, cost
alpha = 0.01
iters = 1500
g, cost = gredientDecent(X, y, theta, alpha, iters)
print("theta变量与最小代价")
print(g)
print(cost)
predict1 = (1, 1650, 3) * g.T
print("预测值:")
print(predict1)
#作图
x = np.linspace(data.Sizes.min(), data.Sizes.max(), 100)
y = np.linspace(data.Bedrooms.min(), data.Bedrooms.max(), 100)
f = g[0, 0] + (g[0, 1] * x) + (g[0, 2] * y)
fig = plt.figure()
ax = Axes3D(fig)
ax.scatter3D(x, y, f, cmap='Blues')
ax.plot3D(x, y, f, 'gray')
plt.show()
从实现的方式上看,单变量线性回归与多变量线性回归的差别并不大,主要的区别有如下几点:
- 在特征较多时,如果特征之间的数量级相差过大,在计算时需要进行归一化处理,避免不必要的震荡。实际上,单变量和多变量都做了归一化处理。
- 在单变量线性回归时,初始化θ用到的是:
theta = np.matrix(np.array([0, 0]))
而在多变量线性回归时,初始化θ用到的是:
theta = np.matrix(np.array([0, 0, 0]))
意思就是,theta的值有两个转变成了多个。
-
最后这一点不同也是由theta初始化的不同导致的,在定义梯度下降函数gredientDecent时,用
parameters = int(theta.ravel().shape[1]) 来获取theta的值,单变量中获取到的是2,而多变量中获取到的是3,所以在函数中的双层循环中遍历的次数是不一样的,但是原理都是相同的。
本文是我个人的学习记录,由于本人才疏学浅,在学习的过程中是边参考着别人的知识总结边学习的,以下是我参考的链接:
https://blog.csdn.net/wangjia2575525474/article/details/119912142
若大家发现本文有任何不当或不正确之处,请在评论区批评指正,我会及时查看并加以修正!