99999久久久久久亚洲,欧美人与禽猛交狂配,高清日韩av在线影院,一个人在线高清免费观看,啦啦啦在线视频免费观看www

熱線電話:13121318867

登錄
首頁精彩閱讀機器學(xué)習(xí)的敲門磚:kNN算法(上)
機器學(xué)習(xí)的敲門磚:kNN算法(上)
2019-10-15
收藏
<a href='/map/jiqixuexi/' style='color:#000;font-size:inherit;'>機器學(xué)習(xí)</a>的敲門磚:kNN算法(上)

作者 | Japson

來源 | 木東居士

0x00 前言

天下苦數(shù)學(xué)久矣!

對于很多想要入門機器學(xué)習(xí)的工程師來說,數(shù)學(xué)是通往AI道路上的第一支攔路虎。一些已經(jīng)工作的同學(xué)不得不撿起早已還給老師的數(shù)學(xué)知識,勉強拿起《統(tǒng)計學(xué)習(xí)方法》、《西瓜書》等入門書籍鉆研?;虮灰粋€個復(fù)雜的機公式勸退,或記下一堆公式定理之后卻不知道和代碼有什么關(guān)系,茫然不知所措。

其實對于工程師來說,最直接的入門方法就是coding。

本系列從最簡單的機器學(xué)習(xí)算法“K-近鄰算法”開始,通過代碼走進機器學(xué)習(xí)的大門,搞定傳統(tǒng)機器學(xué)習(xí)算法。

首先會介紹算法的基本原理,然后依據(jù)原理手動實現(xiàn)算法,最后使用sklearn中提供的機器學(xué)習(xí)庫完成一些小demo。不用擔心,相關(guān)的機器學(xué)習(xí)概念以及算法原理也會穿插其中,幫助你以“代碼->原理->代碼”這種迭代的方式完成學(xué)習(xí)。

需要:

掌握Python語言,能夠使用Numpy、Pandas等工具庫。

安裝Anaconda

不要求對機器學(xué)習(xí)算法以及相關(guān)概念有很深刻的了解,因為在文章中會對首次出現(xiàn)的概念進行介紹。

子曰:“先行其言而后從之”。行動永遠是引發(fā)改變的第一步,話不多說,先讓我們碼起來吧!


0x01 初探kNN算法

為什么選擇kNN

為什么說KNN算法是機器學(xué)習(xí)的敲門磚?

首先KNN算法思想簡單樸素,容易理解,幾乎不需要任何數(shù)學(xué)知識。這一點使得KNN算法非常適合入門。

其次,KNN算法也很好用,理論成熟,簡單粗暴,既可以用來做分類(天然支持多分類),也可以用來做回歸。并且與樸素貝葉斯之類的算法相比,由于其對數(shù)據(jù)沒有假設(shè),因此準確度高,對異常點不敏感。

最后,kNN算法簡單,但是可以解釋機器學(xué)習(xí)算法過程中的很多細節(jié)問題,能夠完整的刻畫機器學(xué)習(xí)應(yīng)用的流程。

當然KNN算法也有缺點,我們會在最后進行總結(jié)。

kNN思想簡介

魯迅曾經(jīng)說過:“想要了解一個人,就去看看他的朋友”。因此,KNN算法是魯迅發(fā)明的。

kNN(k-NearestNeighbor),也就是k最近鄰算法。顧名思義,所謂K最近鄰,就是k個最近的鄰居的意思。也就是在數(shù)據(jù)集中,認為每個樣本可以用離他最距離近的k個鄰居來代表。

貼出一張從百度百科上找的一張圖,我們可以直觀地感受到這樸素的思想:我們要判斷Xu 是什么顏色的,找到與其距離最近的5個點,有4個是紅色的,有1個是綠色的。因此我們認為Xu是屬于紅色的集合

<a href='/map/jiqixuexi/' style='color:#000;font-size:inherit;'>機器學(xué)習(xí)</a>的敲門磚:kNN算法(上)

因此我們說:

在一個給定的類別已知的訓(xùn)練樣本集中,已知樣本集中每一個數(shù)據(jù)與所屬分類的對應(yīng)關(guān)系(標簽)。在輸入不含有標簽的新樣本后,將新的數(shù)據(jù)的每個特征與樣本集中數(shù)據(jù)對應(yīng)的特征進行比較,然后算法提取樣本最相似的k個數(shù)據(jù)(最近鄰)的分類標簽。通過多數(shù)表決等方式進行預(yù)測。即選擇k個最相似數(shù)據(jù)中出現(xiàn)次數(shù)最多的分類,作為新數(shù)據(jù)的分類。

