日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > python >内容正文

python

python勾股定理中三个数的关系是、找出三十以内的_从勾股定理到余弦相似度-程序员的数学基础...

發布時間:2023/12/14 python 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 python勾股定理中三个数的关系是、找出三十以内的_从勾股定理到余弦相似度-程序员的数学基础... 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

大部分程序員由于理工科的背景,有一些高數、線性代數、概率論與數理統計的數學基礎。所以當機器學習的熱潮來臨的時候,都躍躍欲試,對機器學習的算法以及背后的數學思想有比較強烈的探索欲望。

本文的作者就是其中的一位。然而實踐的過程中,又發現數學知識的理解深度有些欠缺,在理解一些公式背后的意義時,有些力不從心的感覺。因此梳理了一些數學上的知識盲點,理順自己的知識脈絡,順便分享給有需要的人。

本文主要講解余弦相似度的相關知識點。相似度計算用途相當廣泛,是搜索引擎、推薦引擎、分類聚類等業務場景的核心點。為了理解清楚余弦相似度的來龍去脈,我將會從最簡單的初中數學入手,逐步推導出余弦公式。然后基于余弦公式串講一些實踐的例子。

一、業務背景

通常我們日常開發中,可能會遇到如下的業務場景。

精準營銷,圖像處理,搜索引擎 這三個看似風馬牛不相及的業務場景,其實面臨一個共同的問題就是相似度的計算。例如精準營銷中的人群擴量涉及用戶相似度的計算;圖像分類問題涉及圖像相似度的計算,搜索引擎涉及查詢詞和文檔的相似度計算。相似度計算中,可能由于《數學之美》的影響,大家最熟悉的應該是余弦相似度。那么余弦相似度是怎么推導出來的呢?

二、數學基礎

理解余弦相似度,要從理解金字塔開始。我們知道金字塔的底座是一個巨大的正方形。例如吉薩大金字塔的邊長超過230m。構造這樣一個巨大的正方形,如何保證構造出來的圖形不走樣呢?比如如何確保構造的結果不是菱形或者梯形。

1、勾股定理

要保證構造出來的四邊形是正方形,需要保證兩個點:其一是四邊形的邊長相等;其二是四邊形的角是直角。四邊形的邊長相等很容易解決,在工程實踐中,取一根定長的繩子作為邊長就可以了。如何保障直角呢?古人是利用勾股定理解決的,更切確地說是勾股定理的逆定理。

構造一個三角形,保證三角形的三邊長分別是3,4,5。那么邊長為5的邊對應的角為直角。中國有個成語“無規矩不成方圓”,其中的矩,就是直角的尺。

勾股證明是初中數學的知識,理解很容易。證明也很簡單,據說愛因斯坦11歲就發現了一種證明方法。勾股定理的證明方法據統計有超過400種, 感興趣的同學可以自行了解。另勾股定理也是費馬大定理的靈感來源,費馬大定理困擾了世間智者300多年,也誕生了很多的逸聞趣事,這里不贅述。

2、余弦定理

勾股定理存在著一個很大的限制,就是要求三角形必須是直角三角形。那么對于普通的三角形,三個邊存在什么樣的關系呢?這就引出了余弦定理。

余弦定理指出了任意三角形三邊的關系,也是初中就可以理解的數學知識,證明也比較簡單,這里就略過了。

其實對于三角形,理解了勾股定理和余弦定理。就已經掌握了三角形的很多特性和秘密了。比如根據等邊三角形,可以推導出cos(60)=1/2。但是如果想理解幾何更多的秘密,就需要進入解析幾何的世界。這個數學知識也不算很高深,高中數學知識。

這里我們理解最簡單就可以了,那就是三角形在直角坐標系中的表示。所謂“橫看成嶺側成峰,遠近高低各不同”,我們可以理解為三角形的另一種表現形式。

比如我們可以用a,b,c三個邊描述一個三角形;在平面直角坐標系中,我們可以用兩個向量表示一個三角形。

3、余弦相似度

