先看看二者定義,給定兩個n維向量A,B:
A = ( a 1 , a 2 , … , a n ) A = (a_1, a_2, \ldots ,a_n) A=(a1,a2,…,an)
B = ( b 1 , b 2 , … , b n ) B = (b_1, b_2, \ldots ,b_n) B=(b1,b2,…,bn)
-
餘弦相似度:
c o s ( θ ) = A ⋅ B ∥ A ∥ ⋅ ∥ B ∥ = ∑ i = 1 n a i × b i ∑ i = 1 n a i 2 × ∑ i = 1 n b i 2 cos(\theta) = {A \cdot B \over \Vert A \Vert \cdot \Vert B \Vert } = \frac{ \sum_{i=1}^n a_i \times b_i }{ \sqrt {\sum_{i=1}^n a_i^2} \times \sqrt {\sum_{i=1}^n b_i^2}} cos(θ)=∥A∥⋅∥B∥A⋅B=∑i=1nai2
×∑i=1nbi2
∑i=1nai×bi
-
皮爾遜相關系數:
p e a r s o n _ r = ∑ i = 1 n ( a i − a ˉ ) × ( b i − b ˉ ) ∑ i = 1 n ( a i − a ˉ ) 2 × ∑ i = 1 n ( b i − b ˉ ) 2 pearson\_r = \frac{ \sum_{i=1}^n (a_i - \bar a ) \times (b_i - \bar b) }{ \sqrt {\sum_{i=1}^n (a_i - \bar a )^2} \times \sqrt {\sum_{i=1}^n (b_i - \bar b)^2}} pearson_r=∑i=1n(ai−aˉ)2
×∑i=1n(bi−bˉ)2
∑i=1n(ai−aˉ)×(bi−bˉ)
其中:
a ˉ = 1 n ∑ i = 1 n a i , b ˉ = 1 n ∑ i = 1 n b i \bar a = {1 \over n} \sum_{i=1}^n a_i, \bar b = {1 \over n} \sum_{i=1}^n b_i aˉ=n1i=1∑nai,bˉ=n1i=1∑nbi
兩式對比,可見皮爾遜相關系數的計算是先對向量每一分量減去分量均值,再求餘弦相似度。這一操作稱為中心化(将特征向量X根據 x ˉ \bar x xˉ 移動)。
這麼做有什麼好處呢?比如小明和小剛愛看電影,他們都看過《夏洛特煩惱》、《羞羞的鐵拳》和《西虹市首富》,兩個人也都在豆瓣上給這幾部電影打了分,分值如下表:
夏洛特煩惱 | 羞羞的鐵拳 | 西虹市首富 | |
---|---|---|---|
小明 | 9.6 | 7.5 | 5.8 |
小剛 | 8.3 | 5.6 | 2.4 |
如果豆瓣的程式員小哥哥想評判小明和小剛的興趣是否相似(以此來給他們推薦類似的電影或投放相同廣告),先初始化兩個特征向量:
import numpy as np
a_scores = np.array([9.6, 7.5, 5.8])
b_scores = np.array([8.3, 5.6, 2.4])
試下餘弦相似度:
from sklearn.metrics.pairwise import cosine_similarity
cosine_similarity([a_scores], [b_scores])
output:
array([[0.9760924]])
兩個人的餘弦相似度是0.9760924,還不錯,再試試皮爾遜相關系數:
from scipy.stats import pearsonr
pearsonr(a_scores, b_scores)[0]
output:
0.9940012359465
效果更好!
餘弦相似度除了可以比較樣本間相似度,也可用于判斷特征的重要性,網上比較多的例子即是評判sklearn庫的iris(鸢尾花)資料集特征,在此一起總結下。
加載資料集:
from scipy.stats import pearsonr
from sklearn.datasets import load_iris
# 加載資料集
iris = load_iris()
看資料前10行,每行包含鸢尾花的4個特征(花萼、花瓣的長寬):
iris.data[:10]
output:
array([[5.1, 3.5, 1.4, 0.2],
[4.9, 3. , 1.4, 0.2],
[4.7, 3.2, 1.3, 0.2],
[4.6, 3.1, 1.5, 0.2],
[5. , 3.6, 1.4, 0.2],
[5.4, 3.9, 1.7, 0.4],
[4.6, 3.4, 1.4, 0.3],
[5. , 3.4, 1.5, 0.2],
[4.4, 2.9, 1.4, 0.2],
[4.9, 3.1, 1.5, 0.1]])
看看label前10行,都是1個品種:
iris.target[:10]
output:
array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
每個樣本有4維特征,通過計算各特征與label的皮爾遜相關系數,即可得到各特征的重要性,是以需要依次取出iris.data的每一列特征,怎麼取呢?sklearn.datasets中的資料集已經幫我們處理好了。iris是sklearn.utils.Bunch類的執行個體,其中iris.data.T就是iris.data的轉置,看看其前10行(由于樣本過多,這裡隻顯示10個):
iris.data.T[:, :10]
output:
array([[5.1, 4.9, 4.7, 4.6, 5. , 5.4, 4.6, 5. , 4.4, 4.9],
[3.5, 3. , 3.2, 3.1, 3.6, 3.9, 3.4, 3.4, 2.9, 3.1],
[1.4, 1.4, 1.3, 1.5, 1.4, 1.7, 1.4, 1.5, 1.4, 1.5],
[0.2, 0.2, 0.2, 0.2, 0.2, 0.4, 0.3, 0.2, 0.2, 0.1]])
下面就可以計算特征重要性了:
from scipy.stats import pearsonr
for feature in iris.data.T:
# 計算皮爾遜相關系數
print(pearsonr(feature, iris.target)[0])
output:
0.7825612318100814
-0.4194462002600275
0.9490425448523336
0.9564638238016173
不過要注意的是,皮爾遜相關系數隻對線性相關有效,并不是所有衡量特征重要性都可以這麼用,需要因地制宜。