k-NN(k-Nearest Neighbors) k临近算法

k-NN(k-Nearest Neighbors) k临近算法

算法介绍
  • 简介
  • 优点
  • 缺点
应用公式
  • 二维欧拉距离
  • 三维欧拉距离
  • 高维欧拉距离
实现代码
  • KNN实现代码
  • 模拟 scikit-learn 实现代码
  • scikit-learn 中使用 KNN 算法



算法介绍
简介

        如果一个样本在特征空间中的K个最相邻的样本中的大多数属于某一个类别,则该样本也属于这个类别,并具有这个类别上样本的特性。KNN方法在类别决策上仅仅依据最邻近的一个或者几个样本的类别来决定待分样本所属的类别。

优点

        简单,易于理解,易于实现;无需估计参数;无需训练。特别适合于多分类问题。

缺点

        K值的确定,比较好的选取K值的方法只能是通过反复试验调整;当样本不平衡时,如一个类的样本容量很大,而其它类样本容量很小时,有可能导致当输入一个新样本时,该样本的K个邻居中大容量类的样本占多数;计算量大,KNN算法的时间复杂度和存储空间的增加会随着训练集规模和特征维数的增大而快速增加。



应用公式
二维欧拉距离

        公式:    (x(a)x(b))2+(y(a)y(b))2 ( x ( a ) − x ( b ) ) 2 + ( y ( a ) − y ( b ) ) 2

a 代表 点a
b 代表 点b
x 代表 x坐标
y 代表 y坐标


例:

计算 点a[1, 1] 到 点b[1, 2] 的欧拉距离.
点a [ x=1, y=1 ]
点b [ x=1, y=2 ]

带入公式:

(a[x]b[x])2+(a[y]b[y])2 ( a [ x ] − b [ x ] ) 2 + ( a [ y ] − b [ y ] ) 2

带入值:

     (11)2+(12)2 ( 1 − 1 ) 2 + ( 1 − 2 ) 2

=(0)2+(1)2 = ( 0 ) 2 + ( − 1 ) 2

=0+1 = 0 + 1

=1 = 1

=1 = 1

最终结果等于 1, 既 点a, 点b 的欧拉距离为 1 .



三维欧拉距离

二维, 三维, 四维………n维, 计算方式同理.
        公式:    (x(a)x(b))2+(y(a)y(b))2+(z(a)z(b))2 ( x ( a ) − x ( b ) ) 2 + ( y ( a ) − y ( b ) ) 2 + ( z ( a ) − z ( b ) ) 2

a 代表 点a
b 代表 点b
x 代表 x坐标
y 代表 y坐标
x 代表 z坐标


例:

计算 点a[1, 1] 到 点b[1, 2] 的欧拉距离.
点a [ x=1, y=1, z=1 ]
点b [ x=2, y=2, z=2 ]

带入公式:

(a[x]b[x])2+(a[y]b[y])2+(a[z]b[z])2 ( a [ x ] − b [ x ] ) 2 + ( a [ y ] − b [ y ] ) 2 + ( a [ z ] − b [ z ] ) 2

带入值:

     (12)2+(12)2+(12)2 ( 1 − 2 ) 2 + ( 1 − 2 ) 2 + ( 1 − 2 ) 2

=(1)2+(1)2+(1)2 = ( − 1 ) 2 + ( − 1 ) 2 + ( − 1 ) 2

=(1)+(1)+(1) = ( 1 ) + ( 1 ) + ( 1 )

=3 = 3

=1.7320508075688772 = 1.7320508075688772

最终结果等于 1.7320508075688772, 既 点a, 点b 的欧拉距离为 1.7320508075688772 .



高维欧拉距离

        公式:

i=1n(x(a)ix(b)i)2 ∑ i = 1 n ( x i ( a ) − x i ( b ) ) 2

a 代表 点a
b 代表 点b
x 代表 x坐标
y 代表 y坐标

∑ 代表 循环
n 代表循环数量
i 代表当前循环值

# ∑ 的含义
for i in n:

计算方式和二维, 三维一样.



实现代码
KNN实现代码


import numpy as np
import matplotlib.pyplot as plt
from collections import Counter

#初始化训练集
data_x = [[3.3, 2.3],
          [3.1, 1.7],
          [1.3, 3.3],
          [3.5, 4.6],
          [2.2, 2.8],
          [7.4, 4.6],
          [5.7, 3.5],
          [9.1, 2.5],
          [7.7, 3.4],
          [7.9, 0.7]
         ]
#初始化训练集结果
data_y = [0, 0, 0, 0, 0, 1, 1, 1, 1, 1]

x_train = np.array(data_x)
y_train = np.array(data_y)

#初始化 预测数据
x = np.array([8.0, 3.3])

#使用欧拉距离计算公式
distances = []
for x_t in x_train:
    d = np.sqrt(np.sum((x_t - x)**2))
    distances.append(d)