K近鄰法不具有顯式的學(xué)習(xí)過程,而是利用訓(xùn)練數(shù)據(jù)集對特征向量空間進行劃分,并作為其分類的“模型”。

kNN算法流程

通過理解算法思想,可以將其簡化為“找鄰居+投票”。K近鄰法使用的模型,實際上是特征空間的劃分。模型由三個基本要素決定:

  • 距離度量
  • k值
  • 分類決策規(guī)則

其中兩個實例點之間的距離反映了相似程度。一般來說使用歐氏距離來計算。

梳理kNN算法流程如下:

  1. 計算測試對象到訓(xùn)練集中每個對象的距離
  2. 按照距離的遠近排序
  3. 選取與當前測試對象最近的k的訓(xùn)練對象,作為該測試對象的鄰居
  4. 統(tǒng)計這k個鄰居的類別頻率
  5. k個鄰居里頻率最高的類別,即為測試對象的類別

<a href='/map/jiqixuexi/' style='color:#000;font-size:inherit;'>機器學(xué)習(xí)</a>的敲門磚:kNN算法(上)


0x02 算法實現(xiàn)

kNN算法自實現(xiàn)

打開Jupyter Notebook,創(chuàng)建Python3文件。

準備數(shù)據(jù)

首先我們準備一組數(shù)據(jù):

import numpy as npimport matplotlib.pyplot as plt# raw_data_x是特征,raw_data_y是標簽,0為良性,1為惡性raw_data_X = [[3.393533211, 2.331273381],
 [3.110073483, 1.781539638],
 [1.343853454, 3.368312451],
 [3.582294121, 4.679917921],
 [2.280362211, 2.866990212],
 [7.423436752, 4.685324231],
 [5.745231231, 3.532131321],
 [9.172112222, 2.511113104],
 [7.927841231, 3.421455345],
 [7.939831414, 0.791631213]
 ]
raw_data_y = [0, 0, 0, 0, 0, 1, 1, 1, 1, 1]# 設(shè)置訓(xùn)練組X_train = np.array(raw_data_X)
y_train = np.array(raw_data_y)# 將數(shù)據(jù)可視化plt.scatter(X_train[y_train==0,0],X_train[y_train==0,1], color='g', label = 'Tumor Size')
plt.scatter(X_train[y_train==1,0],X_train[y_train==1,1], color='r', label = 'Time')
plt.xlabel('Tumor Size')
plt.ylabel('Time')
plt.axis([0,10,0,5])
plt.show()

數(shù)據(jù)可視化后生成的圖片如下圖所示。其中橫軸是腫塊大小,縱軸是發(fā)現(xiàn)時間。每個病人的腫塊大小和發(fā)病時間構(gòu)成了二維平面特征中的一個點。對于每個點,我們通過label明確是惡性腫瘤(綠色)、良性腫瘤(紅色)。

<a href='/map/jiqixuexi/' style='color:#000;font-size:inherit;'>機器學(xué)習(xí)</a>的敲門磚:kNN算法(上)

那么現(xiàn)在給出一個腫瘤患者的數(shù)據(jù)(樣本點)x:[8.90933607318, 3.365731514],是良性腫瘤還是惡性腫瘤

求距離

我們要做的是:求點x到數(shù)據(jù)集中每個點的距離,首先計算距離,使用歐氏距離

<a href='/map/jiqixuexi/' style='color:#000;font-size:inherit;'>機器學(xué)習(xí)</a>的敲門磚:kNN算法(上)

下面寫代碼:

from math import sqrt
distances = [] # 用來記錄x到樣本數(shù)據(jù)集中每個點的距離for x_train in X_train:
 d = sqrt(np.sum((x_train - x) ** 2))
 distances.append(d)# 使用列表生成器,一行就能搞定,對于X_train中的每一個元素x_train都進行前面的運算,把結(jié)果生成一個列表distances = [sqrt(np.sum((x_train - x) ** 2)) for x_train in X_train]
distances
輸出:[5.611968000921151, 6.011747706769277, 7.565483059418645, 5.486753308891268, 6.647709180746875, 1.9872648870854204, 3.168477291709152, 0.8941051007010301, 0.9830754144862234, 2.7506238644678445]

在求出距離列表之后,我們要找到最小的距離,需要進行一次排序操作。其實不是簡單的排序,因為我們把只將距離排大小是沒有意義的,我們要知道距離最小的k個點是在樣本集中的位置。

