機器學習實戰(zhàn)項目9---異常檢測監(jiān)督學習及電影推薦

  1. 描述異常檢測和監(jiān)督學習算法的區(qū)別
  2. 使用keras實現(xiàn)Collaborative Filtering,構(gòu)建電影推薦系統(tǒng)

answer1:
總結(jié)來說:
1)在異常檢測中,異常點是少之又少,大部分是正常樣本,異常只是相對小概率事件;
2)異常點的特征表現(xiàn)非常不集中,即異常種類非常多,不容易歸納。直白地說:正常的情況大同小異,而異常各不相同。這種情況用有限的正例樣本(異常點)給有監(jiān)督模型學習就很難從中學到有效的規(guī)律.

answer2:
關(guān)于 kaggle 中相關(guān)項目的鏈接https://www.kaggle.com/rounakbanik/movie-recommender-systems

我將開源的一個個人比較好的kernel 實踐了一遍

# coding: utf-8

# ## Demographic  filtering 
# 
# 需要注意兩個字段 一個是投票數(shù):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 是投票總數(shù) (vote_count)
# m 是最小投票數(shù)
# R 電影平均得分(vote_average)
# C是所有樣本電影的平均評分的均值
#  
# 
# 
# 
# 

# 關(guān)于movie recommendtion 的背景介紹
#  movies_metadata.csv 包含 movieslen 的45000數(shù)據(jù),字段有海報、背景、預算、收入、發(fā)行時間、語言、產(chǎn)地、公司
#  keywords.csv  包含電影情節(jié)的關(guān)鍵字,以json 格式存儲
#  credits.csv: 包含電影的演員或者場務(wù)人員的信息
#  links.csv:包含完整MovieLens數(shù)據(jù)集中所有電影的TMDB和IMDB id的文件
#  links_small.csv:包含完整數(shù)據(jù)集的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
#  
#  
#  三種典行的推薦系統(tǒng)
#  1. 人口統(tǒng)計過濾——他們根據(jù)電影的流行程度和/或類型,為每個用戶提供一般性的推薦。該系統(tǒng)向具有相似人口統(tǒng)計特征的用戶推薦相同的電影。由于每個用戶都不同,因此這種方法被認為過于簡單。這一體系背后的基本理念是,更受歡迎、更受好評的電影更有可能受到普通觀眾的喜愛。-----根據(jù)下面的例子,該方法的含義是大多數(shù)人對該電影的評價好,那么應(yīng)該就適合其他大部分群體
#  2.基于內(nèi)容的過濾——它們基于特定的項目推薦相似的項目。該系統(tǒng)使用電影類型、導演、描述、演員等項目元數(shù)據(jù)來做出這些推薦。這些推薦系統(tǒng)的基本思想是,如果一個人喜歡某個特定的商品,他或她也會喜歡與之相似的商品。
#  3.該系統(tǒng)匹配具有相似興趣的人,并根據(jù)這種匹配提供建議。協(xié)作過濾器不像基于內(nèi)容的過濾器那樣內(nèi)容的多項特征。

# 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)#分位數(shù)為0.9對應(yīng)的投票數(shù)

df_new=df.loc[df['vote_count']>m]
df_new.shape##得到該分位以上得所有數(shù)據(jù)


# 接下來需要利用上述的式子為電影打分

# 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)##排名第一的是肖申克的救贖
"""
該方法的理念就是評分高的電影(多數(shù)人參與投票,并且打出高分)適合推薦,
這個方法簡單粗暴,沒有結(jié)合電影的內(nèi)容,以個人喜好
"""


# ## 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喜歡的電影的特點,然后再將與其類似的電影推薦給他
# 我們將根據(jù)所有電影的情節(jié)描述計算彼此間相似度評分,并根據(jù)相似度評分推薦電影。電影的描述在數(shù)據(jù)集的overview中給出。讓我們看一下數(shù)據(jù)。
# 
# 該kernels 的作者采用的是TF--IDF的方法,簡單來說一個詞語的重要性,是隨著其在某一個文本中的出現(xiàn)的次數(shù)增多而權(quán)重加大,但是也同時隨著其在多個不同文本中出現(xiàn)的次數(shù)的增多,權(quán)重減少,該詞的權(quán)重是TF*IDF,
# 幸運的就是sklearn 有相關(guān)的 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_##非常重要的兩個方法,這個輸出一個詞語以及對應(yīng)的標量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部相關(guān)的電影
# 接下來就是要計算相似度, kernel 中有以下描述
# <span class="burk">With this matrix in hand, we can now compute a similarity score</span>. 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. <span class="burk">Different scores work well in different scenarios and it is often a good idea to experiment with different metrics.</span>
# 
# 本例子中我們就用的余弦定理,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. <span class="mark">Therefore, we will use sklearn's linear_kernel() instead of cosine_similarities() since it is faster.</span>
# 
# 

# In[42]:


from sklearn.metrics.pairwise import linear_kernel

#compute the cosine similiarity matrix 
cosine_sim=linear_kernel(tfidf_result,tfidf_result)#自身是個方陣,每一行都是其與自己和其他的相似度,因此最高的也就是其行數(shù)對應(yīng)的列,也就是對角線都為1

"""
接下來我們需要定義一個函數(shù)來輸入一部電影的名字,輸出與之類似的10部電影
"""
indices=pd.Series(df.index,index=df["title"]).drop_duplicates(inplace=False)
"""
接下來下來函數(shù)主要完成以下幾個步驟
獲取給定電影名稱的電影索引。

獲取該電影與所有電影的余弦相似度評分列表。將它轉(zhuǎn)換為一個元組列表,其中第一個元素是它的位置,第二個元素是相似度評分。

根據(jù)相似度評分對上述元組列表進行排序;也就是第二個元素。

獲取列表的前10個元素。忽略第一個元素,因為它指的是self(與特定電影最相似的是電影本身)。

返回與頂部元素的索引對應(yīng)的標題。

"""


