網易雲音樂基於使用者的推薦系統

Candy_GL發表於2019-03-04

轉自:https://blog.csdn.net/zhong_ethan/article/details/81393197

網易雲音樂核心功能是其推薦演算法,據觀察,日推主要採用itemCF方法。網易雲音樂根據每日獲取到的聽歌列表,優先推薦跟該歌曲相似的歌曲。如今,網易雲音樂著重社交功能,因此,本文嘗試構建基於使用者的推薦系統。

摘要:本文思路是根據使用者所有時間聽歌排行計算相似度,推薦使用者最近一週聽歌次數大於2次的歌曲。採用jaccard距離和向量餘弦計算相似度。本文目錄為資料集獲取、資料預處理、資料分析、演算法實現和結果輸出

一、資料集獲取

分析網易雲音樂聽歌排行頁面發現最近一週資料和所有時間資料是動態載入,因此使用requests+beautifulsoup很難獲得完整的資料。

進一步分析網頁原始碼,點選network,選擇XHR,重新載入網頁,我們在最後一個檔案中找到我們要的資料,下圖的preview為json檔案,點選headers可以看到,瀏覽器是使用post方法請求json資料,因此我們的爬蟲也使用post方法

上程式碼

import json
from urllib import request, parse
 
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36'
}
 
#從network-XHR-Headers-FromData中獲取data和url
data = {          'params':'bMCucP9w4r9XUMWjHedB1PBdNzcVLrZMbv+3QwlZu0RyNBYCiVYdQr/guQblmlxWuDeQIxQ86HP84U2tADFvAlVUQfZqzEErQpPoAzKgfNmr596MQUW/t+MFuQroJ1OpLYcf2VsSuWGWBZym4/mds70oCqij+kJGsjl1XIXzh6YLF36Nqr2bHWe25RENZ9oZox2mFwmbbBL6v5mQTuk9WgyzShZPJ8V0rmyKuUM='
 
'encSecKey': '31ab03c7f70469fdb89ea8184ee58501106acda3baa831a5e8e89c2950193d6ccff4ac086e089ff6712b9fe90773a042b735cb18c0e87a217baf8ffc40b59de1624527ea1899227be0e435b927346090abac1314b5f7c1da78cb4fdc8399bc1dc8195bb57db64948299c825ae47e9614508197f67fa141429bce875b3'
}
 
# 這個URL從網頁原始碼中查詢,為requestURL對應的
url = 'https://music.163.com/weapi/v1/play/record?csrf_token=74f92d802fc66dade9d176e77480ac'
 
data =parse.urlencode(data).encode('utf-8')
request1 = request.Request(url, data, headers = headers)
response = request.urlopen(request1)
html = response.read().decode('utf-8')
results = json.loads(html)
 
#這裡獲取到的result包括alldata 和 weekdata
從result結果中提取歌名,歌手以及score,最後將我們獲取到的資料儲存為json檔案,這裡的score對應的分數為(次數/max次數)轉為百分比

二、資料預處理

對歌曲名稱的預處理包括:去除歌名中括號,方括號的內容,去除歌名中非字母數字,去除歌名中空格,將大寫字母轉換為小寫

對歌曲作者的預處理包括:去除所有非字母數字,去除空格,將大寫轉換為小寫

這個步驟的作用是格式化字串,提高演算法速度

三、資料分析

常見的相似性度量方法有歐氏距離、皮爾遜相關度、jaccard距離、餘弦相似度。本文使用jaccard距離衡量使用者喜歡歌曲的相似性,用餘弦相似度衡量使用者對喜歡的歌曲的喜歡程度的相似性。根據使用者所有時間聽歌排行評價使用者相似性時,歌單裡的每一首歌都是使用者喜歡的歌,係數score代表使用者喜歡的程度。用A 代表使用者A喜歡的歌曲集合,用B 代表使用者B 喜歡的歌曲集合,則jaccard距離為:A∩B代表兩使用者同時喜歡的歌曲

考慮到使用者喜歡同一個歌手也具有相似性,因此此處的交集應包括兩使用者同時喜歡的歌手。

用C表示使用者A與B同時喜歡的歌曲中A集合對應的分數,D表示使用者A與B同時喜歡的歌曲中B集合對應的分數,則相似性為:

本文在最終處理資料時,使用了jaccard與cossimi的乘積代表其相似度,迭代計算使用者A與其他使用者之間的相似性,選擇值最大的使用者,推薦其最近一週聽歌次數大於一次的歌曲。

四、演算法實現

import json
import re
import numpy as np
 
 
# 開啟爬取到的資料集
with open('NeteaseMusicData.json', 'r') as f:
    data = json.load(f)
 
users = data['username']
 
pattern1 = '\(.*\)'  # 匹配圓括號中的內容
pattern2 = '\[.*\]'  # 匹配中括號中的內容
pattern3 = '\W'  # 匹配非字元內容
patterns = [pattern1, pattern2, pattern3]
 
 
# 清理資料,去除空格,符號,並將大寫轉為小寫
def remove(string, pat):
    obj = re.compile(pat)
    delstring = obj.findall(string)
    if delstring:
        for dels in delstring:
            string = string.replace(dels, '')
    return string.lower()
 
 
# 處理title列表,得到
def handletitle(user):
    title = [each[0] for each in data[user]['alldata']]
 
    titled = []
    for each in title:
        for pattern in patterns:
            each = remove(each, pattern)
        titled.append(each)
 
    return titled
 
 
