Knn算法学习

Knn 算法

邻近算法,或者说K最邻近(KNN,K-NearestNeighbor)分类算法是数据挖掘分类技术中最简单的方法之一。
所谓K最近邻,就是K个最近的邻居的意思,说的是每个样本都可以用它最接近的K个邻近值来代表。
近邻算法就是将数据集合中每一个记录进行分类的方法
  • 图解
    在这里插入图片描述

    》存在w1,w2,w3三种可能性结果
    》Knn 算法。处理给定预测数据Xu,计算出该预测数据属于哪一类结果的可能性。
    
    
     方式11:计算[预测数据]到所有训练集数据的距离
        2:指定K值 取前K个距离最近的数据
        3:评估最近的K个 到各个预测结果的概率 。便可预测数据的类别
        4:调整K值 重复2,3步骤。以得到合适和K和预测的准确性的平衡
      import numpy as np
      from sklearn import datasets
      from sklearn.model_selection import train_test_split
      # 读取iris数据
      iris = datasets.load_iris()
      # 数据源处理
      # data 和 target 进行合并
      iris_data = np.hstack((iris.data, iris.target.reshape(-1, 1)))
      # 拆分数据为 训练集和测试集
      train, test = train_test_split(iris_data, test_size=0.2)
      # 指定K值
      K = 5
      def forecast_data(item):
          forecast = item[:-1]
          distance_arr = []
          for data in train:
              target = data[-1]
              current = data[:-1]
              # 计算预测数据到训练数据的距离
              distance = np.sqrt(np.sum((current - forecast) ** 2))
              distance_arr.append([distance, target])
    
          distance_arr.sort(key=lambda item: item[0], reverse=False)
          # 取得距离最近的前K个数据
          use_data = distance_arr[0:K]
          result = np.array([0, 0, 0])
          for index in range(K):
              if use_data[index][1] == 0.0:
                  result[0] = result[0]+1
              elif use_data[index][1] == 1.0:
                  result[1] = result[1]+1
              elif use_data[index][1] == 2.0:
                  result[2] = result[2]+1
          # 得到预测结果
          result = np.stack((np.array([0, 1, 2]), result), axis=1).tolist()
          result.sort(
              key=lambda item: item[1], reverse=True)
          return result[0][0]
      # 
      if __name__ == '__main__':
          success, fail = 0, 0
          for item in test:
              exec = item[-1]
              forecast = forecast_data(item)
              if exec == forecast:
                  success += 1
              else:
                  fail += 1
      print('样本总数:', len(iris.data),'训练样本:'len(train),'测试样本:',len(test))
      print('success:', success, 'fail:', fail,'预测成功概率:',success/(success+fail))
    
      # 样本总数: 150 训练样本: 120 测试样本: 30
      # success: 28 fail: 2 预测成功概率: 0.9333333333333333
      
    
    方式2( 算法不一致 这里对数据进行加权后 计算概率)
    1:计算[预测数据]到所有训练集数据的距离
    2:评估数据 对各个数据进行加权计算 越近的数据权重越高。
    3:评估最近的K个 到各个预测结果的概率 。便可预测数据的类别
    
    import numpy as np
    from sklearn import datasets
    from sklearn.model_selection import train_test_split
    
    iris = datasets.load_iris()
    # 数据源处理
    # data 和 target 进行合并
    iris_data = np.hstack((iris.data, iris.target.reshape(-1, 1)))
    # 拆数据
    train, test = train_test_split(iris_data, test_size=0.2)
    
    # 权重计算 给定距离得到各个距离的权重
    def weights(distances):
     # print(distances.shape)
    	# 上面方式一 为 return np.ones(distances.shape) 就和方式一一样
    	# 权重直接影响预测的准确性
    	distance_max = np.sum(distances)
    	result = np.zeros(distances.shape)
    	for index in range(len(distances)):
        	result[index] = (distance_max - distances[index]
                         ) / distance_max
    
    	return result
    
    
    def forecast_data2(item, K=5):
    	forecast = item[:-1]
    	# print(train.shape,len(train))
    	distance_arr = []
    	for data in train:
        	target = data[-1]
        	current = data[:-1]
        	distance = np.sqrt(np.sum((current - forecast) ** 2))
        	distance_arr.append([distance, target])
    
     	distance_arr.sort(key=lambda item: item[0], reverse=False)
     	distance_list = distance_arr[0:K]
    	# 计算权重
    	distance_list, result_list = [
        np.ravel(item) for item in np.hsplit(np.array(distance_list), 2)]
    	weights_arr = weights(distance_list)
    	# 通过权重算出概率权重
    	result = np.array([0.0, 0.0, 0.0])
    	for index in range(K):
        	target = result_list[index]
       	 wei = weights_arr[index]
       	 print(target, wei)
       	 if target == 0.0:
       	     result[0] = result[0]+wei
       	 elif target == 1.0:
           	 result[1] = result[1]+wei
       	 elif target == 2.0:
          	  result[2] = result[2]+wei
    	result = np.stack((np.array([0, 1, 2]), result), axis=1).tolist()
    	result.sort(key=lambda item: item[1], reverse=True)
    	return result[0][0]
    
    if __name__ == '__main__':
    	success, fail = 0, 0
    	for item in test:
       	 	exec = item[-1]
        	# Knn 算法之二 加权算法
        	forecast = forecast_data2(item, K=5)
        	if exec == forecast:
           	 success += 1
        	else:
           	 fail += 1
    print('样本总数:', len(iris.data), '训练样本:', len(train), '测试样本:', len(test))
    print('success:', success, 'fail:', fail,
          '预测成功概率:', success/(success+fail))
    # 样本总数: 150 训练样本: 120 测试样本: 30
    # success: 29 fail: 1 预测成功概率: 0.9666666666666667
    
    
    方式3 使用现有KNN模型进行训练
    	from sklearn.neighbors import KNeighborsClassifier
    	# 使用 KNeighborsClassifier 对iris 数据进行Knn算法预测
    	# n_neighbors: int, 可选参数(默认为 5)
    	# weights(权重): str or callable(自定义类型), 可选参数(默认为 ‘uniform’)
    	#         用于预测的权重函数。可选参数如下:
    	#                - ‘uniform’ : 统一的权重. 在每一个邻居区域里的点的权重都是一样的。
    	#                - ‘distance’ : 权重点等于他们距离的倒数。使用此函数,更近的邻居对于所预测的点的影响更大。
    	#                - [callable] : 一个用户自定义的方法,此方法接收一个距离的数组,然后返回一个相同形状并且包含权重的数组。
    	# algorithm(算法): {‘auto’, ‘ball_tree’, ‘kd_tree’, ‘brute’}, 可选参数(默认为 'auto')
    	#         计算最近邻居用的算法:
    	#                - ‘ball_tree’ 使用算法[BallTree](http://scikit-learn.org/stable/modules/generated/sklearn.neighbors.BallTree.html#sklearn.neighbors.BallTree)
    	#                - ‘kd_tree’ 使用算法[KDTree](http://scikit-learn.org/stable/modules/generated/sklearn.neighbors.KDTree.html#sklearn.neighbors.KDTree)
    	#                - ‘brute’ 使用暴力搜索.
    	#                - ‘auto’ 会基于传入[fit](http://scikit-learn.org/stable/modules/generated/sklearn.neighbors.KNeighborsClassifier.html#sklearn.neighbors.KNeighborsClassifier.fit)方法的内容,选择最合适的算法。
    	#         注意 : 如果传入fit方法的输入是稀疏的,将会重载参数设置,直接使用暴力搜索。
    	#  leaf_size(叶子数量): int, 可选参数(默认为 30)
    	#         传入BallTree或者KDTree算法的叶子数量。此参数会影响构建、查询BallTree或者KDTree的速度,以及存储BallTree或者KDTree所需要的内存大小。 此可选参数根据是否是问题所需选择性使用。
    	#  p: integer, 可选参数(默认为 2)
    	#         用于Minkowski metric([闵可夫斯基空间](https://zh.wikipedia.org/wiki/%E9%96%94%E8%80%83%E6%96%AF%E5%9F%BA%E6%99%82%E7%A9%BA))的超参数。p = 1, 相当于使用[曼哈顿距离](https://zh.wikipedia.org/wiki/%E6%9B%BC%E5%93%88%E9%A0%93%E8%B7%9D%E9%9B%A2) (l1),p = 2, 相当于使用[欧几里得距离](https://zh.wikipedia.org/wiki/%E6%AC%A7%E5%87%A0%E9%87%8C%E5%BE%97%E8%B7%9D%E7%A6%BB)(l2)  对于任何 p ,使用的是[闵可夫斯基空间](https://zh.wikipedia.org/wiki/%E9%96%94%E8%80%83%E6%96%AF%E5%9F%BA%E6%99%82%E7%A9%BA)(l_p)
    	#  metric(矩阵): string or callable, 默认为 ‘minkowski’
    	#         用于树的距离矩阵。默认为[闵可夫斯基空间](https://zh.wikipedia.org/wiki/%E9%96%94%E8%80%83%E6%96%AF%E5%9F%BA%E6%99%82%E7%A9%BA),如果和p=2一块使用相当于使用标准欧几里得矩阵. 所有可用的矩阵列表请查询 DistanceMetric 的文档。
    	#  metric_params(矩阵参数): dict, 可选参数(默认为 None)
    	#         给矩阵方法使用的其他的关键词参数。
    	#  n_jobs: int, 选参数(默认为 1)
    	#         用于搜索邻居的,可并行运行的任务数量。如果为-1, 任务数量设置为CPU核的数量。不会影响[fit](http://scikit-learn.org/stable/modules/generated/sklearn.neighbors.KNeighborsClassifier.html#sklearn.neighbors.KNeighborsClassifier.fit)方法。
    
    	from sklearn import datasets
    	from sklearn.model_selection import train_test_split
    	from sklearn.metrics import accuracy_score
    	import numpy as np
    
    	iris_data = datasets.load_iris()
    	data_all = iris_data.data
    	target_all = iris_data.target.reshape(-1, 1)
    	data = np.hstack((data_all, target_all))
    	# 数据拆分
    	train, test = train_test_split(data, test_size=0.2)
    	'''
    	n_neighbors 对于值
    	algorithm:指定算法
    	weights 权重函数
    	'''
    	knn = KNeighborsClassifier(n_neighbors=3)
    	train_X = train[:, :4]
    	train_Y = train[:, -1]
    
    	# 训练
    	knn.fit(train_X, train_Y)
    
    	# 预测
    	test_X = test[:, :4]
    	test_y = test[:, -1]
    	predict_result = knn.predict(test_X)
    
    	print('样本总数:', len(data_all), '训练样本:',len(train), '测试样本:', len(test))
    	print('预测成功概率:', accuracy_score(test_y, predict_result))
    
    	样本总数: 150 训练样本: 120 测试样本: 30
    	预测成功概率: 0.9333333333333333
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值