當我們引入了直角坐標系后,三角形的表示就進入了更靈活、更強大和更抽象的境界了。幾何圖形可以用代數的方法來計算,代數可以用幾何圖形形象化表示,大大降低理解難度。比如我們用一個向量來表示三角形的一個邊,就可以從二維空間直接擴展到高維空間。

這里,向量的定義跟點是一樣的;向量的乘法也只是各個維度值相乘累加;向量的長度看似是新的東西,其實繞了一個圈,本質上還是勾股定理,只是勾股定理從二維空間擴展到了N維空間而已。而且向量長度又是兩個相同向量乘法的特例。數學的嚴謹性在這里體現得淋漓盡致。

結合勾股定理,余弦定理,直角坐標系,向量。我們就可以很自然地推導出余弦公式了,這里唯一的理解難點就是勾股定理和余弦定理都是用向量來表示。

得到了余弦公式后,我們該怎么理解余弦公式呢?

極端情況下,兩個向量重合了,就代表兩個向量完全相似。然而這里的完全相似,其實是指向量的方向。向量有方向和長度兩個要素,這里只使用方向這一個要素,在實踐中就埋下了隱患。但是畢竟一個數學模型建立起來了。我們可以用這個模型解決一些實際中的問題了。

所謂數學模型,有可能并不需要高深的數學知識,對外的表現也僅僅是一個數學公式。比如余弦定理這個數學模型,高中數學知識就足夠理解了。而且關于模型,有這樣一個很有意思的論述:“所有的數學模型都是錯的,但是有些是有用的”。這里我們更多關注其有用的一面。

理解了向量夾角,那么該怎么理解向量呢?它僅僅是三角形的一條邊嗎?

人生有幾何,萬物皆向量。向量在數學上是簡單的抽象,這個抽象我們可以用太多實際的場景來使它落地。比如用向量來指代用戶標簽,用向量來指代顏色,用向量來指代搜索引擎的邏輯...

三、業務實踐

理解了余弦定理,理解了數學建模的方式。接下來我們就可以做一些有意思的事情了。比如前面提到的三個業務場景,我們可以看看如何用余弦相似度來解決。當然實際問題肯定遠遠要復雜得多,但是核心的思想都是類似的。

案例1:精準營銷

假設一次運營計劃,比如我們圈定了1w的用戶,如何擴展到10萬人呢?

利用余弦相似度,我們這里其實最核心的問題就是:如何將用戶向量化?

將每個用戶視為一個向量,用戶的每個標簽值視為向量的一個維度。當然這里實際工程中還有特征歸一化,特征加權等細節。我們這里僅作為演示,不陷入到細節中。

對于人群,我們可以取人群中,所有用戶維度值的平均值,作為人群向量。這樣處理后,就可以使用余弦公式計算用戶的相似度了。

我們通過計算大盤用戶中每個用戶跟圈定人群的相似度,取topN即可實現人群的擴量。

直接“show me the code”吧!

# -*- coding: utf-8 -*-

import numpy as np

import numpy.linalg as linalg

def cos_similarity(v1, v2):

num = float(np.dot(v1.T, v2)) # 若為行向量則 A.T * B

denom = linalg.norm(v1) * linalg.norm(v2)

if denom > 0:

cos = num / denom # 余弦值

sim = 0.5 + 0.5 * cos # 歸一化

return sim

return 0

if __name__ == ‘__main__‘:

u_tag_list = [

["女", "26", "是", "白領"],

["女", "35", "是", "白領"],

["女", "30", "是", "白領"],

["女", "22", "是", "白領"],

["女", "20", "是", "白領"]

]

new_user = ["女", "20", "是", "白領"]

u_tag_vector = np.array([

[1, 26, 1, 1],

[1, 35, 1, 1],

[1, 30, 1, 1],

[1, 22, 1, 1],

[1, 20, 1, 1]

])

c1 = u_tag_vector[0]

c1 += u_tag_vector[1]

c1 += u_tag_vector[2]

c1 += u_tag_vector[3]

c1 += u_tag_vector[4]

c1 = c1/5

