当前位置: 首页 > news >正文

pyspark实现基于协同过滤的电影推荐系统

最近在学一门大数据的课,课程要求很开放,任意做一个大数据相关的项目即可,不知道为什么我就想到推荐算法,一直到着手要做之前还没有新的更好的来代替,那就这个吧。

推荐算法

推荐算法的发展由来已久,但和机器学习一样,没有大量的算力和数据作支撑达不到好的效果,直到如今高速网络和大数据时代才发展得如火如荼。

推荐算法具体有几种:协同过滤,基于内容,基于知识,和混合过滤,具体的知识可以看该文章,简单总结如下:

协同过滤:基于分类的推荐,把用户或物品按类划分,在同类中互相推荐对方的喜好,比如两个都喜欢看动作电影的用户,其中一个又喜欢看爱情片,就把爱情片也推给另一个同样喜欢看动作电影的用户。
该方法根据划分的对象不同,又可以分为基于用户和基于物品两种,后面会对协同过滤算法作稍微详细的介绍。

基于内容:该方案逻辑更为严谨,可以通过用户画像,设定的大致喜好来推荐,该算法需要对物品的特征进行计算,找到最符合用户喜好的几个物品进行推荐。

基于知识:这单独分类就有点牵强了,基于知识的推荐其实就是更严谨的协同过滤和内容推荐,该算法会构造用户的需求列表,根据该列表与物品的相似程度进行推荐,比如高档耐用品用户在满足后就没有了需求,像房子,汽车等,当用户拥有以后就没必要再继续推送。

混合过滤:顾名思义,就是结合多种方法的推荐算法,比如把前面三种方法输入到一个神经网络,最后拟合出一个结果来,希望结合各自的优点,克服他们的缺点。

协同过滤

该算法的核心思想是将被推荐者的同类找出来,基于用户和基于物品的区别,举个例子就是分别找到和你一样喜欢看动作电影的人,把他的其他喜欢推荐给你;和找到和动作电影比较类似的其他电影,把这些电影推荐给喜欢看动作电影的人,这两步殊途同归,而同时都有一个重点——如何衡量相似

相似是我们日常形容的一种感觉,而对计算机来说是可以用数学量化计算的,如余弦相似度,欧几里得距离,皮尔森系数等,其他详细计算方法可见该文章。

相似度计算

本项目中以皮尔斯相关系数作为相似度的衡量标准,表示两个矩阵协方差与标准差的商,计算公式如图:
皮尔斯相关系数
具体计算方法可见该文章,我们编程实现时更多关注其运算规则和返回值即可,该方法返回一个矩阵,对角元素表示其与自身的相似度—为1[0,1][1,0]位置为两矩阵的相似度,该计算方法在np库中有现成的使用方法,示例如下:

    # 计算两个用户的皮尔逊相关系数,越靠近1,表示越相关# 返回相关系数矩阵2*2的矩阵,对角线表示与自身的相关系数,[0, 1](或[1, 0],它们是相等的)则是matrix1和matrix2之间的相关系数pearson=np.corrcoef(matrix1, matrix2)[0, 1]

相似度取值为[-1,1]越大表示越相关,计算出相似度后即相当于找到类似的群体,再推荐该群体的喜好给用户即可。

但在大数据时代中,在动辄几十上百万条的数据里逐条记录计算相似度并推送不那么优雅也不那么准确,并且矩阵中大部分数据都为0,是一个稀疏矩阵,因为很少有人能评价数据库中的所有物品,故数学家研究能不能把这么多记录的大数据矩阵拆成更小的矩阵呢?

SVD奇异值矩阵分解

奇异值矩阵分解可以实现将m×n的矩阵拆解为m×m正交阵、m×n对角阵,多的行列全为0、n×n正交阵三个矩阵,我们可能回想,这拆完其实比之前还大,拆解还有什么意义?
其中对角阵对角线的值我们称为奇异值,奇异值从大到小排列,所以通常我们使用前几位的奇异值组成对角阵,就已经可以大差不差地构造出原有矩阵来,具体原理见该文章。即我们可以将该矩阵压缩为m×rr×rr×n三个矩阵,此时的r我们可以自由选取,这样一来就可以大大压缩矩阵的空间了,实现代码展示如下:

arr1=np.random.randint(0,100,(5,5))
print(arr1)
# svd 分解得到矩阵
a,b,c=np.linalg.svd(arr1)
# 为了节省内存,对角阵使用一维数组保存,故需将其展开
b=np.diag(b)
# 一维数组值到对角线,其余填充0

分别输出后展示如下:
svd分解矩阵展示
随后我们尝试对该矩阵进行压缩,计算后得到的矩阵分别取前k位,方法代码如下:

def get_svd(matrix,k):U, sigma, VT = np.linalg.svd(matrix)# 主对角线数组值,其余均为0,展开sigma=np.diag(sigma)# 截取前k个奇异值U_k=U[:, :k]sigma_k=sigma[:k, :k]VT_k=VT[:k, ]return U_k, sigma_k, VT_k

k取3,即5维矩阵保留前3维奇异值,执行展示如下:
svd压缩
可以看到损失变化并不很大,此时因为我们的矩阵并不稀疏,且压缩率为百分之二十,所以可以说压缩效果相当好。

隐向量

