随机森林回归模型--评分预测

2023-11-06

PS:介绍代码仅供介绍,源代码后期经过修改与介绍代码不一定完全相同

索引表

  1. 使用到的库
  2. 数据加载和预处理
  3. 划分训练集和测试集
  4. 模型选择和训练
  5. 模型评估
  6. 模型优化
  7. 结果展示
  8. 尾声
    在这里插入图片描述

使用到的库

import pandas as pd  # 数据处理库
from gensim.models import Word2Vec  # 自然语言处理模型库
import numpy as np  # 科学计算库
import os # 文件操作

from sklearn.metrics import mean_squared_error # 均方误差评估
from sklearn.metrics import mean_absolute_error # 绝对误差评估
from sklearn.ensemble import RandomForestRegressor # 随机森林回归模型

import matplotlib.pyplot as plt # 绘图库
import random # 随机库
import joblib # 用于模型的保存
import datetime # 获取当前时间

数据加载和预处理

  • 初步检查数据集
初步观察,发现:
1. 有一些游戏属于当时未发行状态(TBD),数据是无效的,故删除
2. 发行日期未格式化,故用excel自带功能将日期从1-May-20修改为2020/5/1
3. 数据集里包含了一些缺失项
4. 数据集里包含了一些重复项
5. 很多字符串类型文本,需要转化为机器学习可使用的向量
6. 有的数据是以1K计数,需要转化为十进制数字
  • 读取CSV文件,并将数据集存储为一个Game_data。
# 读取CSV文件  
df = pd.read_csv('csvs/原始数据集.csv', encoding='gbk')
  • 检查数据集是否存在缺失值或异常值,如果有需要进行数据清洗和处理。
# 获取列名列表  
cols = df.columns  
  
# 遍历每一列,检查缺失值  
for col in cols:  
	# 检查该列是否有NaN  
	if df[col].isnull().any():  
		# 打印该列名称和NaN个数  
		print(col, df[col].isnull().sum())  
	  
		# 删除包含NaN的行  
		df.drop(df[df[col].isnull()].index, inplace=True)
  • 删除过于离群的点
# 获取 Rating 列  
rating = df['Rating']  
  
# 循环遍历 Rating 的值  
for value in rating:  
	# 如果值小于 2,删除该行  
	if value < 2:  
		df.drop(df[df['Rating'] == value].index, inplace=True)  
  • 检查是否有重复值,如果有则消除重复值
# 删除 Title 列重复值对应的行  
df.drop_duplicates(subset=['Title'], inplace=True)
  • ~~对于文本数据列(如 “Title” , “Team”, “Genres”),需要进行文本预处理
  • 通过引入Word2Vec库将字符串转变为矩阵向量
    <font size = "4"color = “pink”>这一段暂时先删除:
# 获取Title,Team,Genres  
Title = df['Title']  
Team = df['Team'].astype(str)  
Genres = df['Genres'].astype(str)  
  
# 对Title分词处理  
Title_sentences = [sentence.split() for sentence in Title]  
  
# 训练Title,Team,Genres的模型  
Title_model = Word2Vec(Title_sentences)  
Team_model = Word2Vec(Team)  
Genres_model = Word2Vec(Genres)  
  
# 获取词汇表  
Title_vocab = Title_model.wv.index_to_key  
  
# 创建词嵌入矩阵  
# 从model中提取词向量,保存为embedding  
Title_embedding_matrix = np.zeros((len(Title_vocab), Title_model.vector_size))  
Team_embedding_matrix = Team_model.wv.vectors  
Genres_embedding_matrix = Genres_model.wv.vectors  
  
# 将词嵌入向量保存到矩阵中  
for i, word in enumerate(Title_vocab):  
Title_embedding_matrix[i] = Title_model.wv.get_vector(word)  
  
# 保存向量矩阵  
np.save("特征/Title_Vector.npy", Title_embedding_matrix)  
np.save("特征/Team_Vector.npy", Team_embedding_matrix)  
np.save("特征/Genres_Vector.npy", Genres_embedding_matrix)  
  • 对于出现K来代替十进制的数字,需要进行修改,即把1.1K --> 1100
