机器学习实战项目9---异常检测监督学习及电影推荐

  1. 描述异常检测和监督学习算法的区别
  2. 使用keras实现Collaborative Filtering,构建电影推荐系统

answer1:
总结来说:
1)在异常检测中,异常点是少之又少,大部分是正常样本,异常只是相对小概率事件;
2)异常点的特征表现非常不集中,即异常种类非常多,不容易归纳。直白地说:正常的情况大同小异,而异常各不相同。这种情况用有限的正例样本(异常点)给有监督模型学习就很难从中学到有效的规律.

answer2:
关于 kaggle 中相关项目的链接https://www.kaggle.com/rounakbanik/movie-recommender-systems

我将开源的一个个人比较好的kernel 实践了一遍

# coding: utf-8

# ## Demographic  filtering 
# 
# 需要注意两个字段 一个是投票数:vote_count,一个是vount_average(电影平均评分) 
# 但是 kaggle 中有这样一段描述 
# We can use the average ratings of the movie as the score but using this won't be fair enough since a movie with 8.9 average rating and only 3 votes cannot be considered better than the movie with 7.8 as as average rating but 40 votes. So, I'll be using IMDB's weighted rating (wr) which is given as
# 
# weighting rating (wr)=(v/v+m)*R+(m/v+m)*C
#  
# v 是投票总数 (vote_count)
# m 是最小投票数
# R 电影平均得分(vote_average)
# C是所有样本电影的平均评分的均值
#  
# 
# 
# 
# 

# 关于movie recommendtion 的背景介绍
#  movies_metadata.csv 包含 movieslen 的45000数据,字段有海报、背景、预算、收入、发行时间、语言、产地、公司
#  keywords.csv  包含电影情节的关键字,以json 格式存储
#  credits.csv: 包含电影的演员或者场务人员的信息
#  links.csv:包含完整MovieLens数据集中所有电影的TMDB和IMDB id的文件
#  links_small.csv:包含完整数据集的9000部电影中的一小部分的TMDB和IMDB id
#  ratings_small.csv:从700名用户对9000部电影的10万个评分中选出的子集
#  
#  写在前面
#  Recommendation Systems are a type of information filtering systems as they improve the quality of search results and provides items that are more relevant to the search item or are realted to the search history of the user.
#  
#  
#  They are used to predict the rating(评论) or preference that a user would give to an item. Almost every major tech company has applied them in some form or the other: Amazon uses it to suggest products to customers, YouTube uses it to decide which video to play next on autoplay
#  
#  
#  三种典行的推荐系统
#  1. 人口统计过滤——他们根据电影的流行程度和/或类型,为每个用户提供一般性的推荐。该系统向具有相似人口统计特征的用户推荐相同的电影。由于每个用户都不同,因此这种方法被认为过于简单。这一体系背后的基本理念是,更受欢迎、更受好评的电影更有可能受到普通观众的喜爱。-----根据下面的例子,该方法的含义是大多数人对该电影的评价好,那么应该就适合其他大部分群体
#  2.基于内容的过滤——它们基于特定的项目推荐相似的项目。该系统使用电影类型、导演、描述、演员等项目元数据来做出这些推荐。这些推荐系统的基本思想是,如果一个人喜欢某个特定的商品,他或她也会喜欢与之相似的商品。
#  3.该系统匹配具有相似兴趣的人,并根据这种匹配提供建议。协作过滤器不像基于内容的过滤器那样内容的多项特征。

# In[2]:


import numpy as np 
import pandas as pd 
df1=pd.read_csv(r'C:\\Users\\Lenovo\\Desktop\\hands-on-machine-learning\\hands on machine\\movie recommendtion\\tmdb_5000_credits.csv')
df2=pd.read_csv(r'C:\\Users\\Lenovo\\Desktop\\hands-on-machine-learning\\hands on machine\\movie recommendtion\\tmdb_5000_movies.csv')
# print (df1.columns)
"""
the first dataset  features
1.movie_id - A unique identifier for each movie.
2.cast - The name of lead and supporting actors.
3.crew - The name of Director, Editor, Composer, Writer etc.
 
the second features
budget - The budget in which the movie was made.
genre - The genre of the movie, Action, Comedy ,Thriller etc.
homepage - A link to the homepage of the movie.
id - This is infact the movie_id as in the first dataset.
keywords - The keywords or tags related to the movie.
original_language - The language in which the movie was made.
original_title - The title of the movie before translation or adaptation.
overview - A brief description of the movie.
popularity - A numeric quantity specifying the movie popularity.
production_companies - The production house of the movie.
production_countries - The country in which it was produced.
release_date - The date on which it was released.
revenue - The worldwide revenue generated by the movie.
runtime - The running time of the movie in minutes.
status - "Released" or "Rumored".
tagline - Movie's tagline.
title - Title of the movie.
vote_average - average ratings the movie recieved.
vote_count - the count of votes recieved.
"""