這里我們使用函數(shù):np.argsort(array) 對一個數(shù)組進行排序,返回的是相應(yīng)的排序后結(jié)果的索引

nearest = np.argsort(distances)
nearest
輸出:array([7, 8, 5, 9, 6, 3, 0, 1, 4, 2])
結(jié)果的含義是:距離最小的點在distances數(shù)組中的索引是7,第二小的點索引是8... 近到遠是哪些點


選k值

然后我們選擇k值,這里暫定為6,那就找出最近的6個點(top 6),并記錄他們的標簽值(y)

k = 6topK_y = [y_train[i] for i in nearest[:k]]
topK_y
輸出:[1, 1, 1, 1, 1, 0]
<a href='/map/jiqixuexi/' style='color:#000;font-size:inherit;'>機器學(xué)習(xí)</a>的敲門磚:kNN算法(上)


決策規(guī)則

下面進入投票環(huán)節(jié)。找到與測試樣本點最近的6個訓(xùn)練樣本點的標簽y是什么。可以查不同類別的點有多少個。

將數(shù)組中的元素和元素出現(xiàn)的頻次進行統(tǒng)計

from collections import Counter
votes = Counter(topK_y)
votes
輸出:一個字典,原數(shù)組中值為0的個數(shù)為1,值為1的個數(shù)有為5Counter({0:1, 1:5})
# Counter.most_common(n) 找出票數(shù)最多的n個元素,返回的是一個列表,列表中的每個元素是一個元組,元組中第一個元素是對應(yīng)的元素是誰,第二個元素是頻次votes.most_common(1)
輸出:[(1,5)]
predict_y = votes.most_common(1)[0][0]
predict_y
輸出:1

得到預(yù)測的y值是1


自實現(xiàn)完整工程代碼

我們已經(jīng)在jupyter notebook中寫好了kNN算法,下面我們在外部進行封裝。

相關(guān)代碼可以在 https://github.com/japsonzbz/ML_Algorithms 中看到

import numpy as npimport math as sqrtfrom collections import Counterclass kNNClassifier:
 def __init__(self, k):
 """初始化分類器"""
 assert k >= 1, "k must be valid"
 self.k = k
 self._X_train = None
 self._y_train = None
 def fit(self, X_train, y_train):
 """根據(jù)訓(xùn)練數(shù)據(jù)集X_train和y_train訓(xùn)練kNN分類器"""
 assert X_train.shape[0] == y_train.shape[0], \ "the size of X_train must be equal to the size of y_train"
 assert self.k <= X_train.shape[0], \ "the size of X_train must be at least k"
 self._X_train = X_train
 self._y_train = y_train return self def predict(self,X_predict):
 """給定待預(yù)測數(shù)據(jù)集X_predict,返回表示X_predict結(jié)果的向量"""
 assert self._X_train is not None and self._y_train is not None, \ "must fit before predict!"
 assert X_predict.shape[1] == self._X_train.shape[1], \ "the feature number of X_predict must be equal to X_train"
 y_predict = [self._predict(x) for x in X_predict] return np.array(y_predict) def _predict(self, x):
 distances = [sqrt(np.sum((x_train - x) ** 2)) for x_train in self._X_train]
 nearest = np.argsort(distances)
 topK_y = [self._y_train[i] for i in nearest]
 votes = Counter(topK_y) return votes.most_common(1)[0][0] def __repr__(self):
 return "kNN(k=%d)" % self.k

當我們寫完定義好自己的kNN代碼之后,可以在jupyter notebook中使用魔法命令進行調(diào)用:

%run myAlgorithm/kNN.py
knn_clf = kNNClassifier(k=6)
knn_clf.fit(X_train, y_train)
X_predict = x.reshape(1,-1)
y_predict = knn_clf.predict(X_predict)
y_predict
輸出:array([1])

現(xiàn)在我們就完成了一個sklearn風格的kNN算法,但是實際上,sklearn封裝的算法比我們實現(xiàn)的要復(fù)雜得多。

<a href='/map/jiqixuexi/' style='color:#000;font-size:inherit;'>機器學(xué)習(xí)</a>的敲門磚:kNN算法(上)


sklearn中的kNN

代碼

對于機器學(xué)習(xí)來說,其流程是:訓(xùn)練數(shù)據(jù)集 -> 機器學(xué)習(xí)算法 -fit-> 模型 輸入樣例 -> 模型 -predict-> 輸出結(jié)果

