KNN算法

參考文章:python

目錄

一.KNN算法

1.1 什麼是KNN算法

KNN算法,也叫K近鄰算法,是一種是一種基本分類和迴歸方法。算法

KNN算法的原理:給定一個訓練數據集,對新的輸入實例,在訓練數據集中找到與該實例最鄰近的K個實例,這K個實例的多數屬於某個類,就把該輸入實例分類到這個類中。數組

根據以往的經驗,腫瘤良性惡性和腫瘤發現時間之間的關係如上圖所示。其中紅色表示良性,藍色表示惡性。如今有這麼一個病人,他的腫瘤發現時間如圖上綠色(紅綠色盲症的朋友們,對不住~~~)所示,那麼他更有多是良性仍是惡性呢?bash

  • 取K = 3,也就是離它最近的3個點,發現都是藍色,那麼很不幸的,這位同志頗有可能患有惡性腫瘤。

1.2 KNN算法的核心和原則

核心:物以類聚,人以羣分app

原則:少數服從多數機器學習

二. KNN算法實現

2.1 KNN算法實戰

KNN算法的核心就是計算待預測點附近的K個點,求他們中佔比最大的分類。學習

因此,KNN算法的求解步驟應該是:spa

  • 計算全部點距離待預測點(咱們叫作x)的距離
  • 取出距離最近的k個點
  • 計算各個分類的佔比
  • 取出佔比最大的那個分類

任務: 經過給定的x點,預測它的y值3d

  • 第一步:造假訓練集
import numpy as np
import matplotlib.pyplot as plt

raw_data_x = [[3.9353233211,2.331273381],
             [3.11007483,1.23792372380],
              [1.9723425435,3.234256432],
              [2.36675576541,4.23347654],
              [7.45465765877655,4.236588767]]
              
raw_data_y =[0,0,1,1,1]
X_train = np.array(raw_data_x)
y_train = np.array(raw_data_y)
複製代碼

準備工做完成,咱們如今有兩個數組,能夠進行繪製散點圖。rest

  • 第二步:繪製散點圖

代碼:

plt.scatter(X_train[y_train==0,0],X_train[y_train==0,1],color='g')
plt.scatter(X_train[y_train==1,0],X_train[y_train==1,1],color='r')
plt.show()
複製代碼

回車後,能夠看到散點圖以下:

OK。如今咱們加入咱們要進行預測的點。

# 定義一個點,假設這是咱們要進行猜想的點
x=  np.array([8.0293657928,3.8928785])
複製代碼

繪圖在圖上:

plt.scatter(X_train[y_train==0,0],X_train[y_train==0,1],color='g')
plt.scatter(X_train[y_train==1,0],X_train[y_train==1,1],color='r')
plt.scatter(x[0],x[0],color='b')
plt.show()
複製代碼

  • 第三步:計算距離

接下來,咱們要進行計算預測的點和圖上各個點的距離。依據咱們偉大的歐拉公式:

接下來,反手就是算:

from math import sqrt
distance=[]
for x_train in X_train:
    d = sqrt(np.sum((x_train - x) ** 2))
    distance.append(d)
distance
複製代碼

固然,更有經驗的小朋友確定知道上面這段代碼能夠簡寫成:

# 更簡便的寫法
distance = [sqrt(np.sum((x_train -x)** 2)) for x_train in X_train]
複製代碼

反正渣渣我是不懂~~

回車後,咱們能夠看到運算結果:

  • 第四步:排序並預測結果

結果計算出來後,咱們要進行排序,並返回它的預測結果:

# 進行排序,並返回索引
nearest = np.argsort(distance)

k = 3
# 獲取每一個索引對應的y值
topK_y =[y_train[i] for i in nearest]
topK_y
複製代碼

獲得結果:

接下來,咱們要預測,預測,也就是說看看當前的點和獲得哪些點的票數最多,因此咱們須要進行投票統計啦。

from collections import Counter
votes = Counter(topK_y)
votes
複製代碼

獲得結果:

從圖中能夠看到,1有3票,0有2票,很明顯,預測點的y值頗有多是1,而不是0。 固然,咱們可讓程序本身輸出預測值:

predict_y = votes.most_common(1)[0][0]
predict_y
複製代碼

結果:

能夠看到,結果是1,跟咱們預測的同樣~~

2.2 本身封裝KNN算法

  • 建立一個kNN.py文件,定義KNN算法
# 定義了一個方法,kNN_classify
def kNN_classify(k,X_train,y_train,x):
# k要大於1,小於矩陣的大小
 assert 1 <= k <= X_train.shape[0], "k must be valid"
 # x,y的大小要相同
 assert X_train.shape[0] == y_train.shape[0],\
 "the size of X_train must equal to the siz of y_train"