df1.columns=['id','tittle','cast','crew']
df=df1.merge(df2,on='id')
# print(df.head(10))


# In[3]:


c=df["vote_average"].mean()# the mean rating for all the movies is approx 6 on a scale of 10
m=df["vote_count"].quantile(0.9)#分位数为0.9对应的投票数

df_new=df.loc[df['vote_count']>m]
df_new.shape##得到该分位以上得所有数据


# 接下来需要利用上述的式子为电影打分

# In[4]:


def weighted_rate(df,m=m,c=c):
    v=df['vote_count']
    r=df['vote_average']
    return (v/(v+m)*r+m/(v+m)*c)


df_new['score']=weighted_rate(df_new)
df_new=df_new.sort_values('score',ascending=False)
df_new[['title', 'vote_count', 'vote_average', 'score']].head(10)##排名第一的是肖申克的救赎
"""
该方法的理念就是评分高的电影(多数人参与投票,并且打出高分)适合推荐,
这个方法简单粗暴,没有结合电影的内容,以个人喜好
"""


# ## content Based  Filtering 
# In this recommender system the content of the movie (overview, cast, crew, keyword, tagline etc) is used to find its similarity with other movies. Then the movies that are most likely to be similar are recommended.
# 简单来说,就是先找到用户A喜欢的电影的特点,然后再将与其类似的电影推荐给他
# 我们将根据所有电影的情节描述计算彼此间相似度评分,并根据相似度评分推荐电影。电影的描述在数据集的overview中给出。让我们看一下数据。
# 
# 该kernels 的作者采用的是TF--IDF的方法,简单来说一个词语的重要性,是随着其在某一个文本中的出现的次数增多而权重加大,但是也同时随着其在多个不同文本中出现的次数的增多,权重减少,该词的权重是TF*IDF,
# 幸运的就是sklearn 有相关的 TF-IDF 的库

# In[13]:


df_new['overview'].head(3)


# In[5]:



from sklearn.feature_extraction.text import TfidfVectorizer#进行分词

tfidf=TfidfVectorizer(stop_words='english')#去掉 a  the  等,sklearn 自带停用词非常好
df['overview']=df['overview'].fillna('')##NaN 替换
tfidf_model=tfidf.fit(df['overview'])
tfidf_model.vocabulary_##非常重要的两个方法,这个输出一个词语以及对应的标量0,1,2,3,,就是编号
tfidf_model.get_feature_names()#只看一下分词有哪些
tfidf_result=tfidf_model.transform(df['overview'])
# tfidf_matrix.toa(rray()
tfidf_result.shape#4803行,20978 列,也就是返回的矩阵每一行代表一部电影,每一列存放切分的词语在该overview zhon


# 我们看到 将近20000的词来描述4800部相关的电影
# 接下来就是要计算相似度, kernel 中有以下描述
# With this matrix in hand, we can now compute a similarity score. There are several candidates for this; such as the euclidean, the Pearson and the cosine similarity scores. There is no right answer to which score is the best. Different scores work well in different scenarios and it is often a good idea to experiment with different metrics.
# 
# 本例子中我们就用的余弦定理,cosine similiarity scores  ===>a与b的点积除以a的模和b的模
# 
# Since we have used the TF-IDF vectorizer, calculating the dot product will directly give us the cosine similarity score. Therefore, we will use sklearn's linear_kernel() instead of cosine_similarities() since it is faster.
# 
# 

# In[42]:


from sklearn.metrics.pairwise import linear_kernel

#compute the cosine similiarity matrix 
cosine_sim=linear_kernel(tfidf_result,tfidf_result)#自身是个方阵,每一行都是其与自己和其他的相似度,因此最高的也就是其行数对应的列,也就是对角线都为1

