文章目录
- 初识k近邻算法
- K近邻算法api初步
- 常见距离度量
- kd树
- 案例分析
- 特征工程
- 案例分析-鸢尾花
- 交叉验证、网格搜索
- 案例实战--预测打卡位置
初识k近邻算法
k近邻算法又叫KNN算法
如果一个样本在特征空间中的k个最相似的样本中的大多数属于某一个类别,则该样本也属于这个类别
距离计算
计算两个样本之间的欧式距离
KNN算法流程
计算已知类别数据集中的点与当前点之间的距离
按距离递增排序
选取与当前点距离最少的k个点
统计前k个点所在类别出现的频率
返回前k个点出现频率最高的类别作为当前点的预测分类
K近邻算法api初步
from sklearn.neighbors import KNeighborsClassifier
# 构造数据
x = [[1],[2],[10],[20]]
y = [0,0,1,1]
# 训练模型
# 实例化一个估计器对象
estimator = KNeighborsClassifier(n_neighbors=1)
# 调用fit方法,进行训练
estimator.fit(x, y)
# 数据预测
ret = estimator.predict([[0]])
print(ret)
ret1 = estimator.predict([[100]])
print(ret1)
常见距离度量
1、欧式距离
2、曼哈顿距离
在曼哈顿街区要从一个十字路口开车到另一个十字路口,驾驶距离显然不是两点之间的直线距离。这个实际的驾驶距离就是曼哈顿距离,曼哈顿距离也称为城市街区距离。
3、切比雪夫距离
在国际象棋中,国王可以直行、横行、斜行,所以国王走一步可以移动到相邻8个方格中的任意一个。国王(x1,y1)走到(x2,y2)最少需要多少步,这个距离就是切比雪夫距离。
4、闵科夫斯基距离
5、标准化欧式距离
在欧式距离的基础上,让各个分量都标准化。 式中sk是标准差
6、余弦距离
7、汉明距离
两个长度相等的字符串,从一个每次改变一位得到另一个字符串,修改的值的和就是汉明距离。
汉明重量是一个序列相对于等长度的全0序列的汉明距离。当是二进制时,就是这个字符串中1的个数。
8、杰卡德距离
kd树
根据knn每次需要预测一个点时,都需要计算训练集中每个点到这个点的距离。当数据集很大时,计算成本非常高。
基本原理是如果a和b距离很远,b和c距离很近,那么a和c的距离也很远。
kd树(K-dimension tree) 是-种对k维空间中的实例点进行存储以便对其进行快速检索的树形数据结构。kd树是一种平衡二叉树,表示对k维空间的一个划分,构造kd树相当于不断地用垂直于坐标轴的超平面将K维空间切分,构成一系列的K维超矩形区域。kd树的每个结点对应于-个k维超矩形区域。利用kd树可以省去对大部分数据点的搜索,从而减少搜索的计算量。
kd树的构造方法
(1)构造根结点,使根结点对应于K维空间中包含所有实例点的超矩形区域;
(2)通过递归的方法,不断地对k维空间进行切分,生成子结点。在超矩形区域上选择-个坐标轴和在坐
标轴上的-个切分点,确定-个超平面,这个超平面通过选定的切分点并垂直于选定的坐标轴,将当前超矩形区域切分为左右两个子区域(子结点) ;这时,实例被分到两个子区域。
(3)上述过程直到子区域内没有实例时终止(终止时的结点为叶结点)。在此过程中,将实例保存在相应的结点上。
(4)通常,循环的选择坐标轴对空间切分,选择训练实例点在坐标轴上的中位数为切分点,这样得到的kd树是平衡的.KD树中每个节点是一个向量,和二叉树按照数的大小划分不同的是,KD树每层 需要选定向量中的某-维,然后根据这一维按左小右大的方式划分数据。
查找点的过程
1.二叉树搜索比较待查询节点和分裂节点的分裂维的值, (小于等于就进入左子树分支,大于就进
入右子树分支直到叶子结点)
2.顺着“搜索路径"找到最近邻的近似点
3.回溯搜索路径,并判断搜索路径上的结点的其他子结点空间中是否可能有距离查询点更近的数据
点,如果有可能,则需要跳到其他子结点空间中去搜索
4.重复这个过程直到搜索路径为空
案例分析
sklearn
load和fetch返回的数据类型datasets.base.Bunch(字典格式)
。data: 特征数据数组,是[n_samples *n_features]的二维numpy.ndarray 数组
。target: 标签数组,是n_samples的一维numpy.ndarray数组
。DESCR: 数据描述
。feature_names: 特征名,新闻数据,手写数字、回归数据集没有
。target_names: 标签名
seaborn是基于matplotlib封装的api库,可以容易的画出图形
seaborn.lmplot()函数在绘制二维散点图时,自动完成回归拟合
sns.lmplot()中x和y分别表示横纵坐标
data=是关联到的数据集
hue=*代表按照species即画的类别分类显示
fit_reg=是否进行线性拟合
from sklearn.datasets import load_iris
import seaborn as sns
import pandas as pd
import matplotlib.pyplot as plt
iris = load_iris()
iris_d = pd.DataFrame(data=iris.data, columns=['sepal_length', 'sepal_width', 'petal_length','petal_width'])
iris_d["target"] = iris.target
def iris_plot(data, col1, col2):
sns.lmplot(x=col1, y=col2, data=data, hue="target", fit_reg=False)
plt.show()
iris_plot(iris_d, "sepal_width", "petal_length")
数据集划分
from sklearn.datasets import load_iris
import seaborn as sns
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
iris = load_iris()
x_train, x_test, y_train, y_test = train_test_split(iris.data, iris.target, test_size=0.2, random_state=22)
特征工程
特征预处理api
sklearn.preprocessing
数值型数据的无量纲化
归一化
通过对原始数据进行变换把数据映射到默认为[0,1]之间
import pandas as pd
from sklearn.preprocessing import MinMaxScaler
data = pd.read_csv("C:\\Users\\dell\\Desktop\\data.txt")
# print(data)
# 实例化
transfer = MinMaxScaler(feature_range=(3,5))
# 进行转换,调用fit_transform
ret_data = transfer.fit_transform(data[["milage", "Liters", "Consumtime"]])
print(ret_data)
标准化
对原始数据进行变化到均值为0,标准差为1的范围内
import pandas as pd
from sklearn.preprocessing import StandardScaler
data = pd.read_csv("C:\\Users\\dell\\Desktop\\data.txt")
# print(data)
# 实例化
transfer = StandardScaler()
# 进行转换,调用fit_transform
ret_data = transfer.fit_transform(data[["milage", "Liters", "Consumtime"]])
# print(ret_data)
print(transfer.mean_)
print(transfer.var_)
案例分析-鸢尾花
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.neighbors import KNeighborsClassifier
# 数据获取
iris = load_iris()
# 数据基本处理
x_train,x_test,y_train,y_test = train_test_split(iris.data, iris.target, test_size=0.2, random_state=22)
# 特征工程
transfer = StandardScaler()
x_train = transfer.fit_transform(x_train)
x_test = transfer.transform(x_test)
# 机器学习-KNN
# 实例化一个估计器
estimator = KNeighborsClassifier(n_neighbors=5)
# 模型训练
estimator.fit(x_train, y_train)
# 模型预估
y_pre = estimator.predict(x_test)
# 准确率计算
score = estimator.score(x_test, y_test)
print(score)
交叉验证、网格搜索
交叉验证
将拿到的训练数据,分为训练和验证集。例如将数据分成4份,其中一份作为验证集。
然后经过4次(组)的测试,每次都更换不同的验证集。即得到4组模型的结果,取平均值作为最终结果。又称4折交叉验证。
注意交叉验证只是为了使结果更加准确可信,并不能提高准确率。
但是通过网格搜索来调参数,可以提高准确率
网格搜索
通常情况下,有很多参数是需要手动指定的(如k-近邻算法中的K值),这种叫超参数。但是手动过程繁杂,所以需要对模型预设几种超参数组合。每组超参数都采用交叉验证来进行评估。最后选出最优参数组合建立模型。
鸢尾花案例分析
api
sklearn.model. selection.GridSearchCV(estimator, param. _grid=None,cv=None)
。对估计器的指定参数值进行详尽搜索
。estimator: 估计器对象
。param. grid:估计器参数(dict{“n. neighbors”:[1,3,51)
。cv:指定几折交叉验证
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.model_selection import GridSearchCV
from sklearn.preprocessing import StandardScaler
from sklearn.neighbors import KNeighborsClassifier
iris = load_iris()
x_train,x_test,y_train,y_test = train_test_split(iris.data, iris.target, test_size=0.2, random_state=22)
transfer = StandardScaler()
x_train = transfer.fit_transform(x_train)
x_test = transfer.transform(x_test)
# 机器学习-KNN
# 实例化一个估计器
estimator = KNeighborsClassifier()
# 准备要调的超参数
param_dict = {"n_neighbors": [1,3,5,7]}
estimator = GridSearchCV(estimator, param_grid=param_dict, cv=3)
# 模型训练
estimator.fit(x_train, y_train)
# 模型预估
y_pre = estimator.predict(x_test)
# 准确率计算
score = estimator.score(x_test, y_test)
print(score)
# 查看交叉验证,网格搜索的一些属性
print("交叉验证中得到的最好结果:\n", estimator.best_score_)
print("交叉验证中得到的最好模型:\n", estimator.best_estimator_)
print("交叉验证中得到的模型结果:\n", estimator.cv_results_)
案例实战–预测打卡位置
from sklearn.model_selection import train_test_split, GridSearchCV
from sklearn.preprocessing import StandardScaler
from sklearn.neighbors import KNeighborsClassifier
import pandas as pd
# 获取数据集
data = pd.read_csv("E:\\train.csv")
# 基本数据处理
# 缩小数据范围
partial_data = data.query("x>2.0 & x<2.5 & y>2.0 & y<2.5")
# 选择时间特征
time = pd.to_datetime(partial_data["time"], unit="s")# type: pandas.core.series.Series
time.head()
time = pd.DatetimeIndex(time)
time.hour
time.day
time.weekday
partial_data["hour"] = time.hour
partial_data["day"] = time.day
partial_data["weekday"] = time.weekday
partial_data.head()
# 去掉签到较少的地方
place_count = partial_data.groupby("place_id").count()
place_count.head()
place_count = place_count[place_count["row_id"]>3]
place_count.head()
partial_data = partial_data[partial_data["place_id"].isin(place_count.index)]
# 确定特征值和目标值
x = partial_data[["x", "y", "accuracy", "hour", "day", "weekday"]]
y = partial_data["place_id"]
# 分割数据集
x_train, x_test, y_train, y_test = train_test_split(x, y, random_state=2, test_size=0.25)
# 特征工程--标准化
transfer = StandardScaler()
x_train = transfer.fit_transform(x_train)
x_test = transfer.fit_transform(x_test)
# 机器学习--knn+cv
estimator = KNeighborsClassifier()
param_grid = {"n_neighbors":[3,5,7,9]}
estimator = GridSearchCV(estimator=estimator, param_grid=param_grid, cv=3, n_jobs=-1)
estimator.fit(x_train, y_train)
# 模型评估
# 准确率
score_ret = estimator.score(x_test, y_test)
print(score_ret)
# 预测结果
y_pre = estimator.predict(x_test)
print(y_pre)