#使用欧拉距离计算公式-简便写法
#distances = [math.sqrt(np.sum((x_t - x)**2)) for x_t in x_train]

#取K个最近的点, 参与计算.
k = 6;

#获得最近元素值的排序下标.
nearest = np.argsort(distances)

#取最靠前的K个数据.
topk_y = [ y_train[i] for i in nearest[:k]]

#统计真实值, 出现的次数.
votes = Counter(topk_y)

#获取次数最多的一个真实值.
res = votes.most_common(1)[0][0]

#输出预测结果.
print("结果:" + str(res))

#展示正确结果为0的学习数据.
plt.scatter(x_train[y_train==0,0], x_train[y_train==0,1], edgecolors='g')
#展示正确结果为1的学习数据.
plt.scatter(x_train[y_train==1,0], x_train[y_train==1,1], edgecolors='r')
#展示需要预测的点
plt.scatter(x[0], x[1], edgecolors='b')

#绘制
plt.show()

'''

     预测结果: 1

'''



模拟 scikit-learn 实现代码
import numpy as np
from collections import Counter
import sklearn.datasets as datasets

#自定义KNN算法
class KNNClasssifier:

    #构造函数, 构造时传入k
    def __init__(self, k=5):
        self.k = k
        self._X_train = None
        self._y_train = None

    #训练模型函数. 因为KNN不需要训练, 所以该函数只是简单的赋值.
    def fit(self, x_train, y_train):
        self._X_train = x_train
        self._y_train = y_train
        return self

    #预测函数. 循环预测每一个数据
    def predict(self, X_predict):
        y_predict = [ self.__predict(x) for x in X_predict]
        return y_predict

    #预测单个数据的具体实现.
    def __predict(self, x):
        # 使用欧拉距离计算公式
        distances = [np.sqrt(np.sum((x_t - x) ** 2)) for x_t in self._X_train]
        # 获得最近元素值的排序下标.
        nearest = np.argsort(distances)
        # 取最靠前的K个数据.
        topk_y = [self._y_train[i] for i in nearest[:self.k]]
        # 统计真实值, 出现的次数.
        votes = Counter(topk_y)
        # 获取次数最多的一个真实值.
        return votes.most_common(1)[0][0]

#运行测试代码
if __name__ == "__main__":

    #拆分训练数据集, 测试数据集. X:总数据集, y:总标签集, test_ratio:测试集占比,
    #seed:随机因子, 传入相同数字, 产生的随机结果一致, 方便测试
    def train_test_split(X, y, test_ratio=0.2, seed=None):

        if seed:
            np.random.seed(seed)

        #随机排序生成 数据集下标
        shuffle_indexes = np.random.permutation(len(X))
        #获取训练数据集数据个数
        test_size = int(len(X) * test_ratio)

        test_indexes = shuffle_indexes[:test_size]
        train_indexes = shuffle_indexes[test_size:]
        #训练集
        X_train = X[train_indexes]
        #训练集标签
        Y_train = y[train_indexes]
        #测试集
        X_test = X[test_indexes]
        #测试集标签
        Y_test = y[test_indexes]
        #返回: 训练集, 训练集标签, 测试集, 测试集标签
        return X_train, Y_train, X_test, Y_test

    # 加载 鸢尾花 数据集, 共 150 张
    iris = datasets.load_iris()
    #获取特征数据
    X = iris.data
    #获取结果数据.
    y = iris.target

    # 数据拆分.
    X_train, Y_train, X_test, Y_test = train_test_split(X, y, test_ratio=0.3)
    knn_clf = KNNClasssifier(15)
    knn_clf.fit(X_train, Y_train)
    Y_predict = knn_clf.predict(X_test)

    print("正确率:" + str(sum(Y_predict == Y_test) / len(Y_test)))



scikit-learn 中使用 KNN 算法
from sklearn.neighbors import KNeighborsClassifier
from sklearn import datasets
from sklearn.model_selection import train_test_split
import numpy as np

#加载 鸢尾花 数据集
iris = datasets.load_iris()
X_data = iris.data
y_data = iris.target

#使用 sklearn.model_selection 中的 train_test_split 函数, 拆分数据.
#X_train:训练集, X_test:测试集, y_train:训练集标签, y_test:测试集标签
X_train, X_test, y_train, y_test = train_test_split(X_data, y_data, test_size=0.2)

#使用 sklearn.neighbors 的 KNeighborsClassifier KNN算法.
kNN_classifier = KNeighborsClassifier(n_neighbors=5)
#调用训练函数, 传入 训练集,训练集标签
kNN_classifier.fit(X_train, y_train)
#传入测试集, 获得预测结果.
y_predict = kNN_classifier.predict(X_test)

#使用 KNN 类的 score 函数, 计算准确率.
accuracy = kNN_classifier.score(X_test, y_test)
print("正确率:" + str(accuracy))

你可能感兴趣的:(算法,Python)