我們之前說過,kNN算法沒有模型,模型其實就是訓(xùn)練數(shù)據(jù)集,predict的過程就是求k近鄰的過程。

我們使用sklearn中已經(jīng)封裝好的kNN庫。你可以看到使用有多么簡單。

from sklearn.neighbors import KNeighborsClassifier# 創(chuàng)建kNN_classifier實例kNN_classifier = KNeighborsClassifier(n_neighbors=6)# kNN_classifier做一遍fit(擬合)的過程,沒有返回值,模型就存儲在kNN_classifier實例中kNN_classifier.fit(X_train, y_train)# kNN進行預(yù)測predict,需要傳入一個矩陣,而不能是一個數(shù)組。reshape()成一個二維數(shù)組,第一個參數(shù)是1表示只有一個數(shù)據(jù),第二個參數(shù)-1,numpy自動決定第二維度有多少y_predict = kNN_classifier.predict(x.reshape(1,-1))
y_predict
輸出:array([1])

在kNN_classifier.fit(X_train, y_train)這行代碼后其實會有一個輸出:

KNeighborsClassifier(algorithm='auto', leaf_size=30, metric='minkowski',
 metric_params=None, n_jobs=1, n_neighbors=6, p=2,
 weights='uniform')

參數(shù)

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

我們研究一下參數(shù):

  • n_neighbors: int, 可選參數(shù)(默認為 5)。用于kneighbors查詢的默認鄰居的數(shù)量
  • weights(權(quán)重): str or callable(自定義類型), 可選參數(shù)(默認為 ‘uniform’)。用于預(yù)測的權(quán)重參數(shù),可選參數(shù)如下:
  • uniform : 統(tǒng)一的權(quán)重. 在每一個鄰居區(qū)域里的點的權(quán)重都是一樣的。
  • distance : 權(quán)重點等于他們距離的倒數(shù)。
  • 使用此函數(shù),更近的鄰居對于所預(yù)測的點的影響更大。
  • [callable] : 一個用戶自定義的方法,此方法接收一個距離的數(shù)組,然后返回一個相同形狀并且包含權(quán)重的數(shù)組。
  • algorithm(算法): {‘a(chǎn)uto’, ‘ball_tree’, ‘kd_tree’, ‘brute’}, 可選參數(shù)(默認為 ‘a(chǎn)uto’)。計算最近鄰居用的算法:
  • ball_tree 使用算法BallTree
  • kd_tree 使用算法KDTree
  • brute 使用暴力搜索
  • auto 會基于傳入fit方法的內(nèi)容,選擇最合適的算法。
  • 注意 : 如果傳入fit方法的輸入是稀疏的,將會重載參數(shù)設(shè)置,直接使用暴力搜索。
  • leaf_size(葉子數(shù)量): int, 可選參數(shù)(默認為 30)。傳入BallTree或者KDTree算法的葉子數(shù)量。此參數(shù)會影響構(gòu)建、查詢BallTree或者KDTree的速度,以及存儲BallTree或者KDTree所需要的內(nèi)存大小。此可選參數(shù)根據(jù)是否是問題所需選擇性使用。
  • p: integer, 可選參數(shù)(默認為 2)。用于Minkowski metric(閔可夫斯基空間)的超參數(shù)。p = 1, 相當于使用曼哈頓距離,p = 2, 相當于使用歐幾里得距離],對于任何 p ,使用的是閔可夫斯基空間。
  • metric(矩陣): string or callable, 默認為 ‘minkowski’。用于樹的距離矩陣。默認為閔可夫斯基空間,如果和p=2一塊使用相當于使用標準歐幾里得矩陣. 所有可用的矩陣列表請查詢 DistanceMetric 的文檔。
  • metric_params(矩陣參數(shù)): dict, 可選參數(shù)(默認為 None)。給矩陣方法使用的其他的關(guān)鍵詞參數(shù)。
  • n_jobs: int, 可選參數(shù)(默認為 1)。用于搜索鄰居的,可并行運行的任務(wù)數(shù)量。如果為-1, 任務(wù)數(shù)量設(shè)置為CPU核的數(shù)量。不會影響fit

方法

對于KNeighborsClassifier的方法:

