Dibuje un árbol kd y analice la relación entre la selección de k y la precisión de la predicción (con ejemplos)

1. Tema

 

Lea y comprenda el código adjunto para lograr las siguientes tareas:

 Para el conjunto de datos D = {(0.1, 2.8), (1.9, 0.6), (1.0, 2.0), (3.0, 2.5), (2.0, 2.5), (1.8, 3.0), (0.1, 0.1), (0.5 , 0.5), (1.5,0.5),(1.5, 1.5), (1.7, 0.1), (2.5, 0.2)}, la etiqueta correspondiente es L = {A, A, A, B, B, B, C, C , C, D, D, D}, dibuje respectivamente la división espacial (árbol kd) compuesta por k-  vecinos más cercanos cuando k = 2 y 4 , y compare la relación entre la selección de k y la precisión de la predicción.

Código adjunto:

# -*- coding: utf-8 -*-
"""
【最近邻算法】通过计算预测点与测试样例点数据的欧式距离,找出待测数据与测试数据的最小欧式距离点,
并返回该测试点的类型,从而确定预测数据类型的算法。
Created on Thu Aug 15 23:18:35 2019
@author: CUP
"""
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei']#SimHei是黑体的意思
plt.rcParams['axes.unicode_minus'] = False#avoid negtive symbol
import numpy as np

#%%
def NNclassify(input,dataSet,label):
    dataSize = dataSet.shape[0]
    ####计算欧式距离
    tarry=np.tile(input,(dataSize,1));#生成dataSet一样的矩阵,进行剪发运算
    diff = tarry - dataSet
    sqdiff = diff ** 2  #各参数平方(X²,Y²),得到距离
    squareDist = np.sum(sqdiff,axis = 1)#行向量分别相加,从而得到新的一个行向量  X²,Y²相加,
    dist = list(squareDist ** 0.5)  #开方,得到欧式距离
    return label[dist.index(np.min(dist))]  #返回最近邻  //找到距离最小值,并得与之对应的类型

#%%
###通过KNN进行分类
def KNNclassify(input,dataSet,label,k):
    dataSize = dataSet.shape[0]
    ####计算欧式距离
    diff = np.tile(input,(dataSize,1)) - dataSet
    sqdiff = diff ** 2
    squareDist = np.sum(sqdiff,axis = 1)###行向量分别相加,从而得到新的一个行向量
    dist = squareDist ** 0.5

    ##对距离进行排序
    sortedDistIndex = np.argsort(dist)##argsort()根据元素的值从大到小对元素进行排序,返回下标

    classCount={}
    for i in range(k):
        voteLabel = label[sortedDistIndex[i]]
        ###对选取的K个样本所属的类别个数进行统计
        classCount[voteLabel] = classCount.get(voteLabel,0) + 1
    ###选取出现的类别次数最多的类别
    maxCount = 0
    for key,value in classCount.items():
        if value > maxCount:
            maxCount = value
            classes = key

    return classes

#%%
dataSet = np.array([[0.1,2.8],[1.9,0.6],[1.0,2.0],
                 [3.0,2.5],[2.0,2.5],[1.8,3.0],
                 [0.1,0.1],[0.5,0.5],[1.5,0.5],
                 [1.5,1.5],[1.7,0.1],[2.5,0.2],
                 ])
labels = ['A','A','A','B','B','B','C','C','C','D','D','D']

#print("input = ",input)
input = np.array([1.9,0.5])
#
plt.figure(figsize=(5,5))
for i,j in enumerate(dataSet):
    if labels[i] == 'A':
        plt.scatter(j[0],j[1],marker ="^",c="blue",s=80)
    elif labels[i] == 'B':
        plt.scatter(j[0],j[1],marker ="D",c ="green",s=80)
    elif labels[i] == 'C':
        plt.scatter(j[0],j[1],marker ="o",c ="darkorange",s=80)
    elif labels[i] == 'D':
        plt.scatter(j[0],j[1],marker ="s",c ="purple",s=80)

plt.scatter(input[0],input[1],marker ="*",c ="red",s=200)
plt.axis('tight')
plt.show()
#plt.legend()
# 最近邻
output = NNclassify(input,dataSet,labels)
print('最近邻时结果')
print("class = ",output)

