CategoryResourceRepost/极客时间专栏/数据结构与算法之美/高级篇/47 | 向量空间:如何实现一个简单的音乐推荐系统?.md
louzefeng d3828a7aee mod
2024-07-11 05:50:32 +00:00

79 lines
8.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<audio id="audio" title="47 | 向量空间:如何实现一个简单的音乐推荐系统?" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/e7/e2/e7642e15e8c038e7503c77487fb48ae2.mp3"></audio>
很多人都喜爱听歌以前我们用MP3听歌现在直接通过音乐App在线就能听歌。而且各种音乐App的功能越来越强大不仅可以自己选歌听还可以根据你听歌的口味偏好给你推荐可能会喜爱的音乐而且有时候推荐的音乐还非常适合你的口味甚至会惊艳到你如此智能的一个功能你知道它是怎么实现的吗
## 算法解析
实际上,要解决这个问题,并不需要特别高深的理论。解决思路的核心思想非常简单、直白,用两句话就能总结出来。
<li>
找到跟你口味偏好相似的用户,把他们爱听的歌曲推荐给你;
</li>
<li>
找出跟你喜爱的歌曲特征相似的歌曲,把这些歌曲推荐给你。
</li>
接下来,我就分别讲解一下这两种思路的具体实现方法。
### 1.基于相似用户做推荐
如何找到跟你口味偏好相似的用户呢或者说如何定义口味偏好相似呢实际上思路也很简单我们把跟你听类似歌曲的人看作口味相似的用户。你可以看我下面画的这个图。我用“1”表示“喜爱”用“0”笼统地表示“不发表意见”。从图中我们可以看出你跟小明共同喜爱的歌曲最多有5首。于是我们就可以说小明跟你的口味非常相似。
<img src="https://static001.geekbang.org/resource/image/cc/06/cc24a9c98a93795c75d8ef7a5892c406.jpg" alt="">
我们只需要遍历所有的用户,对比每个用户跟你共同喜爱的歌曲个数,并且设置一个阈值,如果你和某个用户共同喜爱的歌曲个数超过这个阈值,我们就把这个用户看作跟你口味相似的用户,把这个用户喜爱但你还没听过的歌曲,推荐给你。
不过,刚刚的这个解决方案中有一个问题,我们如何知道用户喜爱哪首歌曲呢?也就是说,如何定义用户对某首歌曲的喜爱程度呢?
实际上,我们可以通过用户的行为,来定义这个喜爱程度。我们给每个行为定义一个得分,得分越高表示喜爱程度越高。
<img src="https://static001.geekbang.org/resource/image/93/a6/93c26a89303a748199528fdd998ebba6.jpg" alt="">
还是刚刚那个例子我们如果把每个人对每首歌曲的喜爱程度表示出来就是下面这个样子。图中某个人对某首歌曲是否喜爱我们不再用“1”或者“0”来表示而是对应一个具体的分值。
<img src="https://static001.geekbang.org/resource/image/05/a9/056552502f1cf4fdf331488e0eed5fa9.jpg" alt="">
有了这样一个用户对歌曲的喜爱程度的对应表之后,如何来判断两个用户是否口味相似呢?
显然,我们不能再像之前那样,采用简单的计数来统计两个用户之间的相似度。还记得我们之前讲字符串相似度度量时,提到的编辑距离吗?这里的相似度度量,我们可以使用另外一个距离,那就是**欧几里得距离**Euclidean distance。欧几里得距离是用来计算两个向量之间的距离的。这个概念中有两个关键词向量和距离我来给你解释一下。
一维空间是一条线我们用123……这样单个的数来表示一维空间中的某个位置二维空间是一个面我们用134222……这样的两个数来表示二维空间中的某个位置三维空间是一个立体空间我们用135317243……这样的三个数来表示三维空间中的某个位置。一维、二维、三维应该都不难理解那更高维中的某个位置该如何表示呢
类比一维、二维、三维的表示方法K维空间中的某个位置我们可以写作$X_{1}$$X_{2}$$X_{3}$,…,$X_{K}$)。这种表示方法就是**向量**vector。我们知道二维、三维空间中两个位置之间有距离的概念类比到高纬空间同样也有距离的概念这就是我们说的两个向量之间的距离。
那如何计算两个向量之间的距离呢?我们还是可以类比到二维、三维空间中距离的计算方法。通过类比,我们就可以得到两个向量之间距离的计算公式。这个计算公式就是欧几里得距离的计算公式:
<img src="https://static001.geekbang.org/resource/image/f4/12/f4d1d906c076688a43380f82e47dce12.jpg" alt="">
我们把每个用户对所有歌曲的喜爱程度,都用一个向量表示。我们计算出两个向量之间的欧几里得距离,作为两个用户的口味相似程度的度量。从图中的计算可以看出,小明与你的欧几里得距离距离最小,也就是说,你俩在高维空间中靠得最近,所以,我们就断定,小明跟你的口味最相似。
<img src="https://static001.geekbang.org/resource/image/3e/89/3e145a3054c1abdea5d3f207d13e9b89.jpg" alt="">
### 2.基于相似歌曲做推荐
刚刚我们讲了基于相似用户的歌曲推荐方法,但是,如果用户是一个新用户,我们还没有收集到足够多的行为数据,这个时候该如何推荐呢?我们现在再来看另外一种推荐方法,基于相似歌曲的推荐方法,也就是说,如果某首歌曲跟你喜爱的歌曲相似,我们就把它推荐给你。
如何判断两首歌曲是否相似呢?对于人来说,这个事情可能会比较简单,但是对于计算机来说,判断两首歌曲是否相似,那就需要通过量化的数据来表示了。我们应该通过什么数据来量化两个歌曲之间的相似程度呢?
最容易想到的是,我们对歌曲定义一些特征项,比如是伤感的还是愉快的,是摇滚还是民谣,是柔和的还是高亢的等等。类似基于相似用户的推荐方法,我们给每个歌曲的每个特征项打一个分数,这样每个歌曲就都对应一个特征项向量。我们可以基于这个特征项向量,来计算两个歌曲之间的欧几里得距离。欧几里得距离越小,表示两个歌曲的相似程度越大。
但是要实现这个方案需要有一个前提那就是我们能够找到足够多并且能够全面代表歌曲特点的特征项除此之外我们还要人工给每首歌标注每个特征项的得分。对于收录了海量歌曲的音乐App来说这显然是一个非常大的工程。此外人工标注有很大的主观性也会影响到推荐的准确性。
既然基于歌曲特征项计算相似度不可行,那我们就换一种思路。对于两首歌,如果喜欢听的人群都是差不多的,那侧面就可以反映出,这两首歌比较相似。如图所示,每个用户对歌曲有不同的喜爱程度,我们依旧通过上一个解决方案中定义得分的标准,来定义喜爱程度。
<img src="https://static001.geekbang.org/resource/image/a3/ff/a324908e162a60efea4bd7c47c04a6ff.jpg" alt="">
你有没有发现,这个图跟基于相似用户推荐中的图几乎一样。只不过这里把歌曲和用户主次颠倒了一下。基于相似用户的推荐方法中,针对每个用户,我们将对各个歌曲的喜爱程度作为向量。基于相似歌曲的推荐思路中,针对每个歌曲,我们将每个用户的打分作为向量。
有了每个歌曲的向量表示,我们通过计算向量之间的欧几里得距离,来表示歌曲之间的相似度。欧几里得距离越小,表示两个歌曲越相似。然后,我们就在用户已经听过的歌曲中,找出他喜爱程度较高的歌曲。然后,我们找出跟这些歌曲相似度很高的其他歌曲,推荐给他。
## 总结引申
实际上,这个问题是**推荐系统**Recommendation System里最典型的一类问题。之所以讲这部分内容主要还是想给你展示算法的强大之处利用简单的向量空间的欧几里得距离就能解决如此复杂的问题。不过今天我只给你讲解了基本的理论实践中遇到的问题还有很多比如冷启动问题产品初期积累的数据不多不足以做推荐等等。这些更加深奥的内容你可以之后自己在实践中慢慢探索。
## 课后思考
关于今天讲的推荐算法,你还能想到其他应用场景吗?
欢迎留言和我分享,也欢迎点击“请朋友读”,把今天的内容分享给你的好友,和他一起讨论、学习。