new_user_v1 = np.array([1, 36, 1, 1])

new_user_v2 = np.array([-1, 20, 0, 1])

print("vector-u1: ", list(map(lambda x: ‘%.2f‘ % x, new_user_v1.tolist()[0:10])))

print("vector-u2: ", list(map(lambda x: ‘%.2f‘ % x, new_user_v2.tolist()[0:10])))

print("vector-c1: ", list(map(lambda x: ‘%.2f‘ % x, c1.tolist()[0:10])))

print("sim: ", cos_similarity(c1, new_user_v1))

print("sim: ", cos_similarity(c1, new_user_v2))

案例2:圖像分類

有兩類圖片,美食和萌寵。對于新的圖片,如何自動分類呢?

這里我們的核心問題是:圖片如何向量化?

圖片由像素構成,每個像素有RGB三個通道。由于像素粒度太細,將圖片分割成大小相對的格子,每個格子定義3個維度,維度值取格子內像素均值。

下面也是給出樣例代碼:

# -*- coding: utf-8 -*-

import numpy as np

import numpy.linalg as linalg

import cv2

def cos_similarity(v1, v2):

num = float(np.dot(v1.T, v2)) # 若為行向量則 A.T * B

denom = linalg.norm(v1) * linalg.norm(v2)

if denom > 0:

cos = num / denom # 余弦值

sim = 0.5 + 0.5 * cos # 歸一化

return sim

return 0

def build_image_vector(im):

"""

:param im:

:return:

"""

im_vector = []

im2 = cv2.resize(im, (500, 300))

w = im2.shape[1]

h = im2.shape[0]

h_step = 30

w_step = 50

for i in range(0, w, w_step):

for j in range(0, h, h_step):

each = im2[j:j+h_step, i:i+w_step]

b, g, r = each[:, :, 0], each[:, :, 1], each[:, :, 2]

im_vector.append(np.mean(b))

im_vector.append(np.mean(g))

im_vector.append(np.mean(r))

return np.array(im_vector)

def show(imm):

imm2 = cv2.resize(imm, (510, 300))

print(imm2.shape)

imm3 = imm2[0:50, 0:30]

cv2.imshow("aa", imm3)

cv2.waitKey()

cv2.destroyAllWindows()

imm4 = imm2[51:100, 0:30]

cv2.imshow("bb", imm4)

cv2.waitKey()

cv2.destroyAllWindows()

imm2.fill(0)

def build_image_collection_vector(p_name):

path = "D:\python-workspace\cos-similarity\images\"

c1_vector = np.zeros(300)

for pic in p_name:

imm = cv2.imread(path + pic)

each_v = build_image_vector(imm)

a=list(map(lambda x:‘%.2f‘ % x, each_v.tolist()[0:10]))

print("p1: ", a)

c1_vector += each_v

return c1_vector/len(p_name)

if __name__ == ‘__main__‘:

v1 = build_image_collection_vector(["food1.jpg", "food2.jpg", "food3.jpg"])

v2 = build_image_collection_vector(["pet1.jpg", "pet2.jpg", "pet3.jpg"])

im = cv2.imread("D:\python-workspace\cos-similarity\images\pet4.jpg")

v3 = build_image_vector(im)

print("v1,v3:", cos_similarity(v1,v3))

print("v2,v3:", cos_similarity(v2,v3))

a = list(map(lambda x: ‘%.2f‘ % x, v3.tolist()[0:10]))

print("p1: ", a)

im2 = cv2.imread("D:\python-workspace\cos-similarity\images\food4.jpg")

v4 = build_image_vector(im2)

print("v1,v4:", cos_similarity(v1, v4))

print("v2,v4:", cos_similarity(v2, v4))

至于代碼中用到的圖片,用戶可以自行收集即可。筆者也是直接從搜索引擎中截取的。程序計算的結果也是很直觀的,V2(萌寵)跟圖像D1的相似度為0.956626,比V1(美食)跟圖像D1的相似度0.942010更高,所以結果也是很明確的。

案例3:文本檢索

