1. 简介
1.1 定义
- k-近邻算法,也叫KNN(k nearest neighbor)算法,是一个非常适合入门的算法
1.2 解释
1.案例介绍
- 上图中的数据点是分布在一个特征空间中的,通常使用一个二维的空间演示
- 横轴表示肿瘤大小,纵轴表示发现时间。
- 恶性肿瘤用蓝色表示,良性肿瘤用红色表示。
- 此时新来了一个病人
- 如上图绿色的点,怎么判断新来的病人(即绿色点)是良性肿瘤还是恶性肿瘤呢?
2. k-近邻算法的做法
- 取一个值k=3(此处的k值可以理解为机器学习的使用者根据经验取得了一个经验的最优值)。
- k近邻判断绿色点的依据就是在所有的点中找到距离绿色点最近的三个点
- 然后让最近的点所属的类别进行投票,发现最近的三个点都是蓝色的
- 所以该病人对应的应该也是蓝色,即恶性肿瘤。
- 上图中和绿色的点距离最近的点包含两个红色和一个蓝色,此处红色点和蓝色点的数量比为2:1,则绿色点为红色的概率最大
- 最后判断结果为良性肿瘤。
1.3 本质
- 两个样本足够相似,那么他们两个就具有更高概率属于同一个类别。
- 但如果只看一个,可能不准确,所以就需要看K个样本
- 如果K个样本中大多数属于同一个类别,则被预测的样本就很可能属于对应的类别。
1.4 特性
- knn算法没有得到模型,它是机器学习中唯一 一个不需要训练过程的算法
- 为了和其他算法统一,可以认为数据集就是模型本身(sklearn就是参照这样的方式设计的)
参照机器学习的主要流程:
-
首先准备X_train,y_train交给机器学习算法
-
算法对数据进行拟合形成模型
-
输入样例交给模型进行预测,得到输出结果
1.5 特点
1. 优点
- 思想极度简单,而且效果好
-
应用数学知识少(近乎为零)
-
天然能够解决多分类问题
-
也解决回归问题
-
由于回归问题是计算一个连续性的数值,所以k-近邻算法计算的距离结果也是一个连续性的数值。
-
如图:可以将绿色的点距离较近的三个点的距离值加权平均,得到绿色点的回归结果
2. 缺点
- 效率低下
如果训练集有m个样本,n个特征,则预测每一个新的数据,需要O(m*n)的时间复杂度
- 优化
使用树结构:K-D tree、Ball-Tree,即便如此,k-近邻算法仍然效率低下。
- 高度数据相关
所有的机器学习算法均高度数据相关,但是k-近邻算法尤为突出。
当特征中出现两个错误值,就足以让k-近邻算法的准确率大大下降。
- 预测结果不具有可解释性
仅仅通过距离较近来判断类别,结果没有可解释性。
- 维数灾难
随着维数的增加,“看似相近”的两个点之间的距离越来越大。
- 解决方法:降维
1.4 欧拉距离公式
- 平面中两点之间的欧拉距离:
- 立体中两点之间的距离:
- 任意维度下的欧拉距离:
- 简化后:
- 欧拉距离:任意空间下两个点的对应维度的坐标值相减的平方和再开方
2. 实现
2.1 手动实现knn
举例:
学生保送案例
思路:
首先有原始已知标签的数据
把需要预测的点和所有已知标签的点去计算距离
找到和待预测点最近的k个点
根据k个点的标签确定待预测点的标签
步骤:
获取原始数据,包括特征值和目标值
画出原始数据
在图中标记出待预测样本
计算出待预测样本和原始样本点的距离
获取k个最近的点
根据这k个的标签确定待预测样本标签(根据标签数量)
代码:
import numpy as np
import matplotlib.pyplot as plt
# 1. 获取样本值,包括特征值和标签值
# 1.1 定义特征值
raw_data_x= [[3.3144558 , 2.33542461],
[3.75497175, 1.93856648],
[1.38327539, 3.38724496],
[3.09203999, 4.47090056],
[2.58593831, 2.13055653],
[7.41206251, 4.80305318],
[5.912852 , 3.72918089],
[9.21547627, 2.8132231 ],
[7.36039738, 3.35043406],
[7.13698009, 0.40130301]]
# 1.2 定义标签值
raw_data_y = [0,0,0,0,0,1,1,1,1,1]
raw_data_y
# 1.3 特征值list转化为ndarray
x_train = np.array(raw_data_x)
x_train
# 1.4 标签值list转化为ndarray
y_train = np.array(raw_data_y)
y_train
# 2. 画出样本值
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号
# 2.1 画出特征值
plt.scatter(x_train[y_train == 0, 0], x_train[y_train == 0, 1], color = 'r')
# 2.2 画出标签值
plt.scatter(x_train[y_train == 1, 0], x_train[y_train == 1, 1], color = 'b')
plt.show()
# 3. 获取并画出待预测样本
# 3.1 获取待预测样本
x_predict = np.array([8.093607318,3.365731514])
x_predict
# 3.2 画出带预测样本
plt.scatter(x_train[y_train == 0, 0], x_train[y_train == 0, 1], color = 'r')
plt.scatter(x_train[y_train == 1, 0], x_train[y_train == 1, 1], color = 'b')
plt.scatter(x_predict[0], x_predict[1], color = 'g')
plt.show()
# 4. 计算待预测样本到样本值之间的距离并排序
# 4.1 计算带预测样本到样本值之间的距离
from math import sqrt
distances = [sqrt(np.sum((x_train - x_predict) ** 2)) for x_train in x_train]
distances
# 4.2 将距离排序
nearest = np.argsort(distances)
nearest
# 5. 获取k个最近的样本
# 5.1 定义超参数k
k = 6
# 5.2 获取k个最近的样本
top_k = [y_train[i] for i in nearest[:k]]
top_k
# 6. 根据k个最近样本的标签的数量来确定带预测点样本的标签
# 6.1 投票
from collections import Counter
votes = Counter(top_k)
votes
# 6.2 获取出现数量最多的样本的标签
y_predict = votes.most_common(1)[0][0]
y_predict
2.2 使用sklearn实现knn
import numpy as np
from sklearn.neighbors import KNeighborsClassifier
# 1. 获取原始样本值
# 1.1 获取原始特征值并转化为ndarray
raw_data_x = [[3.3144558 , 2.33542461],
[3.75497175, 1.93856648],
[1.38327539, 3.38724496],
[3.09203999, 4.47090056],
[2.58593831, 2.13055653],
[7.41206251, 4.80305318],
[5.912852 , 3.72918089],
[9.21547627, 2.8132231 ],
[7.36039738, 3.35043406],
[7.13698009, 0.40130301]]
raw_data_x
x_train = np.array(raw_data_x)
x_train
# 1.2 获取原始标签值并转化为ndarray
raw_data_y = [0,0,0,0,0,1,1,1,1,1]
raw_data_y
y_train = np.array(raw_data_y)
y_train
# 2. 获取带预测样本值
# 2.1 获取待预测样本特征值
x_predict = np.array([8.093607318,3.365731514])
x_predict
# 2.2 查看带预测样本特征值的维度
x_predict.ndim
# x_predict.shape
# 2.2 把带预测样本的特征值维度变为和原始样本特征值的二维
x1_predict = np.array([x_predict])
# x1_predict = x_predict.reshape(-1, 1)
x1_predict
# 3. 创建knn算法分类器对象
knn_classifier = KNeighborsClassifier(n_neighbors = 6)
knn_classifier
# 4. 拟合训练原始样本,形成模型
knn_classifier.fit(x_train, y_train)
# 5. 利用模型进行待预测样本的标签值
y_predict = knn_classifier.predict(x1_predict)
y_predict[0]
2.3 仿sklearn中knn实现
kNN.py
import numpy as np
from math import sqrt
from collections import Counter
class KNNClassifier:
def __init__(self, k):
"""初始化KNN分类器"""
assert k >= 1, "k must be valid"
self.k = k
self._x_train = None
self._y_train = None
def fit(self, x_train, y_train):
"""根据训练数据集x_train 和 y_train 训练KNN分类器"""
assert x_train.shape[0] == y_train.shape[0],\
"the size of x_train must be equal to the size of y_train."
assert self.k <= x_train.shape[0],\
"the size of x_train must be at least k."
self.x_train = x_train
self.x_train = y_train
return self
def predict(self, x_predict):
"""给定待预测样本集x_predict,返回表时x_predict的结果向量"""
assert self.x_train is not None and self.y_train is not None,\
"must fit before predict."
assert x_predict.shape[1] == self.x_train.shape[1],\
"the feature number of x_predict must be equal to x_train"
y_predict = [self._predict(x) for i in x_predict]
return np.array(y_predict)
def _predict(self, x):
"""给定单个待预测样本x,返回x的标签值"""
assert x.shape[0] == self.x_train.shape[1],\
"the feature number of x must be equal to x_train"
distances = [sqrt(np.sum((x_train - x) ** 2)) for x_train in self.x_train]
nearest = np.argsort(distances)
topk_y = [self._y_train[i] for i in nearest[:self.k]]
votes = Counter(topk_y)
return votes.most_common(1)[0][0]
def __repr__(self):
return "KNN(k = %d)" % self.k
x_predict = np.array([8.093607318,3.365731514])
x1_predict = np.array([x_predict])
- 将kNN.py文件放入到和jupyter的代码相同的目录的knn目录下,在jupyter中利用魔法方法进行代码运行
# 利用魔法方法加载KNN.py文件
%run knn/KNN.py
# 创建实例
knn_clf = KNNClassifier(k = 6)
# 拟合训练集
knn_clf.fit(x_train, y_train)
# 预测输入样例
y_predict = knn_clf.predict(x1_predict)
# 得出预测结果
y_predict[0]
3. 划分数据集
3.1 作用
- 训练数据的过程下图所示,将所有的数据都作为训练数据,训练出一个模型,每当得到一个新的数据,则计算新数据到训练数据的距离,预测得到新数据的类别。
-
举例:银行发放信用卡,银行要想得到客户的信用等级,需要跟踪用户两三年时间来收集用户信息,才能得到,如果将两三年的数据全部作为训练集,当新客户来临时,又需要等待两三年,才能知道新用户的真实label,所以在短期内很难根据真实label判断模型好坏,进而无法改进模型。
-
结论:如果把所有数据都去训练,评估模型时需要再收集测试数据,周期长
3.2 应用
- 如下图:
- 原始数据集一般分成训练集和测试集
- 训练集参与模型训练,测试集不能参与训练,只能用作评估
- 考试案例
- 一般 2/8 3/7比例划分
- 上述将数据集进行切分的方式,就是
sklearn
中的train_test_split
from sklearn.model_selection import train_test_split
x_train,x_test,y_train,y_test = train_test_split(x,y,test_size=0.2)
代码
import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets
# 1. 获取sklearn中的内置数据集(鸢尾花)
iris = datasets.load_iris()
# 查看数据集的描述信息
# print(iris.DESCR)
# 1.1获取特征值
x = iris.data
# 1.2 获取标签值
y = iris.target
# 2. 将长度x对应的索引值进行随机排列s
shuffle_indexes = np.random.permutation(len(X))
# 3. 定义测试机的比例
test_ratio = 0.2
# 4. 得到测试集对应的数据量
test_size = int(len(x) * test_ratio)
# 5. 获取测试集的索引和训练集的索引
test_indexes = shuffle_indexes[:test_size]
train_indexes = shuffle_indexes[test_size:]
# 6. 获取训练数据集
x_train = x[train_indexes]
y_train = y[train_indexes]
# 7. 获取测试数据集
x_test = x[test_indexes]
y_test = y[test_indexes]
- 整合为代码model_selection.py:
import numpy as np
def train_test_split(X, y, test_ratio=0.2, seed=None):
"""将数据 X 和 y 按照test_ratio分割成X_train, X_test, y_train, y_test"""
assert X.shape[0] == y.shape[0], \
"the size of X must be equal to the size of y"
assert 0.0 <= test_ratio <= 1.0, \
"test_ration must be valid"
if seed:
np.random.seed(seed)
shuffled_indexes = np.random.permutation(len(X))
test_size = int(len(X) * test_ratio)
test_indexes = shuffled_indexes[:test_size]
train_indexes = shuffled_indexes[test_size:]
X_train = X[train_indexes]
y_train = y[train_indexes]
X_test = X[test_indexes]
y_test = y[test_indexes]
return X_train, X_test, y_train, y_test
- 放入
_init_.py
文件到knn
目录下,使其变为工程目录,以便于后面能够直接导入train_test_split
方法
测试封装的代码:
from knn.model_selection import train_test_split
x_train,x_test,y_train,y_test = train_test_split(x,y)
from knn.KNN import KNNClassifier
knn_clf = KNNClassifier(k=6)
knn_clf.fit(X_train,y_train)
y_predict = knn_clf.predict(X_test)
准确率计算:
(sum([1 if y_predict[i] == y_test[i] else 0 for i in range(len(y_test))]))/len(y_test)
sum(y_predict == y_test)/len(y_test)
5. 分类准确度
准确度用accuracy
表示:
5.1 代码实现准确率计算
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
from sklearn import datasets
# 1. 加载sklearn内置的手写数字集图片数据
digits = datasets.load_digits()
# 1.1 查看该数据集的描述信息
print(digits.DESCR)
# 1.2查看数据集的shape
# 1.3 获取特征值
X = digits.data
X.shape
# 1.4 获取标签值
y = digits.target
y.shape
# 3. 取出某个数据集绘制图像:
some_digit = X[666]
y[666]
# 4. 将数据集变为(8,8)的二维数据
some_digit_image = some_digit.reshape(8,8)
# 5. 绘制二维图片
plt.imshow(some_digit_image,cmap=matplotlib.cm.binary)
plt.show()
# 5. 利用knn算法进行分类预测
from knn.model_selection import train_test_split
X_train,X_test,y_train,y_test = train_test_split(x,y,test_ratio=0.2)
from knn.KNN import KNNClassifier
knn_clf = KNNClassifier(k=6)
knn_clf.fit(X_train,y_train)
y_predict = knn_clf.predict(X_test)
计算准确率:
sum(y_predict==y_test)/y_test.shape[0]
封装为代码metrics.py
import numpy as np
def accuracy_score(y_test, y_predict):
"""计算y_test和y_predict之间的准确率"""
assert len(y_test) == len(y_predict),\
"the size of y_true must be equal to the size of y_predict"
return np.sum(y_test == y_predict)/y_test.shape[0]
- 应用算法进行计算:
from knn.metrics import accuracy_score
accuracy_score(y_test,y_predict)
-
将准确率代码整合封装到kNN.py中
-
上述计算准确率的方式,必须用到
y_predict
,也就是必须进行预测 -
在实际开发的某些情况下,开发者可能不想去进行预测,直接得到准确率
修改kNN.py,代码如下:
from .metrics import accuracy_score
def score(self, x_test, y_test):
"""根据测试数据集 x_test 和 y_test 确定当前模型的准确度"""
y_predict = self.predict(x_test)
return accuracy_score(y_test, y_predict)
测试使用:
knn_clf.score(x_test,y_test)
5.2 sklearn中的accuracy_score
代码:
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
#划分数据集
x_train,x_test,y_train,y_test = train_test_split(x,y,test_size=0.2)
#训练knn模型
knn_classifier = KNeighborsClassifier(n_neighbors=6)
knn_classifier.fit(x_train,y_train)
#预测测试集
y_predict = knn_classifier.predict(x_test)
#计算准确率
from sklearn.metrics import accuracy_score
#方式1:
accuracy_score(y_test,y_predict)
#方式2:
knn_classifier.score(x_test,y_test)
6. 超参数
6.1 定义
- 超参数就是在运行机器学习算法之前需要指定值的参数
6.2 概念对比
超参数:在算法运行前需要指定的参数
模型参数:算法过程中学习的参数
6.3 寻找最优的超参数
- 领域知识
在不同的知识领域中,最优的超参数值不一样
- 经验数值
在处理问题时,存在一些较好的经验数值,可以借鉴。通常机器学习中会对超参数设置默认数值,这个值即为经验数值。sklearn中knn算法中的k值默认为5。
- 实验搜索
在处理具体问题中,经验数值不适用,则需要使用此项操作,来得到不同的超参数。
6.4 代码实现
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
from sklearn import datasets
digits = datasets.load_digits()
X = digits.data
y = digits.target
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
X_train,X_test,y_train,y_test = train_test_split(X,y,test_size=0.2)
knn_classifier = KNeighborsClassifier(n_neighbors=6)
knn_classifier.fit(X_train,y_train)
#得到评分数据
knn_classifier.score(X_test,y_test)
寻找最优的k值:
best_score = 0.0
best_k = -1
for k in range(1,11):
knn_classifier = KNeighborsClassifier(n_neighbors=k)
knn_classifier.fit(X_train,y_train)
score = knn_classifier.score(X_test,y_test)
print("k={}, score={}".format(k, score))
if score > best_score:
best_k = k
best_score = score
print("best_k =",best_k)
print("best_score =",best_score)
k-近邻算法判断结果的两种方式:
- 方式1:
考虑数量:
距离绿色点最近的三个点中,两个点均为蓝色,则结果绿色点预测为蓝色。
但是此时存在问题,绿色点距离红色点比蓝色点近,所以应将距离也作为判定因素考虑进去,这就是另外一种k-近邻算法的计算方式
- 方式2:
考虑距离:
一般将距离的倒数作为判定依据:
红色为1,蓝色为:1/3+1/4=7/12,则判断结果为红色
方式2的优点:解决平票问题
当绿色点的附近三个点均为不同颜色的点时,则为平票
此时考虑距离就可以很好的解决最终结果的选择问题。
- 在sklearn的官方问题中存在此问题的具体实现
-
参数weights默认为uniform,不考虑距离,如传入distance,则考虑距离。
-
考虑距离的代码实现:
best_score = 0.0
best_k = -1
for method in ["uniform","distance"]:
for k in range(1,11):
knn_classifier = KNeighborsClassifier(n_neighbors=k,weights=method)
knn_classifier.fit(X_train,y_train)
score = knn_classifier.score(X_test,y_test)
print("method = {},k={}, score={}".format(method, k, score))
if score > best_score:
best_k = k
best_score = score
best_method = method
print("best_method =",best_method)
print("best_k =",best_k)
print("best_score =",best_score)
7. 归一化
7.1 定义
- 每个特征的取值范围不同,保证每个特征对模型的影响都一样,因此要把每个特征转化到统一个范围
7.2 解释
-
观察如下样本数据,有两个样本,每个样本有两个特征,一个是肿瘤大小,一个是肿瘤的发现时间。
-
如利用欧拉距离计算上述两个样本的距离,由于两个特征的值差距较大,距离结果的值大小由发现时间决定。
如果此时修改发现时间的单位为年,则最终距离结果又由肿瘤大小决定。
- 综上所述,在训练模型时,如果特征之间的值差距较大,不能直接传入模型,需要对数据做归一化处理。
7.3 分类
1. 最值归一化(Normalization)
- x表示特征
- 本质:把所有数据映射到(0,1)之间
- 适用情况:
- 分布有明显边界
- 学生分数0-100有明显边界
- 图片像素点的值0-255有明显边界
- 分布有明显边界
- 缺点
- 受outlier(异常值)影响较大
- 观察公式,结果受x的max和min影响严重
- 受outlier(异常值)影响较大
- 实现
import numpy as np
import matplotlib.pyplot as plt
#随机生成长度为100的数值范围在0-100的一维数组
x = np.random.randint(0,100,size=100)
# 归一化代码实现
(x-np.min(x))/(np.max(x)-np.min(x))
# 随机生成shape为(50,2)的值范围在0-100范围内的二维数组
X = np.random.randint(0,100,(50,2))
X[:10,:]
# 转换数值类型为float
X = np.array(X,dtype=float)
X[:10,:]
# 对两个样本进行最值归一化
X[:,0]=(X[:,0]-np.min(X[:,0]))/(np.max(X[:,0])-np.min(X[:,0]))
X[:,1]=(X[:,1]-np.min(X[:,1]))/(np.max(X[:,1])-np.min(X[:,1]))
# 绘图观察数据分布
plt.scatter(X[:,0],X[:,1])
plt.show()
#观察均值和方差
np.mean(X[:,0])
np.std(X[:,0])
np.mean(X[:,1])
np.std(X[:,1])
2.均值方差归一化(standardization)
2.1 定义
- 把所有数据归一到均值为0方差为1的分布中(正态分布)
2.2 计算流程
- 标准差S:数据一列(身高)的离散程度
- 方差:
- 利用每个特征值减去特征值均值再除以特征值的方差得到均值方差归一化结果
2.3 适用情况
- 数据分布没有明显边界
2.4 优点
- 不容易受到极端数据值的影响
#随机生成shape为(50,2)数值范围在0-100范围内的二维数组
X2 = np.random.randint(0,100,(50,2))
#转换为float类型
X2 = np.array(X2,dtype=float)
#对两个样本进行均值方差归一化
X2[:,0] = (X2[:,0]-np.mean(X2[:,0]))/np.std(X2[:,0])
X2[:,1] = (X2[:,1]-np.mean(X2[:,1]))/np.std(X2[:,1])
#绘图显示
plt.scatter(X2[:,0],X2[:,1])
plt.show()
#观察均值和方差
np.mean(X2[:,0])
np.std(X2[:,0])
np.mean(X2[:,1])
np.std(X2[:,1])
- 通过对比发现,均值方差归一化能够将所有数据转换为均值为0,方差为1的范围内,更适合数据中存在极端数据的情况。
7.4 sklearn中的归一化
- 训练集和测试集的归一化
- 训练集和测试集均利用训练集得到的均值和方差来进行归一化处理
- sklearn中的归一化
- 将训练集交给scaler类,调用fit方法,将关键信息(均值、方差等)保存在scaler类中,再调用scaler类的transform方法,将训练集和测试集进行归一化转换。
代码实现:
import numpy as np
from sklearn import datasets
iris = datasets.load_iris()
X = iris.data
y = iris.target
X[:10,:]
from sklearn.model_selection import train_test_split
X_train,X_test,y_train,y_test = train_test_split(iris.data,iris.target,test_size=0.2,random_state=1)
#进行均值方差归一化处理
from sklearn.preprocessing import StandardScaler
ss = StandardScaler()
ss.fit(X_train,y_train)
ss.mean_
ss.scale_
#转换训练集和测试集
X_train1 = ss.transform(X_train)
X_test1 = ss.transform(X_test)
#对比准确率
from sklearn.neighbors import KNeighborsClassifier
knn_clf = KNeighborsClassifier(n_neighbors=3)
knn_clf.fit(X_train1,y_train)
knn_clf.score(X_test1,y_test)
knn_clf.score(X_test,y_test)
7.5 应用
- 利用MinMaxScaler对数据集进行归一化处理
8. 应用
需求:预测facebook签到位置
8.1 项目描述
- 本次比赛的目的是预测一个人将要签到的地方。 为了本次比赛,Facebook创建了一个虚拟世界,其中包括10公里*10公里共100平方公里的约10万个地方。 对于给定的坐标集,您的任务将根据用户的位置,准确性和时间戳等预测用户下一次的签到位置。 数据被制作成类似于来自移动设备的位置数据。 请注意:只能使用提供的数据进行预测。
8.2 数据集
- 数据介绍:
文件说明 train.csv, test.csv
row id:签入事件的id
x y:坐标
accuracy: 准确度,定位精度
time: 时间戳
place_id: 签到的位置,这也是你需要预测的内容
8.3 步骤分析
-
对于数据做一些基本处理(这里所做的一些处理不一定达到很好的效果,只是简单尝试,有些特征可以根据一些特征选择的方式去做处理)
-
1 缩小数据集范围 DataFrame.query()
-
2 选取有用的时间特征
-
3 将签到位置少于n个用户的删除
-
-
分割数据集
-
标准化处理
-
k-近邻预测
具体步骤:
1.获取数据集
2.基本数据处理
2.1 缩小数据范围
2.2 选择时间特征
2.3 去掉签到较少的地方
2.4 确定特征值和目标值
2.5 分割数据集
3.特征工程 -- 特征预处理(标准化)
4.机器学习 -- knn+cv
5.模型评估
8.4 代码实现
- 1.获取数据集
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.neighbors import KNeighborsClassifier
from sklearn.model_selection import GridSearchCV
# 1. 获取并查看数据集
facebook = pd.read_csv('./train1.csv')
facebook.head()
- 2.基本数据处理
# 2.基本数据处理
# 2.1 缩小数据范围
facebook_data = facebook.query("x>2.0 & x<2.5 & y>2.0 & y<2.5")
facebook_data
# 2.2 选择时间特征
time = pd.to_datetime(facebook_data["time"], unit="s")
time
time = pd.DatetimeIndex(time)
time
# 特征提取
facebook_data["day"] = time.day
facebook_data["hour"] = time.hour
facebook_data["weekday"] = time.weekday
facebook_data
# 2.3 去掉签到较少的地方
place_count = facebook_data.groupby("place_id").count()
place_count
place_count = place_count[place_count["row_id"]>3]
place_count
facebook_data = facebook_data[facebook_data["place_id"].isin(place_count.index)]
facebook_data
# 2.4 确定特征值和目标值
x = facebook_data[["x", "y", "accuracy", "day", "hour", "weekday"]]
x
y = facebook_data["place_id"]
y
# 2.5 分割数据集
X_train, X_test, y_train, y_test = train_test_split(x, y, random_state=22)
- 3.特征工程–特征预处理(标准化)
# 3.特征工程--特征预处理(标准化)
# 3.1 实例化一个转换器
ss = StandardScaler()
# 3.2 调用fit_transform
X_train = ss.fit_transform(X_train)
X_test = ss.transform(X_test)
- 4.机器学习–knn+cv
# 4.机器学习--knn+cv
# 4.1 实例化一个评估器
estimator = KNeighborsClassifier()
# 4.2 调用gridsearchCV
param_grid = {"n_neighbors": [1, 3, 5, 7, 9]}
estimator = GridSearchCV(estimator, param_grid=param_grid, cv=5)
# 4.3 模型训练
estimator.fit(X_train, y_train)
- 5.模型评估
# 5.模型评估
# 5.1 基本评估方式
score = estimator.score(X_test, y_test)
print("最后预测的准确率为:\n", score)
y_predict = estimator.predict(X_test)
print("最后的预测值为:\n", y_predict)
print("预测值和真实值的对比情况:\n", y_predict == y_test)
# 5.2 使用交叉验证后的评估方式
print("在交叉验证中验证的最好结果:\n", estimator.best_score_)
print("最好的参数模型:\n", estimator.best_estimator_)
print("每次交叉验证后的验证集准确率结果和训练集准确率结果:\n",estimator.cv_results_)
调用gridsearchCV
param_grid = {"n_neighbors": [1, 3, 5, 7, 9]}
estimator = GridSearchCV(estimator, param_grid=param_grid, cv=5)
# 网格搜索交叉验证