"""
接下来我们需要定义一个函数来输入一部电影的名字,输出与之类似的10部电影
"""
indices=pd.Series(df.index,index=df["title"]).drop_duplicates(inplace=False)
"""
接下来下来函数主要完成以下几个步骤
获取给定电影名称的电影索引。

获取该电影与所有电影的余弦相似度评分列表。将它转换为一个元组列表,其中第一个元素是它的位置,第二个元素是相似度评分。

根据相似度评分对上述元组列表进行排序;也就是第二个元素。

获取列表的前10个元素。忽略第一个元素,因为它指的是self(与特定电影最相似的是电影本身)。

返回与顶部元素的索引对应的标题。

"""


def movie_recommendations1(title,cosine_sim=cosine_sim):#输入某一个电影的推荐电影
    idx=indices[title]#某一部电影的索引位置
    #得到该电影与其他电影的相似度
    sim_scores=list(enumerate(cosine_sim[idx]))#由远足构成的列表,第一个为电影索引位置,第二个为相似分数
    sim_scores=sorted(sim_scores,key=lambda x:x[1],reverse=True)#注意lambda 的用法
    sim_scores_top=sim_scores[1:11]#排除它自己,然后取出前十
    movies_sim_index=[i[0] for i in sim_scores_top]
    return df['title'].iloc[movies_sim_index]
    
    

movie_recommendations1('The Shawshank Redemption')

"""
到这一步,基本上系统可以将电影情节相似的电影很好的
推荐,但是该kernel的作者举了个例子,比如蝙蝠侠:3 
系统会将所有的蝙蝠侠电影推荐一下,但是可能我们的用户只是喜欢大导演 诺兰 
想要看的仅仅是诺兰的电影而已,这一点我们的推荐系统还做不到
"""




# In[61]:


###首先第一步就是先将字符串变为python 可以处理的表达式
from ast import literal_eval
features=['cast','crew','keywords','genres']#选取四个特征,演员,场务,电影的关键词,电影的类型
for feature in features:
    if isinstance(df[feature],str):
        df[feature]=eval(df[feature])

    
#得到导演的名字,如果没有返回nan 值

def get_director(x):#传入的是df --dataframe 类型
     for i in (x):
            if i['job']=='Director':
                return i['name']
     return np.nan 



##找到前三个演员
def  get_list(x):
    if isinstance(x,list):#由字符串经上边的apply 转化为了列表,即python 可处理的表达式
        names=[i['name'] for i in x]
        if len(names)>3:
            return names[:3]
        else:
            return names
    return []


###利用上述的函数将上述的特征进行处理

df['director']=df['crew'].apply(get_director)#直接构建一列,存放导演
features=['cast','keywords','genres']#存放演员,电影内容的关键词,及电影类型

for  feature in features:
    df[feature]=df[feature].apply(get_list)
    
    
df[['title', 'cast', 'director', 'keywords', 'genres']].head(3)




# 接下来的这一步也非常的关键,其中kernal 是这样写的
# The next step would be to convert the names and keyword instances into lowercase and strip all the spaces between them. This is done so that our vectorizer doesn't count the Johnny of "Johnny Depp" and "Johnny Galecki" as the same. 

# In[64]:


def clean_data(x):
    if isinstance(x,list):
        return [str.lower(i.replace(" ",""))  for i in x]
    else:
       #Check if director exists. If not, return empty string
        if isinstance(x,str):
            return str.lower(x.replace(" ",""))
        else:
            return ''
        
        
features=['cast', 'keywords', 'director', 'genres']

for feature in features:
    df[feature]=df[feature].apply(clean_data)#注意apply的用法是应用到每一列上


df[['title', 'cast', 'director', 'keywords', 'genres']].head(3)


# 接下来我们要做的就是将上述的这些整理好的特征放在一列当中去
# 

# In[70]:


def create_soup(x):
    return ' '.join(x['keywords'])+ ' '+' '.join(x['cast']) + ' ' + x['director'] + ' ' + ' '.join(x['genres'])


df['soup']=df.apply(create_soup,axis=1)

df['soup']


