KNN算法(K-Nearest Neighbors): 一种基本的分类与回归方法,属于监督学习算法。

该算法核心思想:通过计算给定样本与数据集中所有样本的距离,找到距离最近的K个样本,然后根据这K个样本的类别或值来预测当前样本的类别或值

  1. 计算距离,计算待分类样本与训练集中每个样本的距离
  2. 选择K个近邻,根据计算的距离,选择距离最近的K个样本
  3. 分类任务-统计K个近邻各类别的数量,将待分类样本归为数量最多的类别;回归任务-取K个近邻的平均值作为预测结果

在这里插入图片描述

关于距离度量的种类:
在这里插入图片描述
①、欧氏距离:欧几里得距离,这是我们最为熟悉的距离度量方法,指连接两点线段的长度
在这里插入图片描述
②、曼哈顿距离:曼哈顿距离得名于纽约曼哈顿的街道布局。由于曼哈顿的街道多为规则的网格状,车辆只能沿水平和垂直方向行驶,无法直接斜穿。因此,两点之间的实际行驶距离是沿街道行走的距离,而非直线距离。在坐标系中,是两点的轴距之和
在这里插入图片描述

③、切比雪夫距离:点x(x1,…,xn)和y(y1,…,yn)之间的切比雪夫距离d(x,y)=max⁡(|xi-yi |),两点各坐标数值差的最大值
在这里插入图片描述

④、是一种用于度量多维空间中两点间距离的通用方法,点x(x1,…,xn)和y(y1,…,yn)之间的闵可夫斯基距离

  • 其参数p越小,对多个维度的差异更敏感;p越大,更关注最大维度的差异。
  • 通过调整参数p,闵可夫斯基距离可以退化为以下经典距离:曼哈顿距离:p=1;欧氏距离:p=2;切比雪夫距离:p=∞

在这里插入图片描述

API应用

分类

from sklearn.neighbors import KNeighborsClassifier

knn = KNeighborsClassifier(n_neighbors=2) #KNN分类模型,K值为2

X = np.array([[2,1],[3,1],[1,4],[2,6]]) #特征
y = np.array([0,0,1,1])#标签

knn.fit(X,y) #模型训练
X = np.array([[4,9]])
X_class = knn.predict(X)#预测
print(X_class)

#画图
fig,ax = plt.subplots()
ax.axis('equal')
#使用布尔索引将两类点分开
X1 = X[y==0]
X2 = X[y==1]

#定义不同的颜色,画两组点
colors = ["C0","C1"]
plt.scatter(X1[:,0],X1[:,1],c=colors[0])
plt.scatter(X2[:,0],X2[:,1],c=colors[1])

#新点的颜色
x_color = colors[0] if x_class == 0 else colors[1]
plt.scatter(X[:,0],X[:,1],c=x_color)
plt.show()

在这里插入图片描述

"""
鸢尾花分类案例

 - 特征值:花萼长度  花萼宽度   花瓣长度   花瓣宽度
 - 目标值:setosa山鸢尾  versicolor杂色鸢尾  virginica弗吉尼亚鸢尾

"""
from sklearn import datasets
from sklearn.neighbors import KNeighborsClassifier
from sklearn.model_selection import train_test_split

X,y = datasets.load_iris()
X_train,X_test,y_train,y_test = train_test_split(X,y,test_size=0.2,random_State=1024)

model = KNeighborsClassifier(n_neighbors=5)
model.fit(X_train,y_train)

y_ = model.predict(X_test) # 预测值
print((y_ == y_test).mean) # 准确率 或者采用model.score(X_test,y_test)

回归

from sklearn.neighbors import KNeighborsRegressor

knn = KNeighborsRegressor(n_neighbors=2,weights='distance') #KNN回归模型,K为2

X = [[2,1],[3,1],[1,4],[2,6]] 
y = [0.5,0.33,4,3]
knn.fig(X,y)
knn.predict([4,9])
""""
预测波士顿房价

 - 特征:13个
 - 目标:房屋的中位数价格,以千美元为单位

"""
import warings
warnings.filterwarnings('ignore') # 忽略一些API以后过期的警告

from sklearn.datasets import load_boston
from sklearn.neighbors import KNeighborsRegressor # 回归  平均值  计算房价中位数
from sklearn.model_selection import train_test_split

from sklearn.model_selection import GridSearchCV # 交叉验证-超参数(网格搜索)

data = load_boston()
X = data.data
y = data.target

X_train,X_test,y_train,y_test = train_test_split(X,y,test_size=0.2,random_state=42)

