最基础的分类算法-k近邻算法(k-Nearest Neighbors) KNN

  1. 思想极度简单
  2. 应用数学知识少(近乎为零)
  3. 效果好(缺点?)
  4. 可以解释机器学习算法使用过程中的很多细节问题
  5. 更完整的刻画机器学习应用的流程


在这里插入图片描述本质就是看新来的样本和最近的k个样本中,以他们自己的结果给这个新来的样本进行投票,得到新来的样本的概率,本质是认为两个样本足够的相似,大概认为该样本属于哪个类别.相似性,就是在特征空间的距离.

主要解决分类问题

数据准备

import numpy as np
import matplotlib.pyplot as plt
raw_data_X = [
    [3.393533211,2.331273381],
    [3.110073483,1.781539638],
    [1.343808831,3.368360954],
    [3.582294042,4.679179110],
    [2.280362439,2.866990263],
    [7.423436942,4.696522875],
    [5.745051997,3.533989803],
    [9.172168622,2.511101045],
    [7.792783481,3.424088941],
    [7.939820817,0.791637231]
]
raw_data_y = [0,0,0,0,0,1,1,1,1,1]
X_train = np.array(raw_data_X)
y_train = np.array(raw_data_y)

在这里插入图片描述绘图看看数据
在这里插入图片描述假设我们新来了一个样本,我们要推测出他是什么类型的数据
继续绘制一个图,让我们看看在数据空间中他所处的位置是什么
在这里插入图片描述

KNN的过程

根据KNN的思想,我们应该找出来他相邻的k个元素的距离
这时我们就需要用到数学中的一个公式 叫做欧拉距离
在这里插入图片描述上面的公式,可以写成下面这种形式,是不是更加简洁一些呢!
在这里插入图片描述首先我们应该求出所有样本距离他的距离

from math import sqrt 
distances =[]
for x_train in X_train:
    d= sqrt(np.sum((x_train - x)**2))   
    distances.append(d)

在这里插入图片描述得到他的距离之后,我们进行排序 求前K个,这时我们假定他的k为6
这时我们就可以对他进行排序取前6个了
注意:这时我们使用的是argsort 因为使用这个方法会得到他排序前的索引值,这样可以和之前的y向量一一对应的索引,可以直接得到他的类别信息

nearest = np.argsort(distances)
k =6
topK_y =  [y_train[i] for i in nearest[:k]]
topK_y

取出前6个之后,我们需要得到他出现次数最多的那个类别,这时我们需要用到python带有的Counter类来获取出现最多的那个类别.

from collections import Counter
Counter(topK_y)
votes = Counter(topK_y)
votes.most_common(1)[0][0]
predict_y = votes.most_common(1)[0][0]
predict_y

在这里插入图片描述
这时我们就得到了他的推测结果为1这个类别的数据!

我们了解了KNN算法的原理了,我们可以尝试简单封装一下这个KNN算法成为一个方法,这样为了后续的操作更加简单.

scikit-learn的机器学习算法封装

对KNN简单封装后:

import numpy as np
from math import sqrt
from collections import Counter

def KNN_classify(k,X_train,y_train,x):
    assert k>=1 ,"k 必须大于1"
    assert X_train.shape[0] == y_train.shape[0],"矩阵的行数和向量的列必须相等!"
    assert X_train.shape[1] == x.shape[0] ,"矩阵的列必须和传进来的样本的列相等!"

    distances = []
    for x_tarin in X_train:
       d=  sqrt(np.sum((x_tarin-x)**2))
       distances.append(d)
    nearset = np.argsort(distances)
    topK_y = [y_train[i] for i in nearset[:k]]
    votes_res = Counter(topK_y).most_common(1)[0][0]
    return votes_res

测试一下

%run mymodule/KNN.py
KNN_classify(6,X_train,y_train,x)

在这里插入图片描述

什么是机器学习呢?

在这里插入图片描述可以说KNN是一个不需要训练过程的算法*

  1. K近邻算法是非常特殊的,可以被认为是没有模型的算法
  2. 为了和其他算法统一,可以认为训练数据集就是模型本身

如何使用scikt-learn中的KNN算法呢

from sklearn.neighbors import KNeighborsClassifier
kNN_classifier =  KNeighborsClassifier(n_neighbors=6)
kNN_classifier.fit(X_train,y_train)
# 接收的数据是一个二维数组类型,需要进行重整,不然就会报错
kNN_classifier.predict(x.reshape(1,-1))

在这里插入图片描述看到这里我们发现,比我们的多了一个fit的步骤,这时我们对我们写的方法进行进一步的封装,因为机器学习中,我们应当有一个训练的过程得到模型,但是我们这里是没有的,为了机器学习的通用性我们将进行fit操作

