k近邻(k-nearest neighbor,k-NN)是一种基本分类与回归的方法。实现简单,直观:给定一个训练数据集,对新的输入实例,在训练数据集中找到与该实例最邻近的K个实例,这K个实例的多数属于某个类,就把该输入实例分为到这个类里。
k近邻算法使用的模型实际上有三个基本要素,分别是距离度量,k值的选择和分类决策规则。下面分别简述三要素。
1、距离度量
空间中两个实例点的距离反应两个实例点的相似程度。k近邻算法的特征空间一般是n维向量空间,使用的是距离度量方式为欧氏距离,欧氏距离我们高中就学过。当然也可以使用其他距离度量方式。
2、k值的选择
k值的选择会对结果有很大的影响。如果选择较小的k值,相当于用较小的邻域中训练实例进行预测,近似误差会变小,只有与输入实例较近的训练实例才会对预测结果起作用。k值较小意味着整体模型算法变得复杂了,容易发生过拟合。如果k值过大的话,相当于模型算法变得简单,可能会到欠拟合。在实际使用中,k值一般取一个较小的数组,然后通过交叉验证的方法选择最优的k值。
3、分类决策规则
k-nn中的分类决策规则往往是多数表决,即输入实例的k个近邻的训练实例中的多数类决定输入实例的类。
延伸学习-kd树:
实现k近邻模型是,主要问题是如何对训练数据进行快速k近邻搜素,在多维大训练数据中尤其重要。k近邻最简单的实现方法是线性扫描,要计算输入实例与每一个训练实例的距离。当训练集很大的时候,计算非常耗时,此方法是行不通的。为了提高K近邻搜素效率,减少搜素次数,kd树方法是其中一个比较
比较好的方法。
kd树其实是二叉树,对k维空间的一个划分,构造kd树相当于不断地用垂直于坐标轴的超平面将k维空间切分,构成一系列的k维矩形区域,kd树的每一个结点对应于一个k维超矩形区域。利用kd树可以省去对大部分数据点的搜素,从而减少搜素的计算量。
下面通过一个简单实例来看下这个k-nn得使用。
# -*- coding:utf-8 -*-
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
#读取数据
df = pd.read_csv('data.csv')
# print(df.head())
# print(df.info())
# print(df.describe())
"""
使用one-hot编码,将离散特征的取值扩展到了欧式空间,离散特征的某个取值就对应欧式空间的某个点。将离散型特征使用one-hot编码,会让特征之间的距离计算更加合理。离散特征进行one-hot编码后,编码后的特征,其实每一维度的特征都可以看做是连续的特征。就可以跟对连续型特征的归一化方法一样,对每一维特征进行归一化。比如归一化到[-1,1]或归一化到均值为0,方差为1。
"""
#清洗数据
#颜色进行one-hot编码,颜色有多种并且是str类型的,one-hot将颜色变成连续数,便于距离计算。
df_color = df['Color'].str.get_dummies().add_prefix('Color: ')
#type进行one-hot
df_type = df['Type'].apply(str).str.get_dummies().add_prefix('Type: ')
# 添加独热编码数据列
df = pd.concat([df,df_color,df_type],axis=1)
# 去除独热编码对应的原始列
df = df.drop(['Color','Type','Brand'],axis=1)
# print(df)
#数据转换
#corr()相关系数矩阵,即给出任意两个特征之间的相关系数
matrix = df.corr()
fig = plt.figure(figsize=(10,6))
sns.heatmap(matrix,square=True)
plt.title('Car Price Variables')
# plt.show()
from sklearn.neighbors import KNeighborsClassifier
from sklearn.neighbors import KNeighborsRegressor
from sklearn.model_selection import train_test_split
from sklearn import preprocessing
from sklearn.preprocessing import StandardScaler
X = df[['Construction Year', 'Days Until MOT', 'Odometer']]
y = df['Ask Price'].values.reshape(-1,1)
X_train,X_test,y_train,y_test = train_test_split(X,y,test_size=0.3,random_state=41)
X_norm = StandardScaler()
X_train = X_norm.fit_transform(X_train)
X_test = X_norm.transform(X_test)
y_norm = StandardScaler()
y_train = y_norm.fit_transform(y_train)
y_test = y_norm.transform(y_test)
knn = KNeighborsRegressor(n_neighbors=2)
knn.fit(X_train,y_train)
#Now we can predict prices:
y_pred = knn.predict(X_test)
y_pred_reval = y_norm.inverse_transform(y_pred)
y_test_reval = y_norm.inverse_transform(y_test)
fig2 = plt.figure(figsize=(10,8))
plt.scatter(y_pred_reval,y_test_reval)
plt.xlabel('Prediction')
plt.ylabel('Real value')
# Now add the perfect prediction line
fig1 = plt.figure(figsize=(10,8))
diagonal = np.linspace(500, 1500, 100)
plt.scatter(y_pred_reval,y_test_reval)
plt.plot(diagonal, diagonal, '-r')
plt.xlabel('Predicted ask price')
plt.ylabel('Ask price')
plt.show()
# print(y_pred_reval)
"""
[[1199.]
[1199.]
[ 700.]
[ 899.]]
"""
KNeighborsRegressor(algorithm='auto',leaf_size=30,metric='minkowski',metric_params=None,n_jobs=None,n_neighbors=2,p=2,weights='uniform')
pred = knn.predict(X_test)
print(pred)
"""
[[ 1.36676513]
[ 1.36676513]
[-0.68269804]
[ 0.13462294]]
"""
from sklearn.metrics import mean_absolute_error
p = mean_absolute_error(y_pred_reval,y_test_reval)
from sklearn.metrics import mean_squared_error
p1 = mean_squared_error(y_pred_reval,y_test_reval)
print(p) #175.5
print(p1) #56525.5
print(y_pred_reval)
print(y_test_reval)
以上内容参考书《统计学习方法》,机器学习训练营李老师讲课和实践内容。