# k值、weights权重、p表示距离度量:欧氏距离、曼哈顿距离
k = [1,3,5,7,9,15,17,23,30]
weights = ['uniform','distance']
p = [1,2]
params = dict(n_neighbors=k,weights=weights,p=p)
estimator = KNeighborsRegressor()
gCV = GridSearchCV(estimator,params,cv=5,scoring='neg_mean_squared_error')

gCV.fit(X_train,y_train)

print(gCV.best_params_) # 获取最好的参数
print(gCV.best_score_)
print(gCV.best_estimator_)

best_knn = gCV.best_estimator_ # 最好的模型进行预测
y_ = best_knn.predict(X_test).round(1)
print(y_[:20])

print(mean_squared_error(y_test,y_)) # 均方误差

常见距离度量方法

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

归一化与标准化

归一化:
在这里插入图片描述

from sklearn.preprocessing import MinMaxScaler

X = [[2,1],[3,1],[1,4],[2,6]]

#定义归一化类的对象
scaler = MinMaxScaler(feature_range=(-1,1))

#将缩放器应用到特征上
X_scaled = scaler.fit_transform(X)
print(X_scaled)

在这里插入图片描述

标准化:
在这里插入图片描述

from sklearn.preprocessing import StandardScaler

scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
print(X_scaled)

#均值和方差
print(np.mean(X,axis=0))
print(np.std(X,axis=0))

在这里插入图片描述

超参调优
在这里插入图片描述
在这里插入图片描述

import numpy as np
from sklearn import datasets
from sklearn.neighbors import KNeighborsClassifier
from sklearn.model_selection import train_test_split
from sklearn.model_selection import cross_val_score

X,y = datasets.load_iris(return_X_y=True)
X_train,X_test,y_train,y_test = train_test_split(X,y,test_size=0.2,random_state=42)

# 超参数-交叉验证
params_k = np.arange(1,31)
scores = []
for k in params_k:
	knn = KNeighborsClassifier(n_neighbors=k)
	# cv=5 表示5折,使用accuracy进行评估分类问题
	score = cross_val_score(knn,X_train,y_train,cv=5,scoring='accuracy').mean()
	scores.append(score)

k_best = np.argmax(scores) + 1
print("得分最高的k的值是:",k_best)

# 选择最佳超参进行建模和预测
estimator = KNeighborsClassifier(n_neighbors=k_best)
estimator.fit(X_train,y_train)
y_ = estimator.predict(X_test)
print(estimator.score(X_test,y_test))

在这里插入图片描述

from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split,GridSearchCV
from sklearn.preprocessing import StandardScaler
from sklearn.neighbors import KNeighborsClassifier
from sklearn metrics import accuracy_score

# 1.加载鸢尾花数据集
iris_data = load_iris()

# 2.数据预处理,切分训练集和测试集 比例8:2
x_train,x_test,y_train,y_test = train_test_split(iris_data.data,iris_data.target,test_size=0.2,random_state=22)

# 3.特征工程标准化
transfer = StandardScaler()
x_train = transfer.fit_transform(x_train)
x_test = transfer.transform(x_test)

# 模型训练
estimator = KNeighborsClassifier()
# 定义字典记录超参可能出现的值
param_dict = {'n_neighbors':[i for i in range(1,11)]}
# 4次交叉验证,4 * 10 = 40次,返回处理后的模型对象
estimator = GridSearchCV(estimator,param_dict,cv=4)

estimator.fit(x_train,y_train)
print(f'最优评分:{estimator.best_score_}'})
print(f'最优超参组合:{estimator.best_params_}')
print(f'最优的估计器对象:{estimator.best_estimator_}')
print(f'具体的交叉验证结果:{estimator.cv_results_}')

# 模型评估
# estimator = estimator.best_estimator_
estimator = KNeighborsClassifier(n_neighbors=3)
# 模型训练
estimator.fit(x_train,y_train)
y_pre = estimator.predict(x_test)
print(f'准确率:{accuracy_score(y_test,y_pre)}')

案例:心脏病预测
在这里插入图片描述
在这里插入图片描述

import pandas as pd
import sklearn.model_selection import train_test_split

#加载数据集
heart_disease_data = pd.read_csv("heart_disease.csv")

#处理缺失值
heart_disease_data.dropna(inplace=True)

heart_disease_data.info()
print(heart_disease_data.head())

#数据集划分
X = heart_disease_data.drop("是否患有心脏病",axis=1)
y = heart_disease_data["是否患有心脏病"]

X_tain,X_test,y_train,y_test = train_test_split(X,y,test_size=0.3,random_state=42)

#如何处理13中特征?

在这里插入图片描述

from sklearn.preprocessing import StandardScaler,OneHotEncoder
from sklearn.compose import ColumnTransformer

#数值特征
numerical_features = ["年龄","静息血压","胆固醇","最大心率","运动后的ST下降","主血管数量"]
#类别型特征
categorical_features = ["胸痛类型","静息心电图结果","峰值ST段的斜率","地中黑贫血"]