原本纵坐标代表用户,横坐标代表物品,压缩后矩阵不完整,取而代之的是r,那这个r代表什么呢?我在视频中看到如下例子(原视频链接)
原始矩阵
隐向量矩阵
这是一个音乐推荐系统,原有矩阵经过分解,压缩的r取3,用户和歌曲被一个3×3的矩阵联系起来,我们感性上可以把他认为是歌曲种类,但这并不准确,因为r的值具体取多少并不固定,这类似于机器学习中的网络,网络把我们的特征计算得到一个结果,这个结果并没有什么实在意义,但计算机能计算并拟合就足够了,我们将其理解称为计算机做得一个分类也就可以了,这个分类在矩阵分解中被称为隐向量

矩阵分解的应用

说到这我们还没明白,拆解了矩阵以后又怎么样呢?我们从大矩阵得到了小矩阵,并且能利用该小矩阵近似恢复出大矩阵,我们在推荐的时候到底该怎么用这个矩阵呢?

在协同过滤中,使用矩阵分解方法时,我们实际上是在根据用户向量来生成推荐物品矩阵的预测,即获得了r×n的矩阵后,由用户1×r的输入特征,即可获得1×n的用户关于所有物品喜好程度的预测矩阵,我们推荐时只需根据该矩阵即可。
我们由以往基于用户或物品计算相似,粗糙地选择相似者喜好推荐的方法,转变为生成一张近似但量化的,关于用户对所有物品喜好的特征向量来进行推荐,相比较矩阵分解方法更为优雅和准确。

但到这里我想了一个问题,这种方式还叫协同过滤吗?,并没有直接和其他用户和物品协同,这种纯数学的方法是否还符合协同过滤的定义呢?有关问题我问了文心一言,他的解答我直接放在下面以供参考
矩阵分解和协同过滤的关系

数据处理

数据集来自该链接,目录如下:
电影数据集目录
不同文件分别为:影评、电影信息、演员信息、评分信息和用户信息,其中电影又包含电影长度、海报等等信息,具体介绍可以见其中的README
该数据集可以说十分详细,但稍微有些旧,是2019年的,另外是实在太大了,我要构建矩阵时pycharm提示需要153GB的内存。
内存报错信息
以目前想当然来看,应该可以是分批多次读取再组合的,但是因为本次只是一个尝试,就不研究真实大数据条件下的操作了,重点侧重与算法,与项目的完成上,故首先要对数据进行缩减。

先从电影入手,把不包含海报链接的去掉,再把没有豆瓣评分和演员信息等的去掉,最终只保留下两千条数据,再使用这两千条电影的id,在评分文件ratings过滤记录,代码如下:

import pandas as pdfile_source='E:\\software\\DataBase\\Data\\movie_data\\new_movies.csv'
old_source='E:\\software\\DataBase\\Data\\movie\\ratings.csv'
save=pd.read_csv(file_source)
data=pd.read_csv(old_source)
# 获取指定列的值
value_tosave=save["MOVIE_ID"]# 过滤后的数据
filtered_data = data[data['MOVIE_ID'].isin(value_tosave)]# 保存过滤后的数据
filtered_data.to_csv('E:\\software\\DataBase\\Data\\movie\\new_ratings.csv', index=False)

大概步骤为:
先获取电影文件中的电影ID
在评分文件中匹配该ID,符合的保存在变量中;
最后将数据写入csv文件。

同理需要使用排名文件对用户文件进行过滤,此时注意,因为用户名包含中文信息,故在保存csv文件时需要指定编码为utf-8,故保存代码修改为filtered_data.to_csv('E:\\software\\DataBase\\Data\\movie\\new_users.csv', index=False,encoding='utf-8-sig')

过滤前后文件大小对比如下:
文件大小对比
电影数目由十四万降至两千八,打分数目由一百四十万降至十九万,用户数量由六十四万降至八万,此时的数据量计算机大概可以处理了。

但裁后计算svd发现,还是需要50个G的内存,看来分布式系统是不可不用了。
裁后矩阵

Spark系统

大数据框架

之前总是专注算法,对大数据还是一直停留在直观印象上,觉得无非就是数据大一些,记录多一些,但突然想到,这些表象最直接地反映在编程思想上:以往的程序单机运行即可,速度慢的时候只要换一台新的服务器就能得到很好的效果,但到了大数据时代,单个服务器再强也是不可能满足运行要求,故在编程中就要采用分治思想,使用分布式进行计算

目前主流的大数据框架有Hadoopspark,详细介绍和对比可见该文章,二者都是Apache的框架,目前将其理解对比如下:
Hadoop:2012年提出的第一款大数据框架,主要理念为map/reduce,其中map负责数据集的拆解,reduce负责对拆解后的数据集进行运算,其中隐含层为shuffle负责对拆解的数据进行排序归并等操作,总的来说是将大数据采用总分总的形式运行,借助分布式文件系统HDFS实现,如果有计算集群则可以大幅度提升运行效率。
Spark:2014年提出的新一代大数据框架,改进了原有map/reduce,转而使用RAM进行数据暂存,相比更快,并用弹性数据集RDD取代原本HDFS,并且支持Hadoop,其详细教程可看该视频,和极客教程。但具体来说其仅为分布式计算框架,解决了Hadoop原有基于磁盘的效率问题,用内存操作代替了频繁读写磁盘,序列化等步骤,数据在执行完毕前不落地,加快了计算效率,而存储结构仍使用原有的分布式文件系统HDFS

