> 文章列表 > 线性回归讲解

线性回归讲解

线性回归讲解

要将Matplotlib绘制的动态图保存为.mp4格式的文件,你需要安装FFmpeg软件,并使用Matplotlib提供的FFMpegWriter对象来保存动态图。以下是在你的代码中添加保存为.mp4格式的示例代码:

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation, FFMpegWriter
from tqdm import trange# z-score,min_max
years = np.array([i for i in range(2000,2022)]) # 年份 2000 ~ 2021
years = (years - 2000) / 22 # batch_normalizer layer_noramlizer
prices = np.array([10000,11000,12000,13000,14000,12000,13000,16000,18000,20000,19000,22000,24000,23000,26000,35000,30000,40000,45000,52000,50000,60000])/60000epoch = 10k = 1
b = 1
lr = 0.01x_data = []
y_data = []
losses = []fig, ax = plt.subplots()
line, = ax.plot([], [])
ax.set_xlim(0, epoch)
ax.set_ylim(0, 1)
ax.set_xlabel('Iterations')
ax.set_ylabel('Loss')def update(frame):global k, bloss = 0for x,label in zip(years,prices):pre = k * x + bloss += (pre - label) ** 2delta_k = 2 * (k * x + b - label) * xdelta_b = 2 * (k * x + b - label)k = k - delta_k * lrb = b - delta_b * lrlosses.append(loss)  # 记录损失x_data.append(frame)y_data.append(loss)line.set_data(x_data, y_data)return line,ani = FuncAnimation(fig, update, frames=trange(epoch), blit=True)writer = FFMpegWriter(fps=30)
ani.save('animation.mp4', writer=writer)while True:year = (float(input("请输入年份: ")) - 2000)/ 22print("预测房价: ",(k * year + b) * 60000)

在上述代码中,我们创建了一个FFMpegWriter对象,并将其作为参数传递给ani.save()函数,用于将动态图保存为.mp4格式的文件。需要注意的是,保存为.mp4格式的文件需要FFmpeg软件的支持,如果没有安装FFmpeg,需要先通过系统包管理器或者官网下载安装。ow()函数显示图形。

import numpy as np
import matplotlib.pyplot as pltclass MyDataset:def __init__(self,xs,ys,batch_size,shuffle):self.xs = xsself.ys =ysself.shuffle = shuffleself.batch_size = batch_sizedef __iter__(self):return DataLoader(self)def __len__(self):return len(self.xs)class DataLoader:def __init__(self,dataset):self.dataset = datasetself.cursor = 0self.indexs = np.arange(len(self.dataset))if self.dataset.shuffle:np.random.shuffle(self.indexs)def __next__(self):if self.cursor >= len(self.dataset):raise StopIterationindex = self.indexs[self.cursor:self.cursor + self.dataset.batch_size]x = self.dataset.xs[index]y = self.dataset.ys[index]self.cursor += self.dataset.batch_sizereturn x , yif __name__ == "__main__":years = np.array([i for i in range(2000,2022)])floors = np.array([i for i in range(23,1,-1)])years = (years - 2000) / 22prices = np.array([10000,11000,12000,13000,14000,12000,13000,16000,18000,20000,19000,22000,24000,23000,26000,35000,30000,40000,45000,52000,50000,60000])prices = prices/60000# 数据归一化: 除以最大值, z-score归一化, min-maxk = 1b = 0lr = 0.07epoch = 5000batch_size = 2shuffle = Truedataset = MyDataset(years,prices,batch_size,shuffle)for e in range(epoch):for year,price in dataset:predict = k * year + bloss = (predict - price) ** 2delta_k =  (k * year + b - price) * yeardelta_b =  (k * year + b - price)k -= np.sum(delta_k)/batch_size * lrb -= np.sum(delta_b)/batch_size * lrwhile True:test_year = (int(input("请输入预测的年份: ")) - 2000) / 22predict_price = test_year * k + bprint(predict_price * 60000)

这是一个简单的线性回归模型,用于预测房价。模型使用梯度下降法进行训练,可以通过输入年份来预测房价。

在这个模型中,我们首先定义了一个MyDataset类,用于封装输入数据和目标数据,并实现了__iter__方法,以便在训练过程中使用DataLoader类进行数据批量加载和随机打乱。

在训练过程中,我们使用了一个双重循环,外层循环控制训练的迭代次数,内层循环用于按批次加载数据,并计算损失和更新模型参数。

最后,我们可以通过输入年份来进行房价的预测。需要注意的是,模型的预测结果可能会受到多种因素的影响,如数据样本的数量和质量、模型的复杂度和训练方法等,因此在应用模型时需要谨慎考虑。

	predict = k * year + bloss = (predict - price) ** 2delta_k =  (k * year + b - price) * yeardelta_b =  (k * year + b - price)k -= np.sum(delta_k)/batch_size * lrb -= np.sum(delta_b)/batch_size * lr