#二元特征
binary_features = ["性别","空腹血糖","运动性心绞痛"]

#创建列转换器
preprocessor = ColumnTransformer(
	transformers=[
		#对数值型特征进行标准化
		("num",StandardScaler(),numerical_features),
		#对类别型特征进行独热编码,使用drop="first"避免多重共线性
		("cat",OneHotEncoder(drop="first"),categorical_features),
		#二元特征不进行处理
		("binary","passthrouth",binary_features),
	]
)

#执行特征转换
x_train = preprocessor.fit_trainsform(X_train)#计算训练集的统计信息并进行转换
x_test = preprocessor.transform(X_test) #使用训练集计算的信息对测试集进行转换

print(x_train)
print(x_test)
from sklearn.neighbors import KNeighborsClassifier
import joblib

#创建模型
knn = KNeighborsClassifier(n_neighbors=3)

knn.fit(X_train,y_train)

#模型评估,计算预测准确率
score = knn.score(X_test,y_test)
print(score)

#保存模型
joblib.dump(value=knn,filename="knn_model")
#加载保存好的模型做预测
knn_loaded = joblib.load("knn_model")
y_pred = knn_loaded.predict(X_test[10:11])
print(f"预测类别:{y_pred},真实类别:{y_test[10]}")

交叉验证
在这里插入图片描述

from sklearn.model_selection import GridSearchCV

#创建KNN分类器
knn = KNeighborsClassifier()

#定义网络搜索参数列表
param_grid = {"n_neigobors":list(range(1,11))}

grid_search_cv = GridSearchCV(estimator=knn,param_grid=param_grid,dv=10)

#模型训练
grid_search_cv.fit(X_train,y_train)

#打印模型评估结果
# results = grid_search_cv.cv_results_
# results = pd.DataFrame(grid_search_cv.cv_results_)
results = pd.DataFrame(grid_search_cv.cv_results_).toString()
print(results)

在这里插入图片描述

#获取最佳模型、参数和最佳得分
print(grid_search_cv.test_estimator_)
print(grid_search_cv.test_params_)
print(grid_search_cv.best_score_)

#使用最佳模型进行测试评估
knn = grid_search_cv.test_estimater_
print(knn.score(X_test,y_test))

除了上述K值决定的模型优化,此外还有权重影响

#定义网络搜索参数列表
pram_grid = {"n_neighbors":list(range(1,11)),"weights":["uniform","distance"]}

图像识别

在这里插入图片描述

①、数据加载

import numpy as np
import matplotlib.pyplot as plt

data = np.load('./digit.npy')
print(data)
print(data.shape) # (5000,28,28)
# 图片是500个一组,依次是0,1,2……
plt.imshow(data[0],cmap='gray')

# 构建目标值
y = list(np.arange(0,10)) * 500
y.score()
print(y)
# 将列表转换为张量
y = np.array(y)

②、数据拆分与处理

from sklearn.model_selection import train_test_split

X = data.reshape(5000,-1)
X.shape # 进行降维
X_trian,X_test,y_train,y_test = train_test_split(X,y,test_size=0.2,random_state=1024)

print(X_train.shape,y_train.shape)

③、建模

from sklearn.neighbors import KNeighborsClassifier

model = KNeighborsClassifier(n_neighbors=5)
model.fit(X_train,y_train)
model.score(X_test,y_test)

超参数优化算法

# 魔法指令,计算时间
%%tima
from sklearn.model_selection import GridSearchCV

params = dict(
	n_neighbors=[3,5,10,15,17,23,30],
	weights=['uniform','distance'],
	p=[1,2]# 1 曼哈顿距离   2 欧式距离
)
estimator = KNeighborsClassifier()
gCV = GridSearchCV(estimator,params,cv=5,scoring='accuracy')
gCV.fit(X_train,y_train)

print(gCV.best_score_)
print(gCV.best_params_)

best_model = gCV.best_estimator_
y_pred = best_model.predict(X_test)
print(y_pred[:30])
print(y_test[:30])

print(best_model.score(X_test,y_test))

④、可视化

plt.figure(figsize=(5*2,10*3))
for i in range(50):
	plt.subplot(10,5,i+1)
	plt.imshow(X_test[i].reshape(28,28)) # 对数组进行增维,恢复成图片
	true = y_test[i]
	pred = y_pred[i]
	plt.title(f'True:{true}\n Predict:{pred}')
	

在这里插入图片描述

健康医疗

①、数据加载

import numpy as np
import pandas as pd
from sklearn.neighbors import KNeighborsClassifier

from sklearn.model_selection import train_test_split
from sklearn.model_selection import GridSearchCV

