前言
线性回归模型可以用来预测数据的走势。通过对现有数据集的训练,可以得到一个线型函数Y=w*X+b,通过这个线性函数可以预测出后续的值。
一、线性回归模型
线型回归是在假设目标值X与特征值Y有线型相关关系的前提下,通过已知的数据集对线性模型:
进行求解,具体的求解方式为构建损失函数,使得损失函数的值越来越小,直到达到精度要求或者是迭代次数要求。损失函数可以理解为在计算的过程种得到的预测值与真实值之间的差距,使得差距越小,模型就与真实值越相似。损失函数的定义:
要使得损失函数最小,对 Loss(w,b) 最小化。引入梯度下降算法,沿着梯度的方向下降的速度是最快的。每次迭代更新w和b,直到达到要求。
计算 Loss(w,b) 对于w和b的偏导数,分别为(可以将y=w*x+b导入到损失函数中):
爬取BILIBILI上的视频信息,本文获取到“华农兄弟”的视频信息。可以参考博客爬取B站UP的所有视频细节信息。取其中的视频的点赞量和收藏量,对其建立线性回归模型,预测其关系。视频点赞量(x轴)与收藏量(y轴)的散点图如下:
由于数据的集中性很差,需要对数据进行归一化处理,本文使用最大最小值归一化。
经过训练得到w=0.7229486928307687 b=0.20322045504258518 训练后的模型如下:
# 线型回归模型预测B站视频点赞量与收藏量的关系(华农兄弟)
import json
import numpy as np
import time
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
class LR(object):
def __init__(self, max_iterator = 1000, learn_rate = 0.01):
self.max_iterator = max_iterator
self.learn_rate = learn_rate
self.w = np.random.normal(1, 0.1)
self.b = np.random.normal(1, 0.1)
def cal_day(self, release_date, now_date):
# 计算天数
start_time = time.mktime(time.strptime(release_date.split(' ')[0], '%Y-%m-%d'))
end_time = time.mktime(time.strptime(now_date.split(' ')[0], '%Y-%m-%d'))
return int((end_time - start_time)/(24*60*60))
def load_data(self, url):
with open(url, 'r', encoding='utf-8') as f:
data_dect = json.load(f)
# print(data_dect)
# 视频播放数量以及发布距离现在的天数
watched_number_list = []
time_list = []
dm_number_list = []
liked_list = []
collected_list = []
for sample in data_dect:
# 去掉坏点
if sample['watched'] != '':
watched_number_list.append([float(sample['watched'])]) #观看数量
liked_list.append([float(sample['liked'])]) #点赞数
collected_list.append([float(sample['collected'])]) #收藏数
dm_number_list.append([float(sample['bullet_comments'])]) #弹幕数
time_list.append([float(self.cal_day(sample['date'], sample['now_date']))]) #视频发布距离现在时间
return np.array(time_list), np.array(watched_number_list), np.array(liked_list), np.array(collected_list), np.array(dm_number_list)
def train_set_normalize(self, train_set):
data_range = np.max(train_set) - np.min(train_set)
return (train_set - np.min(train_set)) / data_range
def cal_gradient(self, x, y):
# 计算梯度
# print(x, y)
dw = np.mean((x * self.w + self.b - y) * x)
db = np.mean(self.b + x * self.w - y)
return dw, db
def train(self, x, y):
# 训练模型,使用梯度下降
train_w = []
train_b = []
for i in range(self.max_iterator):
print(self.w, self.b)
train_w.append(self.w)
train_b.append(self.b)
i += 1
# 计算梯度值,向着梯度下降的方向
dw, db = self.cal_gradient(x, y)
self.w -= self.learn_rate*dw
self.b -= self.learn_rate*db
return train_w, train_b
def predict(self, x):
# 预测
return x * self.w + self.b
def myplot(self, x, y, train_w, train_b):
plt.pause(2)
plt.ion()
# 动态绘图
for i in range(0, self.max_iterator, 30):
plt.clf()
# 原始散点图
plt.scatter(x, y, marker = 'o',color = 'yellow', s = 40)
plt.xlabel('liked')
plt.ylabel('collected')
plt.plot(x, train_w[i] * x + train_b[i], c='red')
plt.title('step: %d learning-rate: %.2f function: y=%.2f * x + %.2f' %(i, self.learn_rate, train_w[i], train_b[i]))
plt.pause(0.5)
plt.show()
plt.ioff()
plt.pause(200)
lr = LR()
time_list, watched_number_list, liked_list, collected_list, dm_number_list = lr.load_data(r'2020\Crawl\Bilibili\Item1\data\video_detial.json')
# 需要对数据进行归一化处理
tw, tb = lr.train(lr.train_set_normalize(liked_list), lr.train_set_normalize(collected_list))
lr.myplot(lr.train_set_normalize(liked_list), lr.train_set_normalize(collected_list), tw, tb)
参考文献