模仿scikt-learn进行封装我们自己的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_tarin,y_train):
        """根据训练数据集X_tarin 和y_tarin"""
        assert X_tarin.shape[0] == y_train.shape[0], "矩阵的行数和向量的列必须相等!"
        assert X_tarin.shape[0] >= self.k, "矩阵的行必须大于传进来的k!"
        self._X_train = X_tarin
        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,\
        """必须先进行fit操作"""
        assert X_predict.shape[1] == self._X_train.shape[1],\
        """样本的数据集必须和训练数据集的维度一致"""
        y_predict = [self._predict(x) for x in X_predict]
        return np.array(y_predict)
    def _predict(self,x):
        assert self._X_train.shape[1] == x.shape[0], "矩阵的列必须和传进来的样本的列相等!"
        distances = []
        for x_tarin in self._X_train:
            d = sqrt(np.sum((x_tarin - x) ** 2))
            distances.append(d)
        nearset = np.argsort(distances)
        topK_y = [self._y_train[i] for i in nearset[:self.k]]
        votes_res = Counter(topK_y).most_common(1)[0][0]
        return votes_res
    def __repr__(self):
        return "KNN(k=%d)" %self.k

在这里插入图片描述

判断我们机器学习算法的性能

在这里插入图片描述在这里插入图片描述
在我们进行判断模型是否准确的时候,我们遇到了困难,怎么看你的模型是否好用,结果正确的比例是多少,
这个时候我们需要进行数据的拆分,将数据分为训练数据以及测试数据来观察数据的准确性的百分比是多少

import numpy as np

def train_test_split(X,y,test_ratio=0.2,seed=None):
    """将数据 X 和 y 按照test_ratio分割成X_tarin,X_test,y_tarin,y_test"""
    assert X.shape[0] == y.shape[0],\
    "矩阵的行数必须和向量的列数相同"
    assert 0.0<=test_ratio<=1.0,\
    "输入的比例非法"
    if seed:
        np.random.seed(seed)
    X = np.concatenate([X, y.reshape(-1, 1)], axis=1)
    np.random.shuffle(X)
    X,y = np.hsplit(X,[X.shape[1]-1])
    y = y.reshape(1,-1)[0]
    test_size = int(len(X) * test_ratio)
    X_test = X[:test_size]
    X_train= X[test_size:]
    y_test = y[:test_size]
    y_train = y[test_size:]
    return X_train,X_test,y_train,y_test

在这里插入图片描述数据准备好了,我们来进行测试一下

from playML.KNN import KNNClassifier
my_knn = KNNClassifier(k=3)
my_knn.fit(X_train,y_tarin)
y_predict = my_knn.predict(X_test)
y_predict
y_test
sum(y_predict == y_test)/len(y_test)

在这里插入图片描述
当然sklearn中也提供了相应的方法,供我们进行数据的拆分

在这里插入图片描述当然 sklearn中也实现了数据准确率的计算,但是有时候我们不需要知道,模型的结果,只想知道这个模型的准确率怎么样
我们要进行进一步的封装.


def accuracy_score(y_true,y_predict):
    """计算y_true和y_predict之间的准确率"""
    assert y_true.shape[0] ==y_predict.shape[0],\
    "这俩的维度必须相等"
    return  sum(y_true==y_predict)/len(y_true)

在这里插入图片描述

import numpy as np
from .metrics import accuracy_score
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_tarin,y_train):
        """根据训练数据集X_tarin 和y_tarin"""
        assert X_tarin.shape[0] == y_train.shape[0], "矩阵的行数和向量的列必须相等!"
        assert X_tarin.shape[0] >= self.k, "矩阵的行必须大于传进来的k!"
        self._X_train = X_tarin
        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,\
        """必须先进行fit操作"""
        assert X_predict.shape[1] == self._X_train.shape[1],\
        """样本的数据集必须和训练数据集的维度一致"""
        y_predict = [self._predict(x) for x in X_predict]
        return np.array(y_predict)
    def _predict(self,x):
        assert self._X_train.shape[1] == x.shape[0], "矩阵的列必须和传进来的样本的列相等!"
        distances = []
        for x_tarin in self._X_train:
            d = sqrt(np.sum((x_tarin - x) ** 2))
            distances.append(d)
        nearset = np.argsort(distances)
        topK_y = [self._y_train[i] for i in nearset[:self.k]]
        votes_res = Counter(topK_y).most_common(1)[0][0]
        return votes_res
    def score(self,X_test,y_test):
        y_predict = self.predict(X_test)
        return accuracy_score(y_test,y_predict)
    def __repr__(self):
        return "KNN(k=%d)" %self.k

在这里插入图片描述