安装部署

本次实验在Windows上进行,但因为没有服务器集群,故部署为单机,大致部署思路如下:
1,配置Java环境,spark是基于Java编写的,必须要有相应的Java环境。
2,安装spark包,官网下载解压到目录即可。
3,配置环境变量
4,bin文件替换,spark是基于Linux系统,若要在Windows中使用需要替换相关文件

具体操作基本可以参考该文章,本地部署无需使用hadoop的可以将相关操作全部指向spark文件即可,配环境确实十分困难,最后我也不知道怎么配好的,甚至没法复现也不敢再重新来过,目前的教训就是一定注意版本对应

RDD

spark的数据操作基于弹性数据集RDD完成,具体操作可见该文章,一次简单读取文件并输出的示例如下:

from pyspark import SparkContext,SparkConf
# 根据对象名和部署模式获取sparkcontext对象
conf=SparkConf().setAppName("test").setMaster("local")
sc=pyspark.SparkContext(conf=conf)
path="file:///E:\\software\\DataBase\\Data\\movie_data\\new_movies.csv"
# 对象读取文件,获得RDD
data=sc.textFile(path)
# 或者使用parallelize生成对象集合
data=sc.parallelize(List(1,2,3,4))
# 遍历输出
data.foreach(print)

操作函数分为转换和动作两种,其中转换类有

filter(func) 		# 过滤,满足func的元素返回新的数据集
map(func)			# 映射,元素传入func中,计算返回数据集
flatMap(func)		# 与map相似,但输入元素可映射0到多个结果
groupByKey()		# 将键值对的数据集按键分组
reduceByKey(func)	# 分组后用func进行计算

动作类函数有:

count()			# 返回元素个数
collect() 		# 以数组形式返回元素
reduce(func)	# 通过func聚合元素
foreach(func)	# 每个元素传递到func中运行
first()			# 返回第一个元素
take(n)			# 返回前n个元素

spark在编程使用时的确具有很多不同特性,作为了解记录如下:
1,惰性机制。spark在执行中采取有向无环图的形式,每个转换操作如map只是记录动作,只有遇到动作reduce才开始执行。
2,RDD只读。RDD在执行生成后不可修改,我们操作的新变量实质是其拷贝版本,这些不同的拷贝构成了有向无环图的节点,这给我们恢复系统状态提供了方便,同时因为计算不结束不落地,减少磁盘开销,提高了效率。
3,粗颗粒度。只能整体转换,不能只修改其中一条。

DataFrame

RDD只给了数据按行操作的能力,有时我们要对数据进行按列的操作甚至更细比如按标签操作时就无法实现了,以及非关系型数据难以用于机器学习的困境,基于此SparkSQL提供了类似pandas的DataFrame操作,其大概原理是将sql语句转为spark,该方法给spark处理大规模结构化数据的能力,同时也比RDD更简单易用,且计算效率更高。

大概使用方法如下:
from pyspark.sql import SparkSession导入包
spark=SparkSession.builder.config(conf=SparkConf()).getOrCreate()创建实例对象

df=spark.read.csv(path)从文件读入,或使用spark_df = spark.createDataFrame(pandas_df)pandas数据中读入创建DataFrame
df.show()展示数据
df.select(列名)实现按列选取数据
df.write.csv(new_path)保存数据

部分操作函数如下:
df.printSchema()展示结构信息
df.filter()条件如df["age"]>10实现按条件过滤
df.groupby("列名")实现分组
df.sort(df['age'].desc())实现按年龄降序排序

工程实践

其实该算法最关键的就是根据已有的打分矩阵计算svd分解并压缩后的矩阵VV矩阵与用户输入矩阵做矩阵乘法就可以生成一张用户关于每部电影的预测矩阵,后续可以根据该矩阵给用户推荐,关于spark使用svd的官方教程在此,目前打算构建成一个前后端交互项目,前端将用户打分数据传到后台,后台推荐算法把推荐的电影信息给前端展示,流程大概如下:
推荐系统流程图
其中后端推荐算法主要是将用户特征向量与V矩阵做矩阵乘法获得预测矩阵,根据该矩阵给用户推荐电影,流程图如下:
推荐系统流程图
文件代码结构如下:
代码结构
其中internet文件负责处理网络信息,main为主函数,matrix_calculate负责把大打分矩阵拆解压缩出V矩阵,recommend实现给用户推荐的具体算法。

主函数

因为本项目为前后端交互,故采用socket模式,死循环内监听端口,接受处理信息,并发送信息给客户端,主函数代码如下:

