knn算法代码详解(以鸢尾花数据为例)

KNN

欧氏距离:
d ( x , y ) = ∑ k = 1 n ( x k − y k ) 2 d(x,y)=\sqrt{\sum_{k=1}^{n}{(x_k-y_k)^2}} d(x,y)=k=1n(xkyk)2
曼哈顿距离:
d ( x , y ) = ∑ k = 1 n ∣ x k − y k ∣ d(x,y)=\sqrt{\sum_{k=1}^{n}{|{x_k-y_k}|}} d(x,y)=k=1nxkyk

import numpy as np
import pandas as pd
#引入数据加载,直接引入sklearn数据,iris鸢尾花
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split#切分数据集为训练集和测试集
from sklearn.metrics import accuracy_score #计算分类预测准确率
##### 数据加载预处理
iris=load_iris()
##里面是一个封装好的字典,'data':二维数组数据,'target':分类数,'target_names':分类名称,'feature_names':特征名称
###sepal length (cm)',花儿长度;  'sepal width (cm)',花儿宽度;  'petal length (cm)',花瓣长度;  'petal width (cm)'花瓣宽度
df=pd.DataFrame(data=iris.data,columns=iris.feature_names)
df['class']=iris.target#加上一列
#更改class名称
df['class']=df['class'].map({0:iris.target_names[0],1:iris.target_names[1],2:iris.target_names[2]})
df
sepal length (cm) sepal width (cm) petal length (cm) petal width (cm) class
0 5.1 3.5 1.4 0.2 setosa
1 4.9 3.0 1.4 0.2 setosa
2 4.7 3.2 1.3 0.2 setosa
3 4.6 3.1 1.5 0.2 setosa
4 5.0 3.6 1.4 0.2 setosa
145 6.7 3.0 5.2 2.3 virginica
146 6.3 2.5 5.0 1.9 virginica
147 6.5 3.0 5.2 2.0 virginica
148 6.2 3.4 5.4 2.3 virginica
149 5.9 3.0 5.1 1.8 virginica
df.describe()
sepal length (cm) sepal width (cm) petal length (cm) petal width (cm)
count 150.000000 150.000000 150.000000 150.000000
mean 5.843333 3.057333 3.758000 1.199333
std 0.828066 0.435866 1.765298 0.762238
min 4.300000 2.000000 1.000000 0.100000
25% 5.100000 2.800000 1.600000 0.300000
50% 5.800000 3.000000 4.350000 1.300000
75% 6.400000 3.300000 5.100000 1.800000
max 7.900000 4.400000 6.900000 2.500000
#划分训练集和测试集
x=iris.data
y=iris.target.reshape(-1,1)#转为二维数组
##x:(150,4),y:(150,1)
x_train,x_test,y_train,y_test = train_test_split(x,y,test_size=0.3,random_state=35,stratify=y)
##random_state,随机测试的种子数,后期可以调试,strarify表示根据不同层级的y对x随机分


###核心算法实现
#欧式距离
def l1_distance(a,b):
    return np.sum(np.abs(a-b),axis=1)#axis=1指的轴是一,是对矩阵运算,a中的每一行都减去b,最后保存为一列
#曼哈顿距离
def l2_distance(a,b):
    return np.sqrt(np.sum((a-b)**2,axis=1))

#分类器完成
class kNN(object):
    #定义一个初始化方法,__init__ 是类的构造方法
    def __init__(self,n_neighbors = 1,dist_func = l1_distance):#默认近邻数是一,距离使用曼哈顿距离
        self.n_neighbors = n_neighbors
        self.dist_func = dist_func
        
    #训练模型方法
    def fit(self,x,y):
        self.x_train=x
        self.y_train=y
    #模型预测方法
    def predict(self,x):#传入一组样本
        y_pred = np.zeros( (x.shape[0], 1), dtype=self.y_train.dtype )
        #y_prred与x的行数相同,列数为1
        for i,x_test in enumerate(x):
            #取出每一个x_test数据点的序号,枚举
            distances = self.dist_func(self.x_train,x_test)
            #得到的距离按照由近到远排序,返回索引值
            nn_index=np.argsort(distances)
            #选择最近的k点,先要保存他们最近的类别
            #ravel()表示降维
            nn_y = self.y_train[nn_index[:self.n_neighbors]].ravel()
            #统计类别中出现频率最高的那个
            #bincount表示按索引统计个数,argmax返回索引值,此处索引值表示类别(0或1或2)
            y_pred[i] =np.argmax(np.bincount(nn_y))
        return y_pred#输出一组预测分类
    
        
#测试
# 定义一个knn实例
knn = kNN(n_neighbors = 3)
# 训练模型
knn.fit(x_train, y_train)
# 传入测试数据,做预测
y_pred = knn.predict(x_test)
print(y_test.ravel())
print(y_pred.ravel())

# 求出预测准确率
accuracy = accuracy_score(y_test, y_pred)
print("预测准确率: ", accuracy)
[2 1 2 2 0 0 2 0 1 1 2 0 1 1 1 2 2 0 1 2 1 0 0 0 1 2 0 2 0 0 2 1 0 2 1 0 2
 1 2 2 1 1 1 0 0]
[2 1 2 2 0 0 2 0 1 1 1 0 1 1 1 2 2 0 1 2 1 0 0 0 1 2 0 2 0 0 2 1 0 2 1 0 2
 1 2 1 1 2 1 0 0]
预测准确率:  0.9333333333333333
#定义一个实例
knn =kNN()
#训练模型
knn.fit(x_train,y_train)
#用list保存结果
result_list =[]
for p in [1,2]:
    knn.dist_func =l1_distance if p ==1 else l2_distance
    
    #考虑不同的k值,步长为2,使用奇数,减少并列第一的情况
    for k in range(1,10,2):
        knn.n_neighbors =k
        y_pred=knn.predict(x_test)
        accuracy = accuracy_score(y_test,y_pred)
        result_list.append([k,'l1_diatance' if p==1 else 'l2_diatance',accuracy])
df = pd.DataFrame(result_list,columns=['k','距离函数','预测准确率'])
df
k 距离函数 预测准确率
0 1 l1_diatance 0.933333
1 3 l1_diatance 0.933333
2 5 l1_diatance 0.977778
3 7 l1_diatance 0.955556
4 9 l1_diatance 0.955556
5 1 l2_diatance 0.933333
6 3 l2_diatance 0.933333
7 5 l2_diatance 0.977778
8 7 l2_diatance 0.977778
9 9 l2_diatance 0.977778

结果分析:使用含哈顿距离且k值为5-9时,预测准确率更高

你可能感兴趣的:(机器学习,python)