重点解释一下这一段

这一段代码实现了线性回归模型的训练过程。具体来说,它包括以下几个步骤:

预测值计算:根据当前模型参数 k 和 b,以及输入数据 year,计算出预测值 predict,即 predict = k * year + b。

损失计算:根据预测值 predict 和目标值 price,计算出损失 loss,即 loss = (predict - price) ** 2。

梯度计算:根据当前模型参数 k 和 b,以及输入数据 year 和目标值 price,计算出损失函数对 k 和 b 的偏导数 delta_k 和 delta_b,即 delta_k = (k * year + b - price) * year,delta_b = (k * year + b - price)。

参数更新:根据计算出的梯度 delta_k 和 delta_b,以及学习率 lr 和批量大小 batch_size,更新模型参数 k 和 b,即 k -= np.sum(delta_k)/batch_size * lr,b -= np.sum(delta_b)/batch_size * lr。

这个过程可以看做是利用梯度下降法对模型进行训练,通过不断迭代更新模型参数,逐步降低损失,使模型能够更好地拟合数据。需要注意的是,梯度下降法的效果受到学习率和批量大小的影响,过大或过小的学习率和批量大小都可能导致模型训练效果不佳,因此需要在实际应用中进行调参。

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FFMpegWriter, FuncAnimationclass MyDataset:def __init__(self, xs, ys, batch_size, shuffle):self.xs = xsself.ys = ysself.shuffle = shuffleself.batch_size = batch_sizedef __iter__(self):return DataLoader(self)def __len__(self):return len(self.xs)class DataLoader:def __init__(self, dataset):self.dataset = datasetself.cursor = 0self.indexs = np.arange(len(self.dataset))if self.dataset.shuffle:np.random.shuffle(self.indexs)def __next__(self):if self.cursor >= len(self.dataset):raise StopIterationindex = self.indexs[self.cursor : self.cursor + self.dataset.batch_size]x = self.dataset.xs[index]y = self.dataset.ys[index]self.cursor += self.dataset.batch_sizereturn x, yif __name__ == "__main__":years = np.array([i for i in range(2000, 2022)])floors = np.array([i for i in range(23, 1, -1)])years = (years - 2000) / 22prices = np.array([10000, 11000, 12000, 13000, 14000, 12000, 13000, 16000, 18000, 20000, 19000, 22000, 24000, 23000, 26000, 35000, 30000, 40000, 45000, 52000, 50000, 60000])prices = prices / 60000k = 1b = 0lr = 0.07epoch = 50batch_size = 2shuffle = Truedataset = MyDataset(years, prices, batch_size, shuffle)fig, ax = plt.subplots()line, = ax.plot([], [], lw=2)scat = ax.scatter(years, prices)ax.set_xlim(0, 1)ax.set_ylim(0, 1)loss_ax = ax.twinx()loss_line, = loss_ax.plot([], [], lw=2, color='r')def init():line.set_data([], [])loss_line.set_data([], [])return (line,)def update(frame):global k, bx, y = next(iter(dataset))y_pred = x * k + bloss = np.mean((y - y_pred) ** 2)grad_k = np.mean((y_pred - y) * x)grad_b = np.mean(y_pred - y)k -= lr * grad_kb -= lr * grad_bprint(f"frame: {frame}, k: {k:.3f}, b: {b:.3f}, loss: {loss:.3f}")line.set_data(years, k * years + b)scat.set_offsets(np.column_stack((years, prices)))loss_line.set_data(np.arange(frame), np.full(frame, loss))ax.relim()ax.autoscale_view()loss_ax.relim()loss_ax.autoscale_view()return (line, scat, loss_line)ani = FuncAnimation(fig, update, frames=range(epoch), init_func=init, blit=True, save_count=100)writer = FFMpegWriter(fps=30)ani.save('animation.mp4', writer=writer)
import numpy as npclass MyDataset:def __init__(self,xs,ys,zs,batch_size,shuffle):self.xs = xsself.ys = ysself.zs = zsself.shuffle = shuffleself.batch_size = batch_sizedef __iter__(self):return DataLoader(self)def __len__(self):return len(self.xs)class DataLoader:def __init__(self,dataset):self.dataset = datasetself.cursor = 0self.indexs = np.arange(len(self.dataset))if self.dataset.shuffle:np.random.shuffle(self.indexs)def __next__(self):if self.cursor >= len(self.dataset):raise StopIterationindex = self.indexs[self.cursor:self.cursor + self.dataset.batch_size]x = self.dataset.xs[index]y = self.dataset.ys[index]z = self.dataset.zs[index]self.cursor += self.dataset.batch_sizereturn x ,y ,zyears = np.array([i for i in range(2000, 2022)])
years = (years - 2000) / 22floors = np.array([i for i in range(23,1,-1)])
floors = floors/23prices = np.array([10000, 11000, 12000, 13000, 14000, 12000, 13000, 16000, 18000, 20000, 19000, 22000, 24000, 23000, 26000, 35000,30000, 40000, 45000, 52000, 50000, 60000])
prices = prices / 60000lr = 0.05
epoch = 10000k1 = 1
k2 = -1
b = 0
batch_size = 8dataset = MyDataset(years,floors,prices,batch_size,True)for e in range(epoch) :for year,floor,price in dataset:predict = k1 * year  + k2 * floor +  1 * bloss = np.sum((predict - price) ** 2)delta_k1 = np.sum((predict - price) * year)delta_k2 = np.sum((predict - price) * floor)delta_b = np.sum((predict - price))k1 -= lr * delta_k1k2 -= lr * delta_k2b -=  lr * delta_bif e % 100 == 0:print(loss)

