# Import required librariesimport numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.feature_extraction.text import TfidfVectorizer
from nltk.tokenize import RegexpTokenizer
import numpy as np
from sklearn import preprocessing
from scipy.sparse import hstack
import pandas_profiling技术支持
# Load dataset
df = pd.read_csv("tvshow.csv")
df=df.iloc[:,1:]# removing in unnamed index column技术支持
#Finding Missing values in all columns
miss = pd.DataFrame(df.isnull().sum())
miss = miss.rename(columns={0:"miss_count"})
miss["miss_%"]=(miss.miss_count/len(df.ID))*100
miss技术支持
misscount
miss%
ID
0
0.000000
Title
0
0.000000
Year
0
0.000000
Age
9390
56.079790
IMDb
571
3.410177
Rotten Tomatoes
11586
69.194935
Netflix
0
0.000000
Hulu
0
0.000000
Prime Video
0
0.000000
Disney+
0
0.000000
Type
0
0.000000
Directors
726
4.335882
Genres
275
1.642379
Country
435
2.597946
Language
599
3.577401
Runtime
592
3.535595
可以看到,Age 与 Rotten Tomatoes 两个变量的缺失率均超过 50%,这值得警惕。
接下来按如下步骤处理缺失值:
删除缺失率超过 50% 的列
在 IMDb、Directors、Genres、Country、Language 和 Runtime 列中删除 NA
重置索引
将 Year 列转换为 object 类型
# Dropping values with missing % more than 50%
df.drop(['Rotten Tomatoes','Age'], axis =1, inplace=True)# Dropping Na's from the following columns
df.dropna(subset=['IMDb','Directors','Genres','Country','Language','Runtime'],inplace=True)
df.reset_index(inplace=True,drop=True)# Converting into object type
df.Year = df.Year.astype("object")技术支持
# A function to calculate the movies in different Streaming platformsdefm_cnt(plat, count=False):if count==False:print('Platform {} Count: {}'.format(plat, df[plat].sum()))else:return df[plat].sum()技术支持
# Let's see count of movies/shows of each streaming platform
m_cnt('Netflix')
m_cnt('Hulu')
m_cnt('Prime Video')
m_cnt('Disney+')技术支持
Platform Netflix Count:3152
Platform Hulu Count:848
Platform Prime Video Count:11289
Platform Disney+ Count:542技术支持
# Movies on each platform
lab ='Prime Video','Netflix','Hulu','Disney'
s =[m_cnt('Prime Video', count=True),
m_cnt('Netflix', count=True),
m_cnt('Hulu', count=True),
m_cnt('Disney+', count=True)]
explode =(0.1,0.1,0.1,0.1)#plotting
fig1, ax1 = plt.subplots()
ax1.pie(s,
labels = lab,
autopct ='%1.1f%%',
explode = explode,
shadow =True,
startangle =100)
ax1.axis =('equal')
plt.show()技术支持
从上图可见,Prime Video 以 71% 的占比承载了最多片名,Netflix 承载了 20%。Disney+ 与 Hulu 的占比最低,分别为 5.4% 与 3.4%。
##split the genres by ',' & then stack it one after the other for easy analysis.
g = df['Genres'].str.split(',').apply(pd.Series,1).stack()
g.index = g.index.droplevel(-1)# Assign name to column
g.name ='Genres'# delete columndel df['Genres']# join new column with the existing dataframe
df_genres = df.join(g)技术支持
# Count of movies according to genre
plt.figure(figsize=(15,5))
sns.countplot(x='Genres', data=df_genres)
plt.xticks(rotation=90)
plt.show()技术支持
# Split the Country by ',' & then stack it one after the other for easy analysis.
c = df['Country'].str.split(',').apply(pd.Series,1).stack()
c.index = c.index.droplevel(-1)# Assign name to column
c.name ='Country'# delete columndel df['Country']# join new column with the existing dataframe
df_country = df.join(c)技术支持
# plotting top 10 country and movie count
df_country['Country'].value_counts()[:10].plot(kind='bar',figsize=(15,5))
plt.show()技术支持
# perform stacking operation on language column
l = df['Language'].str.split(',').apply(pd.Series,1).stack()
l.index = l.index.droplevel(-1)# Assign name to column
l.name ='Language'# delete columndel df['Language']# join new column with the existing dataframe
df_language = df.join(l)技术支持
# plotting top 10 Language and movie count
df_language['Language'].value_counts()[:10].plot(kind='bar',figsize=(15,3))
plt.show()技术支持
# Reading Data Again
df = pd.read_csv("tvshow.csv")
df=df.iloc[:,1:]技术支持
#Finding Missing values in all columns
miss = pd.DataFrame(df.isnull().sum())
miss = miss.rename(columns={0:"miss_count"})
miss["miss_%"]=(miss.miss_count/len(df.ID))*100
miss
技术支持
#Dropping values with missing % more than 50%
df.drop(['Rotten Tomatoes','Age'], axis =1, inplace=True)# Dropping Na's from the following columns
df.dropna(subset=['IMDb','Directors','Genres','Country','Language','Runtime'],inplace=True)
df.reset_index(inplace=True,drop=True)# converting into object type
df.ID = df.ID.astype("object")
df.Year = df.Year.astype("object")技术支持
您将基于余弦相似度构建两个推荐系统。
1. Using only the numerical variable
2. Using both numerical and categorical variable
技术支持
#importing minmax scalerfrom sklearn import preprocessing
# Create MinMaxScaler Object
scaler = preprocessing.MinMaxScaler(feature_range=(0,1))# Create dataframe after transformation
ndfmx = pd.DataFrame((scaler.fit_transform(ndf)))# assign column names
ndfmx.columns=ndf.columns
# Show initial 5 records
ndfmx.head()技术支持
步骤 3:使用余弦相似度计算相似度得分
现在,使用余弦相似度计算相似度得分。
# Import cosine similarityfrom sklearn.metrics.pairwise import cosine_similarity
# Compute the cosine similarity
sig = cosine_similarity(ndfmx, ndfmx)# Reverse mapping of indices and movie titles
indices = pd.Series(df.index, index=df['Title']).drop_duplicates()技术支持
defgive_rec(title, sig=sig):# Get the index corresponding to original_title
idx = indices[title]# Get the pairwise similarity scores
sig_scores =list(enumerate(sig[idx]))# Sort the movies
sig_scores =sorted(sig_scores, key=lambda x: x[1], reverse=True)# Scores of the 10 most similar movies
sig_scores = sig_scores[1:11]# Movie indices
movie_indices =[i[0]for i in sig_scores]# Top 10 most similar moviesreturn df['Title'].iloc[movie_indices]技术支持
# Execute get_rec() function for getting recommendation
give_rec("The Matrix",sig = sig)技术支持
#the function performs all the important preprocessing stepsdefpreprocess(df):#combining all text columns# Selecting all object data type and storing them in list
s =list(df.select_dtypes(include=['object']).columns)# Removing ID and Title column
s.remove("Title")
s.remove("ID")# Joining all text/object columns using commas into a single column
df['all_text']= df[s].apply(lambda x:','.join(x.dropna().astype(str)),axis=1)# Creating a tokenizer to remove unwanted elements from our data like symbols and numbers
token = RegexpTokenizer(r'[a-zA-Z]+')# Converting TfidfVector from the text
cv = TfidfVectorizer(lowercase=True,stop_words='english',ngram_range =(1,1),tokenizer = token.tokenize)
text_counts= cv.fit_transform(df['all_text'])# Aselecting numerical variables
ndf = df.select_dtypes(include=['float64',"int64"])# Scaling Numerical variables
scaler = preprocessing.MinMaxScaler(feature_range=(0,1))# Applying scaler on our data and converting i into a data frame
ndfmx = pd.DataFrame((scaler.fit_transform(ndf)))
ndfmx.columns=ndf.columns
# Adding our adding numerical variables in the TF-IDF vector
IMDb = ndfmx.IMDb.values[:,None]
X_train_dtm = hstack((text_counts, IMDb))
Netflix = ndfmx.Netflix.values[:,None]
X_train_dtm = hstack((X_train_dtm, Netflix))
Hulu = ndfmx.Hulu.values[:,None]
X_train_dtm = hstack((X_train_dtm, Hulu))
Prime = ndfmx["Prime Video"].values[:,None]
X_train_dtm = hstack((X_train_dtm, Prime))
Disney = ndfmx["Disney+"].values[:,None]
X_train_dtm = hstack((X_train_dtm, Disney))
Runtime = ndfmx.Runtime.values[:,None]
X_train_dtm = hstack((X_train_dtm, Runtime))return X_train_dtm
技术支持
步骤 2:将该函数应用于数据并创建稀疏矩阵
# Preprocessing data
mat =preprocess(df)
mat.shape
技术支持
步骤 3:再次使用余弦相似度计算相似度得分
# using cosine similarityfrom sklearn.metrics.pairwise import cosine_similarity
# Compute the sigmoid kernel
sig2 = cosine_similarity(mat, mat)# Reverse mapping of indices and movie titles
indices = pd.Series(df.index, index=df['Title']).drop_duplicates()技术支持
随着“刷剧”文化兴起,加之 Netflix、Prime Video、Hulu 和 Disney+ 等服务的普及,用户正以极快的速度消费影视内容。这些新平台中的一部分(如 Hulu 和 YouTube TV)还提供体育、演唱会/巡演以及新闻频道等活动的直播功能。而像 Netflix 这样的流媒体平台目前尚未引入直播。
流媒体平台为用户带来更灵活的观影体验:随时、随地、任意设备,想看就看。凭借海量的剧集与电影内容,这类服务尤其能够吸引年轻与注重时尚的受众。用户还可以在自己合适的时间补看错过的节目。在本教程中,您将分析 Netflix、Prime Video、Hulu 和 Disney+ 的电影数据,并尝试理解其受众。
理解数据集
本数据集仅包含 Netflix、Prime Video、Hulu 和 Disney+ 等流媒体平台上可观看的电影。您可以从 Kaggle 此处下载。
下面详细说明各数据字段:
让我们导入必要的模块并加载数据集:
处理缺失值
在本节中,您将使用
isnull()函数处理缺失值。示例如下:可以看到,Age 与 Rotten Tomatoes 两个变量的缺失率均超过 50%,这值得警惕。
接下来按如下步骤处理缺失值:
分布图
您可以使用 seaborn 的
distplot()函数查看 Year 列的分布。让我们绘制电影年份的分布图。该图展示了电影出品年份的分布。可以解读为,大多数电影集中在 2000 至 2020 年间。接着绘制 IMDb 评分分布图。
上面的分布图略有偏斜。可以解读为多数电影的 IMDb 均值约为 6.5。
再来绘制电影片长分布图。
从上图可解读为,电影的平均片长大多落在 80 至 120 分钟之间。
各流媒体平台的影片分布
本节将查看按平台划分的影片分布。首先需要创建一个
m_cnt()函数用于统计指定平台的影片数。随后可使用饼图绘制并了解各平台的占比。从上图可见,Prime Video 以 71% 的占比承载了最多片名,Netflix 承载了 20%。Disney+ 与 Hulu 的占比最低,分别为 5.4% 与 3.4%。
按类型划分的影片分布
本节将查看按类型划分的影片分布。首先需要准备数据:同一单元格内可能包含多个类型,您可以使用
split()、apply()和stack()函数处理。split()用逗号分隔形成列表,apply(pd.Series,1)将每个类型展开为多列,stack()再将其堆叠回单列。完成这三步后,新生成的 Genres 列会与原数据集拼接,便可开始绘图。您可以用
value_counts()展示电影数量最多的前 10 个类型,并使用 pandas 的plot()进行可视化。从上图可见,电影最常见的类型是剧情(Drama)与喜剧(Comedy)。
按国家/地区划分的影片分布
本节将查看按国家/地区划分的影片分布。首先需要准备数据:同一单元格内可能包含多个国家/地区,可使用
split()、apply()和stack()处理。split()用逗号分隔形成列表,apply(pd.Series,1)将每个国家/地区展开为多列,stack()再将其堆叠回单列。完成后,新 Country 列会与原数据集拼接,便可绘图。您可以用
value_counts()展示电影数量最多的前 10 个国家/地区,并使用 pandas 的plot()可视化。上图显示,大多数电影产自美国。
按语言划分的影片分布
本节将查看按语言划分的影片分布。首先需要准备数据:同一单元格可能包含多种语言,您可以使用
split()、apply()和stack()处理。split()用逗号分隔形成列表,apply(pd.Series,1)将每种语言展开为多列,stack()再将其堆叠回单列。完成这三步后,新 Language 列会与原数据集拼接,便可绘图。您可以用
value_counts()展示电影数量最多的前 10 种语言,并使用 pandas 的plot()进行可视化。从上图可以得出,大多数电影使用英语。
各平台的 IMDb 评分分布
本节将绘制按平台划分的 IMDb 评分分布。为得到这些结果,需要使用
melt()函数并绘制 FacetGrid 图。melt()会将宽表转换为长表。示例如下:上图展示了各平台上的 IMDb 评分分布情况。
各平台按年龄分组的总片长
在“处理缺失值”一节中,我们删除了 Age 列。若要查看各平台按年龄分组的总片长,需要重新加载数据并应用
melt()函数。重新加载数据集并完成 melt 操作后,接下来绘制不同年龄组在各流媒体平台上的总片长。
上图显示,Prime Video 上 18+ 年龄组用户的总片长远高于其他平台。可以据此推断,Prime Video 的大部分内容更侧重 18+ 年龄分组。
构建推荐系统
近几年,随着 YouTube、Walmart、Netflix 等众多互联网服务的跨越式发展,推荐系统在业界产生了巨大的影响。从推荐产品/服务,到通过线上广告变现提升企业价值,再到匹配用户相关性与偏好以促成购买,推荐系统已成为我们日常网络活动中不可或缺的一环。
总体而言,推荐系统是基于数学的方法框架,面向终端用户推荐与其需求和偏好相关的产品/服务。例如,看什么电影、读哪些文章、买什么产品、听什么音乐,或其他任何与具体领域相关的内容。构建推荐系统主要有三种方法:
首先对数据集进行推荐系统所需的预处理。先检查缺失值:
您将基于余弦相似度构建两个推荐系统。
仅使用数值列
步骤 1:选择数值变量
步骤 2:使用 Min-Max 缩放器对数值变量进行缩放,以降低模型复杂度与训练时间
步骤 3:使用余弦相似度计算相似度得分
现在,使用余弦相似度计算相似度得分。
步骤 4:编写函数,基于相似度得分获取推荐
此处的推荐效果不尽如人意。造成这一结果的原因在于仅使用了电影评分、片长与平台变量。可通过引入更多信息(如类型、导演与国家/地区)进行改进。
结合数值与文本列
由于此前的推荐系统虽可运行,但推荐结果不够理想,因此我们将尝试一种更优的方法来改进结果。
步骤 1:
将文本列合并为单列,然后使用分词器与 TF-IDF 向量器构建包含所有词语 TF-IDF 分数的稀疏矩阵。随后选择并缩放数值变量,并将其加入稀疏矩阵。在预处理时需执行以下步骤:
步骤 2:将该函数应用于数据并创建稀疏矩阵
步骤 3:再次使用余弦相似度计算相似度得分
步骤 4:从改进版系统获取推荐
这一次的推荐系统效果显著优于之前的版本,说明通过添加更多相关数据(如描述性文本),基于内容的推荐系统能得到大幅提升。
结语
恭喜您阅读完本教程!
在本教程中,您对流媒体平台电影数据集进行了探索性分析。您查看了缺失值、单变量分布图,以及各流媒体平台的影片分布;还洞察了类型、国家/地区、语言、IMDb 评分与电影片长等方面。最后,您还了解了如何在 Python 中构建推荐系统。
欢迎查看 DataCamp 的Python 推荐系统教程。