一:K邻近算法介绍:

  • 1:首先要有原始已知标签的数据。
  • 2:把需要预测的点和所有已知的点计算距离。
  • 3:找到和待遇测点最近的K个点。
  • 4:根据K个点的标签确定待测点的标签。
  • KNN算法可以做回归问题,也可以做分类问题。
  • knn算法没有得到模型,它是机器学习中唯一一个不需要训练过程的算法。

1:欧拉距离:

(二)机器学习---K近邻算法(KNN)_归一化

2:使用K邻近算法实现分类:

1:准备特征值和标签值:

import numpy as np
import matplotlib.pyplot as plt

# 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]]

# 2:定义特征值的属性(0,1是上面标签的类别)
raw_data_y=[0,0,0,0,0,1,1,1,1,1]

# 3:转换成numpy的多维数组
X_train = np.array(raw_data_x)
y_train = np.array(raw_data_y)

2:验证多维数组的方法:
(二)机器学习---K近邻算法(KNN)_其他_02

3:利用matplotlib绘制图像:

#利用matplotlib绘制图像
plt.scatter(X_train[y_train==0,0],X_train[y_train==0,1],color='g')
plt.scatter(X_train[y_train==1,0],X_train[y_train==1,1],color='r')
plt.show()

(二)机器学习---K近邻算法(KNN)_归一化_03
4:加入预测点,再次绘制图像:

# 创建预测点数组
x=np.array([8.093607318,3.365731514])
plt.scatter(X_train[y_train==0,0],X_train[y_train==0,1],color='g')
plt.scatter(X_train[y_train==1,0],X_train[y_train==1,1],color='r')
# 将预测点加入图中
plt.scatter(x[0],x[1],color='b')
plt.show()

(二)机器学习---K近邻算法(KNN)_其他_04
5:实现距离计算:

from math import sqrt # 开根号的函数
# 1: 现在X_train二维数组中,取出每个的一维数组
# 一维数组和一维数组之间可以直接相减 x_train - x 即:[3.3144558 , 2.33542461] - [8.093607318,3.365731514]
# **2 指的是将差值的一维数组,每个数都平方操作。
# np.sum(平方后的一维数组)就是一维数组求和
# sqrt(数):就是求出的最后的开平方后的和

# 最后拿到的数据是个数组,就是各个点到预测点的距离。
distances = [sqrt(np.sum((x_train-x)**2)) for x_train in X_train]
print(distances)
# 对计算的距离进行排序:根据数值进行排序,返回的是排序后的下标
nearest = np.argsort(distances)
# 打印下标
print(nearest)

(二)机器学习---K近邻算法(KNN)_数据集_05
6:定义k值,得出计算结果:

k=6

# 获取距离最近的前k个数据的下标,拿到的是最近的6个数的便签值。
topK_y = [y_train[i] for i in nearest[:k]]

#统计每个y值出现的次数
from collections import Counter

# 拿到的是值与数量的字典
votes = Counter(topK_y)
print(votes) # Counter({1: 5, 0: 1})

#获取出现次数最多的那个y的取值
print(votes.most_common(1)) # [(1, 5)],返回一个数组,先按频数排序,如果频率相同,则按照字母排序。
predict_y = votes.most_common(1)[0][0] # 取出数组的第一个元祖的,元祖第一个位置(key)
print(predict_y)# 这个就应该是该元素的便签值

3: sklearn中knn算法的应用:

1:安装sklearn :
(二)机器学习---K近邻算法(KNN)_数据集_06
2:使用sklearn进行预测:
(二)机器学习---K近邻算法(KNN)_一维数组_07

# 1: 导包
from sklearn.neighbors import KNeighborsClassifier

#2:创建knn算法的分类器实例,选取最近的6个点
knn_classifier = KNeighborsClassifier(n_neighbors=6)

#拟合训练数据
knn_classifier.fit(X_train,y_train)

#将样本维度变为二维,因为我训练的维度就是二维的。
x1 = x.reshape(1, -1)

#利用knn算法进行预测
y_predict = knn_classifier.predict(x1)

#得出预测结果
y_predict[0]
# 输出 1

4:自己写代码模拟KNN算法(了解):

1:自己定义一个KNN算法:

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._y_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 x 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

2:将kNN.py文件放入到和jupyter的代码相同的目录下,在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)
#得出预测结果
y_predict[0]

二:划分数据集:

  • 一般要将数据集划分成测试集和训练集。
  • 训练集参与模型训练,测试集不参与模型训练,只用作评估。一般2/8分。

1:自己模拟实现:

1: 加载数据:

import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets

2: 获取特征值和目标值:

#获取sklearn中的内置数据集
iris = datasets.load_iris()
print(iris.data) # 获取特征值(多维数组)
print(iris.target)# 获取标签值(目标值,一维数组)

(二)机器学习---K近邻算法(KNN)_归一化_08
3:划分测试集和训练集:

思路:1:先求测试集/训练集的长度,根据长度生成随机的一个列表。
2:根据随机比例,和训练集长度,将列表划分成两部分,一部分存储的是训练集的下标,另一部分存储的是测试集的下标。
3:然后根据这个列表,划分测试集和训练集。

X = iris.data
y = iris.target

# 1:将长度X对应的索引值进行随机排列,返回的是打乱顺序的列表。
shuffle_indexes = np.random.permutation(len(X))

#2: 定义测试机的比例
test_ratio = 0.2

#3: 得到测试集对应的数据量
test_size = int(len(X) * test_ratio)

#4:获取测试集的索引和训练集的索引
test_indexes = shuffle_indexes[:test_size] # 测试集的索引
train_indexes = shuffle_indexes[test_size:]# 训练集的索引

#获取训练数据集
X_train = X[train_indexes]
y_train = y[train_indexes]

#获取测试数据集
X_test = X[test_indexes]
y_test = y[test_indexes]

2:封装成工具类:

1:C:\Users\11737\knn,在knn文件夹中创建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

2: C:\Users\11737\knn中新建_init_.py文件,使其变为工程目录,以便于后面能够直接导入train_test_split方法。
(二)机器学习---K近邻算法(KNN)_数据集_09
3:测试封装后的代码:

import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets
#获取sklearn中的内置数据集
iris = datasets.load_iris()
X = iris.data # 特征值
y = iris.target # 目标值
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) # 测试集进行预测

(二)机器学习---K近邻算法(KNN)_数据集_10

3:使用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)

三:划分精确度:

1:自己实现:

1: 加载数据:
(二)机器学习---K近邻算法(KNN)_数据集_11
2:拿出一个数据测试:
(二)机器学习---K近邻算法(KNN)_数据集_12
(二)机器学习---K近邻算法(KNN)_一维数组_13
3:使用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] # 计算准确率

(二)机器学习---K近邻算法(KNN)_一维数组_14

2:封装成工具类使用:

1:计算精确度的代码进行封装:
新建一个文件专门用来计算精确度:C:\Users\11737\knn
(二)机器学习---K近邻算法(KNN)_一维数组_15
2:kNN.py创建一个方法,直接能调用这个方法,得到准确率:

def score(self, X_test, y_test):
        """根据测试数据集 X_test 和 y_test 确定当前模型的准确度"""

        y_predict = self.predict(X_test)
        return accuracy_score(y_test, y_predict)

3: 进行测试:

knn_clf.score(X_test,y_test)

3:直接调用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
# 使用accuracy_score
accuracy_score(y_test,y_predict)

四:超参数:

1:超参数概念:

(二)机器学习---K近邻算法(KNN)_一维数组_16

2:代码实现寻找最优K值:

1: 先用一个随机的K测试:

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)

得到的准确率是:0.9888888888888889

2:寻找最优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近邻算法(KNN)_归一化_17
(二)机器学习---K近邻算法(KNN)_其他_18

3:K近邻算法的优化:

1: 存在的问题:
(二)机器学习---K近邻算法(KNN)_归一化_19
(二)机器学习---K近邻算法(KNN)_数据集_20
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)

        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)

(二)机器学习---K近邻算法(KNN)_一维数组_21
注意第二次的时候,只考虑距离,跟数值就没关系了,即使个数很多,我们也要选择距离近的那个。

五:归一化:

1:为什么要归一化:

问题:我们有两个样本,每个样本有两个特征,一个是肿瘤大小,一个是肿瘤的发现时间。

(二)机器学习---K近邻算法(KNN)_数据集_22

2:归一化的方式?

1:最值归一化:
(二)机器学习---K近邻算法(KNN)_其他_23
2:均值方差归一化:
(二)机器学习---K近邻算法(KNN)_数据集_24

3:代码实现归一化:

1: 一维数组最值归一化:
(二)机器学习---K近邻算法(KNN)_归一化_25
2:二维数组归一化:
(二)机器学习---K近邻算法(KNN)_一维数组_26
3:均值方差归一化:

#随机生成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])

(二)机器学习---K近邻算法(KNN)_其他_27

4:sklearn中的归一化:

1: 数据的准备:

import numpy as np
from sklearn import datasets

iris = datasets.load_iris()
X = iris.data
y = iris.target

# 划分训练集和测试集
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)

2:进行归一化处理:

# 进行均值方差归一化处理
from sklearn.preprocessing import StandardScaler
# 1:创建对象
ss = StandardScaler()
# 2:学习均值和方差
ss.fit(X_train,y_train)

print(ss.mean_)# 内部的均值
print(ss.scale_) # 内部的方差

#3:转换训练集和测试集
X_train1 = ss.transform(X_train)
X_test1 = ss.transform(X_test)

3: 对归一化和没有归一化的进行测试:
(二)机器学习---K近邻算法(KNN)_一维数组_28