# 待預測矩陣要和x相同
 assert  X_train.shape[1] == x.shape[0],\
 "the feature number of x must be equal to X_train"
# 計算各個點到待預測點的距離
 distances = [sqrt(np.sum((x_train-x) ** 2)) for x_train in X_train]
 # 排序,返回索引
 nearest = np.argsort(distances)

 topK_y = [y_train[i] for i in nearest[:k]]
 votes = Counter[topK_y]
 # 返回預測的y值
 return votes.most_common(1)[0][0]
複製代碼
  • 到Jupyter Notebook中調用封裝的方法
%run kNN_function/kNN.py

# 引入咱們上節課的數據
raw_data_x = [[3.9353233211,2.331273381],
             [3.11007483,1.23792372380],
              [1.9723425435,3.234256432],
              [2.36675576541,4.23347654],
              [7.45465765877655,4.236588767]]
raw_data_y =[0,0,1,1,1]
# 這是咱們要進行猜想的點
x=  np.array([8.0293657928,3.8928785])

predict_y = kNN_classify(6,X_train,y_train,x)

#打印預測的y值
predict_y
複製代碼

至此,咱們已經完成了的KNN算法的封裝。

2.3 scikit-learn中KNN算法的封裝

在看scikit-learn的KNN算法以前,先來看一下什麼是機器學習。

機器學習就是 輸入訓練集進行訓練,而後輸出模型,經過模型來對樣例進行預測的過程。

However,對於kNN算法來講,訓練集就是模型。這一點是kNN算法跟其餘算法不太同樣的地方。

爲何這裏要插播機器學習的東西呢?

由於等會咱們就會看到,scikit-learn中封裝的各類機器學習算法,暴露出現的方法無非就是這幾個:

  • fit(參數) -> 訓練模型
  • predict(參數) -> 預測結果
  • score() -> 衡量算法準確度

OK,回到正題。

scikit-learn中封裝了KNN算法,叫KNeighborsClassifier。接下來來學習該如何調用它。

from sklearn.neighbors import KNeighborsClassifier

kNN_classifier = KNeighborsClassfier(n_neighbors = 6)

#進行訓練,輸出模型,這個模型會保存在這個kNN_classifier對象中
kNN_classifier.fit(X_train,y_train)

#基於模型進行預測
#這裏要進行reshape 是由於編譯器會進行警告,你們能夠換成predict(x)看一下警告內容
y_predict = kNN_classifier.predict(x.reshape([1,-1])

# y_predict是一個數組,裏面保存了預測的結果,由於咱們只要預測一個值,因此咱們取第0個

y_predict[0]

# 至此,調用過程結束
複製代碼

2.4 本身再封裝一次KNN算法

爲何要再封裝一次KNN算法?由於,爲了更好的理解scikit-learn中算法的封裝思想,提升代碼質量呀~~

咱們剛剛封裝算法是用面向過程的思想寫的,而是scikit-learn中kNN算法是用面向對象的思想寫的,如今咱們來改造一下。

import numpy as np
from math import sqrt
from collections import Counter

class KNNClassifier:

def _init(self, k):
    """初始化KNN分類器"""
    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):
    """根據訓練集X_train和y_train訓練kNN分類器"""
    assert X_train.shape[0] == y_train.shape[0], \
        "the size of X_train must equal to the siz of y_train"
    assert X_train.shape[1] == x.shape[0], \
    "the feature number of x must be equal to X_train"
    """咱們前面說過,kNN模型比較特殊,它的模型就是它的訓練集,因此這裏直接賦值了~"""
    self._X_train = X_train
    self._y_train = y_train
    return self


def predict(self, X_predict):
        """給定待預測數據集X_predict,返回表示X_predict的結果向量"""
        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):
    """給定單個帶預測數據x,返回x的預測結果值"""
    assert  x.shape[0]== self._X_train.shape[1],\
    "the feature number of x must be equal to train"
    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[:self.k]]
    votes = Counter(topK_y)
    
    return votes.most_common(1)[0][0]
    
def _repr_(self):
    return "KNN(k=%d)" %self.k
複製代碼

接下來,老規矩,驗證一下:

%run kNN/kNN.py

knn_clf = KNNClassifier(k=6)
knn_clf.fit(x_train,y_train)

y_predict = knn_clf.predict(x_predict)
y_predict[0]
複製代碼

em ~~~~ 累了,不想寫了。先這樣吧,下次再更。

哈?你問我啥時更?我也不知道,看心情,略略略O(∩_∩)O

相關文章
相關標籤/搜索