# 處理singer列表資料,去除列表中的非字母數字符號,並將大寫轉換為小寫
def handlesinger(user):
    singers = [each[1] for each in data[user]['alldata']]
    singered = []
 
    for singer in singers:
        singer = remove(singer, pattern3)
        singer = singer.replace(' ', '').lower()
        singered.append(singer)
 
    return singered
 
 
# 計算兩個列表的重複元素
def repeatlist(list1, list2):
    relist = list()
    for each in list1:
        if each in list2:
            relist.append(each)
    return relist
 
 
# 計算jaccard相似度
def jaccardsimi(user1, user2):
    titled1 = handletitle(user1)
    titled2 = handletitle(user2)
 
    singered1 = handlesinger(user1)
    singered2 = handlesinger(user2)
 
    count1 = len(titled1)
    count2 = len(titled2)
 
    repeattitle = repeatlist(titled1, titled2)
    repeatsinger = repeatlist(singered1, singered2)
 
    if not repeattitle:
        return 0
 
    for each in repeattitle:
        index = titled1.index(each)
        dual = 0
        if singered1[index] in repeatsinger:
            dual += 1
 
    num = len(repeattitle) + len(repeatsinger) - dual
    deno = count1 + count2 - num
    jacsimi = (num / deno) * 100
 
    return jacsimi
 
 
# 計算重複歌曲列表的餘弦相似度
def cossimi(user1, user2):
    titled1 = handletitle(user1)
    titled2 = handletitle(user2)
 
    repeattitle = repeatlist(titled1, titled2)
 
    if not repeattitle:
        return 0
 
    def score(titlelist, user):
        scores = list()
        for each in repeattitle:
            index = titlelist.index(each)
            scores.append(data[user]['alldata'][index][2])
        return scores
 
    score1 = score(titled1, user1)
    score2 = score(titled2, user2)
 
    matrix1 = np.array(score1)
    matrix2 = np.array(score2)
    num = np.inner(matrix1, matrix2)
    deno = np.sqrt(matrix1.dot(matrix1)) * np.sqrt(matrix2.dot(matrix2))
    cosimi = (num / deno) * 100
 
    return cosimi
 
 
def main(username):
    if username not in users:
        print('該使用者不存在')
        return
 
    maxsimi = 0
    for eve in users:
        if username != eve:
            jacsimi = jaccardsimi(username, eve)
            cosimi = cossimi(username, eve)
            print('%s與%s的jaccard相似度是:%f%%' % (username, eve, jacsimi))
            print('%s與%s的餘弦相似度是:%f%%' % (username, eve, cosimi))
            if maxsimi < jacsimi * cosimi:
                maxsimi = jacsimi * cosimi
                maxuser = eve
 
    weekdata = data[maxuser]['weekdata']
 
    def minscore(weekdatalist):
        mins = 100
        for each in weekdatalist:
            if mins > each[2]:
                mins = each[2]
        return mins
 
    minsco = minscore(weekdata)
 
    recommendlist = [each for each in weekdata if each[2] > minsco]
    print('%s和%s的相似度最高,推薦的歌單列表為:' % (username, maxuser))
    print(recommendlist)
 
 
if __name__ == '__main__':
 
    main('yuzhong_沐陽')
 
 
五、結果輸出

 
yuzhong_沐陽與Tanya方良的jaccard相似度是:6.382979%
yuzhong_沐陽與Tanya方良的餘弦相似度是:90.803806%
yuzhong_沐陽與HarkerLee的jaccard相似度是:6.382979%
yuzhong_沐陽與HarkerLee的餘弦相似度是:90.968774%
yuzhong_沐陽與hyhsky0825的jaccard相似度是:6.382979%
yuzhong_沐陽與hyhsky0825的餘弦相似度是:94.077937%
yuzhong_沐陽與hi-M3U_玻色子的泛的jaccard相似度是:0.000000%
yuzhong_沐陽與hi-M3U_玻色子的泛的餘弦相似度是:0.000000%
yuzhong_沐陽和hyhsky0825的相似度最高,推薦的歌單列表為:
[['바람에 쓰는 편지', 'July', 100], ['Free Loop', 'Daniel Powter', 100], ['那個人', '周延英(英子-effie)', 100], ['熱勇', '慄先達', 100], ['Need You Now', 'Lady Antebellum', 100], ['借我一生', '水木年華', 100], ['孫大剩', '白亮', 100], ['褪變無路', '夏天播放', 100], ['被馴服的象', '蔡健雅', 100], ['丁香花', '唐磊', 100]]
 

不足之處:

2018/08/30

1.該演算法沒有進行評測。《推薦系統實踐》提出三種評測方法:離線實驗,使用者實驗,線上調查

評測指標有:使用者滿意度、預測準確率、覆蓋率、多樣性、新穎性(流行度),驚喜度

2.該演算法只推薦了一位使用者的歌單,歌曲覆蓋率不是很高,可考慮K個使用者,計算K個使用者的歌單權重,排序後推薦給使用者

3.改進jaccard距離演算法:懲罰了共同興趣列表中熱門物品對相似度的影響


--------------------- 
作者:yuzhong_沐陽 
來源:CSDN 
原文:https://blog.csdn.net/zhong_ethan/article/details/81393197 
版權宣告:本文為博主原創文章,轉載請附上博文連結!

相關文章