使用 Django 实现机器学习的音乐推荐系统
我们什么时候在 YouTube 上看到过一段视频,假设它很有趣,那么下次您打开 YouTube 应用程序时,您会在源中收到一些有趣视频的推荐,您想过吗?这只不过是机器学习的一个应用程序,使用该应用程序构建推荐系统来提供个性化体验并提高客户参与度。
在本文中,我们将尝试构建一个非常基本的推荐系统,可以根据您听到的歌曲推荐歌曲。
导入库和数据集
Python库使我们可以非常轻松地使用一行代码处理数据并执行典型且复杂的任务。
- Pandas – 该库有助于以 2D 数组格式加载数据帧,并具有多种功能来一次性执行分析任务。
- Numpy – Numpy 数组非常快,可以在很短的时间内执行大量计算。
- Matplotlib / Seaborn – 该库用于绘制可视化效果。
- Sklearn – 该模块包含多个具有预实现功能的库,用于执行从数据预处理到模型开发和评估的任务。
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sb
from sklearn.metrics.pairwise import cosine_similarity
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.manifold import TSNE
import warnings
warnings.filterwarnings('ignore')
我们将使用的数据集包含大约 100 年期间发行的歌曲的数据。除了有关歌曲的一些一般信息外,还提供了一些声音的科学测量方法,如响度、声学、言语等。
tracks = pd.read_csv('tracks_records.csv')
tracks.head()
输出:
数据清理
数据清理是重要的步骤之一,没有它,数据将毫无用处,因为原始数据包含大量必须去除的噪音,否则从中进行的观察将不准确,如果我们在其上构建模型,那么它的性能也会很穷。数据清理中包含的步骤包括异常值去除、 空值插补以及修复数据的偏度。
tracks.shape
输出:
(586672, 19)
tracks.info()
输出1:
现在。让我们检查数据框的列中是否有空值。
tracks.isnull().sum()
输出2:
音乐流派是音乐类型的一个非常重要的指标,这就是为什么我们将删除此类具有空值的行。我们也可以进行估算,但我们有一个大约 60 万行的庞大数据集,因此删除 50,000 行不会产生太大影响(取决于情况)。
tracks.dropna(inplace = True)
tracks.isnull().sum().plot.bar()
plt.show()
输出3:
现在让我们删除一些不会用于构建推荐系统的列。
tracks = tracks.drop(['id', 'id_artists'], axis = 1)
探索性数据分析
EDA 是一种使用视觉技术分析数据的方法。它用于发现趋势和模式,或借助统计摘要和图形表示来检查假设。
我们拥有的数据集包含大约 14 个数字列,但我们无法可视化如此高维的数据。但为了解决这个问题,t-SNE来救援。t-SNE 是一种可以将高维数据转换为低维数据的算法,并使用一些非线性方法来实现此目的,这不是本文的讨论范围。
model = TSNE(n_components = 2, random_state = 0)
tsne_data = model.fit_transform(a.head(500))
plt.figure(figsize = (7, 7))
plt.scatter(tsne_data[:,0], tsne_data[:,1])
plt.show()
输出1:
在这里我们可以观察到一些集群。
我们知道同一首歌有多个版本发布,因此我们需要删除同一首歌的不同版本,因为我们正在构建一个基于内容的推荐系统,其背后的主要工作人员是余弦相似度函数,我们的系统将推荐以下版本同一首歌(如果有的话)但这不是我们想要的。
tracks['name'].nunique(), tracks.shape
输出2:
(408902, (536847, 17))
所以,我们的担忧是正确的,所以让我们根据歌曲名称删除重复的行。
tracks = tracks.sort_values(by=['popularity'], ascending=False)
tracks.drop_duplicates(subset=['name'], keep='first', inplace=True)
让我们想象一下每年发行的歌曲数量。
plt.figure(figsize = (10, 5))
sb.countplot(tracks['release_year'])
plt.axis('off')
plt.show()
输出3:
在这里我们可以看到从 1900 年到 1990 年左右音乐产业的繁荣。
floats = []
for col in tracks.columns:
if tracks[col].dtype == 'float':
floats.append(col)
len(floats)
输出4:
10
总共有 10 个这样的列,其中包含浮点值。让我们画出它们的分布图来深入了解数据的分布。
plt.subplots(figsize = (15, 5))
for i, col in enumerate(floats):
plt.subplot(2, 5, i + 1)
sb.distplot(tracks[col])
plt.tight_layout()
plt.show()
输出5:
某些特征具有正态分布,而某些数据分布也呈偏态。
由于数据集太大,计算成本/时间会太高,因此我们将使用最流行的 10,000 首歌曲来展示推荐系统的实现。
tracks = tracks.sort_values(by=['popularity'], ascending=False).head(10000)
下面是一个辅助函数,用于获取输入歌曲与数据集中每首歌曲的相似性
def get_similarities(song_name, data):
#获取输入歌曲的向量。
text_array1 = song_vectorizer.transform(data[data['name']==song_name]['genres']).toarray()
num_array1 = data[data['name']==song_name].select_dtypes(include=np.number).to_numpy()
#我们将为数据集的每一行存储相似度。
sim = []
for idx, row in data.iterrows():
name = row['name']
#获取当前歌曲的向量。
text_array2 = song_vectorizer.transform(data[data['name']==name]['genres']).toarray()
num_array2 = data[data['name']==name].select_dtypes(include=np.number).to_numpy()
# 计算文本和数字特征的相似性
text_sim = cosine_similarity(text_array1, text_array2)[0][0]
num_sim = cosine_similarity(num_array1, num_array2)[0][0]
sim.append(text_sim + num_sim)
return sim
为了计算两个向量之间的相似度,我们使用了余弦相似度的概念。
def recommend_songs(song_name, data=tracks):
# 基本情况
if tracks[tracks['name'] == song_name].shape[0] == 0:
print('This song is either not so popular or you\
have entered invalid_name.\n Some songs you may like:\n')
for song in data.sample(n=5)['name'].values:
print(song)
return
data['similarity_factor'] = get_similarities(song_name, data)
data.sort_values(by=['similarity_factor', 'popularity'],
ascending = [False, False],
inplace=True)
# 第一首歌将是输入歌曲本身,因为相似度最高。
display(data[['name', 'artists']][2:7])
输出1:
让我们再尝试一首歌曲。
输出2:
下图是歌曲名称输入错误时的情况。
recommend_songs('Love me like you do')
输出3:
结论
尽管此模型需要进行大量更改才能用于任何现实世界的音乐应用程序或网站。但这只是推荐系统如何构建和使用的概述。