# 加载需要修改的数字  
K_Reviews = df['Number of Reviews']  
K_Plays = df['Plays']  
K_Playing = df['Playing']  
K_Wishlist = df['Wishlist']  
  
# 执行循环开始乘上1000  
converted_data = []  
for item in K_Reviews:  
if "K" in item:  
	item = item.replace("K", "")  
	item = float(item) * 1000  
	converted_data.append(int(item))  
	dataframe = pd.DataFrame({'Number of Reviews': converted_data})  
	dataframe.to_csv("特征/Number of Reviews.csv", index=False)  
  
converted_data = []  
for item in K_Plays:  
if "K" in item:  
	item = item.replace("K", "")  
	item = float(item) * 1000  
	converted_data.append(int(item))  
	dataframe = pd.DataFrame({'Plays': converted_data})  
	dataframe.to_csv("特征/Plays.csv", index=False)  
  
converted_data = []  
for item in K_Playing:  
if "K" in item:  
	item = item.replace("K", "")  
	item = float(item) * 1000  
	converted_data.append(int(item))  
	dataframe = pd.DataFrame({'Playing': converted_data})  
	dataframe.to_csv("特征/Playing.csv", index=False)  
  
converted_data = []  
for item in K_Wishlist:  
if "K" in item:  
	item = item.replace("K", "")  
	item = float(item) * 1000  
	converted_data.append(int(item))  
	dataframe = pd.DataFrame({'Wishlist': converted_data})  
	dataframe.to_csv("特征/Wishlist.csv", index=False)  
  • 合并以下所有参数
# 定义文件路径和输出文件  
path = '特征/'  
files = ['Rating.csv', 'Plays.csv', 'Playing.csv', 'Release Date.csv', 'Number of Reviews.csv', 'Wishlist.csv']  
output = 'final.csv'  
  
# 读取6个csv文件为DataFrame  
df1 = pd.read_csv(os.path.join(path, files[0]))  
df2 = pd.read_csv(os.path.join(path, files[1]))  
df3 = pd.read_csv(os.path.join(path, files[2]))  
df4 = pd.read_csv(os.path.join(path, files[3]))  
df5 = pd.read_csv(os.path.join(path, files[4]))  
df6 = pd.read_csv(os.path.join(path, files[5]))  
  
# 确认df1列数后修改列名  
col_nums1 = df1.shape[1]  
new_cols1 = ['Release Date', 'Number of Reviews', 'Plays', 'Playing', 'Wishlist', 'Rating']  
mapping1 = dict(zip(df1.columns, new_cols1))  

# 其他df同样修改  
frames = [df4, df5, df2, df3, df1, df6]  
  
# 使用pandas concat()方法拼接6个df  
result = pd.concat(frames, axis=1)  
  
# 输出最终的csv文件  
result.to_csv(os.path.join(path, output), index=False)

划分训练集和测试集

  • 将数据集划分为训练集和测试集
# 打乱训练集  
data = data.sample(frac=1).reset_index(drop=True)  

# 提取特征和目标变量  
features = data[['Number of Reviews', 'Plays', 'Playing', 'Wishlist']]  
label = data['Rating']
  
# 8:2 训练集测试集分割  
train_idx = int(0.8 * len(data))  
train_features = features[:train_idx]  
train_label = label[:train_idx]  
test_features = features[train_idx:]  
test_label = label[train_idx:]  

模型选择和训练

  • 因为给定数据集的特征基本涵盖了评判一个游戏的全部,特征比较完全,为了提高预测结果,所以我们构建模型的时候需要评估每个特征的重要性,我们选择随机森林回归模型来进行训练。

随机森林回归模型:

PS:适当加入以下随机森林回归模型的图片

  1. 它由多个决策树组成,并对每个决策树的预测结果取平均,得到最终的预测结果。这样可以减少模型的方差,提高预测性能。
  2. 在构建每个决策树时,它利用bootstrap抽样在训练数据中选取部分数据进行训练。这种bootstrap抽样的方式可以使每个决策树学习到不同的模式,这进一步提高了随机森林模型的稳定性。
  3. 在每个决策树结点进行分割时,它只选取部分特征进行考虑,这样可以减少相关特征之间的相关性影响,并且可以发现一些与目标弱相关但与其他特征组合后具有预测能力的特征。
  4. 它可以自然地进行并行计算,这使得随机森林模型的训练速度很快。这对大数据集很有利。
  5. 它可以评估每个特征的重要性,这在解释模型和特征选择上很有帮助。
  6. 随机森林回归模型具有减少方差,提高预测精度,强大的并行计算能力以及特征选择能力等优点。它是一个非常实用的机器学习模型,特别适用于解决回归和分类问题。它的思想也启发了许多其他的ensemble方法,如GBDT等。
# 构建随机森林回归模型  
Rating_predict_model = RandomForestRegressor(  
	n_estimators=450, # 数据集较小,不需要太多的决策树  
	max_features=2, # 4个特征  
	max_depth=3, # 限制树的深度,避免过拟合  
	min_samples_split=2,  
	min_samples_leaf=1,  
	bootstrap=True,  
	oob_score=True,
)  

# 训练模型  
Rating_predict_model.fit(train_features, train_label)
  • 模型的保存
# 将模型保存到本地  
now = datetime.datetime.now()  
model_filename = now.strftime("%Y%m%d_%H%M%S") + ".pkl"  
joblib.dump(Rating_predict_model, '数据/模型/' + model_filename)

模型评估

  • 预测
# 预测结果
predict = Rating_predict_model.predict(test_features)  
  • 均方误差评估
# 均方误差评估
mse = mean_squared_error(test_label, predict)  
print(f'随机森林回归模型MSE精度: {mse*100:.2f}%') 
  • 绝对误差评估
# 绝对误差评估  
mae = mean_absolute_error(test_label, predict)  
print(f'随机森林回归模型绝对误差评估: {mae * 100:.2f}%') 
  • 最大误差评估
# 最大误差评估  
max_error = np.max(np.abs(predict - test_label))  
print(f'随机森林回归模型最大误差评估: {max_error:.5f}') 
  • 输出
>>>进入评估环节:
随机森林回归模型均方误差评估: 16.75%
随机森林回归模型绝对误差评估: 31.63%
随机森林回归模型拟合度评估:   34.25%
  • 描述:

    1. 均方误差为 16.7%,这属于比较理想的水平,表明模型的预测效果比较准确,与实际值的偏差不是太大,可以基本满足较高精度的需求。但仍有进一步提高的空间。
    2. 绝对误差为 26.07%,这属于中等的水平。表明模型的单个预测效果不是最稳定的,可能会出现一定程度的偏差,模型的稳定性可以进一步提高。但总体而言,单个预测的误差也还在可控范围内。
    3. 最大误差为 0.78%,这是一个很低的误差,表明模型的预测极端情况下的效果也比较稳定,没有出现太严重的失控预测。
  • 问题:

    • 模型泛化能力不足
    • 训练数据不足

模型优化和调整(有意加入对字符串处理的训练)

待定

结果展示

  1. 游戏评分与实际评分的差异分布
# 设置窗口大小
plt.figure(figsize=(12, 6))  
  
# 设置纵坐标最大值为 8plt.ylim(0, 8)  
plt.ylim(0, 8)

# 预测集 predict 的折线图,蓝色  
plt.plot(predict, color='blue', label='predict')  
  
# 测试集 test_label 的折线图,红色  
plt.plot([value for index, value in test_label], color='green', label='test_label')  
  
# 备注  
plt.xlabel('number')  
plt.ylabel('Rating')  
plt.title('Predict VS test')  

# 显示图例  
plt.legend()  
plt.show()

![[模型在测试集上的预测表现.png|550]]

  1. 展示随着训练数据的增加,模型的均方误差不断减小的图
# 初始训练集为空  
X_train = np.empty((0, features.shape[1]))  
y_train = np.empty(0)  
  