# from sklearn.feature_extraction.text import CountVectorizer
# 
# texts=["dog cat fish","dog cat cat","fish bird", 'bird'] # “dog cat fish” 为输入列表元素,即代表一个文章的字符串
# cv = CountVectorizer()#创建词袋数据结构
# cv_fit=cv.fit_transform(texts)
# #上述代码等价于下面两行
# #cv.fit(texts)
# #cv_fit=cv.transform(texts)
# 
# print(cv.get_feature_names()) ['bird', 'cat', 'dog', 'fish'] 列表形式呈现文章生成的词典
# 
# print(cv.vocabulary_  ) {‘dog’:2,'cat':1,'fish':3,'bird':0} 字典形式呈现,key:词,value:可以理解为每一个词的标记索引,本质上是向量化
# 
# print(cv_fit)
# #(0,3) 1   列表中第0个元素,**词典中索引为3的元素**, 出现的次数
# #(0,1)1
# #(0,2)1
# #(1,1)2
# #(1,2)1
# #(2,0)1
# #(2,3)1
# #(3,0)1
# 
# print(cv_fit.toarray()) #.toarray() 是将结果转化为稀疏矩阵矩阵的表示方式;本身也为方阵,每一行4个数值,分别表示bird,cat,dog,fish 出现的次数
# #[[0 1 1 1]
# #[0 2 1 0]
# #[1 0 0 1]
# #[1 0 0 0]]
# 
# print(cv_fit.toarray().sum(axis=0))  #每个词在所有文档中的词频
# #2 3 2 2]
# 

# In[80]:


#下面计算soup 列的相似度
from sklearn.feature_extraction.text import CountVectorizer

count=CountVectorizer(stop_words='english')
count_num=count.fit(df['soup'])
count_matrix=count_num.transform(df['soup'])
count_num.get_feature_names()
count_num.vocabulary_
count_matrix

from sklearn.metrics.pairwise import cosine_similarity
cosine_sim1=cosine_similarity(count_matrix,count_matrix)

indices=pd.Series(df.index,index=df["title"]).drop_duplicates(inplace=False)


def movie_recommendations2(title,cosine_sim=cosine_sim1):#输入某一个电影的推荐电影
    idx=indices[title]#某一部电影的索引位置
    #得到该电影与其他电影的相似度
    sim_scores=list(enumerate(cosine_sim[idx]))#由远足构成的列表,第一个为电影索引位置,第二个为相似分数
    sim_scores=sorted(sim_scores,key=lambda x:x[1],reverse=True)#注意lambda 的用法
    sim_scores_top=sim_scores[1:11]#排除它自己,然后取出前十
    movies_sim_index=[i[0] for i in sim_scores_top]
    return df['title'].iloc[movies_sim_index]


movie_recommendations2('The Shawshank Redemption')
    
    

    
    
"""
至此,第二种推荐方法完毕
我们既可以通过电影的额内容来进行推荐
也可以通过电影的导演,演员,类型进行相关的推荐
十分棒!良心kernels
"""


# # Collaborative Filtering

# 上面的电影推荐系统,有一个很大的缺陷就是,它只能推荐一些同类型的的电影,不同类型的电影几乎无法推荐,
# 另外这样的推荐系统并没有考虑到个体的差异性,因此,每一位不同的用户通过搜索引擎推荐的电影都是一样的
# 这显然不行,因此也就需要第三种推荐器
# 
# 
# 有两种分析方法--1.计算用户之间的相似度,可以用皮尔逊相似度或者余弦相似度,但是比较法尴尬的是用户的兴趣度是会
# 随着时间的变化而变化的,因此没有长期时效性
# 
# ---2.基于用户评分项目的相似度,用户对哪些项目进行评测后,找寻这些评测项目的相似项目
# 
# 

# In[92]:


### 下面就学习一下,sklearn的相关推荐系统库
from surprise import Dataset, Reader,SVD,evaluate 

reader=Reader()#首先需要定义一个类似于解读器的东西,解读文件
rating=pd.read_csv(r'C:\Users\Lenovo\Desktop\hands-on-machine-learning\ratings_small.csv')
data=Dataset.load_from_df(rating[['userId','movieId','rating']],reader)
data.split(n_folds=5)##分割五次,也就是出来五次结果,相当于做五次平行实验
svd=SVD()
evaluate(svd,data,measures=['RMSE','MAE']) ##不同的损失函数    看一下评估模型


trainset=data.build_full_trainset()#接下来用这个来加载数据集合
# svd.fit(trainset)


svd.predict(1,303,4)##对用户id 为1的人,对电影id303 的评分预测

##该方法只需要知道用户的id,就可以进行相关的预测

经过该项目,真的获益匪浅,明白了TF-IDF的实践用法,和常用的推荐系统理念,总之,对我个人很有启发,可以应用到其他很多实际

至此,关于训练营的作业已经初步完成,之后的一个月会继续寻找kaggle 的优质项目进行打卡训练,预测用时1个月。关于前篇文章中提到的github 上很火的机器学习100天,已经撸完了,周末奉上!

你可能感兴趣的:(机器学习实战项目9---异常检测监督学习及电影推荐)