让我们来继续测试一下
在这里插入图片描述
在这里插入图片描述
来看看sklearn封装好的
在这里插入图片描述

超参数和模型参数

  1. 超参数:在算法运行前需要决定的参数
  2. 模型参数:算法过程中学习的参数
  3. KNN算法中没有模型参数
  4. KNN算法中的K是典型的超参数

在我们KNN算法中,我们之间使用的仅仅是K这个超参数,其实还有很多参数
例如method(有没有距离权重问题),p(明可夫斯基距离)…
接下来我们简单的搜索一下,复合我们算法比较好的超参数

import numpy as np
from sklearn import datasets
digits = datasets.load_digits()
X = digits.data
y = digits.target
from sklearn.model_selection import train_test_split
Xtrain,Xtest,ytrain,ytest = train_test_split(X,y,test_size=0.2,random_state = 666)
from sklearn.neighbors import KNeighborsClassifier
knn = KNeighborsClassifier(n_neighbors=3)
knn.fit(Xtrain,ytrain)
knn.score(Xtest,ytest)
bestscore = 0.0
besk_k = -1
for k in range(1,11):
    knn = KNeighborsClassifier(k)
    knn.fit(Xtrain,ytrain)
    score = knn.score(Xtest,ytest)
    if(score>bestscore):
        besk_k=k
        bestscore=score
print("best_k",besk_k)
print("best_score",bestscore)

在这里插入图片描述
这时我们找到了最好的k是4
再继续寻找method
在这里插入图片描述
再继续找明可夫斯基距离的p这个最好的超参数

在这里插入图片描述

网格搜索

可以搜索你想要的超参数中在该数据集中比较好的参数

param_grid = [
    {'weights':['uniform'],
    'n_neighbors':[i for i in range(1,11)]},
    {
        'weights':['distance'],
    'n_neighbors':[i for i in range(1,11)],
        'p':[i for i in range(1,6)]
    }
]
knn = KNeighborsClassifier()
from sklearn.model_selection import GridSearchCV
grid_search = GridSearchCV(knn,param_grid)
%%time
grid_search.fit(Xtrain,ytrain)

在这里插入图片描述得到knn对象

grid_search.best_estimator_

在这里插入图片描述得到成绩

grid_search.best_score_

在这里插入图片描述
得到参数

grid_search.best_params_

在这里插入图片描述在使用的时候可以加入两个参数,一个是当前使用的核心数,第二个就是打印执行进度
在这里插入图片描述可以明显看到 数据快了很多

数据归一化

在这里插入图片描述将所有的数据映射到同一尺度
在这里插入图片描述
适用于分布有明显边界的情况;受outlier影响较大

在这里插入图片描述
最值归一化

X = np.random.randint(0,100,(50,2))
X[:10,:]
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]))

在这里插入图片描述均值方差归一化

X2 = np.random.randint(0,100,(50,2))
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])

在这里插入图片描述在这里插入图片描述看看sklearn自带的数据归一化我们怎么使用

#数据准备
iris = datasets.load_iris()
X=iris.data
y = iris.target
from sklearn.model_selection import train_test_split
Xtrain,Xtest,ytrain,ytest = train_test_split(iris.data,iris.target,random_state=666,test_size=0.2)
from sklearn.preprocessing import StandardScaler
standardScaler = StandardScaler()
standardScaler.fit(Xtrain)
Xtrain_standard = standardScaler.transform(Xtrain)
Xtest_standard = standardScaler.transform(Xtest)
from sklearn.neighbors import KNeighborsClassifier
knn = KNeighborsClassifier(3)
knn.fit(Xtrain_standard,ytrain)
knn.score(Xtest_standard,ytest)

在这里插入图片描述

KNN算法缺点