假設有三個文檔,描述的內容如下。一個是疫情背景下,蘋果公司的資訊,另外兩個是水果相關的信息。輸入搜索詞“蘋果是我最喜歡的水果”,? 該怎么找到最相關的文檔?

這里的核心問題也是文本和搜索詞如何向量化?

這里其實可以把搜索詞也視為文檔,這樣問題就簡化成:文檔如何向量化?

出于簡化問題的角度,我們可以給出最簡單的答案:文檔由詞組成,每個詞作為一個維度;文檔中詞出現的頻率作為維度值。

當然,實際操作時我們維度值的計算會更復雜一些,比如用TF-IDF。這里用詞頻(TF)并不影響演示效果,所以我們從簡。

將文本向量化后,剩下也是依樣畫葫蘆,用余弦公式計算相似度, 流程如下:

最后,給出代碼:

# -*- coding: utf-8 -*-

import numpy as np

import numpy.linalg as linalg

import jieba

def cos_similarity(v1, v2):

num = float(np.dot(v1.T, v2)) # 若為行向量則 A.T * B

denom = linalg.norm(v1) * linalg.norm(v2)

if denom > 0:

cos = num / denom # 余弦值

sim = 0.5 + 0.5 * cos # 歸一化

return sim

return 0

def build_doc_tf_vector(doc_list):

num = 0

doc_seg_list = []

word_dic = {}

for d in doc_list:

seg_list = jieba.cut(d, cut_all=False)

seg_filterd = filter(lambda x: len(x)>1, seg_list)

w_list = []

for w in seg_filterd:

w_list.append(w)

if w not in word_dic:

word_dic[w] = num

num+=1

doc_seg_list.append(w_list)

print(word_dic)

doc_vec = []

for d in doc_seg_list:

vi = [0] * len(word_dic)

for w in d:

vi[word_dic[w]] += 1

doc_vec.append(np.array(vi))

print(vi[0:40])

return doc_vec, word_dic

def build_query_tf_vector(query, word_dic):

seg_list = jieba.cut(query, cut_all=False)

vi = [0] * len(word_dic)

for w in seg_list:

if w in word_dic:

vi[word_dic[w]] += 1

return vi

if __name__ == ‘__main__‘:

doc_list = [

"""

受全球疫情影響,3月蘋果宣布關閉除大中華區之外數百家全球門店,其龐大的供應鏈體系也受到沖擊,

盡管目前富士康等代工廠已經開足馬力恢復生產,但相比之前產能依然受限。中國是iPhone生產的大本營,

為了轉移風險,iPhone零部件能否實現印度制造?實現印度生產的最大難點就是,相對中國,印度制造業仍然欠發達

""",

"""

蘋果是一種低熱量的水果,每100克產生大約60千卡左右的熱量。蘋果中營養成分可溶性大,容易被人體吸收,故有“活水”之稱。

它有利于溶解硫元素,使皮膚潤滑柔嫩。

""",

"""

在生活當中,香蕉是一種很常見的水果,一年四季都能吃得著,因其肉質香甜軟糯,且營養價值高,所以深受老百姓的喜愛。

那么香蕉有什么具體的功效,你了解嗎?

"""

]

query = "蘋果是我喜歡的水果"

doc_vector, word_dic = build_doc_tf_vector(doc_list)

query_vector = build_query_tf_vector(query, word_dic)

print(query_vector[0:35])

for i, doc in enumerate(doc_vector):

si = cos_similarity(doc, query_vector)

print("doc", i, ":", si)

我們檢索排序的結果如下:

文檔D2是相似度最高的,符合我們的預期。這里我們用最簡單的方法,實現了一個搜索打分排序的樣例,雖然它并沒有實用價值,但是演示出了搜索引擎的工作原理。

四、超越余弦

前面通過簡單的3個案例,演示了余弦定理的用法,但是沒有完全釋放出余弦定理的洪荒之力。接下來展示一下工業級的系統中是如何使用余弦定理的。這里選取了開源搜索引擎數據庫ES的內核Lucene作為研究對象。研究的問題是:Lucene是如何使用余弦相似度進行文檔相似度打分?