方法名含義fit(X, y)使用X作為訓(xùn)練數(shù)據(jù),y作為目標值(類似于標簽)來擬合模型。get_params([deep])獲取估值器的參數(shù)。neighbors([X, n_neighbors, return_distance])查找一個或幾個點的K個鄰居。kneighbors_graph([X, n_neighbors, mode])計算在X數(shù)組中每個點的k鄰居的(權(quán)重)圖。predict(X)給提供的數(shù)據(jù)預(yù)測對應(yīng)的標簽。predict_proba(X)返回測試數(shù)據(jù)X的概率估值。score(X, y[, sample_weight])返回給定測試數(shù)據(jù)和標簽的平均準確值。set_params(**params)設(shè)置估值器的參數(shù)。


0xFF 總結(jié)

在本文中我們了解了第一個ML算法kNN,kNN憑借著自己樸素成熟的特點成為機器學(xué)習(xí)的敲門磚。

然后我們學(xué)習(xí)了kNN算法的流程,并且在jupyter notebook上手動實現(xiàn)了代碼,并且在外部也進行了封裝。最后我們學(xué)習(xí)了sklearn中的kNN算法。

雖然我們自己實現(xiàn)了一個機器學(xué)習(xí)算法,但是它的效果怎樣樣?預(yù)測準確率高不高?我們在機器學(xué)習(xí)過程中還有哪些需要注意的問題呢?

且聽下回分解。

數(shù)據(jù)分析咨詢請掃描二維碼

若不方便掃碼,搜微信號:CDAshujufenxi

數(shù)據(jù)分析師資訊
更多

OK
客服在線
立即咨詢
客服在線
立即咨詢
') } function initGt() { var handler = function (captchaObj) { captchaObj.appendTo('#captcha'); captchaObj.onReady(function () { $("#wait").hide(); }).onSuccess(function(){ $('.getcheckcode').removeClass('dis'); $('.getcheckcode').trigger('click'); }); window.captchaObj = captchaObj; }; $('#captcha').show(); $.ajax({ url: "/login/gtstart?t=" + (new Date()).getTime(), // 加隨機數(shù)防止緩存 type: "get", dataType: "json", success: function (data) { $('#text').hide(); $('#wait').show(); // 調(diào)用 initGeetest 進行初始化 // 參數(shù)1:配置參數(shù) // 參數(shù)2:回調(diào),回調(diào)的第一個參數(shù)驗證碼對象,之后可以使用它調(diào)用相應(yīng)的接口 initGeetest({ // 以下 4 個配置參數(shù)為必須,不能缺少 gt: data.gt, challenge: data.challenge, offline: !data.success, // 表示用戶后臺檢測極驗服務(wù)器是否宕機 new_captcha: data.new_captcha, // 用于宕機時表示是新驗證碼的宕機 product: "float", // 產(chǎn)品形式,包括:float,popup width: "280px", https: true // 更多配置參數(shù)說明請參見:http://docs.geetest.com/install/client/web-front/ }, handler); } }); } function codeCutdown() { if(_wait == 0){ //倒計時完成 $(".getcheckcode").removeClass('dis').html("重新獲取"); }else{ $(".getcheckcode").addClass('dis').html("重新獲取("+_wait+"s)"); _wait--; setTimeout(function () { codeCutdown(); },1000); } } function inputValidate(ele,telInput) { var oInput = ele; var inputVal = oInput.val(); var oType = ele.attr('data-type'); var oEtag = $('#etag').val(); var oErr = oInput.closest('.form_box').next('.err_txt'); var empTxt = '請輸入'+oInput.attr('placeholder')+'!'; var errTxt = '請輸入正確的'+oInput.attr('placeholder')+'!'; var pattern; if(inputVal==""){ if(!telInput){ errFun(oErr,empTxt); } return false; }else { switch (oType){ case 'login_mobile': pattern = /^1[3456789]\d{9}$/; if(inputVal.length==11) { $.ajax({ url: '/login/checkmobile', type: "post", dataType: "json", data: { mobile: inputVal, etag: oEtag, page_ur: window.location.href, page_referer: document.referrer }, success: function (data) { } }); } break; case 'login_yzm': pattern = /^\d{6}$/; break; } if(oType=='login_mobile'){ } if(!!validateFun(pattern,inputVal)){ errFun(oErr,'') if(telInput){ $('.getcheckcode').removeClass('dis'); } }else { if(!telInput) { errFun(oErr, errTxt); }else { $('.getcheckcode').addClass('dis'); } return false; } } return true; } function errFun(obj,msg) { obj.html(msg); if(msg==''){ $('.login_submit').removeClass('dis'); }else { $('.login_submit').addClass('dis'); } } function validateFun(pat,val) { return pat.test(val); }