赞
踩
本系列文章使用MovieLens数据集进行机器学习综合实战。本文主要记录的是数据预处理、数据可视化。由于平台有点鸡肋,不能显示运行代码块的结果,大家可以在评论区留言或私信我获取有结果显示的源码。文章和代码均是小编原创,为小编的期末实训项目。仅供大家参考,请勿全篇抄袭本文!!
系列文章目录:
MovieLens个性化电影推荐系统实战(二):用户群体划分(聚类)-CSDN博客
MovieLens个性化电影推荐系统实战(三):个性化电影推荐(推荐算法)-CSDN博客
资料:
MovieLens个性化电影推荐系统实战——系列文章资料-CSDN博客
文章资源,百度网盘永久有效:
链接: https://pan.baidu.com/s/1P45bvnp6ezE-0J06Wjx2sQ?pwd=csdn 提取码: csdn 复制这段内容后打开百度网盘手机App,操作更方便哦
数据集链接:https://files.grouplens.org/datasets/movielens/ml-1m.zip
若无法下载,评论区留言或私信获取数据集。
MovieLens数据集是一个经典的电影评分数据集,由GroupLens Research实验室收集整理。该数据集包含了用户对电影的评分和观看记录,以及电影本身的元数据信息,如电影类型、导演、演员等。
MovieLens数据集可以用于推荐系统的研究和开发,通过分析用户对电影的评分和观看习惯,可以构建个性化的推荐算法,为用户提供更好的电影推荐。此外,MovieLens数据集还可以用于用户行为分析、市场调研和商业决策,以及数据挖掘和机器学习等领域的研究和应用。
MovieLens数据集是一个公开的数据集,可以从GroupLens Research实验室的网站上进行下载。同时,还有一些第三方网站提供MovieLens数据集的下载和使用,如Kaggle、GitHub等。在使用MovieLens数据集时需要注意保护用户隐私和数据安全。
本文章使用ml-1m数据集,稳定的基准数据集。6000 名用户在 4000 部电影上获得了 100 万次评分。在2003 年 2 月发布。
- unames = ['user_id', 'gender', 'age', 'occupation', 'zip']
- user_df = pd.read_csv('users.dat',
- sep='::',
- header=None,
- names=unames,
- engine='python')
- # 电影信息
- mnames = ['movie_id', 'title', 'genres']
- movies_df = pd.read_csv('movies.dat',
- sep='::',
- header=None,
- names=mnames,
- engine='python',
- encoding='ISO-8859-1')
- # 评分信息
- rnames = ['user_id', 'movie_id', 'imdbId', 'timestamp']
- ratings_df = pd.read_csv('ratings.dat',
- sep='::',
- header=None,
- engine='python',
- names=rnames)
年龄分段
* 1: "Under 18"
* 18: "18-24"
* 25: "25-34"
* 35: "35-44"
* 45: "45-49"
* 50: "50-55"
* 56: "56+"
职业
* 0: "other" or not specified
* 1: "academic/educator"
* 2: "artist"
* 3: "clerical/admin"
* 4: "college/grad student"
* 5: "customer service"
* 6: "doctor/health care"
* 7: "executive/managerial"
* 8: "farmer"
* 9: "homemaker"
* 10: "K-12 student"
* 11: "lawyer"
* 12: "programmer"
* 13: "retired"
* 14: "sales/marketing"
* 15: "scientist"
* 16: "self-employed"
* 17: "technician/engineer"
* 18: "tradesman/craftsman"
* 19: "unemployed"
* 20: "writer"
去除电影名字段的年份。
- #使用正则表达式去除title字段的年份
- import re
-
- patter = re.compile(r'^(.*)\((\d+)\)$')
- title = {val: patter.match(val).group(1) for i, val in enumerate(set(movies_df['title']))}
- movies_df['title'] = movies_df['title'].map(title)
- movies_df.head()
将性别字段编码,不知道后面有没有用,下意识的处理。
- #将性别字段进行数值编码
- from sklearn.preprocessing import LabelEncoder
-
- # 假设df是你的数据框,其中"color"是一个分类变量
- le = LabelEncoder()
- user_df['gender_encoding'] = le.fit_transform(user_df['gender'])
- # user_df.drop(['gender'], axis=1, inplace=True)
- user_df.head()
查看重复值,需要一行一行运行。结果是没有重复值。
- #重复值查看以及处理
- user_df.duplicated().value_counts()
-
- movies_df.duplicated().value_counts()
-
- ratings_df.duplicated().value_counts()
异常值查看,使用描述性统计,乍一看是没有异常值的。
user_df.describe()
画出箱线图,确定了确实没有异常值。
- import seaborn as sns
- import matplotlib.pyplot as plt
-
- # 提取所有特征列
- feature_columns = user_df.columns
- # 创建一个包含多个子图的画布
- fig, axes = plt.subplots(nrows=1, ncols=len(feature_columns), figsize=(20, 5))
- # 遍历每个特征并绘制箱线图
- for i, feature in enumerate(feature_columns):
- sns.boxplot(x=feature, data=user_df, ax=axes[i])
- axes[i].set_title(feature) # 设置子图标题
- plt.tight_layout() # 自动调整子图布局
- plt.show()
- #观察描述性统计和箱线图,数据集无异常值,年龄为1表示18岁以下
- #评分人数和平均评分的气泡图
- import plotly.express as px
- movie_stats = ratings_df.groupby('movie_id').agg({'imdbId': ['mean', 'count']})
- movie_stats.columns = movie_stats.columns.droplevel(0)
- movie_stats = movie_stats.rename(columns={'mean': 'mean_rating', 'count': 'rating_count'})
- movie_stats = movie_stats[movie_stats['rating_count'] >= 50].iloc[:200, :]
- fig = px.scatter(movie_stats, x='mean_rating', y='rating_count', hover_name=movie_stats.index, size='rating_count',
- color='mean_rating',
- labels={'mean_rating': 'Mean Rating', 'rating_count': 'Rating Count'}, title='Movie Ratings')
- fig.show()
将鼠标放上去有交互的,这里做不到。评分最高同时评论数最高的是id为260的电影。
- #用户评论数与平均评分气泡图
- user_stats = ratings_df.groupby('user_id').agg({'imdbId': ['mean', 'count']})
- user_stats.columns = user_stats.columns.droplevel(0)
- user_stats = user_stats.rename(columns={'mean': 'mean_rating', 'count': 'rating_count'})
- user_stats = user_stats[user_stats['rating_count'] >= 50].iloc[:100, :]
- fig = px.scatter(user_stats, x='mean_rating', y='rating_count', hover_name=user_stats.index, size='rating_count',
- color='mean_rating',
- labels={'mean_rating': 'Mean Rating', 'rating_count': 'Rating Count'}, title='User Ratings')
- fig.show()
可以看出是哪位宝宝在恶评!!!!
- rating_val_count = ratings_df.imdbId.value_counts()
- fig = px.bar(rating_val_count, x=rating_val_count.index, y=rating_val_count, text=rating_val_count,
- labels={
- "index": "Ratings",
- 'y': 'Number of Ratings'},
- color=rating_val_count
- )
- fig.update_traces(textposition='outside')
- fig.update_layout(title_text='Frequency of the Ratings',
- title_x=0.5, title_font=dict(size=24))
- fig.update_traces(marker=dict(line=dict(color='#000000', width=2)))
- fig.update_layout({'plot_bgcolor': 'rgba(0, 0, 0, 0)'})
- fig.show()
可以看到,大多数平分分布在3分到5分。说明电影质量杠杠的!!世界上还是好人多。
- #职业用户人数占比
-
- users_by_occupation = user_df.groupby('occupation').size()
- # 对用户人数进行排序
- sorted_users_by_occupation = users_by_occupation.sort_values(ascending=False)
- sorted_users_by_occupation.plot(kind='bar')
- plt.xlabel('Occupation')
- plt.ylabel('Number of Users')
- plt.title('User Counts by Occupation (Sorted)')
- plt.show()
看出来了,职业ID为4、0、7的评论电影的打工人很多,可能是这三种职业的人比较爱表达自己的看法,喜欢分享自己的感受。
- # 根据年龄对用户进行分组,并统计每个年龄段的用户数量
- users_by_age = user_df.groupby('age').size()
- users_by_age.plot(kind='bar')
- plt.xlabel('Age')
- plt.ylabel('Number of Users')
- plt.title('User Counts by Age')
- plt.show()
- #观察柱状图,符合正态分布
25-34这个年龄段的人,似乎有很多想分享的!!
- #用户男女性别占比
- users_by_gender = user_df['gender'].value_counts()
- users_by_gender.plot(kind='pie', autopct='%1.1f%%')
- plt.axis('equal')
- plt.title('User Gender Distribution')
- plt.show()
男性占比7成!!女生不喜欢分享吗??
- movies_data = pd.concat([movies_df, movies_df['genres'].str.get_dummies(sep='|')], axis=1)
- movies_data.drop('genres', axis=1, inplace=True)
-
- #%%
- #每个职业,用户最关注的电影类型(最关注的电影类型,非最喜欢的电影类型,即评论数最多的电影类型)
- merged_data = pd.merge(pd.merge(user_df, ratings_df), movies_data)
- genre_columns = ['Action', 'Adventure', 'Animation', "Children\'s", 'Comedy', 'Crime', 'Documentary', 'Drama',
- 'Fantasy', 'Film-Noir', 'Horror', 'Musical', 'Mystery', 'Romance', 'Sci-Fi', 'Thriller', 'War',
- 'Western']
- genre_by_occupation = merged_data.groupby('occupation')[genre_columns].sum()
-
- # 计算每个职业对所有电影类型的评论数
- total_ratings_by_occupation = genre_by_occupation.sum(axis=1)
-
- # 计算每个职业对每种电影类型的评论数比例
- genre_proportions_by_occupation = genre_by_occupation.divide(total_ratings_by_occupation, axis=0)
-
- plt.figure(figsize=(12, 8))
- genre_proportions_by_occupation.plot(kind='bar', stacked=True)
- plt.title('Proportions of Genre Ratings by Occupation')
- plt.xlabel('Occupation')
- plt.ylabel('Proportion of Ratings')
- plt.legend(title='Genre', bbox_to_anchor=(1.05, 1), loc='upper left')
- plt.show()
可以看出,大家都关注戏剧和喜剧。但是不同的职业,对其他的电影类型关注度不同。
- reviews_by_genre = merged_data.iloc[:, 10:].sum()
- reviews_by_genre = reviews_by_genre.sort_values(ascending=False)
-
- reviews_by_genre.plot(kind='bar')
- plt.xlabel('Genre')
- plt.ylabel('Number of Reviews')
- plt.title('Review Counts by Genre')
- plt.show()
总的来看,大家很关注戏剧和喜剧,但是记录片不为大家所关注,但是某些用户肯定是喜欢的。这就为后面构建推荐系统提供细节,不放过任何电影推荐细节。
- #每个性别用户最关注的电影类型(最关注的电影类型,非最喜欢的电影类型,即评论数最多的电影类型)
- genre_by_gender = merged_data.groupby('gender')[genre_columns].sum()
-
- total_ratings_by_gender = genre_by_gender.sum(axis=1)
-
- # 计算每个职业对每种电影类型的评论数比例
- genre_proportions_by_gender = genre_by_gender.divide(total_ratings_by_gender, axis=0)
- plt.figure(figsize=(12, 8))
- genre_proportions_by_gender.plot(kind='bar', stacked=True)
- plt.title('Proportions of Genre Ratings by Occupation')
- plt.xlabel('Occupation')
- plt.ylabel('Proportion of Ratings')
- plt.legend(title='Genre', bbox_to_anchor=(1.05, 1), loc='upper left')
- plt.show()
不难看出,男生更关注动作片,女生更关注喜剧和儿童片。
- #每个电影类型的电影数量
- genres_df = movies_df['genres'].str.get_dummies('|')
- # 计算每个电影类型的数量
- genre_counts = genres_df.sum().sort_values(ascending=False)
-
- genre_counts.plot(kind='bar')
- plt.title('Number of Movies per Genre')
- plt.xlabel('Genre')
- plt.ylabel('Count')
- plt.xticks(rotation=45)
- plt.tight_layout()
- plt.show()
怪不得戏剧和喜剧的关注度高,原来是拥有这两个元素的电影这么多啊!!!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。