算法介绍
如图是鸢尾花特征及类别数据的部分显示。有0,1,2三个类别,我们可以通过比较鸢尾花样本特征的相似程度来对鸢尾花种类进行判断。
KNN:
- 得到与目标样本特征的相似度最高的k个样本
- 在这k个样本中,统计各个类别的多少,目标样本类别=多数样本类别
算法实现
划分训练集和测试集
from sklearn.model_selection import train_test_split
def split_df(df,test_size,random_state):
y = df['target']
x = df.drop(['target'],axis=1)
#划分数据集
x_train, x_test, y_train, y_test = train_test_split(x,y, test_size=test_size, random_state=random_state)
return x_train, x_test, y_train, y_test
#导入鸢尾花数据
import pandas as pd
df = pd.read_csv('./iris.csv')
#做数据划分
x_train, x_test, y_train, y_test = split_df(df,0.1,42)
计算相似度
这里,我们使用欧氏距离来衡量相似度:
d
i
s
t
a
n
c
e
(
a
,
b
)
=
∑
i
=
1
n
(
a
i
−
b
i
)
2
distance(a,b) = \sqrt{\sum_{i=1}^{n}(a_i-b_i)^2}
distance(a,b)=i=1∑n(ai−bi)2
def cal_simlarity(df,test):
#输入:df 训练集 test 测试集
#输出: distances 每列代表测试集里不同的样本与训练集的特征相似度
distances= pd.DataFrame()
#取训练集的行数
p = df.shape[0]
#对测试集每行操作
for row in test.index:
#求测试集的每个样本与训练集样本的相似度
distance = np.sqrt(((df - np.tile(test.loc[row],(p,1)))**2).sum(axis=1))
column_name = f"Distance_{row}"
distances[column_name] = distance
return distance,distances
distance,distances = cal_simlarity(x_train,x_test)
distances:
测试集与原训练集的相似度矩阵
knn分类
由上一节我们可以得到,某一个目标样本与训练样本的相似度。接下来只需对相似度排序,选出最小的前k个相似度对于的样本索引,从而得到对于的类别。接着对这些类别进行统计,找到出现次数最多的类别,我们的目标样本的类别则表示为该类别。
from collections import Counter
def knnselect(distance,k,y_train):
#每一列做从小到大排序,记得保留索引
sort_distance = distance.sort_values().reset_index(drop=False)
#取前k行
k_sort = sort_distance.head(k)
y_sorts=[]
#找到前k相似度对应的y标签值
for i in range(k):
y_sort = y_train.loc[k_sort.iloc[i,0]]
y_sorts.append(y_sort)
#对类别进行统计
count = Counter(y_sorts)
max_freq = max(count.values())
most_common = [num for num, freq in count.items() if freq == max_freq]
return most_common
#对每个测试集样本调用knnselect函数
result = distances.apply(lambda col: knnselect(col,5,y_train),axis=0 )
最后测试样本的类别标签为:
计算正确率
def cal_correct(re1,y_test):
re1 = result.stack().reset_index(drop=True).values
y_test = y_test.values
num = len(y_test)
#如果类别是一样的 记为1
correct = sum(re1==y_test)
return correct/num
cal_correct(re1,y_test)
# print;1.0