这是一个多变量线性回归的示例代码,使用了三个特征变量years、floors和prices,其中years和floors是输入特征,prices是输出特征。

在每个epoch中,迭代整个数据集,计算预测值和损失,并更新模型参数k1、k2和b。在这个示例中,使用的优化算法是梯度下降法,学习率为lr。

其中,MyDataset类和DataLoader类用于实现数据集的迭代器,可以方便地使用for循环迭代数据集中的每个batch。MyDataset类的初始化函数接收输入特征xs、输出特征ys、第二个输入特征zs、batch大小batch_size和是否随机打乱数据集shuffle等参数。DataLoader类的初始化函数接收一个MyDataset对象,并根据shuffle参数打乱数据集的索引,以便按照随机顺序迭代数据集。next()方法实现了每次迭代返回一个batch的功能,其中使用了self.cursor变量来记录当前迭代到的位置。

整个代码实现了一个简单的多变量线性回归模型,可以用于预测房价等问题。
首先,我们可以在每个epoch结束时记录下模型的损失值,然后使用Matplotlib将损失值随时间的变化进行可视化。可以在代码中添加以下代码来记录损失值:

losses = []
for e in range(epoch):# ...losses.append(loss)# ...

然后,可以使用Matplotlib来绘制损失随时间的变化曲线。可以在代码的最后添加以下代码:

import matplotlib.pyplot as pltplt.plot(np.arange(epoch), losses)
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.show()

这将绘制一个损失随时间变化的曲线,横轴是epoch数,纵轴是损失值。可以用这个曲线来监视模型的训练过程,以及选择合适的epoch数来停止训练,以避免过拟合或欠拟合。

完整的可视化代码如下:

import numpy as np
import matplotlib.pyplot as pltclass MyDataset:def __init__(self, xs, ys, zs, batch_size, shuffle):self.xs = xsself.ys = ysself.zs = zsself.shuffle = shuffleself.batch_size = batch_sizedef __iter__(self):return DataLoader(self)def __len__(self):return len(self.xs)class DataLoader:def __init__(self, dataset):self.dataset = datasetself.cursor = 0self.indexs = np.arange(len(self.dataset))if self.dataset.shuffle:np.random.shuffle(self.indexs)def __next__(self):if self.cursor >= len(self.dataset):raise StopIterationindex = self.indexs[self.cursor:self.cursor + self.dataset.batch_size]x = self.dataset.xs[index]y = self.dataset.ys[index]z = self.dataset.zs[index]self.cursor += self.dataset.batch_sizereturn x, y, zyears = np.array([i for i in range(2000, 2022)])
years = (years - 2000) / 22floors = np.array([i for i in range(23, 1, -1)])
floors = floors / 23prices = np.array([10000, 11000, 12000, 13000, 14000, 12000, 13000, 16000, 18000, 20000, 19000, 22000, 24000, 23000, 26000, 35000,30000, 40000, 45000, 52000, 50000, 60000])
prices = prices / 60000lr = 0.05
epoch = 10000k1 = 1
k2 = -1
b = 0
batch_size = 8dataset = MyDataset(years, floors, prices, batch_size, True)losses = []
for e in range(epoch):for year, floor, price in dataset:predict = k1 * year + k2 * floor + 1 * bloss = np.sum((predict - price) ** 2)delta_k1 = np.sum((predict - price) * year)delta_k2 = np.sum((predict - price) * floor)delta_b = np.sum((predict - price))k1 -= lr * delta_k1k2 -= lr * delta_k2b -= lr * delta_blosses.append(loss)if e % 100 == 0:print(loss)plt.plot(np.arange(epoch), losses)
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.show()