# 训练模型  
mae_scores = []  
print(">>>训练模型阶段:\n")  
for i in range(len(train_features)):  
	# 读取第i条训练数据  
	new_x = features.iloc[i]  
	new_y = label.iloc[i]  
	  
	# 添加到训练集  
	X_train = np.concatenate((X_train, new_x.values.reshape(1, -1)), axis=0)  
	y_train = np.concatenate((y_train, np.array([new_y])), axis=0)  
	  
	# 训练模型并在测试集上评估  
	Rating_predict_model.fit(X_train, y_train)  
	predict = Rating_predict_model.predict(test_features)  
	mae = mean_absolute_error(test_label, predict)  
	mae_scores.append(mae)  
	print(f"已训练{i}次,当前训练集量为{len(X_train)}条,MAE均方误差为{mae*100:.3f}%")  
print("\n>>>模型训练完成!\n")

# 画图
plt.plot(mae_scores)  
plt.xlabel('data number')  
plt.ylabel('scores')  
plt.title('mae_scores')  
plt.show()

尾声

数据集只有1500组,虽说是从上世纪到现在的全部质量还不错的游戏,不免让人有些感慨 1. 游戏开发的难度较大 2. 游戏类型和机制的创新空间有限 总体来说,这一现象的产生有多方面的原因,不仅仅局限于数据采集本身,更受游戏开发难度、创新发展瓶颈和产业成熟度的制约。但随着技术的进步、人才的培养和产业的发展,高质量游戏的数量会不断增加,这也为未来的游戏体验带来更多期待。 人类历史上真正影响深远的作品永远是稀缺的,这体现在各个文化领域。游戏作为一种比较年轻的文化形式,其精品游戏的数量相对而言会少一些也在情理之中。但我相信,随着时间的推移,这一数量会不断丰富,为游戏文化的繁荣与传承做出更大贡献。

最后附上一些图

在这里插入图片描述
在这里插入图片描述
PS:这篇文章本来是自己的一个笔记,因为要换设备,也不想保存在本地,索性就发上来了/doge,代码可能和实际会有一些出入,学一学就好,展示代码不一定能跑起来,估计也没人看hh

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

随机森林回归模型--评分预测 的相关文章

