目次
序文
このプロジェクトは、Netease Cloud の豊富な音楽データに基づいて、協調フィルタリングとコンテンツ推奨アルゴリズムを中心的な手法として使用し、さまざまなユーザー向けに音楽推奨をカスタマイズすることを目的としています。
まず、ユーザーの視聴履歴、好きな歌手、好きな曲などの情報を含む、Netease Cloud Music の大量のユーザーデータを最大限に活用します。協調フィルタリング アルゴリズムを通じて、さまざまなユーザー間の類似性を分析し、同様の音楽嗜好を持つユーザー グループを見つけることができます。
次に、コンテンツ推薦アルゴリズムを導入し、音楽の特徴、ジャンル、歌手のスタイルなどの側面から詳細な分析を行います。このアルゴリズムにより、ユーザーの好みや興味に合った音楽作品をより正確にレコメンドできるようになります。
協調フィルタリングの結果とコンテンツの推奨を組み合わせて、ユーザーごとにパーソナライズされた音楽推奨リストを作成します。このようにして、さまざまなユーザーが Netease Cloud Music プラットフォームで自分の音楽の好みに合った曲を入手できるようになり、音楽体験が向上します。
このプロジェクトの目標は、ビッグデータ分析とインテリジェントな推奨アルゴリズムの利点を最大限に活用し、NetEase Cloud Music ユーザーに、よりパーソナライズされた多様な音楽推奨サービスを提供することです。これにより、ユーザーにさらなる音楽の発見と楽しみをもたらすと同時に、音楽プラットフォームの発展とユーザー満足度の向上を促進します。
全体的なデザイン
システムの全体構成図とシステムフローチャートを記載します。
システム全体構成図
システムの全体構成を図に示します。
システムフローチャート
システムフローを図に示します。
動作環境
このセクションには、Python 環境、MySQL 環境、および VUE 環境が含まれます。
Python環境
Python 3.6 以降の動作環境が必要で、PyCharm IDE が推奨されます。Python パッケージと対応するバージョンMusicRecSys/MusicRec/z-others/files/requirement.txt
ファイルのインストール コマンドは次のとおりです。
pip install -r requirement.txt
インストールする必要がある依存パッケージは次のとおりです: Django 2.1、PyMySQL 0.9.2、jieba 0.39、xlrd 1.1.0、gensim 3.6.0
マシンの IP アドレスを確認し、MusicRecSys/MusicRec/Music Rec/settings.py ファイル内のローカル IP アドレスと MySQL 構成情報を変更しますALLOWED_HOSTS
。
MusicRecSys/MusicRec と入力し、 を実行しますpythonmanage.pyrunserver0.0.0.0: 8000
。
Django のバックグラウンド アクセス アドレスはhttp://127.0.0.1:8000/admin/(admin, admin)
MySQL環境
最新バージョンの MySQL と Navicat 視覚化ツールをインストールし、コマンド ラインでローカル ユーザー データベースを作成して接続します。ダウンロード アドレスはhttps://pan.baidu.com/s/1dYtKQxnoSZywuRfgCOfPRQ、抽出コードは qw8k です。
新しい musicrec データベースを作成し、ファイルをインポートしますMusicRecSys/MusicRec/z-others/fles/musicrec.sql
VUE環境
Node.js 10.13 以降と npm パッケージ マネージャーをインストールします (速度を向上させるために Taobao ミラー cnpm をインストールできます)。VSCODEIDE が推奨されます。
変更されるserverUrlはMusicRecSys/MusicRec-Vue/config/index.js
ローカルIPアドレスです。
変更されるserverUrlはMusicRecSys/MusicRec-Vue/src/assets/js/linkBase.js
ローカルIPアドレスです。
と入力しMusicRecSys/MusicRec-Vue
、npminstall/npmrundev
必要な依存関係パッケージの自動インストールを実行し、webpack を使用してパッケージ化して実行します。
ブラウザにhttp://127.0.0.1:8001と入力して、プロジェクト インターフェイスにアクセスします。
モジュールの実装
このプロジェクトには、データ要求と保存、データ処理、データ保存とバックグラウンド、データ表示の 4 つのモジュールが含まれており、各モジュールの機能と関連コードを以下に紹介します。
1. データのリクエストと保存
リクエストに応じて、音楽とユーザーに関連するすべてのデータを取得します。NetEase Cloud API アドレスはhttps://api.imjad.cnです。曲リスト データが開始点として選択されるのは、曲リストがユーザー、曲、歌手に関連しており、データの最も幅広い次元が含まれており、ユーザーの主観的な行動であるためです。プレイリストのURLは以下の通りです。
https://music163.com/playlist?id=2308644764
https://music163.com/playlist?id=2470855457
https://music163.com/playlist?id=2291941158
https://music163.com/playlist?id =2452844647
URL 処理を通じて曲リスト ID を取得し、必要なデータをリクエストし、リクエストの各ステップで失敗したデータを保存し、その後のデータ処理中にリクエストに失敗したデータ URL をスキップします。
1) 楽曲リスト情報
ソングリスト情報を図に示します。
楽曲リスト情報には、楽曲リストID、作成者ID、名前、作成時刻、更新時刻、楽曲数、再生回数、シェア回数、コメント回数、お気に入り回数、タグ、楽曲リストのカバーなどが含まれます。
2) クリエイター情報
作成者情報を図に示します。
作成者情報には、ユーザー ID、ニックネーム、誕生日、性別、都道府県、都市、タイプ、ラベル、アバター リンク、ユーザー ステータス、アカウント ステータス、djStatus、vipStatus、署名が含まれます。
3) 楽曲情報
曲ID情報を図に示します。
曲情報は図のとおりです。
曲情報には、曲 ID、曲タイトル、アルバム ID、公開時刻、歌手情報、総コメント数、人気コメント数、サイズ、曲リンクが含まれます。
4) 曲に対応する歌手情報
歌手情報は図に示されています。
歌手情報には、歌手ID、曲名、音楽作品数、MV作品数、アルバム数、アバターリンクなどが含まれます。データファイルの構造は図に示されています。
最後に、必要な基本データと失敗したリクエスト データが取得され、プレイリスト情報を取得して保存するための関連コードは次のとおりです。
import requests
import traceback
#获取每个歌单的信息类
class PlayList:
def __init__(self):
self.playlist_file = "./data/playlist_url/playlist_id_name_all.txt"
#获取出错的歌单ID保存文件
self.error_id_file = "./data/error_playlist_ids.txt"
#歌单创造者信息
self.creator_mess = "./data/user_mess/"
#每个歌单的json信息
self.playlist_mess = "./data/playlist_mess/"
#歌单包含的歌曲ID信息
self.trackid_mess = "./data/song_mess/"
self.ids_list = self.getIDs()
self.url = "https://api.imjad.cn/cloudmusic/?type=playlist&id="
#获得的歌单信息出错的歌单ID
self.error_id = list()
#由歌单url 获取歌单ID
def getIDs(self):
print("根据歌单链接获取歌单ID ...")
ids_list = list()
for line in open(self.playlist_file,"r",encoding="utf-8").readlines():
try:
id = line.strip().split("\t")[0].split("id=")[1]
ids_list.append(id)
except Exception as e:
print(e)
pass
print("获取歌单ID完成 ...")
return ids_list
#获取每个歌单的具体信息url #https://api.imjad.cn/cloudmusic/?type=playlist&id=2340739428
def getEveryPlayListMess(self):
print("获取每个歌单的具体信息")
i = 0
while self.ids_list.__len__() !=0 :
i += 1
id = self.ids_list.pop()
url = self.url + str(id)
try:
print("%s - 歌单ID为:%s" % (i,id))
r = requests.get(url)
#解析信息
self.getFormatPlayListMess(r.json())
except Exception as e:
#将出错ID写入记录及写入文件,出错时进行跳过
print(e)
traceback.print_exc()
print("歌单ID为:%s 获取出错,进行记录" % id)
self.error_id.append(id)
pass
#break
self.writeToFile(self.error_id_file,",".join(self.error_id))
print("歌单信息获取完毕,写入文件: %s" % self.playlist_mess)
#每个歌单的内容进行格式化处理写入文件
#需要获取的信息: 歌单信息、创建者信息、歌单音乐信息
def getFormatPlayListMess(self,json_line):
#创建者信息:用户ID、昵称、生日、性别、省份、城市、类型、标签、头像链接、用户状态、账号状态、djStatus,vipStatus、签名
creator = json_line["playlist"]["creator"]
c_list = (
str(creator["userId"]),
str(creator["nickname"]),
str(creator["birthday"]),
str(creator["gender"]),
str(creator["province"]),
str(creator["city"]),
str(creator["userType"]),
str(creator["expertTags"]),
str(creator["avatarUrl"]),
str(creator["authStatus"]),
str(creator["accountStatus"]),
str(creator["djStatus"]),
str(creator["vipType"]),
str(creator["signature"]).replace("\n","")
)
self.writeToFile(self.creator_mess + "user_mess_all.txt"," |=| ".join(c_list))
#歌单信息
#歌单ID、创建者ID、名字、创建时间、更新时间、播放次数、分享次数、评论次数、收藏次数、标签、歌单封面、描述
playlist = json_line["playlist"]
p_list = [
str(playlist["id"]),
str(playlist["userId"]),
str(playlist["name"]).replace("\n",""),
str(playlist["createTime"]),
str(playlist["updateTime"]),
str(playlist["trackCount"]),
str(playlist["playCount"]),
str(playlist["shareCount"]),
str(playlist["commentCount"]),
str(playlist["subscribedCount"]),
str(playlist["tags"]),
str(playlist["coverImgUrl"]),
str(playlist["description"]).replace("\n","")
]
self.writeToFile(self.playlist_mess + "pl_mess_all.txt"," |=| ".join(p_list))
#歌单包含的歌曲信息
t_list = list()
trackids = json_line["playlist"]["trackIds"]
for one in trackids:
t_list.append(str(one["id"]))
self.writeToFile(self.trackid_mess + "ids_all1.txt",str(playlist["id"])+"\t"+",".join(t_list))
#写入文件
def writeToFile(self,filename,one):
fw = open(filename,"a",encoding="utf8")
fw.write(str(one) + "\n")
fw.close()
if __name__ == "__main__": #主函数
print("开始获取歌单信息 ..")
pl = PlayList()
pl.getEveryPlayListMess()
print("歌单信息获取完毕 ... Bye !")
2. データ処理
このセクションには、曲、歌手、ユーザーの類似性の計算、およびユーザーの推奨セットの計算が含まれます。
曲、歌手、ユーザーの類似性を計算します
プレイリストの作成時にユーザーがタグを指定すると、システムはユーザーがそのタグに好みがあると判断し、ユーザーが作成したすべてのプレイリストを走査してタグ ベクトルを与えます。
たとえば、システムに 3 つのタグ (日本語、ヒップホップ、沈黙) があり、曲リストでユーザー Zhang San が使用するタグが日本語とヒップホップの場合、対応するタグ ベクトルは [1, 1] になります。 , 0]、ユーザーの類似度に従ってラベル ベクトルは Jaccard 距離アルゴリズムを使用してユーザーの類似性を計算します。プレイリスト、歌手、曲の類似度の計算ロジックは、ユーザーの類似度の計算ロジックと同じです。関連するコードは次のとおりです。
#计算用户相似度,全量用户存储数据量大,所以这里只存储了20个用户,并且要求相似度大于0.8
def getUserSim(self):
sim = dict()
if os.path.exists("./data/user_sim.json"): #路径
sim = json.load(open("./data/user_sim.json","r",encoding="utf-8"))
else:
i = 0
for use1 in self.userTags.keys():
sim[use1] = dict()
for use2 in self.userTags.keys():
if use1 != use2:
j_len = len (self.userTags[use1] & self.userTags[use2] )
if j_len !=0:
result = j_len / len(self.userTags[use1] | self.userTags[use2])
if sim[use1].__len__() < 20 or result > 0.8:
sim[use1][use2] = result
else:
#找到最小值并删除
minkey = min(sim[use1], key=sim[use1].get)
del sim[use1][minkey]
i += 1
print(str(i) + "\t" + use1)
json.dump(sim, open("./data/user_sim.json","w",encoding="utf-8"))
print("用户相似度计算完毕!")
return sim
#将计算出的相似度转成导入mysql的格式
def transform(self):
fw = open("./data/user_sim.txt","a",encoding="utf-8")
for u1 in self.sim.keys():
for u2 in self.sim[u1].keys():
fw.write(u1 + "," + u2 + "," + str(self.sim[u1][u2]) + "\n")
fw.close()
print("Over!")
ユーザー推奨セットを計算する
このパートでは主に、ユーザー向けの曲の推奨を生成するための協調フィルタリング アルゴリズムを紹介します。これは、曲リスト、ユーザー、歌手の推奨アルゴリズムと同様です。
(1) RecSongクラスの作成
関連するコードは次のとおりです。
class RecSong:
def __init__(self):
self.playlist_mess_file = "../tomysql/data/pl_mess_all.txt"
self.playlist_song_mess_file = "../tomysql/data/pl_sing_id.txt"
self.song_mess_file = "../tomysql/data/song_mess_all.txt"
# 在__init__(self)中指定了所使用的文件
2) ユーザーと楽曲の対応関係を構築する
ユーザーは、曲を含むプレイリストを作成します。ユーザーが曲をプレイリストにアーカイブすると、その曲のスコア値は 1 とみなされます。同じ曲が複数回アーカイブされた場合、各アーカイブのスコア値は 1 ずつ増加します。関連するコードは次のとおりです。
#加载数据 =>用户对歌曲的对应关系
def load_data(self):
#所有用户
user_list = list()
#歌单和歌曲对应关系
playlist_song_dict = dict()
for line in open(self.playlist_song_mess_file, "r", encoding="utf-8"):
#歌单 \t 歌曲s
playlist_id, song_ids = line.strip().split("\t")
playlist_song_dict.setdefault(playlist_id, list())
for song_id in song_ids.split(","):
playlist_song_dict[playlist_id].append(song_id)
#print(playlist_sing_dict)
print("歌单和歌曲对应关系!")
#用户和歌曲对应关系
user_song_dict = dict()
for line in open(self.playlist_mess_file, "r", encoding="utf-8"):
pl_mess_list = line.strip().split(" |=| ")
playlist_id, user_id = pl_mess_list[0], pl_mess_list[1]
if user_id not in user_list:
user_list.append(user_id)
user_song_dict.setdefault(user_id, {
})
for song_id in playlist_song_dict[playlist_id]:
user_song_dict[user_id].setdefault(song_id, 0)
user_song_dict[user_id][song_id] += 1
#print(user_song_dict)
print("用户和歌曲对应信息统计完毕 !")
return user_song_dict, user_list
3) ユーザー類似度の計算
ユーザーへの曲の推奨は協調フィルタリング アルゴリズムに基づいており、ユーザーの類似性を計算する必要があります。計算は、転置リストの作成と類似度行列の作成の 2 つのステップに分かれており、計算式は次のとおりです。
wuv = ∑ i ∈ N ( u ) ∩ N ( v ) 1 lg ( 1 + ∣ N ( i ) ∣ ) ∣ N ( u ) ∥ N ( v ) ∣ {w_{uv}}=\frac{\sum_ {i \in N(u) \cap N(v)} \frac{1}{\lg (1+|N(i)|)}}{\sqrt{|N(u) \| N(v)|}}w紫外線=∣ N ( u ) ∥ N ( v ) ∣∑i ∈ N ( u ) ∩ N ( v )l g ( 1 + ∣ N ( i ) ∣ )1
関連するコードは次のとおりです。
#计算用户之间的相似度,采用惩罚热门商品和优化复杂度的算法
def UserSimilarityBest(self):
#得到每个item被哪些user评价过
tags_users = dict()
for user_id, tags in self.user_song_dict.items():
for tag in tags.keys():
tags_users.setdefault(tag,set())
if self.user_song_dict[user_id][tag] > 0:
tags_users[tag].add(user_id)
#构建倒排表
C = dict()
N = dict()
for tags, users in tags_users.items():
for u in users:
N.setdefault(u,0)
N[u] += 1
C.setdefault(u,{
})
for v in users:
C[u].setdefault(v, 0)
if u == v:
continue
C[u][v] += 1 / math.log(1+len(users))
#构建相似度矩阵
W = dict()
for u, related_users in C.items():
W.setdefault(u,{
})
for v, cuv in related_users.items():
if u==v:
continue
W[u].setdefault(v, 0.0)
W[u][v] = cuv / math.sqrt(N[u] * N[v])
print("用户相似度计算完成!")
return W
4) 曲に対するユーザーの考えられる好みを計算します。
同様のユーザーをすべて調査し、アーカイブされていない曲に対するユーザーの好みを計算します。関連するコードは次のとおりです。
#为每个用户推荐歌曲
def recommend_song(self):
#记录用户对歌手的评分
user_song_score_dict = dict()
if os.path.exists("./data/user_song_prefer.json"):
user_song_score_dict = json.load(open("./data/user_song_prefer.json", "r", encoding="utf-8"))
print("用户对歌手的偏好从文件加载完毕!")
return user_song_score_dict
for user in self.user_song_dict.keys():
print(user)
user_song_score_dict.setdefault(user, {
})
#遍历所有用户
for user_sim in self.user_sim[user].keys():
if user_sim == user:
continue
for song in self.user_song_dict[user_sim].keys():
user_song_score_dict[user].setdefault(song,0.0)
user_song_score_dict[user][song] += self.user_sim[user][user_sim] * self.user_song_dict[user_sim][song]
json.dump(user_song_score_dict, open("./data/user_song_prefer.json", "w", encoding="utf-8"))
print("用户对歌曲的偏好计算完成!")
return user_song_score_dict
5) ファイルに書き込む
各曲の好みを分類し、ユーザーがアーカイブする可能性が最も高い上位 100 曲をファイルに書き込みます。このファイルは、システムで使用するためにデータベースに簡単にインポートできます。関連するコードは次のとおりです。
#写入文件
def write_to_file(self):
fw = open("./data/user_song_prefer.txt","a",encoding="utf-8")
for user in self.user_song_score_dict.keys():
sort_user_song_prefer = sorted(self.user_song_score_dict[user].items(), key=lambda one:one[1], reverse=True)
for one in sort_user_song_prefer[:100]:
fw.write(user+','+one[0]+','+str(one[1])+'\n')
fw.close()
print("写入文件完成")
user_song_prefer.txt
ファイルの内容を図に示します。
プレイリスト、歌手、ユーザーの推薦結果も同様に算出されます。
3. データストレージとバックグラウンド
PyCharm で新しい Django プロジェクトと 5 つのテンプレート (ホームページ、プレイリスト、アーティスト、ソング、ユーザー) を作成します。テンプレートは、プレゼンテーションとコンテンツを分離するために使用されるテキスト ファイルです。以下では、ソングリストテンプレートを例に、各ファイルの用途を紹介します。Django プロジェクトの構造を図に示します。
一部のファイルには大きなデータが含まれており、Navicat ソフトウェア ツールを使用してインポートされます。残りのファイルは、データベースに接続するための Python コードを使用してインポートされます。曲リスト情報インポートデータベースを例として、Django で作成された Model レイヤーの関連コードは次のとおりです。
#歌单信息:歌单ID、创建者ID、名字、创建时间、更新时间、包含音乐数
#播放次数、分享次数、评论次数、收藏次数、标签、歌单封面、描述
class PlayList(models.Model):
pl_id = models.CharField(blank=False, max_length=64, verbose_name="ID", unique=True)
pl_creator = models.ForeignKey(User, related_name="创建者信息", on_delete=False)
pl_name = models.CharField(blank=False, max_length=64, verbose_name="歌单名字")
pl_create_time = models.DateTimeField(blank=True, verbose_name="创建时间")
pl_update_time = models.DateTimeField(blank=True, verbose_name="更新时间")
pl_songs_num = models.IntegerField(blank=True,verbose_name="包含音乐数")
pl_listen_num = models.IntegerField(blank=True,verbose_name="播放次数")
pl_share_num = models.IntegerField(blank=True,verbose_name="分享次数")
pl_comment_num = models.IntegerField(blank=True,verbose_name="评论次数")
pl_follow_num = models.IntegerField(blank=True,verbose_name="收藏次数")
pl_tags = models.CharField(blank=True, max_length=1000, verbose_name="歌单标签")
pl_img_url = models.CharField(blank=True, max_length=1000, verbose_name="歌单封面")
pl_desc = models.TextField(blank=True, verbose_name="歌单描述")
def __str__(self):
return self.pl_id
class Meta:
db_table = 'playList'
verbose_name_plural = "歌单信息"
#歌单信息写入数据库
def playListMessToMysql(self):
i=0
for line in open("./data/pl_mess_all.txt", "r", encoding="utf-8"):
pl_id, pl_creator, pl_name, pl_create_time, pl_update_time, pl_songs_num, pl_listen_num, \
pl_share_num, pl_comment_num, pl_follow_num, pl_tags, pl_img_url, pl_desc = line.split(" |=| ")
try:
user = User.objects.filter(u_id=pl_creator)[0]
except:
user = User.objects.filter(u_id=pl_creator)[0]
pl = PlayList(
pl_id = pl_id,
pl_creator = user,
pl_name = pl_name,
pl_create_time = self.TransFormTime(int(pl_create_time)/1000),
pl_update_time = self.TransFormTime(int(pl_update_time)/1000),
pl_songs_num = int (pl_songs_num),
pl_listen_num = int( pl_listen_num ),
pl_share_num = int( pl_share_num) ,
pl_comment_num = int (pl_comment_num),
pl_follow_num = int(pl_follow_num),
pl_tags = str(pl_tags).replace("[","").replace("]","").replace("\'",""),
pl_img_url = pl_img_url,
pl_desc = pl_desc
)
pl.save()
i+=1
print(i)
実行が完了すると、図 1 と図 2 に示すように、データベース視覚化管理ソフトウェア Navicat および Django のバックグラウンド管理で、対応するデータ テーブルを表示できます。
最後に、次の 2 つの図に示すように、すべてのデータ テーブルが取得されます。
4. データ表示
フロントエンドによって実装される機能には、ユーザーのログインと好みの曲と歌手の選択、あなたへのおすすめ (さまざまなユーザーの行動、さまざまなおすすめ)、各ページに入るときに、コンテンツベースのおすすめアルゴリズムがユーザーに曲リストをおすすめします。協調フィルタリング アルゴリズムにより、ユーザー、歌手に曲を推奨します。クリックすると詳細情報が表示され、個々のプレイリスト、曲、歌手、ユーザーに関する推奨事項が提供されます。パーソナライズされたランキング (類似性を大きいものから小さいものに並べ替えます)、サイト内でのユーザーの行動を示す足跡(クリックすると単一レコード)。
(1) Django バックグラウンドはフロントエンド リクエストを処理して、ビュー レイヤーの推奨タグと関連コードを取得します。
#首页推荐标签
"""
由于标签个数原因,且歌单、歌手、歌曲共用一套标签,这里标签推荐基于
1)用户进入系统时的选择
2)用户在站内产生的单击行为
3)热门标签进行补数
"""
def GetRecTags(request, base_click):
#从接口中获取传入的歌手和歌曲ID
sings = request.session["sings"].split(",")
songs = request.session["songs"].split(",")
#歌手标签
sings_tags = getSingRecTags(sings, base_click)
#歌曲标签
songs_tags,pl_tags = getSongAndPlRecTags(songs, base_click)
return {
"code": 1,
"data": {
"playlist": {
"cateid": 2, "tags": list(pl_tags)},
"song": {
"cateid": 3, "tags": list(songs_tags)},
"sing": {
"cateid": 4, "tags": list(sings_tags)},
}
}
#获得歌曲、歌单标签推荐
def getSongAndPlRecTags(songs, base_click):
song_tags = list()
pl_tags = list()
#base_click =1 表示用户是在站内产生行为后返回推荐,此时用户行为对象对应的标签排序在前
#否则基于用户选择的标签排序在前
if base_click == 1: #表示前端是基于单击行为进入为你推荐模块
click_songs = UserBrowse.objects.filter(click_cate="3").values("click_id")
if click_songs.__len__() != 0:
for one in click_songs:
filter_one = SongTag.objects.filter(song_id=one["click_id"])
if filter_one.__len__() != 0 and filter_one[0].tag not in song_tags:
song_tags.append(filter_one[0].tag)
#歌单tag
pl_one = PlayListToSongs.objects.filter( song_id=filter_one[0].song_id )
if pl_one.__len__() !=0:
for pl_tag_one in PlayListToTag.objects.filter(pl_id=pl_one[0].song_id):
if pl_tag_one.tag not in pl_tags:
pl_tags.append(pl_tag_one.tag)
if songs.__len__() != 0: #表示前端选择了相关歌曲
for sing in songs:
choose_one = SongTag.objects.filter(song_id=sing)
if choose_one.__len__() != 0 and choose_one[0].tag not in song_tags:
song_tags.append(choose_one[0].tag)
#歌单tag
pl_one= layListToSongs.objects.filter(song_id=choose_one[0].song_id)
if pl_one.__len__() != 0:
for pl_tag_one in PlayListToTag.objects.filter(pl_id=pl_one[0].song_id):
if pl_tag_one.tag not in pl_tags:
pl_tags.append(pl_tag_one.tag)
#print("songs_tags_by_click %s" % songs_tags_by_click)
#print("pl_tags_by_click %s" % pl_tags_by_click)
else: #表示用户是首次进入为你推荐模块
if songs.__len__() != 0: #表示前端选择了相关歌曲
for sing in songs:
choose_one = SongTag.objects.filter(song_id=sing)
if choose_one.__len__() != 0 and choose_one[0].tag not in song_tags:
song_tags.append(choose_one[0].tag)
#歌单tag
pl_one = PlayListToSongs.objects.filter(song_id=choose_one[0].song_id)
if pl_one.__len__() != 0:
for pl_tag_one in PlayListToTag.objects.filter(pl_id=pl_one[0].song_id):
if pl_tag_one.tag not in pl_tags:
pl_tags.append(pl_tag_one.tag)
#print("songs_tags_by_choose: %s" % songs_tags_by_choose)
#print("pl_tags_by_choose: %s" % pl_tags_by_choose)
#如果click和choose的tag不够以hot来补充
if song_tags.__len__() < 15:
hot_tag_dict = dict()
for one in SongTag.objects.all():
hot_tag_dict.setdefault(one.tag, 0)
hot_tag_dict[one.tag] += 1
tag_dict_song = sorted(hot_tag_dict.items(), key=lambda k: k[1], reverse=True)[:15-song_tags.__len__()]
for one in tag_dict_song:
if one[0] not in song_tags:
song_tags.append(one[0])
#print("songs_tags_by_hot: %s" % songs_tags_by_hot)
#如果 click 和 choose的tag不够,以 hot来补充
if pl_tags.__len__() < 15:
hot_tag_dict = dict()
for one in PlayListToTag.objects.all():
hot_tag_dict.setdefault(one.tag, 0)
hot_tag_dict[one.tag] += 1
tag_dict_pl = sorted(hot_tag_dict.items(), key=lambda k: k[1], reverse=True)[:15-pl_tags.__len__()]
for one in tag_dict_pl:
if one[0] not in pl_tags:
pl_tags.append(one[0])
#print("pl_tags_by_hot: %s" % pl_tags_by_hot)
return song_tags,pl_tags
(2) 各ページに入ると、ユーザーに曲リストを推奨するコンテンツベースの推奨アルゴリズムと、曲と歌手を推奨する協調フィルタリング アルゴリズムが表示されます。曲リストの例は次のとおりです。
def rec_right_playlist(request): #推荐歌单
user = request.GET.get("username")
u_id = User.objects.filter(u_name=user)[0].u_id
rec_all = UserPlayListRec.objects.filter(user=u_id).order_by("-sim")[:12]
_list = list()
for rec in rec_all:
one = PlayList.objects.filter(pl_id=rec.related)[0]
_list.append({
"pl_id": one.pl_id,
"pl_creator": one.pl_creator.u_name,
"pl_name": one.pl_name,
"pl_img_url": one.pl_img_url
})
return {
"code": 1,
"data": {
"recplaylist": _list
}
}
(3) クリックすると詳細情報が表示され、タグに基づいて個々のプレイリスト、曲、歌手、ユーザーが推奨されます。ユーザー向けの例は次のとおりです。
def all(request):
#接口传入的tag参数
tag = request.GET.get("tag")
#接口传入的page参数
_page_id = int(request.GET.get("page"))
print("Tag : %s, page_id: %s" % (tag,_page_id))
_list = list()
#全部用户
if tag == "all":
sLists = User.objects.all().order_by("-u_id")
#拼接用户信息
for one in sLists[(_page_id - 1) * 30:_page_id * 30]:
_list.append({
"u_id": one.u_id,
"u_name": one.u_name,
"u_img_url": one.u_img_url
})
#指定标签下的用户
else:
sLists = UserTag.objects.filter(tag=tag).values("user_id").order_by("user_id")
for sid in sLists[(_page_id - 1) * 30:_page_id * 30]:
one = User.objects.filter(u_id=sid["user_id"])
if one.__len__() == 1:
one = one[0]
else:
continue
_list.append({
"u_id": one.u_id,
"u_name": one.u_name,
"u_img_url": one.u_img_url
})
total = sLists.__len__()
return {
"code": 1,
"data": {
"total": total,
"sings": _list,
"tags": getAllUserTags()
}
}
#获取所有用户标签
def getAllUserTags():
tags = set()
for one in UserTag.objects.all().values("tag").distinct().order_by("user_id"):
tags.add(one["tag"])
return list(tags)
def one(request): #处理用户请求
u_id = request.GET.get("id")
one = User.objects.filter(u_id=u_id)[0]
wirteBrowse(user_name=request.GET.get("username"),click_id=u_id,click_cate="5", user_click_time=getLocalTime(), desc="查看用户")
return JsonResponse({
"code": 1,
"data": [
{
"u_id": one.u_id,
"u_name": one.u_name,
"u_birthday":one.u_birthday,
"u_gender":one.u_gender,
"u_province":one.u_province,
"u_city":one.u_city,
"u_tags":one.u_tags,
"u_img_url": one.u_img_url,
"u_sign":one.u_sign,
"u_rec": getRecBasedOne(u_id),
"u_playlist":getUserCreatePL(u_id)
}
]
})
#获取单个用户的推荐
def getRecBasedOne(u_id):
result = list()
sim_users = UserSim.objects.filter(user_id=u_id).order_by("-sim").values("sim_user_id")[:10]
for user in sim_users:
one = User.objects.filter(u_id= user["sim_user_id"])[0]
result.append({
"id": one.u_id,
"name": one.u_name,
"img_url": one.u_img_url,
"cate":"5"
})
return result
#获取用户创建的歌单
def getUserCreatePL(uid):
pls = PlayList.objects.filter(pl_creator__u_id=uid)
result = list()
for one in pls:
result.append(
{
"pl_id": one.pl_id,
"pl_name":one.pl_name,
"pl_creator": one.pl_creator.u_name,
"pl_create_time": one.pl_create_time,
"pl_img_url": one.pl_img_url,
"pl_desc":one.pl_desc
}
)
return result
#用户浏览信息进行记录
"""
user_name = models.CharField(blank=False, max_length=64, verbose_name="用户名")
click_id = models.CharField(blank=False, max_length=64, verbose_name="ID")
click_cate = models.CharField(blank=False, max_length=64, verbose_name="类别")
user_click_time = models.DateTimeField(blank=False, verbose_name="浏览时间")
desc = models.CharField(blank=False, max_length=1000, verbose_name="备注",default="Are you ready!")
"""
def wirteBrowse(user_name="",click_id="",click_cate="",user_click_time="",desc=""):
if "12797496" in click_id: click_id = "12797496"
UserBrowse(user_name=user_name,
click_id=click_id,
click_cate=click_cate,
user_click_time = user_click_time,
desc=desc).save()
print("用户【 %s 】的行为记录【 %s 】写入数据库" % (user_name, desc))
#获取当前格式化的系统时间
def getLocalTime():
return time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
システムテスト
このセクションには、システム フローとテスト結果が含まれます。
(1) システムに入るユーザーを選択します。図に示すように、毎回パーツがシステム ユーザーとしてデータベースからランダムに返され、動作の好みを区別するために異なるユーザーが使用されます。
(2) 歌手と曲を選択します(3つ以上、スキップ可能)。ユーザーとシステムの対話プロセスにより、システムのコールド スタートが解決されます。もちろん、歌手を選択せずに直接スキップすることもできます。このとき、システムの「あなたにおすすめの歌手タグ」の部分はホットタグデータであり、インターフェイスは次の 2 つの図に示されています。
(3) ユーザーのプレイリスト作成の好みに応じて、ユーザーの好みのプレイリストや楽曲をレコメンドします。ラベルをクリックすると、対応するラベルの下にあるすべての曲が表示され、図に示すように、それぞれ曲リスト、曲、およびアーティストの推奨ページに移動します。
(4) 楽曲リストのおすすめページです。図に示すように、左側にはタグによって分類されたすべてのプレイリストが表示され、右側にはコンテンツベースの推奨アルゴリズムによってユーザーに推奨されるプレイリストが表示されます。
(5) プレイリストの詳細ページ。プレイリストとプレイリスト内の楽曲の詳細情報が含まれており、図に示すように、右側にはタグの類似性に基づいたプレイリストの推奨が表示されます。
(6) 曲のおすすめページ。図に示すように、左側にはタグによって分類されたすべての曲が表示され、右側には協調フィルタリング アルゴリズムに基づいてユーザーに推奨される曲が表示されます。
(7)の楽曲詳細ページです。図に示すように、曲情報と歌詞が含まれており、右側にはタグの類似性に基づいたおすすめの曲リストが表示されます。
(8) 歌手の推薦ページ。図に示すように、左側にはタグによって分類されたすべての歌手が表示され、右側には協調フィルタリング アルゴリズムに基づいてユーザーに推奨される曲が表示されます。
(9) 歌手の詳細ページです。図に示すように、歌手の情報と曲が含まれており、右側にはタグの類似性に基づいた歌手の推薦が表示されます。
(10) ユーザーの推薦ページ。図に示すように、左側はタグによって分類されたすべてのユーザー、右側は協調フィルタリング アルゴリズムに基づいてユーザーに推奨されるユーザーです。
(11) ユーザー詳細ページ。図に示すように、ユーザーの情報と作成されたプレイリストが含まれており、右側はタグの類似性に基づいた推奨です。
(12) パーソナライズされたリーダーボード。図 5 から図 8 に示すように、ユーザーの好みの度合い (協調フィルタリング アルゴリズムの計算結果) に基づいて表示が並べ替えられ、異なるユーザーには異なる表示インターフェイスが表示されます。
(13) 私の足。ユーザーがプレイリスト、曲、歌手を閲覧するときにシステム内で生成される行動記録を図に示します。
プロジェクトのソースコードのダウンロード
詳細については、ブログ リソースのダウンロード ページをご覧ください。
その他の情報ダウンロード
人工知能関連の学習ルートと知識システムについて学び続けたい場合は、私の他のブログ「重い | 完全な人工知能 AI 学習 - 基本知識学習ルート、すべての資料は料金を支払わずにネットワーク ディスクから直接ダウンロードできます」を参照してください。 「ルーチンへの注意」
このブログでは、Github の有名なオープンソース プラットフォーム、AI テクノロジー プラットフォーム、および関連分野の専門家 (Datawhale、ApacheCN、AI Youdao、Huang Haiguang 博士など) について言及しています。関連資料は約 100G あります。友達全員を助けてください。