在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
项目1:基于sklearn的数据分挖掘 一、项目任务 熟悉sklearn数据挖掘的基本功能。 进行用朴素贝叶斯、KNN、决策树C4.5、SVM算法进行数据分分析。 二、项目环境及条件 sklearn-0.18.0 python-2.7.13 numpy-1.11.3+mkl-cp27-cp27m-win_amd64 scipy-0.19.0-cp27-cp27m-win_amd64 matplotlib-1.5.3-cp27-cp27m-win_amd64 三、实验数据 Iris数据集 Iris数据集是常用的分实验数据集,由Fisher, 1936收集整理。Iris也称鸢尾花卉数据集,是一多重变量分析的数据集。数据集包含 150个数据集,分为3,每50个数据,每个数据包含4个属性。可通过花萼长度,花萼 宽度,花瓣长度,花瓣宽度4个属性预测鸢尾花卉属于(Setosa,Versicolour,Virgin ica)三个种中的哪一。 Digits数据集 美国著名数据集NIST的子集,模式识别常用实验数据集,图像属于灰度图像。分辨率 为8x8 四、项目内容及过程 1.读取数据集 从sklearn中读取iris和digits数据集并测试打印 "from sklearn import datasets " " " "iris = datasets.load_iris() " "digits = datasets.load_digits() " "print 'iris:',iris.data,'\ndigits:',digits.data " 打印的数据集存在numpy.ndarray中,ndarray会自动省略较长矩阵的中间部分。 Iris数据集的样本数据为其花瓣的各项属性 Digits数据集的样本数据为手写数字图像的像素值 2.划分数据集 引入sklearn的model_selection使用train_test_split划分digits数据集,训练集和测 试集比例为8:2 "from sklearn.model_selection import train_test_split " "x_train,x_test,y_train,y_test=train_test_split(digits.data,digits.t" "arget,test_size=0.2) " "print " "'x_train:',x_train,'\nx_test:',x_test,'\ny_train:',y_train,'\ny_tes" "t:',y_test " 3.使用KNN和SVM对digits测试集分 引用sklearn的svm.SVC和neighbors.KNeighborsClassifier模块调用算法,使用classi fication_report查看预测结果的准确率和召回率 "from sklearn.metrics import classification_report " " " "from sklearn import neighbors " "clf = neighbors.KNeighborsClassifier() " "clf.fit(x_train,y_train) " "y_pred=clf.predict(x_test) " "print classification_report(y_test, y_pred) " " " "from sklearn.svm import SVC " "clf = SVC() " "clf.fit(x_train,y_train) " "y_pred=clf.predict(x_test) " "print classification_report(y_test, y_pred) " KNN的预测结果:所有数字的预测正确率几乎达到了100% SVM的预测结果:对部分数字的预测误差较大,基本情况不如KNN 考虑SVM分器的特性,在分前对特征值进行标准化后再分: "from sklearn import preprocessing " "min_max_scaler = preprocessing.MinMaxScaler() " "x_train = min_max_scaler.fit_transform(x_train) " "x_test = min_max_scaler.fit_transform(x_test) " 标准化数据后SVM的预测结果达到了KNN的准度: 4.使用贝叶斯和决策树对iris数据集分 "from sklearn.model_selection import train_test_split " "x_train,
鸢尾花数据集-数据分析 from sklearn import datasets import pandas as pd import matplotlib.pyplot as plt import numpy as np # 获取鸢尾花数据集 lris_df = datasets.load_iris() # 输⼊特征 lris_df.data # ⽬标特征 lris_df.target data_DF = pd.DataFrame(lris_df.data) target_DF = pd.DataFrame(lris_df.target) # dataframe按列拼接 join_DF = pd.concat([data_DF,target_DF],axis=1) # 修改列名 join_DF.columns=['sepal-length','sepal-width','petal-length','petal-width','class'] # 查看数据分布 x_axis = lris_df.data[:,0] y_axis = lris_df.data[:,2] plt.scatter(x_axis,y_axis,c=lris_df.target) plt.show() # 输⼊特征直⽅图分布 join_DF.iloc[:,0:4].hist() plt.show() # 箱线图 join_DF.iloc[:,0:4].plot(kind='box',subplots=True,layout=(2,2),sharex=False,sharey=False) plt.show() ft_DF = join_DF.iloc[:,0:4] # 相关系数 ft_DF.corr() x_val=ft_DF['petal-width'] y_val=ft_DF['petal-length'] plt.scatter(x_val,y_val) data_array = join_DF.values from sklearn import model_selection # 数据集划分 X = data_array[:,0:4] Y = data_array[:,4] validation_size = 0.2 seed = 6 X_train,X_validation,Y_train,Y_validation = model_selection.train_test_split(X,Y,test_size=validation_size,random_state=seed) # KNN from sklearn.neighbors import KNeighborsClassifier knn = KNeighborsClassifier() knn.fit(X_train,Y_train) knn.fit(X_train,Y_train) print(knn.score(X_validation,Y_validation)) # K折交叉验证 from sklearn.model_selection import cross_val_score scores = cross_val_score(knn,X,Y,cv=5,scoring='accuracy') print(scores) from sklearn.model_selection import KFold dfold = model_selection.KFold(n_splits=10,random_state=7) from sklearn import model_selection import matplotlib.pyplot as plt X=lris_df.data Y=lris_df.target k_range = range(1,31) k_scores = [] for k in k_range: knn = KNeighborsClassifier(n_neighbors=k) #调整K值 scores = model_selection.cross_val_score(knn,X,Y,cv=10,scoring='accuracy') k_scores.append(scores.mean()) plt.plot(k_range,k_scores) plt.xlabel('value of K for KNN') plt.ylabel('Cross-Validated Accuracy') plt.show()

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值