# K近邻
print('K近邻,k取不同值时结果')
for K in range(1,13):  #交叉验证
    output = KNNclassify(input,dataSet,labels,K)

    print("K = ",K,"class = ",output)




dos, la respuesta

El resultado de ejecutar el código adjunto:

244b70eaecac45a437dd05bf968e38b8.png

Cuando el vecino más cercano es el resultado
clase = A
K vecino, cuando k toma valores diferentes el resultado
K = 1 clase = A
K = 2 clase = A
K = 3 clase = A
K = 4 clase = D
K = 5 clase = D
K = 6 clase = D
K = 7 clase = D
K = 8 clase = C
K = 9 clase = C
K = 10 clase = C
K = 11 clase = C
K = 12 clase = A

Se puede ver que cuando k=2, los puntos de entrada se dividen en A; cuando k=4, los puntos de entrada se dividen en D. A continuación, dibuje el diagrama kd y analice la relación.

El código para generar el diagrama de árbol kd:

# -*- coding: utf-8 -*-
"""
Created on Sun Apr  2 11:32:18 2023

@author: 18705
"""
'''
画图二叉树代码
'''
import numpy as np
from graphviz import Digraph
from matplotlib import pyplot as plt
from matplotlib.pyplot import MultipleLocator
#data = [[2,3],[6, 4],[9, 6],[4, 7],[8, 1],[7, 2], [8,2], [10,4], [6,6]]
data = [[0.1,2.8],[1.9,0.6],[1.0,2.0],
                 [3.0,2.5],[2.0,2.5],[1.8,3.0],
                 [0.1,0.1],[0.5,0.5],[1.5,0.5],
                 [1.5,1.5],[1.7,0.1],[2.5,0.2],
                 ]
data = np.array(data)

# 节点
class node:
    def __init__(self, _data=None, _left=None, _right=None, _father=None, _dim=None, _index=None, _visiable=True):
        self.data = _data
        self.left = _left
        self.right = _right
        self.father = _father
        self.dim = _dim
        self.index = _index
        self.visiable = _visiable
    def getData(self):
        s = "("
        for i in range(self.data.size):
            if i!=0:
                s += ','
            s+=str(self.data[i])
        s += ")"
        return s
    def __str__(self):
        if(self.visiable):
            return str(self.index)
        else:
            return "_invis"+str(self.index)