随机推荐

  • git fatal: unable to access  Failed to connect to localhost port 1080: Connection refused

    git 拉取 更新子模块失败 提示失败 Submodule libXesBase https git xxxxx com xesoa libXesBase git registered for path libXesBase Cloning
  • 整合google,51ditu和mapbar的地图API

    http blog 163 com goodluck lq 126 blog static 63285386201001994058213
  • Java中的异常处理机制的简单原理和应用。

    异常是指java程序运行时 非编译 所发生的非正常情况或错误 与现实生活中的事件很相似 现实生活中的事件可以包含事件发生的时间 地点 人物 情节等信息 可以用一个对象来表示 Java使用面向对象的方式来处理异常 它把程序中发生的每个异常也都
  • 基于STM32F103单片机的车牌识别图像处理识别系统 原理图PCB程序设计

    硬件电路的设计 末尾附文件 系统硬件系统分析设计 1 STM32单片机核心电路设计 STM32系列处理器是意法半导体ST公司生产的一种基于ARM 7架构的32位 支持实时仿真和跟踪的微控制器 选择此款控制芯片是因为本系统设计并非追求成本的最
  • React通过axios拿到数据后,使用hooks,通过map函数对列表进行渲染

    导入hooks 导入你封装的http模块 引入样式 import React useEffect useState from react import http from API import index scss 默认导出一个函数组价 并
  • C#学习记录——.NET的三层架构

    每一个不曾起舞的日子 都是对生命的辜负 尼采 每一个不读书的的日子 都是对时光的辜负 今天学习 零基础学C 3 0 NET的三层架构 为了实现大型应用系统后续功能的扩展性和程序的灵活性 NET编程语言借鉴了JAVA的MVC思想 产生了三层架
  • MySQL - 第9节 - MySQL内外连接

    目录 1 内连接 2 外连接 2 1 左外连接 2 2 右外连接 3 简单案例 1 内连接 表的连接分为内连接和外连接 内连接实际上就是利用where 子句对两种表形成的笛卡儿积进行筛选 我们前面学习的查询都是内连接 也是在开发过程中使用的
  • Markdown语法--Obsidian笔记

    Markdown 语法 笔记 文章目录 Markdown 语法 笔记 语法分类 文字层级类 1 标题 2 段落 3 区块引用 4 代码区块 5 列表 6 待办事项 文字格式类 1 样式 2 表格 链接引用类 1 链接 2 图片 3 脚注 4
  • Dubbo与Spring Cloud的区别

    这是个老生常谈的问题 每个技术团队在业务转型微服务化架构的时候都会纠结过这个选型问题 首先 dubbo 之前确实在 2012 年的时候发布了最后一个版本 2 5 3 并且停止维护更新 在2017年的时候又 起死回生 官方宣布重启更新 并重点
  • 2021图像检索综述

    论文地址 Deep Image Retrieval A Survey 本文是2021年最新的关于图像检索的综述 介绍了基于内容的图像检索 content based image retrieval CBIR 在深度学习技术上的进展 目录 0
  • Traceback (most recent call last): File “D:/python_workspace/hello.py“, line 3, in <module>

    错误背景 python的初学者 在学习多行语句 错误信息如下 错误原因 变量有字符串类型 有整型类型 有浮点型 在java 里面 String标识字符串类型 Int标识整型 在python里面 a yy1 就是字符串类型 a 1就是数字类型
  • 29_content 阶段的concat 模块

    文章目录 提升性能 content 阶段的 caoncat 模块 concat 模块的指令 示例配置 提升性能 content 阶段的 caoncat 模块 功能 当页面需要访问多个小文件时 把它们内容合并到一次http 响应中返回 提升性
  • 数组排序的方法?

    1 sort排序 let arr 1 2 3 4 5 6 7 8 9 0 9 8 7 6 3 4 5 5 var res console log arr 排序前 1 2 3 4 5 6 7 8 9 0 9 8 7 6 3 4 5 5 arr
  • SSD目标检测算法原理(上)

    目录 一 目标检测概述 1 1 项目演示介绍 1 2 图片识别背景 1 3 目标检测定义 二 目标检测算法原理 2 1 任务描述 2 2 目标检测算法必备基础 2 3目标检测算法模型输出 目标检测 overfeat模型 R CNN模型 候选
  • h2database源码解析-查询优化器原理

    目录 一 成本计算规则 二 单表查询 三 多表关联查询 一 成本计算规则 h2的查询优化器基于成本的 因此在执行查询前 会基于成本计算使用哪个索引 如果涉及多表关联 还会计算不同表关联顺序的成本 最终基于最小成本得出执行计划 单表查询时 遍
  • 树莓派驱动开发简单案例完整过程(动态加载驱动)

    1 下载树莓派os镜像 https www raspberrypi org downloads raspbian 2 使用命令 uname a 查看树莓派内核 Linux raspberrypi 4 19 118 v7 1311 SMP M
  • JQuery筛选器

    jQuery提供了强大的选择器让我们获取对象 在这边 我人为地将jQuery选择器分为两大部分 选择对象和筛选条件 选择对象表示要获取什么对象 筛选条件是对获取的对象进行筛选 最终留下符合某些特征的对象 1 选择对象1 基本 id根据给定的
  • VC++、MFC中最好的开源项目

    介绍一下用VC MFC写的最好的开源项目 Sourceforge net中有许多高质量的VC 开源项目 我列举了一些可以作为VC 程序员的参考 一 优秀的开源项目 7 Zip http sourceforge net projects se
  • react项目路由组件懒加载方法对比,@loadable/component和react-loadable和suspense lazy

    1 使用 loadable component方法 推荐使用这个 npm install loadable component S 先安装一下 2 在app js中引入 loadable component import Loadable
  • 随机森林回归模型--评分预测

    PS 介绍代码仅供介绍 源代码后期经过修改与介绍代码不一定完全相同 索引表 使用到的库 数据加载和预处理 划分训练集和测试集 模型选择和训练 模型评估 模型优化 结果展示 尾声 使用到的库 import pandas as pd 数据处理库