import recommend
import pandas as pd
import socket
import internet
score_matrix=pd.read_csv('"E:\\software\\DataBase\\Data\\movie_data\\ratings_matrix.csv',header=0,index_col=0)
predict_matrix=pd.read_csv('"E:\\software\\DataBase\\Data\\movie_data\\predict_matrix.csv',header=0,index_col=0)
if __name__ == '__main__':sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  # 实例化对象sock.bind(('ip', 1111))  # 绑定IP端口sock.listen(2)  # 监听端口,允许排队的个数为nconn, addr = sock.accept()  # 获取连接对象和地址while True:try:print("等待客户端发送数据...")data = conn.recv(1024)  # 接收文件数据if not data:breakprint("收到:", data.decode())# 电影id,评分movie_list,score_list, = internet.parse(data.decode())# 信息更新到数据库internet.receive(movie_list, score_list)# 建立用户向量,指定user用户分解矩阵user_vector=recommend.zip_user_vector(score_matrix,"user")# 获得k个预测结果movie_id=recommend.predict_movie_id(user_vector,predict_matrix,20)# 在电影表中查找信息movie_list=recommend.predict_movie(movie_id)# 电影信息发送给前端internet.send_recommendation(conn,movie_list)except:print("连接断开")

预测矩阵spark计算

该节是最体现大数据工作的地方,也是本次项目不得不用大数据框架之处,2k电影×8万用户的打分矩阵计算svd矩阵分解在个人电脑上会直接内存溢出,如果用原始数据想必服务器也遭不住,所以该方法一定需要分布式计算来负载压力。

同时该部分是我卡的最久的地方,首先spark语法不清楚,内部使用的数据结构不了解,每步执行都处在为什么报错和为什么能执行的疑惑中,如今结束了再次整理思路:
1,svd分解pyspark有现成的库,调库computeSVD即可实现,其中参数k表示取前k个奇异值
2,computeSVDRowMatrix的一个方法,故执行前要先将数据转为RowMatrix,但该结构又是一个分布式矩阵,在本地使用前要先收集一下,相关介绍如下:

RowMatrix是ApacheSparkMLlib库中的一个类,它表示一个分布式行矩阵。
它主要用于对大规模数据集进行线性代数操作,如奇异值分解(SVD)、主成分分析(PCA)等。RowMatrix的每行都是一个向量,并且这些向量可以分布式地存储在集群的不同节点上。
这使得它特别适合处理大型数据集,因为它允许在分布式环境中进行线性代数操作,而不需要将所有数据加载到单个节点上。

3,分解矩阵u,s,v分别是三种不同类型的矩阵,要分别处理保存,相关介绍如下:

    U:左奇异矩阵,类型为RowMatrix。它是一个分布式行矩阵,其中包含了SVD分解后的左奇异向量。由于它是一个分布式矩阵,因此无法直接像本地矩阵那样进行操作,但可以通过其方法(如rows)来访问其行数据。s:奇异值向量,类型为Vector。它是一个包含所有奇异值的向量,这些奇异值按照从大到小的顺序排列。这个向量是一个本地向量,可以直接在驱动程序中进行操作。V:右奇异矩阵,类型为Matrix。它是一个本地矩阵,包含了SVD分解后的右奇异向量。这个矩阵可以直接在驱动程序中进行操作,例如进行矩阵乘法或提取特定的列向量。

4,该过程计算量大,耗时长,执行前无比谨慎,别因为一点小问题白费一个小时的等待。

计算过程直接展示代码:

def caculate_svd_v(csv_path):start_time = time.time()print("正在加载spark...")conf = SparkConf().setAppName("svd").setMaster("local")sc = SparkContext(conf=conf)print("正在加载数据...")# 直接使用textFile的方式读取数据,然后再进行map操作raw_data = sc.textFile(csv_path)raw_data = raw_data.map(lambda x: x.split(","))matrix = RowMatrix(raw_data)print('矩阵构建完成')print('开始计算SVD...')# 是否计算U矩阵,压缩阶数k为15svd = matrix.computeSVD(15, computeU = True)cost_time=time.time()-start_timeprint("计算完成,耗时:",cost_time)print("正在转化矩阵为pandas...")df_u = row_to_df(svd.U)df_s=pd.DataFrame(svd.s.toArray())df_V=vector_to_df(svd.V)print("正在保存结果...")df_u.to_csv("E:\\software\\DataBase\\Data\\movie_data\\u.csv")df_s.to_csv("E:\\software\\DataBase\\Data\\movie_data\\s.csv")df_V.to_csv("E:\\software\\DataBase\\Data\\movie_data\\v.csv")

其中转化pandas过程中有两个函数需要自行编写,分别处理RowMatrixVector,代码展示如下:

def row_to_df(vector):# collect 方法将分布式向量转换为本地向量,然后将其转换为pandas数据框print("正在转化u矩阵...")# 返回一个列表u=vector.rows.collect()print("计算U矩阵规格为:",len(u),"*",len(u[0]),"=",len(u)*len(u[0]))return pd.DataFrame(u)
def vector_to_df(dense_matrix):# 用于将dense矩阵转换为pandas数据框print("获取到dense的值为:",dense_matrix)print("正在转化V矩阵...")# 获取行列数rows = dense_matrix.numRowscols = dense_matrix.numColsprint("计算V矩阵规格为:", rows, "*", cols,"=", rows * cols)value=dense_matrix.toArray()# 获得np值nplist=list(value)v_list=np.array(nplist).reshape(rows,cols)# 根据np值转为pandas数据框df=pd.DataFrame(v_list)print("获取到的pandas值为:",df)return df

这部分开始一直报错也是因为不了解其中的结构,要对矩阵s,u,v分别输出时发现总也不行,仔细看看会发现其实是类型问题,此时再根据类型去查解决方案即可,计算机中遇到的每个问题都有前人解决过,只要把问题问得够具体够详细,就没有解决不了的困难。