dataIndex = 1
def drawKDTree(data, depth, k, dot):
    # 根据数据生成KD树
    dim = depth % k
    length = data.shape[0]
    if(length==0):
        return None, dot
    index = []
    for i in range(length):
        index.append([data[i][dim], i])
    index.sort()
    root = data[index[length//2][1]]
    left = [data[index[i][1]] for i in range(length//2)]
    left = np.array(left)
    right = [data[index[i][1]] for i in range(length//2+1, length)]
    right = np.array(right)
    global dataIndex
    root_node = node(_data=root, _dim=dim, _index=dataIndex)
    dataIndex+=1

    dot.node(str(root_node.index), root_node.getData())

    root_node.left, dot=drawKDTree(left, depth+1, k, dot)
    if(root_node.left==None):
        pass
        dot.node("_left"+str(root_node.index), root_node.getData(), style="invis")
        dot.edge(str(root_node.index), "_left"+str(root_node.index), style="invis")
    else:
        dot.edge(str(root_node.index), str(root_node.left.index))

    dot.node("_middle"+str(root_node.index), root_node.getData(), style="invis")
    dot.edge(str(root_node.index), "_middle"+str(root_node.index), style="invis", weight="10")

    root_node.right, dot=drawKDTree(right, depth+1, k, dot)

    if(root_node.right==None):
        pass
        dot.node("_right"+str(root_node.index), root_node.getData(), style="invis")
        dot.edge(str(root_node.index), "_right"+str(root_node.index), style="invis")
    else:
        dot.edge(str(root_node.index), str(root_node.right.index))

    if(root_node.left):
        root_node.left.father=root_node
    if(root_node.right):
        root_node.right.father=root_node
    
    return root_node, dot

dot = Digraph(node_attr={'shape': 'circle'})
_, dot = drawKDTree(data, 0, 2, dot)
dot.view()
print(dot.source)

 

resultado:

División espacial de k-vecinos más cercanos cuando k=2

da2e0120c8391e7cc72b61c8e5e9c7c3.png

 

División espacial de k-vecinos más cercanos cuando k=4

 

f343b6c3d957034b4ba0e62fe7d9fd88.png

Genere un árbol kd y analice y compare la relación entre la selección de k y la precisión de la predicción.

código:

# -*- coding: utf-8 -*-
"""
Created on Sun Apr  2 12:50:48 2023

@author: 18705
"""
'''
kd树生成代码
'''
from scipy import spatial
import numpy as np
from sklearn.neighbors import KNeighborsClassifier
import matplotlib.pyplot as plt

 
X=np.array([[0.1,2.8],[1.9,0.6],[1.0,2.0],
                 [3.0,2.5],[2.0,2.5],[1.8,3.0],
                 [0.1,0.1],[0.5,0.5],[1.5,0.5],
                 [1.5,1.5],[1.7,0.1],[2.5,0.2],
                 ])
labels = ['A','A','A','B','B','B','C','C','C','D','D','D']
testX=[[1.9,0.5]]

tree=spatial.KDTree(data=X)

dist,ind=tree.query(testX,k=2)
print("两个最近的邻居分别为")
for i in ind[0]:
    print(X[i],labels[i])
print('最近的距离',dist)
print('\n')
dist1,ind1=tree.query(testX,k=4)
print("四个最近的邻居分别为")
for i in ind1[0]:
    print(X[i],labels[i])
print('最近的距离',dist1)

knn2=KNeighborsClassifier(n_neighbors=2)
knn2.fit(X,labels)
score2=knn2.score(X,labels,sample_weight=None)
print('\n k=2时分类正确率:',score2)

knn4=KNeighborsClassifier(n_neighbors=4)
knn4.fit(X,labels)
score4=knn4.score(X,labels,sample_weight=None)
print('\n k=2时分类正确率:',score4)
xx=[i for i in range(1,10)]
all_score=[]
plt.figure()
for i in range(1,10):
    knn=KNeighborsClassifier(n_neighbors=i)
    knn.fit(X,labels)
    score=knn.score(X,labels,sample_weight=None)
    all_score.append(score)
    plt.plot(i, score, color="#FF3B1D", marker='*')
    plt.text(i+0.01, score+0.02,str(round(score, 2)))
plt.plot(xx,all_score,linestyle="-")
plt.title("K-预测准确率")
plt.xlabel("K")
plt.ylabel("预测准确率")
plt.show()

resultado :

 

Cuando k=2, los dos vecinos más cercanos son:
[1.9 0.6] A
[1.5 0.5] C
La distancia más cercana [[0.1 0.4]]


Cuando k=4, los cuatro vecinos más cercanos son:
[1.9 0.6] A
[1.5 0.5] C
[1,7 0,1] D
​​[2,5 0,2]
La distancia más cercana de D [[0,1 0,4 0,4472136 0,67082039]]

 Cuando k=2, la tasa de precisión de clasificación: 0,6666666666666666 Cuando

 k=2, la tasa de precisión de clasificación: 0,8333333333333334

 

Puede obtener el mismo resultado que el código proporcionado por el profesor. Debido a que 0.6666<0.83333, al mismo tiempo, se puede concluir que cuanto mayor es k, mayor es la precisión de la predicción. ¿Pero es realmente el caso? Simplemente comparar la selección de dos k no puede obtener resultados extensos, por lo que volví a seleccionar k = 1:10, y los resultados de k y la precisión se muestran en la figura:

844d5724246c4e7f8785e2dc3346926f.png

 

Se puede ver que los resultados del vecino más cercano no se consideran. A medida que aumenta k, la tasa de precisión aumenta primero y luego disminuye.

 

 

 

Supongo que te gusta

Origin blog.csdn.net/m0_57491181/article/details/129910490
Recomendado
Clasificación