<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          KNN算法簡(jiǎn)單?我竟用3萬字沒寫清楚······

          共 15268字,需瀏覽 31分鐘

           ·

          2022-04-23 12:14

          79b3c7b3939c8d88b77eb13e0b816231.webp

          大家好,我是小伍哥,本文非常長(zhǎng),建議先收藏,有空再看,實(shí)在不行就關(guān)注下我,二維碼放到前面了,我知道大家讀不完,生成了45頁的PDF文檔,關(guān)注我的另一個(gè)號(hào)小伍哥聊風(fēng)控后臺(tái)回復(fù)【KNN】領(lǐng)取。

          談起KNN,很多人都會(huì)覺得非常簡(jiǎn)單,甚至?xí)冻霾恍?鄙視,包括我自己,當(dāng)初也是如此,當(dāng)我進(jìn)行深入的研究,發(fā)現(xiàn)真是大意了。

          大家都知道KNN可以用于分類,但是它能不能用于回歸?KNN的5個(gè)有監(jiān)督方法你是否都知道?K值怎么確定呢?距離可以加權(quán)么?為了取Top K,必須要對(duì)距離全部排序嗎?基于質(zhì)心的KNN你了解么?有沒有方法減少KNN的計(jì)算復(fù)雜度?KNN還可以做圖發(fā)現(xiàn)?KNN還可以限定鄰居半徑的有監(jiān)督?KNN怎么進(jìn)行異常檢測(cè)?KNN是否能夠找到我想要的鄰居?

          在萬物皆顆Embedding的時(shí)代,我們就可以用近鄰?fù)仆扑]Nearest Neighbor(KNN并不低級(jí),Youtube也是用這個(gè),之前還有開源,對(duì)視頻庫中的所有視頻根據(jù)向量做最近鄰算法,得到top-N的視頻作為召回結(jié)果)可以做到:物物推薦,人人推薦,人物推薦。有了文本的Embedding,我們可以進(jìn)行文本聚類挖掘·····,可以說這個(gè)算法非常非常的豐富,加上代碼,30000字,都有很多寫的不是很到位,后面我們慢慢挖。

          本文涉及兩個(gè)庫:scikit-learn 和 pyod,前者做有監(jiān)督和距離等計(jì)算,后者負(fù)責(zé)無監(jiān)督,本文的框架也是依據(jù)這兩個(gè)庫展開。

          sklearn中KNN相關(guān)類庫:在scikit-learn 中,與近鄰法這一大類相關(guān)的庫都在sklearn.neighbors包之中。KNN分類樹的類是KNeighborsClassifier,KNN回歸樹的類是KNeighborsRegressor。除此之外,還有KNN的擴(kuò)展,即限定半徑最近鄰分類樹的類RadiusNeighborsClassifier和限定半徑最近鄰回歸樹的類RadiusNeighborsRegressor, 以及最近質(zhì)心分類算法NearestCentroid

          在這些算法中,KNN分類和回歸的類參數(shù)完全一樣。限定半徑最近鄰法分類和回歸的類的主要參數(shù)也和KNN基本一樣

          比較特別是的最近質(zhì)心分類算法,由于它是直接選擇最近質(zhì)心來分類,所以僅有兩個(gè)參數(shù),距離度量和特征選擇距離閾值,比較簡(jiǎn)單,因此后面就不再專門講述最近質(zhì)心分類算法的參數(shù)。

          另外幾個(gè)在sklearn.neighbors包中但不是做分類回歸預(yù)測(cè)的類也值得關(guān)注,kneighbors_graph類返回用KNN時(shí)和每個(gè)樣本最近的K個(gè)訓(xùn)練集樣本的位置,radius_neighbors_graph返回用限定半徑最近鄰法時(shí)和每個(gè)樣本在限定半徑內(nèi)的訓(xùn)練集樣本的位置NearestNeighbors是個(gè)大雜燴,它即可以返回用KNN時(shí)和每個(gè)樣本最近的K個(gè)訓(xùn)練集樣本的位置,也可以返回用限定半徑最近鄰法時(shí)和每個(gè)樣本最近的訓(xùn)練集樣本的位置,常常用在聚類模型中,

          PyOD中KNN相關(guān)的類庫概述:里面就一個(gè)knn,用于對(duì)異常值的檢測(cè),繼承的是scikit-learn中的NearestNeighbors,所以我們把scikit-learn中的KNN系列理解了,那異常檢測(cè)也就是輕而易舉的拿下了。

          一、圖解KNN有監(jiān)督算法

          當(dāng)KNN用于有監(jiān)督時(shí)可以做分類,也可以回歸,我們這里用分類舉例,也就是喂給該算法模型的數(shù)據(jù)需要帶有類別標(biāo)簽,為了方便算法的理解,我們虛構(gòu)了如下的數(shù)據(jù)集

          477b34e057c804402f6a87e4d5a94ba7.webp

          身高、顏值、財(cái)力、人品為數(shù)據(jù)集的特征,最后一列為label,我們需要根據(jù)0-7號(hào)男嘉賓的四個(gè)特征訓(xùn)練模型誰,判斷8號(hào)男嘉賓是好人還是海王。

          1、KNN原理

          KKN原理:KNN算法非常簡(jiǎn)單粗暴,就是將預(yù)測(cè)點(diǎn)所有訓(xùn)練集的點(diǎn)進(jìn)行距離計(jì)算,然后保存并排序,選出前面K個(gè)值看看哪個(gè)類別比較多,就將預(yù)測(cè)點(diǎn)歸于哪一類,如下圖,原點(diǎn)為預(yù)測(cè)點(diǎn),最近的三個(gè)樣本,兩個(gè)為紅色三角形,那圓點(diǎn)的類別預(yù)測(cè)紅色三角形類別。

          41679c0e6afb2ea8d5f80194659144c1.webp

          KNN過程:對(duì)未知類別的數(shù)據(jù)集中的每個(gè)點(diǎn)依次執(zhí)行以下操作:

          1) 計(jì)算當(dāng)前點(diǎn) 與 已知類別數(shù)據(jù)集中每個(gè)點(diǎn)的距離

          2) 按照距離遞增次序排序

          3) 選取與當(dāng)前點(diǎn)距離最小的k個(gè)點(diǎn)

          4) 確定前k個(gè)點(diǎn)所在類別的出現(xiàn)頻率

          5) 返回前k個(gè)點(diǎn)出現(xiàn)比例最高的類別作為當(dāng)前點(diǎn)的預(yù)測(cè)類別

          2、KNN實(shí)例講解

          這里會(huì)利用上訴的kNN數(shù)據(jù)集對(duì)KNN算法做逐步解釋:

          1) 計(jì)算預(yù)測(cè)點(diǎn) 與 已知類別數(shù)據(jù)集中的點(diǎn)之間的距離:

          要度量空間中兩個(gè)點(diǎn)的距離,有多種度量方式,常見的有曼哈頓距離、歐式距離等。KNN算法默認(rèn)使用的是歐式距離,計(jì)算方法如下:bcc6755504a95a619e3914637c3ab538.webp我們計(jì)算8號(hào)與每個(gè)樣本之間的距離,計(jì)算結(jié)果如下:

          d772fae926e1a1d5479e5394bf14dad6.webp

          2) 按照計(jì)算的距離降序排列,看看誰與8號(hào)嘉賓的距離最近

          按照與8號(hào)的距離排序,如下,可以看到,5號(hào),0號(hào),2號(hào)三個(gè)排的最近

          aa69f5f64e2661d6947dd59ed8a6c198.webp

          3) 選取與預(yù)測(cè)點(diǎn)距離最小的k個(gè)點(diǎn)

          我們知道K的取值比較重要,那么一般如何確定K的取值呢?答案是通過交叉驗(yàn)證,從選取一個(gè)較小的K值開始,不斷增加K的值,然后計(jì)算驗(yàn)證集合的準(zhǔn)確率,最終找到一個(gè)比較合適的K值。我們這里取3和5分別看看預(yù)測(cè)的結(jié)果,大家對(duì)取不同的K值有個(gè)直觀的感受。

          K = 3

          d53285f466b99d5e46d457ad9a7aa385.webp

          K = 5

          e67484738c9d369811bbaf51f1b25786.webp

          4) 確定最近的k個(gè)鄰居所在類別的頻率

          當(dāng) k = 3 的時(shí)候,包含2個(gè)海王和1個(gè)好人

          好人的概率:1/3 = 0.3333

          海王的概率:2/3 = 0.6666

          當(dāng) k =5 的時(shí)候,包含4個(gè)海王和1個(gè)好人

          好人的概率:1/5 = 0.2000

          海王的概率:4/5 = 0.8000

          由此可以看出來,k大小會(huì)影響我們對(duì)概率的判斷,在本例中,不影響判斷的類別,但是影響概率

          5) 返回前k個(gè)點(diǎn)出現(xiàn)頻率最高的類別作為當(dāng)前點(diǎn)的預(yù)測(cè)分類

          無論是k取3還是5,都是海王的概率大于好人的概率,因此我們對(duì)8號(hào)嘉賓的預(yù)測(cè)時(shí)海王,當(dāng)然,最后的概率也可以輸出是0.6666或者0.8.由此也可以看到,K值會(huì)比較大的影響預(yù)測(cè)結(jié)果


          6)利用sklearn進(jìn)行檢驗(yàn)

          我們手動(dòng)算了上面的數(shù)據(jù),現(xiàn)在用sklearn的算法檢驗(yàn)我們的計(jì)算結(jié)果,看看有沒有算對(duì) ? ? ?

          # 構(gòu)建數(shù)據(jù)集,按上面的表格
          X = np.array([[7, 7, 9, 3],
          [5, 4, 5, 6],
          [8, 6, 9, 3],
          [9, 9, 7, 7],
          [5, 5, 5, 5],
          [9, 9, 9, 1],
          [5, 2, 5, 5],
          [8, 8, 7, 6]])
          # 訓(xùn)練Label準(zhǔn)備,1-海王,0-好人
          y = [1, 0, 0, 1,0,1,0,1]


          # 加載分類模型 k = 3
          from sklearn.neighbors import KNeighborsClassifier
          neigh = KNeighborsClassifier(n_neighbors=3)
          neigh.fit(X, y)
          # 預(yù)測(cè)8號(hào)嘉賓 [[9, 9, 9, 2]] 的類別和概率
          print(neigh.predict([[9, 9, 9, 2]]))
          [1]
          print(neigh.predict_proba([[9, 9, 9, 2]]))
          [[0.33333333 0.66666667]]


          # 加載分類模型 k = 5
          neigh = KNeighborsClassifier(n_neighbors=5)
          neigh.fit(X, y)
          # 預(yù)測(cè)8號(hào)嘉賓 [[9, 9, 9, 2]] 的類別和概率
          print(neigh.predict([[9, 9, 9, 2]]))
          [1]
          print(neigh.predict_proba([[9, 9, 9, 2]]))
          [[0.2 0.8]]

          簡(jiǎn)直完美,和我們手動(dòng)計(jì)算的一模一樣,到此,我們就算理解了基礎(chǔ)的KNN算法,當(dāng)然,應(yīng)用的時(shí)候,涉及到更多的數(shù)據(jù)處理以及更多的參數(shù),我們?cè)谙旅尜N出來。我們上面用分類任務(wù)舉例,其實(shí)對(duì)于回歸任務(wù),我們只要找到最近的鄰居,然后按鄰居的取值取平均值或者中位數(shù)就可以了。

          二、KNN有監(jiān)督算法應(yīng)用

          KNN用于有監(jiān)督算法主要有五個(gè),分類的類是KNeighborsClassifier,回歸的類是KNeighborsRegressor,除此之外,還有KNN的擴(kuò)展,即限定半徑最近鄰分類的類RadiusNeighborsClassifier和限定半徑最近鄰回歸樹的類RadiusNeighborsRegressor, 以及最近質(zhì)心分類算法NearestCentroid。我們下面看看這個(gè)五個(gè)算法的基本用法和案例。

          1、KNeighborsClassifier

          1)基本用法

          sklearn.neighbors.KNeighborsClassifier(n_neighbors=5, *, weights='uniform', algorithm='auto', leaf_size=30, p=2, metric='minkowski', metric_params=None, n_jobs=None)

          2)參數(shù)詳解

          n_neighbors: ?默認(rèn)為5, ?就是k-NN的k的值, ?選取最近的k個(gè)點(diǎn)

          weights: ?默認(rèn)是uniform, ?參數(shù)可以是uniform、distance, ?也可以是用戶自己定義的函數(shù)

          • uniform: ?是均等的權(quán)重, ?就說所有的鄰近點(diǎn)的權(quán)重都是相等的

          • distance: ?是不均等的權(quán)重, ?距離近的點(diǎn)比距離遠(yuǎn)的點(diǎn)的影響大

          • 用戶自定義的函數(shù), ?接收距離的數(shù)組, ?返回一組維數(shù)相同的權(quán)重

          algorithm: ?快速k近鄰搜索算法, ?默認(rèn)參數(shù)為auto, ?可以理解為算法自己決定合適的搜索算法. ?除此之外, ?用戶也可以自己指定搜索算法: ?ball_treekd_treebrute方法進(jìn)行搜索.

          • kd_tree: ?構(gòu)造kd樹存儲(chǔ)數(shù)據(jù)以便對(duì)其進(jìn)行快速檢索的樹形數(shù)據(jù)結(jié)構(gòu). ?kd樹也就是數(shù)據(jù)結(jié)構(gòu)中的二叉樹. 以中值切分構(gòu)造的樹, ?每個(gè)結(jié)點(diǎn)是一個(gè)超矩形, ?在維數(shù)小于20時(shí)效率高

          • ball_tree: ?是為了克服kd樹高緯失效而發(fā)明的,其構(gòu)造過程是以質(zhì)心 C 和半徑 r 分割樣本空間, ?每個(gè)節(jié)點(diǎn)是一個(gè)超球體

          • brute: ?是蠻力搜索, ?也就是線性掃描, ?當(dāng)訓(xùn)練集很大時(shí), ?計(jì)算非常耗時(shí)

          leaf_size: 默認(rèn)是30, ?這個(gè)是構(gòu)造的kd樹和ball樹的大小. ?這個(gè)值的設(shè)置會(huì)影響樹構(gòu)建的速度和搜索速度, ?同樣也影響著存儲(chǔ)樹所需的內(nèi)存大小. ?需要根據(jù)問題的性質(zhì)選擇最優(yōu)的大小

          p: ? minkowski距離度量里的參數(shù). p=2時(shí)是歐氏距離, p=1時(shí)是曼哈頓距離,對(duì)于任意p, 就是minkowski距離

          metric: ?用于距離度量, ?默認(rèn)的度量是minkowski距離 (也就是L_p距離), ?當(dāng)p=2時(shí)就是歐氏距離

          metric_params: ?距離公式的其他關(guān)鍵參數(shù). 默認(rèn)為None

          n_jobs: ?并行處理的個(gè)數(shù). 默認(rèn)為1. ?如果為-1, 那么那么CPU的所有cores都用于并行工作

          3)Attributes-屬性

          effective_metric_:模型計(jì)算距離是用的距離類型

          effective_metric_params_:模型計(jì)算距離是用的距離類型

          n_features_in_:訓(xùn)練集用的特征數(shù)量

          feature_names_in_:特征名稱

          n_samples_fit_:訓(xùn)練集中的樣本數(shù)

          4)Methods-方法

          fit(X, y)

          使用X作為訓(xùn)練數(shù)據(jù),y作為目標(biāo)值(類似于標(biāo)簽)來擬合模型。

          get_params([deep])

          獲取估值器的參數(shù)。

          kneighbors([X, n_neighbors, return_distance])

          查找一個(gè)或幾個(gè)點(diǎn)的K個(gè)鄰居。

          kneighbors_graph([X, n_neighbors, mode])

          計(jì)算在X數(shù)組中每個(gè)點(diǎn)的k鄰居的(權(quán)重)圖。

          predict(X)

          給提供的數(shù)據(jù)預(yù)測(cè)對(duì)應(yīng)的標(biāo)簽。

          predict_proba(X)

          返回測(cè)試數(shù)據(jù)X的概率估值。

          score(X, y[, sample_weight])

          返回給定測(cè)試數(shù)據(jù)和標(biāo)簽的平均準(zhǔn)確值。

          set_params(**params)

          設(shè)置估值器的參數(shù)

          2、KNeighborsRegressor

          1)基本用法

          sklearn.neighbors.KNeighborsRegressor(n_neighbors=5, *, weights='uniform', algorithm='auto', leaf_size=30, p=2, metric='minkowski', metric_params=None, n_jobs=None)

          2)參數(shù)詳解

          通上,KNeighborsClassifier,回歸的參數(shù)和分類的參數(shù)一模一樣,無須贅述,看上面的數(shù)據(jù)就行。

          3)案例分析

          X = [[0], [1], [2], [3]]
          y = [0, 0, 1, 1]
          from sklearn.neighbors import KNeighborsRegressor
          neigh = KNeighborsRegressor(n_neighbors=2)
          neigh.fit(X, y)
          KNeighborsRegressor(n_neighbors=2)
          print(neigh.predict([[1.5]]))
          [0.5]

          3、RadiusNeighborsClassifier

          除了上面KNeighborsClassifier KNeighborsRegressor,與之對(duì)應(yīng)的還有RadiusNeighborsClassifierRadiusNeighborsRegressor,那么他們之間有什么區(qū)別呢?一個(gè)是靠半徑來確定最近鄰居,確定半徑,有多少算多少,通過半徑內(nèi)的鄰居確定預(yù)測(cè)數(shù)據(jù)的類別或者回歸值,一個(gè)是靠K值來確定鄰居,K幾個(gè)就取幾個(gè),不管跨度有多大,就是要找到K個(gè)才罷休,然后根據(jù)找到的K個(gè)計(jì)算預(yù)測(cè)數(shù)據(jù)的類別或者回歸值,具體用法和參數(shù)我們看下面的介紹。

          1)基本用法

          sklearn.neighbors.RadiusNeighborsClassifier(radius=1.0, *, weights='uniform', algorithm='auto', leaf_size=30, p=2, metric='minkowski', outlier_label=None, metric_params=None, n_jobs=None, **kwargs)

          2)參數(shù)注釋

          radius:尋找最鄰近數(shù)據(jù)點(diǎn)的半徑,半徑的選擇與樣本分布有關(guān),可以通過交叉驗(yàn)證來選擇一個(gè)較小的半徑,盡量保證每類訓(xùn)練樣本其他類別樣本的距離較遠(yuǎn),默認(rèn)值是1.0。如果數(shù)據(jù)是三維或者三維以下的,可以通過可視化觀察來調(diào)參。

          weights: ?默認(rèn)是uniform, ?參數(shù)可以是uniform、distance, ?也可以是用戶自己定義的函數(shù)

          • uniform: ?是均等的權(quán)重, ?就說所有的鄰近點(diǎn)的權(quán)重都是相等的

          • distance: ?是不均等的權(quán)重, ?距離近的點(diǎn)比距離遠(yuǎn)的點(diǎn)的影響大

          • 自定義:用戶自定義的函數(shù), ?接收距離的數(shù)組, ?返回一組維數(shù)相同的權(quán)重

          選擇默認(rèn)的"uniform",意味著所有最近鄰樣本權(quán)重都一樣,在做預(yù)測(cè)時(shí)一視同仁。如果是"distance",則權(quán)重和距離成反比例,即距離預(yù)測(cè)目標(biāo)更近的近鄰具有更高的權(quán)重,這樣在預(yù)測(cè)類別或者做回歸時(shí),更近的近鄰所占的影響因子會(huì)更加大。當(dāng)然,我們也可以自定義權(quán)重,即自定義一個(gè)函數(shù),輸入是距離值,輸出是權(quán)重值。這樣我們可以自己控制不同的距離所對(duì)應(yīng)的權(quán)重。一般來說,如果樣本的分布是比較成簇的,即各類樣本都在相對(duì)分開的簇中時(shí),我們用默認(rèn)的"uniform"就可以了,如果樣本的分布比較亂,規(guī)律不好尋找,選擇"distance"是一個(gè)比較好的選擇。如果用"distance"發(fā)現(xiàn)預(yù)測(cè)的效果的還是不好,可以考慮自定義距離權(quán)重來調(diào)優(yōu)這個(gè)參數(shù)。

          algorithm: ?快速k近鄰搜索算法, ?默認(rèn)參數(shù)為auto, ?可以理解為算法自己決定合適的搜索算法. ?除此之外, ?用戶也可以自己指定搜索算法: ?ball_treekd_treebrute方法進(jìn)行搜索。

          • kd_tree: ?構(gòu)造kd樹存儲(chǔ)數(shù)據(jù)以便對(duì)其進(jìn)行快速檢索的樹形數(shù)據(jù)結(jié)構(gòu), ?kd樹也就是數(shù)據(jù)結(jié)構(gòu)中的二叉樹. 以中值切分構(gòu)造的樹, ?每個(gè)結(jié)點(diǎn)是一個(gè)超矩形, ?在維數(shù)小于20時(shí)效率高

          • ball_tree: ?是為了克服kd樹高緯失效而發(fā)明的,其構(gòu)造過程是以質(zhì)心 C 和半徑 r 分割樣本空間, ?每個(gè)節(jié)點(diǎn)是一個(gè)超球體

          • brute: ?是蠻力搜索, ?也就是線性掃描, ?當(dāng)訓(xùn)練集很大時(shí), ?計(jì)算非常耗時(shí)

          leaf_size: 默認(rèn)是30, ?這個(gè)是構(gòu)造的kd樹和ball樹的大小. ?這個(gè)值的設(shè)置會(huì)影響樹構(gòu)建的速度和搜索速度, ?同樣也影響著存儲(chǔ)樹所需的內(nèi)存大小. ?需要根據(jù)問題的性質(zhì)選擇最優(yōu)的大小

          outlier_label:主要用于預(yù)測(cè)時(shí),如果目標(biāo)點(diǎn)半徑內(nèi)沒有任何訓(xùn)練集的樣本點(diǎn)時(shí),應(yīng)該標(biāo)記的類別,不建議選擇默認(rèn)值 none,因?yàn)檫@樣遇到異常點(diǎn)會(huì)報(bào)錯(cuò)。一般設(shè)置為訓(xùn)練集里最多樣本的類別。

          p: ? minkowski距離度量里的參數(shù). p=2時(shí)是歐氏距離, p=1時(shí)是曼哈頓距離,對(duì)于任意p, 就是minkowski距離

          metric: ?用于距離度量, ?默認(rèn)的度量是minkowski距離 (也就是L_p距離), ?當(dāng)p=2時(shí)就是歐氏距離

          metric_params: ?距離公式的其他關(guān)鍵參數(shù),默認(rèn)為None

          n_jobs: ?并行處理的個(gè)數(shù). 默認(rèn)為1, ?如果為-1, 那么那么CPU的所有cores都用于并行工作

          3)屬性詳解

          classes_類別數(shù)量

          effective_metric_使用的距離度量。它將與度量參數(shù)相同或與其相同,例如 如果metric參數(shù)設(shè)置為“ minkowski”,而p參數(shù)設(shè)置為2,則為“ euclidean”。

          effective_metric_params_度量功能的其他關(guān)鍵字參數(shù)。對(duì)于大多數(shù)指標(biāo)而言,它與metric_params參數(shù)相同,但是,如果將valid_metric_屬性設(shè)置為“ minkowski”,則也可能包含p參數(shù)值。

          n_features_in_多少個(gè)特征

          feature_names_in_特征的名稱

          n_samples_fit_訓(xùn)練集的樣本數(shù)

          outlier_label_不在半徑內(nèi)的數(shù)據(jù)怎么處理

          outputs_2d_如果在擬合期間y的形狀為(n_samples,)或(n_samples,1),則為True。

          4)方法詳解

          fit(X, y)

          Fit the radius neighbors classifier from the training dataset.

          get_params([deep])

          Get parameters for this estimator.

          predict(X)

          Predict the class labels for the provided data.

          predict_proba(X)

          Return probability estimates for the test data X.

          radius_neighbors([X, radius, ...])

          Find the neighbors within a given radius of a point or points.

          radius_neighbors_graph([X, radius, mode, ...])

          Compute the (weighted) graph of Neighbors for points in X.

          score(X, y[, sample_weight])

          Return the mean accuracy on the given test data and labels.

          set_params(**params)

          Set the parameters of this estimator.

          5)案例分析

          X = [[0], [1], [2], [3]]
          y = [0, 0, 1, 1]
          from sklearn.neighbors import RadiusNeighborsClassifier
          neigh = RadiusNeighborsClassifier(radius=1.0)
          neigh.fit(X, y)

          print(neigh.predict([[1.5]]))
          [0]
          print(neigh.predict_proba([[1.0]]))
          [[0.66666667 0.33333333]]



          # 我把半徑調(diào)小,就可以看到,找不到鄰居會(huì)報(bào)錯(cuò)
          neigh = RadiusNeighborsClassifier(radius=0.1)
          neigh.fit(X, y)

          print(neigh.predict([[1.5]]))

          No neighbors found for test samples array([0], dtype=int64), you can try using larger radius, giving a label for outliers, or considering removing them from your dataset.



          # 我們可以設(shè)置下outlier_label這個(gè)參數(shù),然后沒有鄰居的就默認(rèn)一個(gè)類型了
          neigh = RadiusNeighborsClassifier(radius=0.1,
          outlier_label = 'most_frequent')
          neigh.fit(X, y)

          print(neigh.predict([[1.5]]))
          [0]
          print(neigh.predict_proba([[1.0]]))
          [[1. 0.]]
          neigh.outlier_label_
          [0]

          # 其他方法
          neigh = RadiusNeighborsClassifier(radius=1.0)
          neigh.fit(X, y)
          neigh.radius_neighbors([[1.3]])
          (array([array([0.3, 0.7])], dtype=object),array([array([1, 2], dtype=int64)], dtype=object))


          4、RadiusNeighborsRegressor

          1)基本用法

          sklearn.neighbors.RadiusNeighborsRegressor(radius=1.0, *, weights='uniform', algorithm='auto', leaf_size=30, p=2, metric='minkowski', metric_params=None, n_jobs=None)

          2)參數(shù)詳解

          參考RadiusNeighborsClassifier,參數(shù)少了outlier_label,因?yàn)闊o需分類,其他一模一樣的參數(shù)、和方法

          3)案例詳解

          X = [[0], [1], [2], [3]]
          y = [0, 0.5, 1.8, 2]
          from sklearn.neighbors import RadiusNeighborsRegressor
          neigh = RadiusNeighborsRegressor(radius=1.0)
          neigh.fit(X, y)

          print(neigh.predict([[1.3]]))
          [1.15]


          5、NearestCentroid

          常規(guī)的KNN分類,如果有1億個(gè)訓(xùn)練樣本,那么就要求計(jì)算1億個(gè)距離,然后對(duì)這1億個(gè)跨度進(jìn)行排序,取最近的K個(gè)鄰居,顯然數(shù)量大了,算法運(yùn)行效率就低了,基于此,質(zhì)心分類提出了一種全新的思路,利用樣本質(zhì)心來判定類別,如果已知樣本有1億個(gè),共有3個(gè)類別,先計(jì)算出3個(gè)質(zhì)心,那么在進(jìn)行分類時(shí),只要把預(yù)測(cè)數(shù)據(jù)與3個(gè)類別的質(zhì)心求3次距離并求一個(gè)最小值,這極大地提高了運(yùn)行效率。示意圖如下:

          0566821015c90c6d76388f72babcf8b9.webp

          該 NearestCentroid 分類器是一個(gè)簡(jiǎn)單的算法, 它表示每個(gè)類都通過其成員的質(zhì)心組成, 實(shí)際上, 這使得它類似于 KMeans算法的標(biāo)簽更新階段,它也沒有參數(shù)選擇,使其成為良好的基準(zhǔn)分類器。

          1)基本用法

          sklearn.neighbors.NearestCentroid(metric='euclidean', *,

          shrink_threshold=None)

          星號(hào)(*):這是PEP-3102和Python3.0引入的一種新的函數(shù)參數(shù)規(guī)范語法,它指示KNeighborsClassifier類的構(gòu)造函數(shù)在n_neighbors之后不接受任何其他位置參數(shù),其余所有參數(shù)都是僅關(guān)鍵字的。僅關(guān)鍵字參數(shù)與名稱和值一起提供,而位置參數(shù)則不必提供。在這種情況下,您可以合法地使用以下語法(為n_neighbors提供值)

          2)參數(shù)說明

          shrink_threshold:最近縮小質(zhì)心, 它實(shí)現(xiàn)了 nearest shrunken centroid 分類器.,實(shí)際上, 每個(gè)質(zhì)心的每個(gè)特征的值除以該特征的類中的方差, 然后通過shrink_threshold 來減小特征值, 最值得注意的是,如果特定特征值與零相交, 則將其設(shè)置為零. 實(shí)際上, 這將從影響的分類上刪除該特征. 這是有用的, 例如, 去除噪聲特征。

          3)Attributes

          centroids_:每個(gè)類別的質(zhì)心

          classes_:訓(xùn)練集類別的數(shù)量

          n_features_in_:特征的數(shù)量

          feature_names_in_:查看特征的名稱

          4)案例分析

          from sklearn.neighbors import NearestCentroid
          import numpy as np
          X = np.array([[-1, -1], [-2, -1], [-3, -2], [1, 1], [2, 1], [3, 2]])
          y = np.array([1, 1, 1, 2, 2, 2])
          clf = NearestCentroid()
          clf.fit(X, y)
          NearestCentroid()
          print(clf.predict([[-0.8, -1]]))
          [1]

          # 查看質(zhì)心
          clf.centroids_
          array([[-2. , -1.33333333],
          [ 2. , 1.33333333]])

          6、K值的確定

          我們用數(shù)據(jù)集load_digits進(jìn)行數(shù)據(jù)評(píng)估,使用常規(guī)的算法KNeighborsClassifier

          from sklearn import datasets
          from sklearn.neighbors import KNeighborsClassifier
          from sklearn.model_selection import train_test_split

          digits = datasets.load_digits()

          X_digits = digits.data
          y_digits = digits.target

          # 查看下數(shù)據(jù)集的大小
          X_digits.shape
          (1797, 64)

          # 數(shù)據(jù)集進(jìn)行拆分,按3-7比例分為測(cè)試集+訓(xùn)練集
          X_train, X_test, y_train, y_test = train_test_split(\
          X_digits,
          y_digits,
          test_size=0.3,
          random_state=250
          )


          # 尋找最優(yōu)k值
          best_s = 0
          best_k = -1
          k_list = [] #存儲(chǔ)K值
          s_list = [] #存儲(chǔ)準(zhǔn)確率值


          for k in range(1,10):
          clf = KNeighborsClassifier(k,weights='distance')
          clf.fit(X_train, y_train)
          score = clf.score(X_test, y_test)

          k_list.append(k)
          s_list.append(score)

          if score > best_s:
          best_s = score
          best_k = k

          plt.plot(k_list, score_list, color='steelblue')
          plt.show()

          print('最好的參數(shù)k為{}'.format(best_k))
          print('最好準(zhǔn)確率為{}'.format(best_s))

          最好的參數(shù)k為1
          最好準(zhǔn)確率為0.9907407407407407

          708e291d7f1f8495759d8e5f7838aa94.webp

          可以看出,k=1的時(shí)候,準(zhǔn)確率最高,并且隨著K的增加,準(zhǔn)確率在不斷的下降,這個(gè)數(shù)據(jù)比較特殊,一般都是K值取一個(gè)10左右比較高。對(duì)于自己的數(shù)據(jù)集,可以根據(jù)實(shí)際情況進(jìn)行調(diào)整。

          7、KNN優(yōu)缺點(diǎn)

          KNN算法真是個(gè)愛憎分明的算法,優(yōu)點(diǎn)缺點(diǎn)都特別明顯,哈哈,我找了一堆,大家可以慢慢體會(huì),發(fā)現(xiàn)還是缺點(diǎn)多很多。具體總結(jié)如下,很多缺點(diǎn)也慢慢的進(jìn)行了優(yōu)化和解決。

          1)優(yōu)? 點(diǎn)

          原理簡(jiǎn)單,易于理解和實(shí)現(xiàn)

          無需參數(shù),也不用實(shí)際進(jìn)行訓(xùn)練

          比較適用于多分類問題

          kNN可以用來做無監(jiān)督異常檢驗(yàn);

          自適應(yīng)kNN可以根據(jù)不同的區(qū)域,在局部選擇不同的k

          kNN非常適合做時(shí)間序列

          2)缺? 點(diǎn)

          基于KNN模型尋找異常點(diǎn)是不適合于高維數(shù)據(jù)和大批量數(shù)據(jù)的,kNN算法必須保存全部的數(shù)據(jù)集,如果訓(xùn)練數(shù)據(jù)集很大,那么就需要耗費(fèi)大量的存儲(chǔ)空間。此外,由于必須對(duì)待分類數(shù)據(jù)計(jì)算與每一個(gè)訓(xùn)練數(shù)據(jù)的距離,非常耗時(shí)。

          而且距離的計(jì)算采用的是歐式距離公式,只能針對(duì)球形簇的樣本數(shù)據(jù)尋找異常,對(duì)于非球形簇則無法很好的搜尋異常。

          可解釋性較差,無法給出決策樹那樣的規(guī)則,對(duì)變量的縮放非常敏感、無法處理categorical變量、難以處理不同單位和不同數(shù)值范圍的變量

          kNN還有個(gè)問題就是k的選擇。k總是在過擬合與欠擬合之間游走。你可以說通過cross validation來選k,可是呢,你選出的k是全局適用的,而每個(gè)局部都是這個(gè)k最佳。所以kNN總是無法避免地在一些區(qū)域過擬合,同時(shí)在另一些區(qū)域欠擬合。

          如果用K近鄰模型做回歸的話,一個(gè)比較明顯的缺陷,就是K-NN無法做out of sample的回歸預(yù)測(cè)。因?yàn)橛肒-NN做回歸的時(shí)候,預(yù)測(cè)值是它附近幾個(gè)值的平均值。所以預(yù)測(cè)值不可能超過預(yù)測(cè)樣本的最大值,也不可能小于樣本的最小值。這個(gè)缺點(diǎn)其實(shí)是和回歸樹一樣的。

          k太小,容易受到噪聲數(shù)據(jù)影響,k太大可能在近鄰中包含其它類別的點(diǎn),可通過對(duì)距離加權(quán)解決,已經(jīng)有這個(gè)參數(shù)了。

          三、圖解KNN異常檢算法

          KNN怎么進(jìn)行無監(jiān)督檢測(cè)呢,其實(shí)也是很簡(jiǎn)單的,異常點(diǎn)是指遠(yuǎn)離大部分正常點(diǎn)的樣本點(diǎn),再直白點(diǎn)說,異常點(diǎn)一定是跟大部分的樣本點(diǎn)都隔得很遠(yuǎn)。基于這個(gè)思想,我們只需要依次計(jì)算每個(gè)樣本點(diǎn)與它最近的K個(gè)樣本的平均距離,再利用計(jì)算的距離與閾值進(jìn)行比較,如果大于閾值,則認(rèn)為是異常點(diǎn),同樣,為了幫助讀者理解如何利用KNN思想,實(shí)現(xiàn)異常值的識(shí)別,我畫了下面這張圖。對(duì)于第一個(gè),3個(gè)鄰居的平均距離為(2+2+3)/3=2.33,對(duì)于第二點(diǎn),3個(gè)鄰居的平均距離為(7+8+5)/3=6.667,明顯,第二個(gè)點(diǎn)的異常程度要高與第一個(gè)點(diǎn)。

          45ddbf1a604b370ce3c24229af024723.webp

          優(yōu)點(diǎn)是不需要假設(shè)數(shù)據(jù)的分布,缺點(diǎn)是不適合高維數(shù)據(jù)、只能找出異常點(diǎn),無法找出異常簇、你每一次計(jì)算近鄰距離都需要遍歷整個(gè)數(shù)據(jù)集,不適合大數(shù)據(jù)及在線應(yīng)用、有人用hyper-grid技術(shù)提速將KNN應(yīng)用到在線情況,但是還不是足夠快,僅可以找出全局異常點(diǎn),無法找到局部異常點(diǎn)。

          KNN異常檢測(cè)過程:對(duì)未知類別的數(shù)據(jù)集中的每個(gè)點(diǎn)依次執(zhí)行以下操作:

          1) 計(jì)算當(dāng)前點(diǎn) 與 數(shù)據(jù)集中每個(gè)點(diǎn)的距離

          2) 按照距離遞增次序排序

          3) 選取與當(dāng)前點(diǎn)距離最小的k個(gè)點(diǎn)

          4) 計(jì)算當(dāng)前點(diǎn)與K個(gè)鄰居的距離,并取均值、或者中值、最大值三個(gè)中的一個(gè)作為異常值

          1、異常實(shí)例計(jì)算

          無監(jiān)督,我們就要標(biāo)簽去掉,為了演示過程,我們引進(jìn)了9號(hào)嘉賓,這個(gè)人非常自信,每一項(xiàng)都填的非常高,明顯異常,我們的目的就是要把這種類似的錯(cuò)誤找出來。

          8a388cc4eb3aeb2cd05fdc1d96161e57.webp

          2、距離計(jì)算和排序

          我們計(jì)算9號(hào)的異常程度,我們這里把計(jì)算和排序兩步統(tǒng)一到一起了

          先計(jì)算9號(hào)與其他樣本的距離,然后排序,取最近的三個(gè),我們計(jì)算平均距離,可以看到,9號(hào)與最近的三個(gè)鄰居的平均距離是9.29

          09f436f2a09be6782235b8912a6080f1.webp

          3、計(jì)算距離值

          我們?cè)儆?jì)算4號(hào)嘉賓的距離,可以看到,最近的三個(gè)鄰居與4號(hào)的平均距離為3.07,只是9號(hào)的三分之一,相對(duì)來說就比較正常了。當(dāng)然距離計(jì)算可以用最大值,平均值,中位數(shù)三個(gè),算法中通過method這個(gè)參數(shù)進(jìn)行調(diào)節(jié)。

          f1e4eb30867badac1ef0fdb6f4f92a7a.webp

          我們依次計(jì)算,就可以得到每個(gè)樣本3個(gè)鄰居的平均距離了,越高的越異常,我們也可以用Python的包來檢測(cè)下我們計(jì)算的對(duì)不對(duì)。

          import numpy as np
          X_train = np.array([
          [7, 7, 9, 3],
          [5, 4, 5, 6],
          [8, 6, 9, 3],
          [9, 9, 7, 7],
          [5, 5, 5, 5],
          [9, 9, 9, 1],
          [5, 2, 5, 5],
          [8, 8, 7, 6],
          [10,10, 12, 13]])
          # import kNN分類器
          from pyod.models.knn import KNN

          # 訓(xùn)練一個(gè)kNN檢測(cè)器
          clf_name = 'kNN'
          # 初始化檢測(cè)器clf
          clf = KNN( method='mean', n_neighbors=3, )
          clf.fit(X_train)

          # 返回訓(xùn)練數(shù)據(jù)X_train上的異常標(biāo)簽和異常分值
          # 返回訓(xùn)練數(shù)據(jù)上的分類標(biāo)簽 (0: 正常值, 1: 異常值)
          y_train_pred = clf.labels_
          y_train_pred
          array([0, 0, 0, 0, 0, 0, 0, 0, 1])

          # 返回訓(xùn)練數(shù)據(jù)上的異常值 (分值越大越異常)
          y_train_scores = clf.decision_scores_
          y_train_scores
          array([2.91709951, 3.01181545, 3.09299219, 4.16692633, 3.07001503,
          4.25784112, 3.98142397, 3.24271326, 9.42068891])

          我們自己計(jì)算的平均距離為9.29,系統(tǒng)算的9.42,有一點(diǎn)點(diǎn)的差異,可能是哪里加了一個(gè)微調(diào)的系數(shù),大家可以探索下。

          四、KNN異常檢測(cè)算法應(yīng)用

          上面大概知道了KNN怎么進(jìn)行異常檢測(cè)的,現(xiàn)在我們找個(gè)具體的案例,看看更加明細(xì)的參數(shù)以及實(shí)現(xiàn)的過程,有個(gè)更加立體的感覺,并且學(xué)完能夠應(yīng)用起來。

          1、算法基本用法

          地址:https://pyod.readthedocs.io/en/latest/pyod.models.html#module-pyod.models.knn

          pyod.models.knn.KNN(contamination=0.1,
          n_neighbors=5,
          method='largest',
          radius = 1.0,
          algorithm='auto',
          leaf_size=30,
          metric='minkowski',
          p=2,
          metric_params=None,
          n_jobs=1,
          **kwargs)

          2、參數(shù)詳解

          contamination:污染度,contamination : float in (0., 0.5), optional (default=0.1)數(shù)據(jù)集的污染量,即數(shù)據(jù)集中異常值的比例。在擬合時(shí)用于定義決策函數(shù)的閾值。如果是“自動(dòng)”,則確定決策函數(shù)閾值,如原始論文中所示。在版本0.20中更改:默認(rèn)值contamination將從0.20更改為'auto'0.22。

          n_neighbors:選取相鄰點(diǎn)數(shù)量

          method:‘largest’、‘mean’、‘median’

          • largest:使用與第k個(gè)相鄰點(diǎn)的距離作為異常得分

          • mean:使用k個(gè)相鄰點(diǎn)距離的平均值作為異常得分

          • median:使用k個(gè)相鄰點(diǎn)距離的中值作為異常得分

          radius : radius_neighbors使用的參數(shù)空間半徑

          algorithm:找到最近的k個(gè)樣本

          • kd_tree:依次對(duì)K維坐標(biāo)軸,以中值切分,每一個(gè)節(jié)點(diǎn)是超矩形,適用于低維(<20時(shí)效率最高)

          • ball_tree:以質(zhì)心c和半徑r分割樣本空間,每一個(gè)節(jié)點(diǎn)是超球體,適用于高維(kd_tree高維效率低)

          • brute:暴力搜索

          • auto:通過 fit() 函數(shù)擬合,選擇最適合的算法;如果數(shù)據(jù)稀疏,擬合后會(huì)自動(dòng)選擇brute,參數(shù)失效

          leaf_sizekd_tree和ball_tree中葉子大小,影響構(gòu)建、查詢、存儲(chǔ),根據(jù)實(shí)際數(shù)據(jù)而定。樹葉中可以有多于一個(gè)的數(shù)據(jù)點(diǎn),算法在達(dá)到葉子時(shí)在其中執(zhí)行暴力搜索即可。如果leaf size 趨向于 N(訓(xùn)練數(shù)據(jù)的樣本數(shù)量),算法其實(shí)就是 brute force了。如果leaf size 太小了,趨向于1,那查詢的時(shí)候 遍歷樹的時(shí)間就會(huì)大大增加。

          metric:距離計(jì)算標(biāo)準(zhǔn),距離標(biāo)準(zhǔn)圖例

          • euclidean:歐氏距離(p = 2)

          • manhattan:曼哈頓距離(p = 1)

          • minkowski:閔可夫斯基距離

          p : metric參數(shù),默認(rèn)為2

          metric_params : metric參數(shù)

          n_jobs : 并行作業(yè)數(shù),-1時(shí),n_jobs為CPU核心數(shù)。

          3、屬性詳解

          decision_scores_數(shù)據(jù)X上的異常打分,分?jǐn)?shù)越高,則該數(shù)據(jù)點(diǎn)的異常程度越高

          threshold_異常樣本的個(gè)數(shù)閾值,基于contamination這個(gè)參數(shù)的設(shè)置,總量最多等于n_samples * contamination

          labels_: 數(shù)據(jù)X上的異常標(biāo)簽,返回值為二分類標(biāo)簽(0為正常點(diǎn),1為異常點(diǎn))

          4、方法詳解

          fit(X): 用數(shù)據(jù)X來“訓(xùn)練/擬合”檢測(cè)器clf。即在初始化檢測(cè)器clf后,用X來“訓(xùn)練”它。

          fit_predict_score(X, y): 用數(shù)據(jù)X來訓(xùn)練檢測(cè)器clf,并預(yù)測(cè)X的預(yù)測(cè)值,并在真實(shí)標(biāo)簽y上進(jìn)行評(píng)估。此處的y只是用于評(píng)估,而非訓(xùn)練

          decision_function(X): 在檢測(cè)器clf被fit后,可以通過該函數(shù)來預(yù)測(cè)未知數(shù)據(jù)的異常程度,返回值為原始分?jǐn)?shù),并非0和1。返回分?jǐn)?shù)越高,則該數(shù)據(jù)點(diǎn)的異常程度越高

          predict(X): 在檢測(cè)器clf被fit后,可以通過該函數(shù)來預(yù)測(cè)未知數(shù)據(jù)的異常標(biāo)簽,返回值為二分類標(biāo)簽(0為正常點(diǎn),1為異常點(diǎn))

          predict_proba(X): 在檢測(cè)器clf被fit后,預(yù)測(cè)未知數(shù)據(jù)的異常概率,返回該點(diǎn)是異常點(diǎn)概率

          當(dāng)檢測(cè)器clf被初始化且fit(X)函數(shù)被執(zhí)行后,clf就會(huì)生成兩個(gè)重要的屬性:

          decision_scores: 數(shù)據(jù)X上的異常打分,分?jǐn)?shù)越高,則該數(shù)據(jù)點(diǎn)的異常程度越高

          KNN算法專注于全局異常檢測(cè),所以無法檢測(cè)到局部異常。首先,對(duì)于數(shù)據(jù)集中的每條記錄,必須找到k個(gè)最近的鄰居。然后使用這K個(gè)鄰居計(jì)算異常分?jǐn)?shù)。

          最 ? 大:使用到第k個(gè)鄰居的距離作為離群值得分

          平均值:使用所有k個(gè)鄰居的平均值作為離群值得分

          中位數(shù):使用到k個(gè)鄰居的距離的中值作為離群值得分

          在實(shí)際方法中后兩種的應(yīng)用度較高。然而,分?jǐn)?shù)的絕對(duì)值在很大程度上取決于數(shù)據(jù)集本身、維度數(shù)和規(guī)范化。參數(shù)k的選擇當(dāng)然對(duì)結(jié)果很重要。如果選擇過低,記錄的密度估計(jì)可能不可靠。(即過擬合)另一方面,如果它太大,密度估計(jì)可能太粗略。K值的選擇通常在10-50這個(gè)范圍內(nèi)。所以在分類方法中,選擇一個(gè)合適的K值,可以用交叉驗(yàn)證法。

          但是,事實(shí)上基于KNN的算法都是不適用于欺詐檢測(cè)的,因?yàn)樗麄儽旧砭蛯?duì)噪聲比較敏感。

          5、案例分析

          #導(dǎo)入
          from pyod.models.knn import KNN
          from pyod.utils.data import generate_data
          from pyod.utils.data import evaluate_print
          from pyod.utils.example import visualize

          #參數(shù)設(shè)置
          contamination = 0.1 # percentage of outliers
          n_train = 200 # number of training points
          n_test = 100 # number of testing points

          X_train, y_train, X_test, y_test = generate_data(
          n_train=n_train, n_test=n_test, contamination=contamination)

          # import kNN分類器
          from pyod.models.knn import KNN

          # 訓(xùn)練一個(gè)kNN檢測(cè)器
          clf_name = 'kNN'
          clf = KNN() # 初始化檢測(cè)器clf
          clf.fit(X_train) # 使用X_train訓(xùn)練檢測(cè)器clf

          # 返回訓(xùn)練數(shù)據(jù)X_train上的異常標(biāo)簽和異常分值
          y_train_pred = clf.labels_ # 返回訓(xùn)練數(shù)據(jù)上的分類標(biāo)簽 (0: 正常值, 1: 異常值)
          y_train_scores = clf.decision_scores_ # 返回訓(xùn)練數(shù)據(jù)上的異常值 (分值越大越異常)

          # 用訓(xùn)練好的clf來預(yù)測(cè)未知數(shù)據(jù)中的異常值
          y_test_pred = clf.predict(X_test) # 返回未知數(shù)據(jù)上的分類標(biāo)簽 (0: 正常值, 1: 異常值)
          y_test_scores = clf.decision_function(X_test) # 返回未知數(shù)據(jù)上的異常值 (分值越大越異常)


          對(duì)識(shí)別結(jié)果可視化

          # 模型可視化
          visualize(clf_name,
          X_train,
          y_train,
          X_test,
          y_test,
          y_train_pred,
          y_test_pred,
          show_figure=True,
          save_figure=False
          )

          fcd5d93274b60f7a2d4b4515ee64ef06.webp


          五、KNN的其他用途

          KNN除了能夠進(jìn)行有監(jiān)督,另外幾個(gè)在sklearn.neighbors包中但不是做分類、回歸預(yù)測(cè)的類也值得關(guān)注,用于尋找最鄰近的數(shù)據(jù)點(diǎn),是其他最鄰近算法的基礎(chǔ)。kneighbors_graph類返回用KNN時(shí)和每個(gè)樣本最近的K個(gè)訓(xùn)練集樣本的位置。radius_neighbors_graph返回用限定半徑最近鄰法時(shí)和每個(gè)樣本在限定半徑內(nèi)的訓(xùn)練集樣本的位置。NearestNeighbors是個(gè)大雜燴,它即可以返回用KNN時(shí)和每個(gè)樣本最近的K個(gè)訓(xùn)練集樣本的位置,也可以返回用限定半徑最近鄰法時(shí)和每個(gè)樣本最近的訓(xùn)練集樣本的位置,常常用在聚類模型中。

          許多學(xué)習(xí)方法都是依賴最近鄰作為核心。一個(gè)例子是 核密度估計(jì) 和LOF, 這兩個(gè)我們?cè)谄渌胤皆儆懻?/span>

          1、NearestNeighbors

          NearestNeighbors (最近鄰)尋找N個(gè)最近的鄰居以及計(jì)算之間的距離,實(shí)現(xiàn)了 unsupervised nearest neighbors learning(無監(jiān)督的最近鄰學(xué)習(xí))。它為三種不同的最近鄰算法提供統(tǒng)一的接口:BallTree, KDTree, 還有基于 sklearn.metrics.pairwise 的 brute-force 算法。選擇算法時(shí)可通過關(guān)鍵字 'algorithm' 來控制, 并指定為 ['auto', 'ball_tree', 'kd_tree', 'brute'] 其中的一個(gè)即可。當(dāng)默認(rèn)值設(shè)置為 'auto' 時(shí),算法會(huì)嘗試從訓(xùn)練數(shù)據(jù)中確定最佳方法。

          1)基本用法

          sklearn.neighbors.NearestNeighbors(*, n_neighbors=5, radius=1.0, algorithm='auto', leaf_size=30, metric='minkowski', p=2, metric_params=None, n_jobs=None)

          2)參數(shù)含義

          n_neighbors(n鄰域):所要選用的最近鄰的數(shù)目,相當(dāng)于knn算法(k近鄰算法)中的 k,(default = 5),在設(shè)置此參數(shù)時(shí)輸入的需為整形(int)。

          radius(半徑):要使用的參數(shù)空間范圍,在設(shè)置此參數(shù)時(shí)輸入的需為浮點(diǎn)數(shù)(float)。

          algorithm{‘a(chǎn)uto’, ‘ball_tree’, ‘kd_tree’, ‘brute’}:即用于選取計(jì)算最近鄰的算法:這里主要包括

          ‘a(chǎn)uto’ ? ? ?:根據(jù)樣本數(shù)據(jù)自動(dòng)刷選合適的算法。

          ‘ball_tree’:構(gòu)建“球樹”算法模型。

          ‘kd_tree’ :‘’kd樹‘’算法。

          ‘brute’ ? ? :使用蠻力搜索,即或相當(dāng)于Knn算法,需遍歷所有樣本數(shù)據(jù)與目標(biāo)數(shù)據(jù)的距離,進(jìn)而按升序排序從而選取最近的K個(gè)值,采用投票得出結(jié)果。

          leaf_size:葉的大小,針對(duì)算法為球樹或KD樹而言。這個(gè)設(shè)置會(huì)影響構(gòu)造和查詢的速度,以及存儲(chǔ)樹所需的內(nèi)存。最優(yōu)值取決于問題的性質(zhì)。

          metric:用于樹的距離度量。默認(rèn)度量是Minkowski,p=2等價(jià)于標(biāo)準(zhǔn)的歐幾里德度量。有關(guān)可用度量的列表,可以查閱距離度量類的文檔。如果度量是“預(yù)先計(jì)算的”,則假定X是距離矩陣,在擬合期間必須是平方。

          p:Minkowski度量參數(shù)的參數(shù)來自sklearn.emeics.pairwise.pairwise_距離。當(dāng)p=1時(shí),這等價(jià)于使用曼哈頓距離(L1),歐幾里得距離(L2)等價(jià)于p=2時(shí),對(duì)于任意的p,則使用Minkowski_距離(L_P)。

          metric_params:度量函數(shù)的附加關(guān)鍵字參數(shù),設(shè)置應(yīng)為dict(字典)形式。

          n_jobs:要為鄰居搜索的并行作業(yè)的數(shù)量。None指1,除非在 joblib.parallel_backend背景。-1意味著使用所有處理器,若要了解相關(guān)的知識(shí)應(yīng)該具體查找一下。

          3)案例解析

          from sklearn.neighbors import NearestNeighbors
          import numpy as np

          #定義一個(gè)數(shù)組
          X = np.array([[-1,-1],
          [-2,-1],
          [-3,-2],
          [1,1],
          [2,1],
          [3,2] ])


          nbrs = NearestNeighbors(n_neighbors=3, algorithm= 'ball_tree').fit(X)
          distances, indices = nbrs.kneighbors(X)


          # 訓(xùn)練一個(gè)模型,并計(jì)算距離

          samples = [[0, 0, 2], [1, 0, 0], [0, 0, 1]]

          neigh = NearestNeighbors(n_neighbors=2,
          radius=0.4,
          algorithm='ball_tree')

          neigh.fit(samples)

          neigh.kneighbors([[0, 0, 1.3]], 2,
          return_distance=True, )

          distances, neighs = neigh.kneighbors([[0, 0, 1.3]], 2, return_distance=True, )
          distances
          array([[0.3, 0.7]])
          neighs
          array([[2, 0]], dtype=int64)


          from sklearn.neighbors import NearestNeighbors
          import numpy as np
          X = np.array([
          [7, 7, 9, 3],
          [5, 4, 5, 6],
          [3, 6, 6, 9],
          [9, 9, 7, 5],
          [5, 5, 5, 5],
          [9, 9, 9, 1],
          [5, 2, 5, 5],
          [8, 8, 7, 6]])

          nbrs = NearestNeighbors(n_neighbors=3, algorithm= 'ball_tree').fit(X)

          distances, indices = nbrs.kneighbors([[9, 9, 9, 2]])

          2、KDTree 和 BallTree 類

          我們可以使用 KDTree 或 BallTree 其中一個(gè)類來找最近鄰。這是上文使用過的 NearestNeighbors 類所包含的功能。KDTree 和 BallTree 具有相同的接口;我們將在這里展示使用 KDTree 的例子

          1)BallTree

          sklearn.neighbors.BallTree(X, leaf_size=40, metric='minkowski', **kwargs)

          21)KDTree

          sklearn.neighbors.KDTree(X, leaf_size=40, metric='minkowski', **kwargs)?

          3)案例應(yīng)用

          from sklearn.neighbors import KDTree
          import numpy as np
          X = np.array([[-1, -1], [-2, -1], [-3, -2], [1, 1], [2, 1], [3, 2]])
          kdt = KDTree(X, leaf_size=30, metric='euclidean')
          kdt.query(X, k=2, return_distance=False)
          array([[0, 1],
          [1, 0],
          [2, 1],
          [3, 4],
          [4, 3],
          [5, 4]]...)

          計(jì)算距離,方便其他算法進(jìn)行調(diào)用。

          3、kneighbors_graph

          k-近鄰圖(k-nearest neighbor graph),選定參數(shù)k,對(duì)于頂點(diǎn)vi,i=1,..,n,把離它最近的k個(gè)點(diǎn)與之相連,所得到的圖就是k-近鄰圖。需要注意的是,因?yàn)檫@樣的鄰近關(guān)系并不是對(duì)稱的(vj是vi的k近鄰 ≠vi是vj的k近鄰),故而得到的圖將會(huì)是“有向”的。為了得到無向的圖(圖的賦權(quán)鄰接矩陣W應(yīng)是對(duì)稱的)

          1)基本用法

          sklearn.neighbors.kneighbors_graph(X, n_neighbors, *, mode='connectivity', metric='minkowski', p=2, metric_params=None, include_self=False, n_jobs=None)

          2)參數(shù)詳解

          X:樣本數(shù)據(jù),以numpy數(shù)組或預(yù)先計(jì)算的BallTree的形式

          n_neighbors:每個(gè)樣本的鄰居數(shù)量。

          mode:'connectivity'將返回具有1和0的連通性矩陣,而'distance'將根據(jù)給定的度量返回鄰居之間的距離。

          metric:用于計(jì)算每個(gè)采樣點(diǎn)的k鄰居的距離度量。DistanceMetric類提供了可用指標(biāo)的列表。默認(rèn)距離為'euclidean'(“ minkowski”度量標(biāo)準(zhǔn),p參數(shù)等于2。)

          p:Minkowski度量的功率參數(shù)。當(dāng)p=1時(shí),相當(dāng)于使用manhattan_distance (l1),p=2時(shí)使用歐氏距離(l2)。對(duì)于任意的p,使用minkowski_distance (l_p)。

          metric_params:計(jì)量函數(shù)的附加關(guān)鍵字參數(shù)。

          include_self:是否將每個(gè)樣本標(biāo)記為其自身的第一個(gè)最近鄰居。如果為'auto',則將True用于mode ='connectivity',將False用于mode ='distance'。

          n_job:為鄰居搜索運(yùn)行的并行作業(yè)數(shù)。None 意味著 1 除非在joblib.parallel_backend上下文中。-1 表示使用所有處理器。

          返回值:圖形,其中A[i,j]被賦予連接i和j的邊的權(quán)重,矩陣為CSR格式。

          3)案例數(shù)據(jù)

          可以看到,這里的聯(lián)通,包含了自己,當(dāng)鄰居等于1的時(shí)候,只有自己和自己聯(lián)通

          X = [[0], [3], [1]]
          from sklearn.neighbors import kneighbors_graph
          A = kneighbors_graph(X, 2, mode='connectivity', include_self=True)
          A.toarray()
          array([[1., 0., 1.],
          [0., 1., 1.],
          [1., 0., 1.]])

          X = [[0], [3], [1]]
          from sklearn.neighbors import kneighbors_graph
          A = kneighbors_graph(X,1, mode='connectivity', include_self=True)
          A.toarray()
          array([[1., 0., 0.],
          [0., 1., 0.],
          [0., 0., 1.]])

          4)數(shù)據(jù)可視化

          https://blog.csdn.net/pylittlebrat/article/details/121914230

          import networkx as nx
          import matplotlib.pyplot as plt

          X = np.array([[7, 7, 9, 3],
          [5, 4, 5, 6],
          [8, 6, 9, 3],
          [9, 9, 7, 7],
          [5, 5, 5, 5],
          [9, 9, 9, 1],
          [5, 2, 5, 5],
          [8, 2, 7, 6],
          [1, 8, 7, 4],
          [4, 3, 7, 8],
          [8, 1, 7, 6]
          ])
          from sklearn.neighbors import kneighbors_graph
          A = kneighbors_graph(X, 4, mode='connectivity', include_self=False)


          # 繪圖
          G = nx.from_numpy_matrix(A.toarray())
          plt.figure(figsize=(4,4),dpi=600)
          nx.draw_networkx(G,
          pos = nx.kamada_kawai_layout(G),
          node_color = 'r',
          node_size=500,
          alpha=0.8
          )
          plt.axis('off')
          plt.show()

          376718b789acab66cbdab67dd68bab1b.webp

          我們這里的圖比較簡(jiǎn)單,如果繼續(xù)增加復(fù)雜度,畫出的圖如下,大家可以找比較大的數(shù)據(jù)集進(jìn)行測(cè)試,文章寫的太多了,不能再寫下去了。KNN寫成圖算法了。


          271133c7a3ef537f9b446ce32934c05a.webp

          https://www.cylab.be/blog/47/distributed-k-nn-graphs-and-similarity-search

          4、radius_neighbors_graph

          1)基本用法

          sklearn.neighbors.radius_neighbors_graph(X, radius, *, mode='connectivity', metric='minkowski', p=2, metric_params=None, include_self=False, n_jobs=None)

          2)參數(shù)詳解

          參考kneighbors_graph,除了半徑限制參數(shù)radius,其他的參數(shù)均一模一樣,這里不再贅述。


          3)應(yīng)用案例

          X = [[0], [3], [1]]
          from sklearn.neighbors import radius_neighbors_graph
          A = radius_neighbors_graph(X, 1.5, mode='connectivity',
          include_self=True)
          A.toarray()
          array([[1., 0., 1.],
          [0., 1., 0.],
          [1., 0., 1.]])


          4)可視化

          import networkx as nx
          import matplotlib.pyplot as plt

          X = np.array([[7, 7, 9, 3],
          [5, 4, 5, 6],
          [8, 6, 9, 3],
          [9, 9, 7, 7],
          [5, 5, 5, 5],
          [9, 9, 9, 1],
          [5, 2, 5, 5],
          [8, 2, 7, 6],
          [1, 8, 7, 4],
          [4, 3, 7, 8],
          [8, 1, 7, 6]
          ])
          from sklearn.neighbors import kneighbors_graph
          A = radius_neighbors_graph(X, 4, mode='connectivity', include_self=False)


          # 繪圖
          G = nx.from_numpy_matrix(A.toarray())
          plt.figure(figsize=(4,4),dpi=600)
          nx.draw_networkx(G,
          pos = nx.kamada_kawai_layout(G),
          node_color = 'r',
          node_size=500,
          alpha=0.8
          )
          plt.axis('off')
          plt.show()

          10b401b61fa626e45364977d37fc2bd7.webp

          可以看到,我們的半徑設(shè)置為4,有的節(jié)點(diǎn)并沒有找到鄰居,我們自己的用戶或者文本數(shù)據(jù),也是可以通過構(gòu)建類似的矩陣,然后計(jì)算每個(gè)樣本的K相似或者半徑相識(shí),這樣就能夠一目了然的找出一堆樣本相互之間的關(guān)系了,并且還可以考慮其中的權(quán)重。

          六、總 ?結(jié)

          通過本文,我們發(fā)現(xiàn)KNN系列是一個(gè)非常豐富且有意思的內(nèi)容,還有很多有待我們?nèi)ヌ剿鳌:芏嗨惴ǎ鋵?shí)學(xué)的是思想,如果認(rèn)真的徹底搞清楚幾個(gè)算法的原理,你會(huì)瞬間覺得,學(xué)其他算法也簡(jiǎn)單起來,如果你沒有深刻的學(xué)過幾個(gè)算法,總覺得學(xué)啥都是朦朦朧朧,似懂非懂的,好像什么都會(huì)了,好像又啥都不會(huì)。

          思考題:KNN是不是也可以做個(gè)KNN森林,如果可以,怎么做,如果不行,為什么?看完本文來做這個(gè)思考題。

          瀏覽 56
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  天天干天天色天天射 | 亚洲色图欧美电影 | 久久性生活视频 | 日韩无码五月天 | 中文字幕之中文字幕 |