但该步仍有疑问没能解决:
1,单机如何实现性能扩展
spark负责分布式计算的资源调度和负载均衡,可以用集群的力量解决一个大问题,但本次实验中,spark采用单机部署,并没有其他计算机可供spark调度,它是如何实现大矩阵运算而不内存溢出呢?

2,文件读入方式不同导致崩溃
上述代码几乎重构过三次,第二次时我为了借助pandas库对标签过滤的方便,选择将数据先读入pandas,再由pandas传给RDD,到此都一切顺利,而等到计算svd时又会出现内存溢出错误。当时观察了RDD输出都和spark直接读取文件无异,其背后原因到目前尚不得解。

推荐流程

该部分实现四个函数:
1,计算svd的k阶压缩。spark加载计算较慢,处理后的V矩阵和用户矩阵可以用本机环境直接计算,故需自行编写该函数。
2,计算用户的特征向量。计算V矩阵时将隐向量设置为15,大意为15种电影类型,用户的标记也应该压缩到对15种电影的标记,该步使用svd分解压缩法实现。
3,计算预测矩阵并返回其中前k个最大值的电影id。V矩阵与特征向量做点积生成预测矩阵,因为只针对一个用户预测,故该矩阵其实是一个向量,在向量中选取前k个索引,到电影表中查找对应的电影id。(为了免去对indexcolumns的过滤处理,我单独设置了一张不含标签纯打分信息的表nolabel,该过程增加了磁盘开销,但减少了我的大脑开销)
4,根据电影id在电影表中查找电影信息。该步就比较简单了,用pd.loc索引查找电影id,相关电影信息加入列表即可。
四个函数的代码展示如下:

def get_svd(matrix,k):# 根据矩阵计算svd,并取前k个奇异值U, sigma, VT = np.linalg.svd(matrix,full_matrices=False)# 主对角线数组值,其余均为0sigma=np.diag(sigma)# 截取前k个奇异值U_k=U[:, :k]sigma_k=sigma[:k, :k]VT_k=VT[:k, ]return U_k, sigma_k, VT_kdef zip_user_vector(file,user_id):# 负责将用户特征向量分解成3个矩阵,分别是U,S,VT,只用U作为用户的特征向量print("正在计算用户特征向量...")record=file.loc[user_id].valuesprint(record)print(record.shape)print("正在分解用户矩阵")record=record.reshape(5, -1)# 隐向量压缩为15u,s,v=get_svd(record,3)u=u.reshape(1,-1)print("分解后的矩阵格式为:", u.shape)print("分解后的矩阵为:", u)return udef predict_movie_id(user_matrix,predict_matrix,k):# 给出k部预测的电影idprint("正在预测用户评分...")matrix=np.dot(user_matrix,predict_matrix)# 将数组降序排列,返回数组的索引print("正在选择电影")sort_list=np.argsort(matrix)[::-1]# 选前k个最大值的索引index_list=sort_list[0][0:k]print("获得电影索引为:",index_list)# 根据索引查找电影idmovie = pd.read_csv("E:\\software\\DataBase\\Data\\movie_data\\blank_ratings_matrix.csv", header=0, index_col=0)label = movie.columnsmovie_id=[]for i in index_list:movie_id.append(label[i])print("预测结果为:",movie_id)return movie_iddef predict_movie(movie_id):# 根据电影id在表中查找相关电影信息df=pd.read_csv("E:\\software\\DataBase\\Data\\movie_data\\new_movies.csv",header=0,index_col=0)movie_list=[]for i in movie_id:# csv文件中id为整型i=int(i)movie_list.append(df.loc[i])return movie_list

综合使用如下代码进行推荐:

# 获得用户向量
user_vector=zip_user_vector(pd.read_csv('E:\\software\\DataBase\\Data\\movie_data\\ratings_matrix.csv',header=0,index_col=0),"user")
# 获得预测电影id
movie_id=predict_movie_id(user_vector,pd.read_csv('E:\\software\\DataBase\\Data\\movie_data\\predict_matrix.csv',header=0,index_col=0),3)
# 根据id查找电影信息
print(predict_movie(movie_id))

输出结果如下:
推荐电影信息
目前可以实现推荐功能,但因为数据集问题,其中记录有重复的,因为算法本身依赖数据集格式,时间精力有限,故暂时不作调整。

报文解析

该部分就两个功能:
1,将前端传来的数据解析成电影id和打分情况,写入打分表文件。
2,将后端生成的电影信息发送到前端。

直接展示代码:

def receive(movie_list,score_list):# 接受电影id和打分情况并写入文件file=pd.read_csv("E:\\software\\DataBase\\Data\\movie_data\\ratings_matrix.csv",header=0,index_col=0)for i in range(len(movie_list)):file.loc["user",movie_list[i]]=score_list[i]file.to_csv("E:\\software\\DataBase\\Data\\movie_data\\ratings_matrix.csv")def send_recommendation(conn,movie_list):for i in movie_list:conn.send(i)

总结

要说推荐系统也从属于机器学习?我是有点doubt的,它可一点没学全是我教的。不过就到现在的学习经历来说,计算机内的定义和区分并不十分严谨和界限分明,流传的很多说法甚至根本不是它的真正意思,只是因为它看起来是这样而一直被这么叫,所以实现之前不管对方是大佬还是小白,多问一嘴也是给自己省事。

