MoviesLens.py
此项目用到的数据集是MoviesLens数据集,其中包括用户评分、电影信息等数据。MoviesLens.py是进行数据的预处理文件。下面是对数据预处理流程代码的详解过程。
首先,涉及到的库如下所示
import csv
import re
import pandas as pd
from surprise import Reader
from surprise import Dataset
from collections import defaultdict
import os
import sys
其中我们较为不熟悉的是surprise库,用到的Reader和Dataset类都是为了让数据集适配之后的训练过程,在此就不详细介绍此库。如果想了解这两个类的参数配置,请点击Reader和Dataset去做相应的了解。
除此之外,collections中的defaultdict类是用来初始化字典的,如a = defaulydict(int)等。
loadMovieLensDataset函数
这个函数主要用于获取用户评价数据
def loadMovieLensDataset(self):
ratingsDataset = 0
self.movieId_to_movieName = {} # 将电影ID和电影名称一一对应的字典
self.movieName_to_movieId = {} # 将电影名称和电影ID一一对应的字典
# 读取用户对电影评价的csv和作者自己对电影评价的csv并设置header
df1 = pd.read_csv(self.rating_file_location, skiprows=1)
df1.columns = ['user', 'item', 'rating', 'timestamp']
df2 = pd.read_csv(self.my_rating_file_location, skiprows=1)
df2.columns = ['user', 'item', 'rating', 'timestamp']
frame = [df1, df2]
ratingsData = pd.concat(frame, ignore_index=True) # 将两个dataframe进行合并
print(ratingsData.head())
ratingsData.to_csv("ratings-Data.csv", index=False)
ratingsData = ratingsData.astype({'user': str, 'item': str, 'rating': str, 'timestamp': str})
print(ratingsData.tail()) # 打印数据的后五行数据
# 将数据转化成surprise使用的数据形式
reader = Reader(line_format='user item rating timestamp')
ratingsDataset = Dataset.load_from_df(ratingsData[['user', 'item', 'rating']], reader)
# 打开电影文件, 采用'ISO-8859-1'编码避免编码错误
# 如果 csvfile 是文件对象,则应使用newline打开它。
# 获取电影Id和名称的对应的两个字典
with open(self.movies_file_location, newline='', encoding='ISO-8859-1') as csv_file:
# 返回reader器对象,该对象将迭代给定csvfile中的行。
movie_Reader = csv.reader(csv_file)
next(movie_Reader) # 跳过文件的第一行(标签)
for row in movie_Reader:
movieID = int(row[0]) # 获取电影的ID
movieName = row[1] # 获取电影名称
# 将电影名称和Id进行对应,得到两个字典
self.movieId_to_movieName[movieID] = movieName
self.movieName_to_movieId[movieName] = movieID
# 返回合并完并且修改好的数据表
return ratingsDataset
getMovieName函数
此函数根据电影Id获取电影名称
def getMovieName(self, movieID):
if movieID in self.movieId_to_movieName:
return self.movieId_to_movieName[movieID]
else:
return ""
getPopularityRanks函数
根据用户的评分获取电影受欢迎程度排行榜(被评分次数排行榜)
def getPopularityRanks(self):
ratings = defaultdict(int) # 电影被评次数字典
rankings = defaultdict(int) # 电影受欢迎排行榜字典
with open(self.new_rating_csv, newline='') as cvsfile:
ratingReader = csv.reader(cvsfile)
next(ratingReader)
for row in ratingReader:
movieID = int(row[1])
ratings[movieID] += 1 # 电影ID出现一次,被评次数加一
rank = 1 # 初始排位第一名
# 根据rating的被评次数给rating字典进行排序(升序)
for movieID, _ in sorted(ratings.items(), key=lambda x: x[1], reverse=True):
# 根据排序依次排名
rankings[movieID] = rank
rank += 1
return rankings
getGenres函数
根据电影分类标签获取向量化的标签
def getGenres(self):
genres = defaultdict(list) # 每个电影分类标签列表字典
genreIDs = {} # 电影ID和电影分类标签(数字形式)对照字典
maxGenreID = 0 # 电影分类标签数量
with open(self.movies_file_location, newline='', encoding='ISO-8859-1') as csvfile:
movieReader = csv.reader(csvfile)
next(movieReader) # Skip header line
for row in movieReader:
movieID = int(row[0])
genreList = row[2].split('|') # 获取每一部电影的多个分类标签
genreIDList = [] # 每个电影拥有的分类标签列表
for genre in genreList:
if genre in genreIDs: # 如果genre存在于已有的分类标签
genreID = genreIDs[genre] # 将genreID赋值为该标签对应的数字
else: # 如果不存在
genreID = maxGenreID # 把一个新的数字类别赋值给genreID
genreIDs[genre] = genreID # 添加新的类别对照进入对照字典
maxGenreID += 1 # 类别数量加一
genreIDList.append(genreID) # 更新每个电影拥有的分类标签列表(数字形式)
genres[movieID] = genreIDList # 获得每个电影分类标签列表字典
# 将数字形式的分类标签列表转换成0、1表示的矩阵
for (movieID, genreIDList) in genres.items():
bitfield = [0] * maxGenreID # 创建一个类别数量长度的行向量
for genreID in genreIDList: # 遍历拥有的类别列表(数字列表),以此来确定行向量的哪些位置赋值为1
bitfield[genreID] = 1
genres[movieID] = bitfield # 将标签字典换成标签行向量
return genres
getYears函数
获取电影年份
def getYears(self):
expToMatch = re.compile(r"(?:\((\d{4})\))?\s*$") # 取出年份的正则表达式
years = defaultdict(int)
with open(self.movies_file_location, newline='', encoding='ISO-8859-1') as csvfile:
movieReader = csv.reader(csvfile)
next(movieReader)
for row in movieReader:
movieId = int(row[0])
title = row[1]
rawYear = expToMatch.search(title) # 在电影标题中根据正则表达式搜索年份
year = rawYear.group(1) # 获取第二个括号匹配的内容
if year:
years[movieId] = int(year)
return years