該文章爲筆記
在前文中記錄了方差表示的是一組數據相對於平均數的離散程度的博客,一個班的學生成績方差很大,說明這個班的學生成績波動很厲害,有的特別好,有的特別差。這裏描述的是某一個變量所體現背後的含義(維度或者稱爲指標)。
相似度與相關性不是一種產物,不能被他們的名字搞混淆;比如兩個文本的相似度,在考察兩個文本的相似度時,需要分別文本進行分詞計算每個詞語的詞頻,形成詞頻向量。再計算兩個詞頻向量的餘弦夾角,根據夾角的值域得出兩個文本的相似度。
詞頻向量中有多個詞,每一個詞就是向量中的一個維度;而下圖中的菜品銷售量,某個菜品的銷售量是一個維度下含有多個值,不是多個維度。某兩個菜品的相關性,是指兩個維度的進行比較;而相似度是若干個維度進行比較。
在一個菜館中,會有一個菜品的銷量,關於這個銷量。我們想要得出,某個客人點了百合醬蒸風爪,要給他做一個推薦。推薦的規則是與百合醬蒸風爪銷量有相關性的菜品。
相關性係數方式計算
樣本協方差 =
樣本協方差的是表示兩個指標之間的親疏關係,比如指標指標的值成正相關的關係,你增加我也增加,你減少我也減少。
相關性係數的計算公式 = ;表示的是向量的標準差,同理。
相關係數展開式子: =
相關性係數方式的代碼實現
=
private double[] alpha;
private double[] beta;
public double correlate() {
if ((alpha == null || alpha.length == 0)
|| (beta == null || beta.length == 0)) {
throw new Exception("alpha或者beta沒有初始化");
}
int length = alpha.length;
if (length != beta.length) {
throw new Exception("向量維度必須相等");
}
//向量平均數,平均數求法很簡單,就不貼了
double alphaMean = mean(alpha);
double betaMean = mean(beta);
double numerator = 0;
double alphaDenominatorSum = 0;
double betaDenominatorSum = 0;
for (int i = 0; i < length; i++) {
double numericX = Math.pow((alpha[i] - alphaMean), 2d);
double numericY = Math.pow((beta[i] - betaMean), 2d);
alphaDenominatorSum += numericX;
betaDenominatorSum += numericY;
double alphaDeviation = alpha[i] - alphaMean;
double betaDeviation = beta[i] - betaMean;
numerator += alphaDeviation * betaDeviation;
}
return numerator / Math.sqrt(alphaDenominatorSum * betaDenominatorSum);
}
相似度
兩個向量之間的相似就是這兩個向量之間的夾角
= 計算方式 =,=, =
= ;同理也是這種計算方式
得出結果值就是兩個向量的相似度,而且他們的相關性不會超過 [-1, 1] 這個區間(的值域爲[-1, 1]);-1意味着兩個向量指向的方向正好截然相反,1表示它們的指向是完全相同的,0通常表示它們之間是獨立的。
文本A:陳瑞是一個歌手,也是一個男人
分詞結果:陳瑞 1,是 2,一個 2,歌手 1,也是 1,男人 1,女人 0
詞頻向量: [1, 2, 2, 1, 1, 1, 0]
文本B:陳瑞是一個男人,也是一個女人
分詞結果:陳瑞 1,是 2,一個 2,歌手 0,也是 1,男人 1,女人 1
詞頻向量: [1, 2, 2, 0, 1, 1, 1]
通過計算詞頻向量與得出兩文本內容的相似度
中文分詞的文章請參考 https://blog.csdn.net/Hello_Ray/article/details/104139024
TF-IDF 相似度優化
TF-IDF算法介紹
依據上面的內容,我們已經可以求出兩篇文章的相似度了,但是有一些缺點的。比如根據中文分詞選擇詞頻較大的, 然而、得出、的、是的 這些詞都是一些語氣詞或者明顯不能表示出意思的詞;會對兩篇文章的相似度行程干擾。
所以需要做的是,使用一個規則性的方法能夠避免這些詞選入詞頻向量中,這個規則性的方法就是TF-IDF算法。TF-IDF算法意義是:某個詞其他文章比較少見,然而它在這篇文章中詞頻很高,那麼它很可能就反映了這篇文章的特性,正是我們所需要的關鍵詞。
TF-IDF算法:詞頻率 與 逆文檔頻率 相乘得來。
詞頻率(TF)=
逆文檔頻率(IDF)=,分母加1 是要避免沒有文檔有這個詞,不然分母就爲0了。
TF-IDF與餘弦夾角結合計算文章的相似度
第一步:選擇文章
在真正的環境下可能是多篇文章,那麼我們選擇多篇文章,然後提取摘要(一般文章都有摘要,如果沒有就選擇前幾段和後幾段)形成語料文章。
第二步:分詞
對這些文章進行分詞,去重;形成一個詞向量。比如
文章A:我/喜歡/看/小說
文章B:我/不/喜歡/看/電視,也/不/喜歡/看/電影
那麼變成詞向量是 [ 我,喜歡,看,小說,電視,電影,不,也 ] 。例子是兩篇文章,詞向量比較短,如果是多篇文章詞向量會變得特別長。
統計每個文章的詞頻向量:
文章A:我 1,喜歡 1,看 1,小說 1,電視 0,電影 0,不 0,也 0。
文章B:我 1,喜歡 2,看 2,小說 0,電視 1,電影 1,不 2,也 1。
第三步:計算每個文檔中各個詞的詞頻率TF
第四步:計算各個詞的逆文檔頻率IDF
我 log(2/2)=0,喜歡 log(2/2)=0,看 log(2/2)=0,小說 log(2/1)=1,電視 log(2/1)=1,電影 log(2/1)=1,不log(2/1)=1,也 log(2/1)=1。
第五步:計算每個文檔中各個詞的TF-IDF值
文章A:我 0,喜歡 0,看 0,小說 1,電視 0,電影 0,不 0,也 0。
文章B:我 0,喜歡 0,看 0,小說 0,電視 1,電影 1,不 1,也 1。
第六步:每篇文章根據詞向量的TF-IDF選擇靠前的N個詞
文章A:我 0,喜歡 0,小說 1
文章B:電視 1,電影 1,不 1
第七步: 根據每篇文章選擇的 N個詞構造詞頻向量;如 [ 我,喜歡,小說,電視,電影,不 ]
文檔新的詞頻向量
文章A:[1 1 1 0 0 0]
文章B: [1 2 0 1 1 2]
注意:這時構造出來的詞頻向量中的詞頻或者詞頻率,是原來所在文章的詞頻或者詞頻率。TF-IDF所做工作是選擇一些精簡有用的詞參與餘弦夾角計算。
第八步:計算餘弦值,形成一個兩兩相似度的餘弦矩陣(有點類似於協方差矩陣)
第九步: 取出某一篇文章時,提取大小前幾位的相似度文章就形成了 推薦 文章
餘弦夾角的代碼實現
public double cdot() {
if ((alpha == null || alpha.length == 0)
|| (beta == null || beta.length == 0)) {
throw new Exception("alpha或者beta沒有初始化");
}
int length = alpha.length;
if (length != beta.length) {
throw new Exception("向量維度必須相等");
}
double sum = 0;
for (int i = 0; i < length; i++) {
double alphaIndex = alpha[i];
double betaIndex = beta[i];
double mult = alphaIndex * betaIndex;
sum += mult;
}
return sum;
}
public double vectorDistence(double[] arr) {
if (arr == null || arr.length == 0) {
throw new Exception("alpha或者beta沒有初始化");
}
double sum = 0;
for (int i = 0, len = arr.length; i < len; i++) {
double mult = arr[i] * arr[i];
throws sum += mult;
}
return Math.sqrt(sum);
}
圖中部分測試數據
百合醬蒸鳳爪:17,11,10,9,4,13,9,9,6,9,6,5,9,10,13,4,6,9,3,8,11,11,4,7,8,4,6,8,8
翡翠蒸香茜餃:6,15,8,6,10,10,7,12,8,11,7,9,7,8,12,8,12,15,10,7,6,6,7,5,8,10,7,5,6
金銀蒜汁蒸排骨:8,14,12,6,13,13,13,13,8,13,8,4,11,10,12,12,10,4,13,9,11,5,10,6,12,12,7,11,7
樂膳真味雞:24,13,13,3,8,16,8,6,3,6,9,7,9,6,10,11,9,12,13,20,8,15,7,7,14,9,11,10,9
蜜汁焗餐包:13,9,8,10,12,8,5,7,8,4,8,11,14,9,9,11,7,13,5,7,7,6,12,8,7,7,8,6
生炒菜心:13,10,3,9,10,9,7,8,4,7,7,9,8,13,11,7,4,9,8,12,8,14,10,15,11,8,7,11,4