Bilibili(哔哩哔哩)是当下最热门的视频播放网站,人们在该网站对视频进行浏览,会根据自己喜好对视频进行点赞、投币、收藏、分享、回复等操作,Bilibili同时还有一个排行榜机制,记录了近期比较热门的视频,并给出了一个评分,排行榜的排序规则即根据该评分,本文将根据这些排行榜视频的各项数据,进行线性回归分析,结合实际情况找出对评分影响最大的数据。
Bilibili提供了获取排行榜数据的API,因此我们可以利用该API获取实时的排行榜数据,获取的数据为json格式,经过解析,已将数据保存至Bilibili.csv文件中。
本文的思路即为多元线性回归,在统计学中,线性回归(linear regression)是利用称为线性回归方程的最小二乘函数对一个或多个自变量和因变量之间关系进行建模的一种回归分析。这种函数是一个或多个称为回归系数的模型参数的线性组合。只有一个自变量的情况称为简单回归,大于一个自变量情况的叫做多元回归(multivariable linear regression)。
完成了对各个自变量权重的计算,找出了对评分影响权重最高的因素,并得到了验证。
数据获取
在哔哩哔哩官网首页处获取排行榜信息的API,得到为
https://api.bilibili.com/x/web-interface/ranking/v2?rid=0
请求参数为
返回格式为json格式,json中的data字段为视频信息数组。
为了防止请求次数过多增加服务器压力,导致本机IP禁止访问哔哩哔哩,先将请求的response保存到data.txt文件中。
使用python的json包进行解析
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
|
{
"aid": 375696064,
"videos": 1,
"tid": 17,
"tname": "单机游戏",
"copyright": 1,
"pic": "http://i0.hdslb.com/bfs/archive/85005893d4c4959ff096d6fb061040e223842bcb.jpg",
"title": "史上最骚魔法师!(第二集)",
"pubdate": 1621566911,
"ctime": 1621566912,
"desc": "本期请到了Warma参与配音!鼓掌!!!!!\n游戏:Darkside Detective\n第一集:BV1M64y1m7gA\n各位如果看得开心,希望三连支持一下!",
"state": 0,
"duration": 658,
"mission_id": 24025,
"rights": {
"bp": 0,
"elec": 0,
"download": 0,
"movie": 0,
"pay": 0,
"hd5": 0,
"no_reprint": 1,
"autoplay": 1,
"ugc_pay": 0,
"is_cooperation": 0,
"ugc_pay_preview": 0,
"no_background": 0
},
"owner": {
"mid": 546195,
"name": "老番茄",
"face": "http://i0.hdslb.com/bfs/face/bc5ca101313d4db223c395d64779e76eb3482d60.jpg"
},
"stat": {
"aid": 375696064,
"view": 1149043,
"danmaku": 7300,
"reply": 3278,
"favorite": 37490,
"coin": 98319,
"share": 1780,
"now_rank": 0,
"his_rank": 1,
"like": 210211,
"dislike": 0
},
"dynamic": "用魔法击败魔法",
"cid": 341808079,
"dimension": {
"width": 1920,
"height": 1080,
"rotate": 0
},
"short_link": "https://b23.tv/BV1jo4y117Vf",
"short_link_v2": "https://b23.tv/BV1jo4y117Vf",
"bvid": "BV1jo4y117Vf",
"score": 2446535
}
|
通过解析json格式文件并整理得到bilibili.csv
数据处理的代码如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
|
import numpy as np
import pandas as pd
import os
from urllib.request import Request, urlopen
import urllib
import requests
import json
def getDataFromFile():
if not os.path.isfile('./data.txt'):
raise TypeError("file not exist")
text = open('./data.txt').read()
return text
def getResponse(url):
headers = {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.8 5 Safari/537.36'}
data = requests.get(url = url, headers=headers).text
return data
url = 'https://api.bilibili.com/x/web-interface/ranking/v2?rid=0&type=all'
res = getDataFromFile()
jsonData = json.loads(res)
title = [] # 标题
author= [] # up🐷
view = [] # 播放量
danmu = [] # 弹幕数
coins = [] # 投币
share = [] # 分享
like = [] # 点赞
score = [] # 分数
favor = [] # 收藏
reply = [] # 评论
rank = [] # 排名
cnt = 0
for i in range(0, 104):
temp = ''
try:
videoData = jsonData['data']['list'][i]
score.append(videoData['score'])
title.append(videoData['title'])
author.append(videoData['owner']['name'])
videoStat = videoData['stat']
danmu.append(videoStat['danmaku'])
view.append(videoStat['view'])
rank.append(videoStat['his_rank'])
reply.append(videoStat['reply'])
favor.append(videoStat['favorite'])
coins.append(videoStat['coin'])
share.append(videoStat['share'])
like.append(videoStat['like'])
cnt = cnt + 1
except:
continue
outfile = pd.DataFrame({"title": title ,"author": author, "rank": rank, "score": score, "view": view, "coins": coins, "favorite": favor, "reply": reply, "danmu": danmu})
outfile.to_csv("bilibili2.csv", index = False)
|
数据分析
数据加载
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
import pandas as pd # csv文件读写分析
import numpy as np # 线性代数
import matplotlib.pyplot as plt # 制图
data = pd.read_csv('./bilibili.csv', index_col='title')
# 评分
score = data['score']
# 播放量
view = data['view']
# 投币
coins = data['coins']
# 收藏
favor = data['favorite']
# 评论
reply = data['reply']
# 点赞
like = data['like']
# 弹幕数量
danmu = data['danmu']
# 分享次数
share = data['share']
|
绘制图像,观察数据之前的关系
由图像可以得出,b站综合打分的评分和各个数据之前有一定的相关性,主要为正相关。
多元线性回归
我们的目的是得到
$f(x_i) = w^{T} x_i + b $
类似的,使用最小二乘法估计w和b
利用求解公式
$ \hat w^{} = (X^{T}X)^{-1}X^{T}y$
1
2
3
4
5
6
|
# 计算系数矩阵w-hat
w_hat = np.dot(np.dot(np.linalg.inv(np.dot(X.T, X)), X.T), Y)
# 获取b矩阵
b = w_hat[-1]
# 获取w系数矩阵
w = w_hat[:-1]
|
看查w的值
1
2
3
4
5
6
7
|
[[ 0.53588246]
[ 2.01063732]
[ 5.79443124]
[-4.91889223]
[17.51523907]
[-3.73019387]
[ 0.89537493]]
|
这里发现w系数矩阵中出现了负值,经检查发现该项目对应的自变量为like和reply,即视频的点赞次数和评论数,这与实际情况是不符的,猜测是因为该自变量对结果的影响过小,导致预测出现了偏差,同时发现弹幕数量对视频评分的影响过大,远超于其他参数,显然与实际生活不符,并且作为对视频质量的估计,弹幕数也的确不能作为一个重要的参数。
因此我们对弹幕数进行剔除重新进行拟合。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
# 获取自变量矩阵,剔除弹幕数
X = data.iloc[:,[3, 4, 5, 6, 8, 9]].values
# 获取因变量矩阵
Y = data.iloc[:,2].values.reshape(-1,1)
# 生成设计矩阵
om = np.ones(X.shape[0]).reshape(-1,1)
X = np.hstack((X, om))
# 计算系数矩阵w-hat
w_hat = np.dot(np.dot(np.linalg.inv(np.dot(X.T, X)), X.T), Y)
# 获取b矩阵
b = w_hat[-1]
# 获取w系数矩阵
w = w_hat[:-1]
print(w)
|
得到w的值为
1
2
3
4
5
6
|
[[ 0.60269881]
[ 2.82157809]
[ 5.35461617]
[ 3.04630747]
[-3.9125348 ]
[ 0.33063835]]
|
观察发现此时各项参数对于评分的影响已经较为接近正常水平。但是share,视频分享数对于评分的影响仍为负值,依然根据上述猜测,share对于总分的影响过小,导致拟合的结果差,因此再次剔除share字段。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
# 获取自变量矩阵,剔除弹幕数,分享数
X = data.iloc[:,[3, 4, 5, 6, 9]].values
# 获取因变量矩阵
Y = data.iloc[:,2].values.reshape(-1,1)
# 生成设计矩阵
om = np.ones(X.shape[0]).reshape(-1,1)
X = np.hstack((X, om))
# 计算系数矩阵w-hat
w_hat = np.dot(np.dot(np.linalg.inv(np.dot(X.T, X)), X.T), Y)
# 获取b矩阵
b = w_hat[-1]
# 获取w系数矩阵
w = w_hat[:-1]
X_test = data.iloc[:, [3, 4, 5, 6, 9]].values
Y_predict = np.dot(X_test, w) + b
|
得到w矩阵为
1
2
3
4
5
|
[[0.59149795]
[2.85961313]
[4.47955342]
[0.34492927]
[0.35243338]]
|
绘制预测值与实际值图像
观察预测值与实际值的差距,发现拟合的趋势基本吻合,但仍有较大的误差
分析得出,该线性模型的拟合误差较为集中,集中在[0, 181348.81788162683]即平均误差之间。
1
2
3
4
5
|
[0.59149795]
[2.85961313]
[4.47955342]
[0.34492927]
[0.35243338]
|
根据权重分析各个数据对总分的影响,可以发现,收藏对于视频总评分的影响占比最高,其次是硬币数,播放数,说明哔哩哔哩对与视频的质量高低评判有一定的综合考量,播放量属于可以由视频制作人通过其他方式刷取,但是收藏量是由用户对于视频质量的高低做出的决定,因而更具代表性,更有说服力。反观实际观看体验中,有些视频制作人会以视频收藏满几万后,更新下一期视频,因为该项对视频的收益影响最大,更能给视频制作人带来实际收益。
本次线性回归的拟合可以较为准确的判断出各各数据对于视频评分的影响,但是对于视频评分的预测误差较大,但是仍能较准确的判断出视频评分所影响的视频排名,认为有如下原因:
- 数据量过少,导致拟合程度不足
- 评分规则非线形模型,应该更换模型
- 还有其他未考虑的因素
如果要更准确的对视频评分进行预测,应该综合分析数据的特性,或者采用机器学习等更优秀的手段来进行求解和预测,线性回归仍有一定的局限性。