机器学习之KNN

KNN即k近邻法,k-nearest neighbor,是1967年由Cover T和Hart P提出的一种基本分类与回归方法,也是机器学习的基础算法之一。

本文参考教程:《机器学习实战》

KNN算法原理

​ 在一个样本数据集合,也称作为训练样本集,并且样本集中每个数据都存在标签,即我们知道样本集中每一个数据与所属分类的对应关系。输入没有标签的新数据后,将新的数据的每个特征与样本集中数据对应的特征进行比较,然后算法提取样本最相似数据(最近邻)的分类标签。一般来说,我们只选择样本数据集中前k个最相似的数据,这就是k-近邻算法中k的出处,通常k是不大于20的整数。最后,选择k个最相似数据中出现次数最多的分类,作为新数据的分类。

​ 因此也可以说,KNN算法实际上没有进行训练,即它的训练复杂度为0;KNN近邻算法是用相似性来判断类别的,你和谁更像,那就认为你是哪种人。

    KNN适用于数值型和标称型的数据,其优点是精度高、对异常值不敏感、无数据输入假定,但是缺点也很明显,我们每次使用都需要遍历整个训练集,计算复杂度和空间复杂度都很高。

KNN代码模板

1.导入依赖

1
2
import numpy as np
from collections import Counter

2.生成样本

1
2
3
4
def createDateSet():
group = np.array([[1.0,1.1],[1.0,1.0],[0,0],[0,0.1]])
labels = ['A','A','B','B']
return group,labels

3.KNN算法

1
2
3
4
5
6
7
8
9
10
def classify0(inX, dataSet, labels, k):
dataSetSize = dataSet.shape[0]
diffMat = np.tile(inX, (dataSetSize,1)) - dataSet
sqDiffMat = diffMat**2
sqDistances = sqDiffMat.sum(axis = 1)
distances = sqDistances**0.5
sortedDistIndicies = np.argsort(distances)

voteIlabel = np.array(labels)[sortedDistIndicies[:k]]
return Counter(voteIlabel).most_common(1)[0][0]

4.主函数

1
2
3
4
5
6
7
8
9
def main():
k = 3
test=[0,0]
group,labels = createDateSet()
result = classify0(test, group ,labels,k)
print(result)

if __name__ == '__main__':
main()

KNN步步推进

  • 仿jupyter,第一个代码框为In[ ],第二个代码框为Out[ ]

  • KNN的实现很简单,但利用numpy实现会很很神奇

1.获取样本数量

1
2
3
4
group = np.array([[1.0,1.1],[1.0,1.0],[0,0],[0,0.1]])
labels = ['A','A','B','B']
dataSetSize = group.shape[0]
dataSetSize

4

2.获取inX与样本的坐标差值

1
2
3
test=[0,0]
diffMat = np.tile(test, (dataSetSize,1)) - group
diffMat
1
2
3
4
array([[-1. , -1.1],
[-1. , -1. ],
[ 0. , 0. ],
[ 0. , -0.1]])

可以发现,利用np.tile()重复test,一次性求出test与每个样本的坐标差值

3.获取距离

1
2
3
sqDiffMat = diffMat**2
sqDistances = sqDiffMat.sum(axis = 1)
sqDistances
1
array([2.21, 2.  , 0.  , 0.01])

注意sum求和时轴的方向

4.排序取索引

1
2
sortedDistIndicies = np.argsort(distances)
sortedDistIndicies
1
array([2, 3, 1, 0], dtype=int64)

5.获取前K个相邻点的标签

1
2
3
k=3
voteIlabel = np.array(labels)[sortedDistIndicies[:k]]
voteIlabel
1
array(['B', 'B', 'A'], dtype='<U1')

label原为列表类型,先转化成ndarray

6.统计,返回数量最多的标签

1
2
3
from collections import Counter
cnt=Counter(voteIlabel)
cnt.most_common(1)
1
[('B', 2)]

KNN实战讲解

约会大作战:

​ 海伦小姐提供了一份她以前相亲经历的所有案例,总共有1000场,现在希望通过机器学习分析一下这些数据,让她以后不用见面就能先大致知道对方属于自己心目中的哪一类人。

    海伦小姐总共考察了三个指标,分别是:

  • 每年获得的飞行常客里程数

  • 玩视频游戏所耗时间百分比

  • 每周消费的冰淇淋公升数

    那么怎样通过KNN来分类呢?

  1. 获取数据

    1
    2
    3
    4
    5
    6
    def getDateSet():
    df = pd.read_excel('date.xlsx')
    labels = np.array(df['label'])
    df.drop('label', axis=1, inplace=True)
    data = np.array(df)
    return data, labels
  2. 标准化

    因为有的特征数值绝对值特别大,因此要对数据进行归一化处理

    1
    2
    3
    4
    5
    6
    def normalization(data):
    min_val = data.min(0)
    max_val = data.max(0)
    ranges = max_val - min_val # 极差
    norm_data = (data - min_val) / ranges
    return norm_data

    也可以利用sklearn进行归一化:

    1
    data = MinMaxScaler().fit_transform(data)
  3. KNN算法

    与前文一致。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    def classify0(inX, dataSet, labels, k):
    dataSetSize = dataSet.shape[0]
    diffMat = np.tile(inX, (dataSetSize,1)) - dataSet
    sqDiffMat = diffMat**2
    sqDistances = sqDiffMat.sum(axis = 1)
    distances = sqDistances**0.5
    sortedDistIndicies = np.argsort(distances)

    voteIlabel = np.array(labels)[sortedDistIndicies[:k]]
    return Counter(voteIlabel).most_common(1)[0][0]
  4. 主函数

    1
    2
    3
    4
    5
    6
    7
    8
    def main():
    data,labels = getDateSet()
    norm_data = normalization(data)
    test=np.array([26052, 1.441871, 0.805124])
    norm_test=normalization(test)

    result = classify0(norm_test, norm_data ,labels,k=5)
    print(result)

    结果为1,说明是一个极具魅力的男性。

KNN调包能手

在手码一遍KNN以后,其实对其原理以及有了充分的认识,那么以后就可以调包了【狗头】

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier

def getDateSet():
df = pd.read_excel('date.xlsx')
labels = np.array(df['label'])
df.drop('label', axis=1, inplace=True)
data = np.array(df)
return data, labels

data,labels = getDateSet()

# 按7:3 划分训练集与测试集
x_train, x_test , y_train, y_test = train_test_split(data, labels, test_size = 0.3)

# k=3
knn = KNeighborsClassifier(n_neighbors=3)
knn.fit(x_train, y_train)
error_index = np.nonzero(knn.predict(x_test) - y_test)[0]
print(f'预测准确率为: {100*(1 - len(error_index) / len(data))}%')

简单的训练之后,即可达到94%的准确率。

不要打赏,只求关注呀QAQ