该项目实现了简单的推荐系统,浅尝了一次推荐算法,再次搞了前后端的交互,要说读了研就是不一样,这项目含金量比起本科不知道高了多少,可跟实际情况比起来还是差很多,但毕竟只是个作业,了解到这一步我觉得已经极限了,对于刚入学两个月的我,做到这我认为已经极限了,对不一定当作主要方向,纯粹爱好驱动的尝试,也已经极限了。

总结与展望:
1,真正的大数据。不说上亿条数据,起码把整个数据集跑起来吧,这期间需要应该要学一些性能优化的方法。
2,改进的推荐算法,算法在实际应用中可能仍然不够实际,相关算法也有改进算法可以使用,甚至直接自己改进算法也不是不可能的。
3,优化安全的前后端。到目前前后端通信框架从来没使用过,安全性健壮性压根没考虑,只是单纯从实现角度完成,看现在行情都是要全栈,开发岗应该对整个流程都是要花点心思。

写在后面

前面的总结都是写于算法原理的初步探索阶段,在求知欲得到满足的快乐时期,真正实现起来,暂时想不到比一步一个坑更雅的说法。当时的很多小想法到现在都被磨平了,现在只觉得尽快实现比什么都重要,可以看到在我的代码中不乏简单粗暴和力大飞砖——反正电脑累总比我累强;另一方面也是期末时间紧任务重,不太有精力和心境去慢慢打磨作品了,再加上可能人知道的越多就知道自己有更多不知道的,到现在结束阶段只觉得项目实在粗糙,甚至像小孩过家家,不过还是不能站在当下嘲笑过去幼稚的自己,最近的话怎么说:那不是小丑,那是我的来时路,写csdn一方面算是做笔记,另一方面也算记录自己的成长之路。

相关文章:

pyspark实现基于协同过滤的电影推荐系统

最近在学一门大数据的课,课程要求很开放,任意做一个大数据相关的项目即可,不知道为什么我就想到推荐算法,一直到着手要做之前还没有新的更好的来代替,那就这个吧。 推荐算法 推荐算法的发展由来已久,但和…...

视觉语言模型(VLM)学习笔记

目录 应用场景举例 VLM 的总体架构包括: 深度解析:图像编码器的实现 图像编码器:视觉 Transformer 注意力机制 视觉-语言投影器 综合实现 训练及注意事项 总结 应用场景举例 基于文本的图像生成或编辑:你输入 “生成一张…...

学习笔记:黑马程序员JavaWeb开发教程(2024.11.29)

10.5 案例-部门管理-新增 如何接收来自前端的数据: 接收到json数据之后,利用RequestBody注解,将前端响应回来的json格式的数据封装到实体类中 对代码中Controller层的优化 发现路径中都有/depts,可以将每个方法对应请求路径中的…...

文档加密怎么做才安全?

公司的文档包含很多机密文件,这些文件不仅关乎公司的核心竞争力,还涉及到客户隐私、商业策略等敏感信息。因此,文档的保管和传递一直是我们工作的重中之重。 为了确保机密文件的安全,公司需要制定了一系列严格的保密措施。从文件的…...

使用Setup Factory将C#的程序打包成安装包

一、软件下载 https://download.csdn.net/download/qq_65356682/90042701 可以直接下载 二、软件使用 打开 1、创建一个新的项目 2、设置如下信息,也可以不设置,最好填非空的、 产品名就是你安装成功后生成文件的名称 3、如下文件夹路径就是你C#中ex…...

解决 java -jar 报错:xxx.jar 中没有主清单属性

问题复现 在使用 java -jar xxx.jar 命令运行 Java 应用程序时,遇到了以下错误: xxx.jar 中没有主清单属性这个错误表示 JAR 文件缺少必要的启动信息,Java 虚拟机无法找到应用程序的入口点。本文将介绍该错误的原因以及如何通过修改 pom.xm…...

Java HashSet 介绍

怀旧网个人博客网站地址:怀旧网,博客详情:Java HashSet 介绍 哈希值介绍 创建一个实体类 public class Student {private String name;private int age;public Student(String name, int age) {this.name name;this.age age;} }使用测试…...

2024年几款免费的AI对话工具介绍

目前几款免费的AI对话工具介绍 文章目录 目前几款免费的AI对话工具介绍一、前言二、AI对话工具介绍1、讯飞星火认知大模型2、百度文心一言3、通义千问4、豆包5、百川大模型6、智谱清言7、月子暗面-KIMI下面是国外的 AI 对话工具: 8、Replika8、Cleverbot9、Coze 三、…...

Gazebo构建模型(含GNSS、IMU、LiDAR、Camera传感器)

将GNSS、IMU、LiDAR、Camera传感器和机器人的base分别放在不同的文件中。这样可以提高模型的可维护性和模块化。下面是一个示例,展示如何将这些部分分别放在不同的.xacro文件中,然后通过导入的方式组合在一起。 1. 创建基础文件:my_robot.xa…...

#Js篇: 链式判断运算符 ?.和Null判断运算符 ??和逻辑赋值运算符||= = ??=