當然,對于Lucene的實現,它有另一個名字:向量空間模型。即許多向量化的文檔集合形成了向量空間。我們首先直接看公式:

很明顯,實際公式跟理論公式長相差異很大。那么我們怎么理解呢?換言之,我們怎么基于理論公式推導出實際公式呢?

首先需要注意的是,在Lucene中,文檔向量的特征不再是我們案例3中展示的,用的詞頻,而是TF-IDF。關于TF-IDF相關的知識,比較簡單,主要的思路在于:

如何量化一個詞在文檔中的關鍵程度?? TF-IDF給出的答案是綜合考慮詞頻(詞在當前文檔中出現的次數)以及逆文檔頻率(詞出現的文檔個數)兩個因素。

詞在當前文檔中出現次數(TF)越多,? 詞越重要

詞在其他文檔出現的次數(IDF)越少,詞越獨特

感興趣的話,可以自行參考其他資料,這里不展開說明。

回到我們的核心問題:?我們怎么基于理論公式推導出實際公式呢?

四步走就可以了,如下圖:

第一步:計算向量乘法

向量乘法就是套用數學公式了。這里需要注意的是,這里有兩個簡化的思想:

查詢語句中不存在的詞tf(t,q)=0

查詢語句基本沒有重復的詞tf(t,q)=1

所以我們比較簡單完成了第一步推導:

第二步: 計算查詢語句向量長度|V(q)|

計算向量長度,其實就是勾股定理的使用了。只不過這里是多維空間的勾股定理。

這里取名queryNorm, 表示這個操作是對向量的歸一化。這個其實是當向量乘以queryNorm后,就變成了單位向量。單位向量的長度為1,所以稱為歸一化,也就是取名norm。理解了這一層,看lucene源碼的時候,就比較容易理解了。這正如瑯琊榜的臺詞一樣:問題出自朝堂,答案卻在江湖。這里是問題出自Lucene源碼,答案卻在數學。

第三步:計算文檔向量長度|V(d)|

這里其實是不能沿用第二步的做法的。前面已經提到,向量有兩大要素:方向和長度。余弦公式只考慮了方向因素。這樣在實際應用中,余弦相似度就是向量長度無關的了。

這在搜索引擎中,如果查詢語句命中了長文檔和短文檔,按照余弦公式TF-IDF特征,偏向于對短小的文檔打較高的分數。對長文檔不公平,所以需要優化一下。

這里的優化思路就是采用文檔詞個數累積,從而降低長文檔和短文檔之間的差距。當然這里的業務訴求可能比較多樣,所以在源碼實現的時候,開放了接口允許用戶自定義。借以提升靈活度。

第四步:混合用戶權重和打分因子

所謂用戶權重,就是指用戶指定查詢詞的權重。例如典型地競價排名就是人為提升某些查詢詞的權重。所謂打分因子,即如果一個文檔中相比其它的文檔出現了更多的查詢關鍵詞,那么其值越大。綜合考慮了多詞查詢的場景。經過4步,我們再看推導出來的公式和實際公式,發現相似度非常高。

推導公式和官方公式基本就一致了。

五、總結

本文簡單介紹了余弦相似度的數學背景。從埃及金字塔的建設問題出發,引出了勾股定理,進而引出了余弦定理。并基于向量推導出來了余弦公式。

接下來通過三個業務場景的例子,介紹余弦公式的應用,即數學模型如何落地到業務場景中。這三個簡單的例子代碼不過百行,能夠幫助讀者更好地理解余弦相似度。

最后介紹了一個工業級的樣例。基于Lucene構建的ES是當前最火熱的搜索引擎解決方案。學習余弦公式在Lucene中落地,有助于理解業界的真實玩法。進一步提升對余弦公式的理解。

六、參考文獻

作者:Shuai Guangying

總結

以上是生活随笔為你收集整理的python勾股定理中三个数的关系是、找出三十以内的_从勾股定理到余弦相似度-程序员的数学基础...的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。