data = pd.read_csv('./cancer.csv',sep='\t') # 源数据是以tap键进行分割的
print(data.head())

y = data['Diagnosis']
X = data.iloc[:,2:]

X_train,X_test,y_train,y_test = train_test_split(X,y,test_size=0.2,random_state=100)

在这里插入图片描述

②、网格搜索超参数

%%time
estimator = KNeighborsClassifier()
params = dict(
	n_neighbors=np.arange(1,30),
	weights=['uniform','distance'],
	p=[1,2]
)
gCV = GridSearchCV(estimator,params,cv=6,scoring='accuracy')
gCV.fit(X_train,y_train)

print(gCV.best_score_)
print(gCV.best_params_)

model = gCV.best_estimator_
y_pred = model.predict(X_test)
print('算法预测值:',y_pred[:20])

③、评估

from sklearn.metircs import accuracy_score

accuracy_score(y_test,y_pred)

# 或者直接采用
model.score(X_test,y_test)
gCV.score(X_test,y_test)

数据进行归一化处理

在这里插入图片描述

from sklearn.preprocessing import MinMaxScaler

mms = MinMaxScaler()
X_norml = mms.fit_transform(X)

X_train,X_test,y_train,y_test = train_test_split(X_norml,y,test_size=0.2,random_state=100)

estimator = KNeighborsClassifier()
params = dict(n_eighbors=np.arange(1,30),weights=['uniform','distance'],p=[1,2])

gCV = GridSearchCV(estimator,params,cv=6,scoring='accuracy')
gCV.fit(X_train,y_train)

score = gCV.score(X_test,y_test)
print('Min-Max归一化数据,模型得分是:',score)

在这里插入图片描述

from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
X_norm2 = scaler.fit_transform(X)

X_train,X_test,y_train,y_test = train_test_split(X_norm2,y,test_size=0.2,random_state=100)

estimator = KNeighborsClassifier()
params = dict(n_neighbors=np.arange(1,30),weights=['uniform','distance'],p=[1,2])

gCV = GridSearchCV(estimator,params,cv=6,scoring='accuracy')
gCV.fit(X_train,y_train)

print('超参数:',gCV.best_params_)
score = gCV.score(X_test,y_test)
print('Z-Score标准化数据:',score)

人力资源

①、数据加载

import numpy as np
import pandas as pd
from sklearn.neighbors import KNeighborsClassifier
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
from sklearn.model_selection import GridSearchCV
from sklearn.processing import MinMaxScaler,LabelEncoder

data = pd.read_csv('./adules.txt')
print(data.head(),data.shape)

data.isna().sum() # 统计空数据
data['workclass'].unique() # 出现?符号
data.replace("?",np.nan).dropna().reset_index(drop=True) # 删除空数据


data['capital_gain'].sort_values(asecnding=False).unique() # 异常值  过滤掉收益特别大的
data['capital_loss'].sort_values(ascending=False).unique() # 过滤掉损失特别大
cond = (data['capital_gain']!=99999) & (data['capital_loss']!=4356)
data = data[cond]
data.shape

# 字符串->数值型数据
le = LabelEncoder()
le.fit(["paris","paris","tokyo","amsterdam"])
le.transform(["paris","paris","tokyo","amsterdam"])

columns = ['workclass','education','marital_status','occupation','relationship','race','sex','native_country']
le = LabelEncoder()
for col in columns:
	data[col] = le.fit_transform(data[col])

data.head()

# 归一化
scaler = MinMaxScaler()
col_norm = ['age','final_weight','workclass','education_num','education','marital_status','occupation','relationship','race','capital_gain','capital_loss','hours_per_week','native_country']
data[col_norm] = scaler.fit_transform(data[col_norm])

在这里插入图片描述

②、数据拆分

y = data['salary']
X = data.drop(labels='salary',axis=1)
print(X.shape)

③、建模预测

knn = KNeighborsClassifier()
knn.fit(X_train,y_train)
y_pred = knn.predict(X_test)
print('真实值:',y_test[:20].values)
print('预测值:',y_pred[:20])

accuracy_score(y_test,y_pred)

④、模型优化

%%time

knn = KNeighborsClassifier()
params = dict(n_neighbors=[3,5,9,15,23,31,39],weights=['uniform','distance'],p=[1,2])
gCV = GridSearchCV(knn,params,cv=5)
gCV.fit(X_train,y_train)

print(gCV.best_params_)

knn_best = gCV.best_estimator_
knn_best.score(X_test,y_test) # gCV.score(X_test,y_test)
Logo

码道开发者社区,聚焦华为云码道 CodeArts 代码智能体,沉淀 Agent、Skill、鸿蒙开发实战内容,供开发者查阅资料、交流技术、分享工程实践

更多推荐