链式判断运算符 ?. ?.运算符,直接在链式调用的时候判断,左侧的对象是否为null或undefined。如果是的,就不再往下运算,而是返回undefined。 链判断运算符?.有三种写法。 obj?.prop // 对象属性是否存在 obj?.[expr] // 同上…...

IDEA敲Web前端快捷键

1.html基础格式 英文符号TAB键 <!doctype html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport"content"widthdevice-width, user-scalableno, initial-scale1.0, maximum-scale1.0, mini…...

【Vue3】【Naive UI】<NDropdown>标签

【Vue3】【Naive UI】 标签 基本设置自定义渲染交互事件其他属性 【VUE3】【Naive UI】&#xff1c;NCard&#xff1e; 标签 【VUE3】【Naive UI】&#xff1c;n-button&#xff1e; 标签 【VUE3】【Naive UI】&#xff1c;a&#xff1e; 标签 【VUE3】【Naive UI】&#xff1c…...

技术总结(四十一)

一、MySQL 索引概述 索引的概念&#xff1a;索引就好比一本书的目录&#xff0c;它能帮助 MySQL 快速定位到表中的数据行&#xff0c;而不用全表扫描。通过创建合适的索引&#xff0c;可以大大提高查询的效率。例如&#xff0c;在一个存储了大量员工信息的表中&#xff0c;如果…...

Android布局

一、线性布局 属性&#xff1a;orientation vertical horizontal layout_weight【水平均分&#xff0c;width"0dp"】 layout_height layout_width 小动物连连看 1<?xml version"1.0" encoding"utf-8"?>2<LinearLayout xmlns:and…...

k8s集成skywalking

如果能科学上网的话&#xff0c;安装应该不难&#xff0c;如果有问题可以给我留言 本篇文章我将给大家介绍“分布式链路追踪”的内容&#xff0c;对于目前大部分采用微服务架构的公司来说&#xff0c;分布式链路追踪都是必备的&#xff0c;无论它是传统微服务体系亦或是新一代…...

如何写一份优质技术文档

作者简介&#xff1a; 本文作者拥有区块链创新专利30&#xff0c;是元宇宙标准化工作组成员、香港web3标准工作组成员&#xff0c;参与编写《数据资产确权与交易安全评价标准》、《链接元宇宙&#xff1a;应用与实践》、《香港Web3.0标准化白皮书》等标准&#xff0c;下面提供…...

LeetCode:206.反转链表

跟着carl学算法&#xff0c;本系列博客仅做个人记录&#xff0c;建议大家都去看carl本人的博客&#xff0c;写的真的很好的&#xff01; 代码随想录 LeetCode&#xff1a;206.反转链表 给你单链表的头节点 head &#xff0c;请你反转链表&#xff0c;并返回反转后的链表。 示例…...

详解高斯消元

详解高斯消元 好东西,可以求所有一次方程组的解。 \color {red} 好东西,可以求所有一次方程组的解。 好东西,可以求所有一次方程组的解。 前置知识 一般消元法的公理: 两方程互换,解不变; 一方程乘以非零数 k k k,解不变; 一方程乘以数 k k k加上另一方程,解不变。 …...

Maven - 优雅的管理多模块应用的统一版本号

文章目录 概述一、使用 versions-maven-plugin 插件1. 在主 pom.xml 中定义插件2. 修改版本号3. 回退修改4. 提交修改 二、使用占位符统一管理版本号1. 在主 pom.xml 中定义占位符2. 使用 flatten-maven-plugin 插件自动替换占位符3. 修改版本号4. 为什么这种方式更方便&#x…...

国际网络安全趋势

1. 亲近拥抱人工智能自动化。 随着安全协调、人工智能自动化和响应(SOAR)的日益普及&#xff0c;人工智能自动化开始成为现实并将继续扩展到其他安全行动领域。寻求将人工智能自动化整合到原有的工具中&#xff0c;通过将威胁情报整合在一起&#xff0c;将其转换为可用格式并主…...

基于米尔全志T527开发板的FacenetPytorch人脸识别方案

本篇测评由优秀测评者“小火苗”提供。 本文将介绍基于米尔电子MYD-LT527开发板&#xff08;米尔基于全志 T527开发板&#xff09;的FacenetPytorch人脸识别方案测试。 一、facenet_pytorch算法实现人脸识别 深度神经网络 1.简介 Facenet-PyTorch 是一个基于 PyTorch 框架实…...

Altium Designer脚本工具定制

原理图设计自动化 ➡️Altium原理图检查工具 ➡️元器件参数集导入导出 ➡️原理图符号自动创建 ➡️原理图高级查找 ➡️原理图库文档高级查找 ➡️原理图文档对比 ➡️原理图库文档对比 PCB设计自动化 ➡️各种各样的PCB线圈自动创建 ➡️PCB文档导出成SVG格式文档…...

贝锐自研智慧网关系统OrayOS升级,适配Banana PI开发板BPI-R3 Mini

为了满足多元化的应用场景&#xff0c;贝锐与Banana PI携手合作&#xff0c;贝锐自研新一代云智慧网关系统OrayOS不仅已成功适配BPI-R3&#xff0c;还进一步扩展至BPI-R3 Mini&#xff0c;提供了更丰富的选择。在全球工业物联网、视频监控管理以及企业级办公存储等领域&#xf…...

