第2章 KNN邻近规则算法及其在潜在客户发掘的应用

本文主要介绍KNN邻近规则算法的过程:

目录

1.KNN临近规则算法概述

2.KNN算法的构建

2.1 KNN

2.2 KNN构建

2.3 KNN优缺点

3.KNN算法编码实现

3.1 编码过程

3.2 输出


 

1.KNN临近规则算法概述

KNN是机器学习领域一个简单又实用的算法。所谓K最近邻,就是k个最近的邻居的意思,说的是每个样本都可以用它最接近的k个邻居来代表。

kNN算法的核心思想是如果一个样本在特征空间中的k个最相邻的样本中的大多数属于某一个类别,则该样本也属于这个类别,并具有这个类别上样本的特性。有点类似,“物以类聚,人以群分”的意味。

2.KNN算法的构建

2.1 KNN

KNN中用欧式距离来度量特征向量之间的距离。欧式距离,即对于两个n维向量x和y,两者的欧式距离定义为:

当然特征向量之间的距离求法有很多种,但是欧式距离的求法基本上能满足我们的日常需求。

2.2 KNN构建

为了判断未知实例的类别,以所有已知类别的实例作为参照,算法过程为:

  1. 选择参数K,人为设定即可,一般为奇数较佳;
  2. 计算未知实例与所有已知实例的距离;
  3. 选择最近K个已知实例;
  4. 根据少数服从多数的投票法则,让未知实例归类为K个最邻近样本中最多数的类别。

我这里杜撰了一批数据集,用于具体实现KNN算法:

                 

构建数学模型,这里列举了前十个,映射到空间坐标点为:

           

于是,编写计算方法:

import math
def ComputeEuclideanDistance(x1, y1, x2, y2):
    '''计算两点之间的欧式距离'''
    d = math.sqrt(math.pow((x1-x2), 2) + math.pow((y1-y2), 2))
    return d

## 数据集	
data_set = []
## 坐标点
A=(3,104)
data_set.append(A)
B=(2,100)
data_set.append(B)
C=(1,81)
data_set.append(C)
D=(101,10)
data_set.append(D)
E=(99,5)
data_set.append(E)
F=(98,2)
data_set.append(F)
G=(0,5)
data_set.append(G)
H=(0,20)
data_set.append(H)
I=(0,3)
data_set.append(I)
J=(18,90)
data_set.append(J)
## 坐标名称
point_dict = {0:'A',1:'B',2:'C',3:'D',4:'E',5:'F',6:'G',7:'H',8:'I',9:'J'}

size = len(data_set)
for i in range(size):
    for j in range(size):
        if i <j:
            x1,y1 = data_set[i][0],data_set[i][1]
            x2,y2 = data_set[j][0],data_set[j][1]
            d_ij = ComputeEuclideanDistance(x1, y1, x2, y2)
            print("坐标点%s-%s之间的欧式距离为:%s"%(point_dict[i],point_dict[j],int(d_ij)))

算出每个点之间的欧式距离分别为:

按照实际应用需求,分为三类,故设定k=3,生成的分类图:

2.3 KNN优缺点

优点:易于理解,容易实现,通过对K的选择可具备丢噪音数据的健壮性。

缺点:需要大量空间储存所有已知实例;算法复杂度高(需要比较所有已知实例与要分类的实例);当其样本分布不平衡时,比如其中一类样本过大(实例数量过多)占主导的时候,新的未知实例容易被归类为这个主导样本,因为这类样本实例的数量过大,但这个新的未知实例实际并木接近目标样本。

3.KNN算法编码实现

3.1 编码过程

实现关键步骤在代码中做了注释,如下:

import numpy as np
from numpy import *
import operator
import matplotlib.pylab as plt


# 创建一个数据集,包含3个类别共40个样本
def createDataSet():
    # 生成一个矩阵,每行表示一个样本
    group = array([[3,104], [2,100], [1,81], [101,10],[99,5],[98,2],[0,5],[0,20],[0,3],[18,90],
                   [1,50],[2,6],[4,7],[5,21],[20,80],[10,30],[12,91],[2,103],[40,132],[34,131],
                   [21,101],[112,54],[92,65],[110,87],[20,30],[40,12],[50,1],[3,32],[43,2],[21,5],
                   [1,32],[2,45],[7,31],[121,92],[105,21],[91,32],[105,31],[32,87],[65,102],[10,91]])
    # 4个样本分别所属的类别
    labels = '''潜客,潜客,潜客,熟客,熟客,熟客,生客,生客,生客,潜客,潜客,生客,生客,生客,潜客,生客,潜客,潜客,潜客,潜客,潜客,熟客,熟客,熟客,生客,生客,生客,生客,生客,生客,生客,生客,生客,熟客,熟客,熟客,熟客,潜客,潜客,潜客'''.split(',')
    return group, labels


def plot_figure(data_mat, labels):
    """
    没有加入legend
    有需要参考:https://www.zhihu.com/question/37146648
    """
    # 生成一个新的图像
    fig = plt.figure()
    # 这里的111的意思就是,图像画成一行一列(其实就一个框),最后一个1就是放在从左到右,从上到下的第1个
    # 想在一个画面里面放多几个子图和分配位置改下这个参数就好了
    ax = fig.add_subplot(111)
    # 前两个参数试一试data_mat[:,1],data_mat[:,2]
    # 或者data_mat[:,1],data_mat[:,0]  # 这种的区分度更高
    # scatter是画散点图
    # 10是点的大小,前后是颜色
    l = []
    for label in labels:
        if label =='潜客':
            l.append(1)
        elif label =='熟客':
            l.append(2)
        elif label =='生客':
            l.append(3)
        else:print('ERR:',label)
    labels = l
    t = ax.scatter(data_mat[:,1],data_mat[:,0],
               10 * np.array(labels),np.array(labels))
    plt.rcParams['font.sans-serif'] = ['SimHei']  # 用来正常显示中文标签
    plt.rcParams['axes.unicode_minus'] = False  # 用来正常显示负号
    plt.title('Potential Customer Discovery')
    plt.xlabel('Buy Times')
    plt.ylabel('Click Times')
    plt.show()


# KNN分类算法函数定义
def kNNClassify(newInput, dataSet, labels, k):
    numSamples = dataSet.shape[0]
    # shape[0]表示行数
    diff = tile(newInput, (numSamples, 1)) - dataSet  # 按元素求差值
    squaredDiff = diff ** 2  # 将差值平方
    squaredDist = sum(squaredDiff, axis = 1)   # 按行累加
    distance = squaredDist ** 0.5  # 将差值平方和求开方,即得距离

    # step 2: 对距离排序
    # argsort() 返回排序后的索引值
    sortedDistIndices = argsort(distance)
    classCount = {} # define a dictionary (can be append element)
    for i in range(k):
        # step 3: 选择k个最近邻
        voteLabel = labels[sortedDistIndices[i]]

        # step 4: 计算k个最近邻中各类别出现的次数
        classCount[voteLabel] = classCount.get(voteLabel, 0) + 1

    # step 5: 返回出现次数最多的类别标签
    maxCount = 0
    for key, value in classCount.items():
        if value > maxCount:
            maxCount = value
            maxIndex = key
    return maxIndex


# 生成数据集和类别标签
dataSet, labels = createDataSet()
# 定义一个未知类别的数据
testX = array([18, 90])
k = 3
# 调用分类函数对未知数据分类
outputLabel = kNNClassify(testX, dataSet, labels, 3)
plot_figure(dataSet, labels)
print ("输入测试集:", testX, "分类: ", outputLabel)

3.2 输出

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值