def movie_recommendations1(title,cosine_sim=cosine_sim):#輸入某一個電影的推薦電影
    idx=indices[title]#某一部電影的索引位置
    #得到該電影與其他電影的相似度
    sim_scores=list(enumerate(cosine_sim[idx]))#由遠足構(gòu)成的列表,第一個為電影索引位置,第二個為相似分數(shù)
    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')

"""
到這一步,基本上系統(tǒng)可以將電影情節(jié)相似的電影很好的
推薦,但是該kernel的作者舉了個例子,比如蝙蝠俠:3 
系統(tǒng)會將所有的蝙蝠俠電影推薦一下,但是可能我們的用戶只是喜歡大導演 諾蘭 
想要看的僅僅是諾蘭的電影而已,這一點我們的推薦系統(tǒng)還做不到
"""




# In[61]:


###首先第一步就是先將字符串變?yōu)閜ython 可以處理的表達式
from ast import literal_eval
features=['cast','crew','keywords','genres']#選取四個特征,演員,場務(wù),電影的關(guān)鍵詞,電影的類型
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):#由字符串經(jīng)上邊的apply 轉(zhuǎn)化為了列表,即python 可處理的表達式
        names=[i['name'] for i in x]
        if len(names)>3:
            return names[:3]
        else:
            return names
    return []


###利用上述的函數(shù)將上述的特征進行處理

df['director']=df['crew'].apply(get_director)#直接構(gòu)建一列,存放導演
features=['cast','keywords','genres']#存放演員,電影內(nèi)容的關(guān)鍵詞,及電影類型

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




# 接下來的這一步也非常的關(guān)鍵,其中kernal 是這樣寫的
# The next step would be to convert the names and keyword instances into lowercase and strip all the spaces between them. <span class="burk">This is done so that our vectorizer doesn't count the Johnny of "Johnny Depp" and "Johnny Galecki" as the same.</span> 

# 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的用法是應(yīng)用到每一列上


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()#創(chuàng)建詞袋數(shù)據(jù)結(jié)構(gòu)
# cv_fit=cv.fit_transform(texts)
# #上述代碼等價于下面兩行
# #cv.fit(texts)
# #cv_fit=cv.transform(texts)
# 
# print(cv.get_feature_names()) ['bird', 'cat', 'dog', 'fish'] 列表形式呈現(xiàn)文章生成的詞典
# 
# print(cv.vocabulary_  ) {‘dog’:2,'cat':1,'fish':3,'bird':0} 字典形式呈現(xiàn),key:詞,value:可以理解為每一個詞的標記索引,本質(zhì)上是向量化
# 
# print(cv_fit)
# #(0,3) 1   列表中第0個元素,**詞典中索引為3的元素**, 出現(xiàn)的次數(shù)
# #(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() 是將結(jié)果轉(zhuǎn)化為稀疏矩陣矩陣的表示方式;本身也為方陣,每一行4個數(shù)值,分別表示bird,cat,dog,fish 出現(xiàn)的次數(shù)
# #[[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]))#由遠足構(gòu)成的列表,第一個為電影索引位置,第二個為相似分數(shù)
    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')
    
    

    
    
"""
至此,第二種推薦方法完畢
我們既可以通過電影的額內(nèi)容來進行推薦
也可以通過電影的導演,演員,類型進行相關(guān)的推薦
十分棒!良心kernels
"""


# # Collaborative Filtering

# 上面的電影推薦系統(tǒng),有一個很大的缺陷就是,它只能推薦一些同類型的的電影,不同類型的電影幾乎無法推薦,
# 另外這樣的推薦系統(tǒng)并沒有考慮到個體的差異性,因此,每一位不同的用戶通過搜索引擎推薦的電影都是一樣的
# 這顯然不行,因此也就需要第三種推薦器
# 
# 
# 有兩種分析方法--1.計算用戶之間的相似度,可以用皮爾遜相似度或者余弦相似度,但是比較法尷尬的是用戶的興趣度是會
# 隨著時間的變化而變化的,因此沒有長期時效性
# 
# ---2.基于用戶評分項目的相似度,用戶對哪些項目進行評測后,找尋這些評測項目的相似項目
# 
# 

# In[92]:


### 下面就學習一下,sklearn的相關(guān)推薦系統(tǒng)庫
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)##分割五次,也就是出來五次結(jié)果,相當于做五次平行實驗
svd=SVD()
evaluate(svd,data,measures=['RMSE','MAE']) ##不同的損失函數(shù)    看一下評估模型


trainset=data.build_full_trainset()#接下來用這個來加載數(shù)據(jù)集合
# svd.fit(trainset)


svd.predict(1,303,4)##對用戶id 為1的人,對電影id303 的評分預測

##該方法只需要知道用戶的id,就可以進行相關(guān)的預測

經(jīng)過該項目,真的獲益匪淺,明白了TF-IDF的實踐用法,和常用的推薦系統(tǒng)理念,總之,對我個人很有啟發(fā),可以應(yīng)用到其他很多實際

至此,關(guān)于訓練營的作業(yè)已經(jīng)初步完成,之后的一個月會繼續(xù)尋找kaggle 的優(yōu)質(zhì)項目進行打卡訓練,預測用時1個月。關(guān)于前篇文章中提到的github 上很火的機器學習100天,已經(jīng)擼完了,周末奉上!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容