搭建环境-PHP简介及环境搭建教程

搭建环境-PHP简介及环境搭建教程 前言 在现代Web开发中,PHP是一种广泛使用的服务器端脚本语言,它以简洁、高效和跨平台的特性受到开发者的青睐。无论是小型网站还是大型企业应用,PHP都能提供强大的支持。本文将为您详细介绍PHP的基本概念、特点,以及如何搭建PHP开发环境。…...

Maven 配置

参考学习&#xff1a; eclipse&#xff08;或myeclipse&#xff09;通过maven配置连接neo4j_eclipse 链接 neo4j-CSDN博客 爆肝十小时—我终于用Java连上Neo4j数据库 - 知乎 全站最全Maven下载安装配置教学&#xff08;2024更新...全版本&#xff09;建议收藏...赠送IDEA配置Ma…...

js常见函数实现

文章目录 一、数组Array1、forEach2、filter3、map4、reduce5、find6、findIndex7、includes8、join 二、对象Object1、Object.keys2、深复制 js环境中有很多工具函数&#xff0c;比如es6添加了很多新的属性和方法&#xff0c;这些方法也可以自定义实现&#xff0c;但是官方也提…...

点云3DHarris角点检测算法推导

先回顾2D的Harris角点检测算法推导 自相关矩阵是Harris角点检测算法的核心之一&#xff0c;它通过计算图像局部区域的梯度信息来描述该区域的特征。在推导Harris角点检测算法中的自相关矩阵时&#xff0c;我们首先需要了解自相关矩阵的基本思想和数学背景。 参考 1. 能量函数…...

mysql-binlog的三种模式

MySQL的binlog&#xff08;二进制日志&#xff09;有三种主要模式&#xff0c;分别是Statement、Row和Mixed。这三种模式在记录数据库更改的方式上有显著的区别&#xff0c;以下是对这三种模式的详细解释及对比&#xff1a; 一、Statement模式&#xff08;基于SQL语句的复制&a…...

自动类型推导(auto 和 decltype);右值引用和移动语义

1) 自动类型推导&#xff08;auto 和 decltype&#xff09; 自动类型推导&#xff08;auto&#xff09; 在C11及以后的版本中&#xff0c;auto关键字被引入用于自动类型推导。这意味着编译器会自动推断变量的类型&#xff0c;基于其初始化的表达式。使用auto可以让代码更加简…...

(Linux 系统)进程控制

目录 一、进程创建 1、fork函数初识 二、进程终止 1、正常终止 2、异常终止 三、进程等待 1、进程等待必要性 2、进程等待的方法&#xff1a; 四、获取子进程status 1、基本概念 2、进程的阻塞等待方式 3、进程的非阻塞等待方式 五、进程程序替换 1、六种替换函数…...

电子商务网站软件建设的/手机百度下载免费安装

据说某些公司需要员工们不仅要写好程序&#xff0c;而且要写好API&#xff0c;对于一些编程大神来说&#xff0c;写API是一件麻烦的事情&#xff0c; 其实Eclipse能够轻松地生成API来忽悠人&#xff0c;尤其是你讨厌的根本不会写代码的上司。 当然&#xff0c;这些API根本就不…...

一款简洁的个人主页源码/澳门seo关键词排名

C explicit关键字可以帮助我们用来进行构造函数的修饰。那么其具体的操作方法是如何进行的呢&#xff1f;在这里将会为大家一一介绍。 AD&#xff1a; C编程语言中有很多比较重要的关键字在实际编程中起着非常重要的作用。我们今天为大家介绍的C explicit关键字就是其中一个应用…...

利用博客做网站/seo实战密码第三版pdf下载

在 Apache RocketMQ 中&#xff0c;当消费者去消费消息的时候&#xff0c;无论是通过 pull 的方式还是 push 的方式&#xff0c;都可能会出现大批量的消息突刺。如果此时要处理所有消息&#xff0c;很可能会导致系统负载过高&#xff0c;影响稳定性。但其实可能后面几秒之内都没…...

福州外贸网站制作/精准营销包括哪几个方面

《迷你世界》作为一款功能强大的沙盒游戏&#xff0c;有着高度的自由性&#xff0c;鼓励玩家们进行创造。同时也因为玩法奇特&#xff0c;有着卡通的画风&#xff0c;人物形象可爱精美&#xff0c;游戏当中的道具和方块颜色鲜艳&#xff0c;给玩家们带来了很好的游戏体验。所以…...

专门做尿不湿的网站/常德网站建设公司

Web开发做得多了&#xff0c;总觉得是体力活&#xff0c;于是搞些代码让自己脱离无聊的Coding吧&#xff08;是脱离“无聊的”Coding&#xff0c;不是脱离无聊的“Coding”&#xff09;。初级阶段 为每个QueryString写转换的代码&#xff0c;针对不同的类型&#xff0c;进行转换…...

做网站的动态图片/苏州网站优化公司

文章目录一、循环语句1.1 for循环语句1.1.1 for语句的结构1.1.2 for语句应用示例1.2 while循环语句1.3 until循环语句1.3.1 until语句的结构二、 Shell函数2.1 Shell函数2.1 函数应用示例2.2 函数的作用范围2.3 函数的参数2.4 递归函数三、 Shell数组3.1 Shell数组3.2 Shell脚本…...