KNN与线性分类器

    xiaoxiao2024-11-28  72

    问题:

    图像分类:我们给出了一组标记图像的训练集,要求预测测试集上的标签。

    KNN(K最近邻算法 K-NearestNeighbor):

    所谓K近邻算法,即是给定一个训练数据集,对新的输入实例,在训练数据集中找到与该实例最邻近的K个实例(也就是上面所说的K个邻居), 这K个实例的多数属于某个类,就把该输入实例分类到这个类中。

    如何判断两张图片的不同:

    曼哈顿算法(L1)

    每张图片由大量的像素点组成(0-255),两者像素点相减并求和,如果相同则应该为0

    欧式距离算法(L2)

    使用平方开根号的方法定义距离

    困难:

    使用哪种距离算法如何确定超参数K,参数取什么工作的最好(交叉验证等)

    overfit问题: 某一种类别的数据过大时可能会存在误判的情况。当过于的追求准确度而增大K值,则可能会出现overfit问题

    KNN在图片处理上已经不用

    当图片出现偏移,灰度不同问题时,使用L2都会使判断出现误差,这是不可避免的

    线性分类器:

    线性分类器

    构造一个函数,输入一张图片,对每一类输出一个数值

    例子:

    假设pixel是单列的,有三个类别,有如下结果: 损失函数

    分类器(W)不一定按照我们的想法工作的很好,损失函数的作用就是量化分类器(W)的好坏


    实现:

    环境

    pythonnumpyscikit-learn

    scikit-learn是面向机器学习的Python开源框架,scikit-learn可以在一定范围内为开发者提供非常好的帮助。它内部实现了各种各样成熟的算法,容易安装和使用,样例丰富,而且教程和文档也非常详细。

    在scikit-learn的datasets数据集种有多种多样的数据库帮助学习,本例使用iris集(某种花),它有4种属性,3个类别

    from sklearn import datasets # 一种花的数据集 iris=datasets.load_iris() # 花的属性 iris_x=iris.data # 花的类别 iris_y=iris.target print(iris_x) print(iris_y)

    上图截取一部分打印,分割线以上为数据属性集(data),下面为标签集,可以看到有4个属性,3个类别,每一行对应一类

    创建KNN

    #用于分割数据集 from sklearn.model_selection import train_test_split # KNN对象 from sklearn.neighbors import KNeighborsClassifier # 将数据分为测试部分和训练部分,训练部分占比30% # 同时将数据打乱,增加数据的随机性 X_train,X_test,y_train,y_test=train_test_split(iris_x,iris_y,test_size=0.3) # 实例化一个KNN knn=KNeighborsClassifier() # 传入data、label 进行训练train knn.fit(X_train,y_train) # 将测试数据传入已经训练好的model种,获取label print(knn.predict(X_test)) print('----------') # 对比y_test 查看效果 print(y_test)

    可以看到训练train效果很好,几乎100%,只判断错了,但是也从另一方面说明再好的机器学习也会有误差

    创建线性分类器

    from sklearn import datasets import matplotlib.pyplot as plt from sklearn.linear_model import LinearRegression lr=LinearRegression()#y=wx+b #随机生成数据 #也可以同上加载显现有数据 X,y=datasets.make_regression(n_samples=100,n_features=100,n_targets=30,noise=1000) lr.fit(X,y) print("获取W:",lr.coef_) print("获取b:",lr.intercept_) print("获取分数(吻合程度):",lr.score(X,y))

    scikit-learn补充:

    当数据项相差过大时,机器训练的过程是相当曲折的,如下图曲线1,这样可能会造成较大的误差,但是先对数据进行预处理,在进行训练会减小机器学习的困难,如图2

    # 预处理 from sklearn import preprocessing from sklearn.datasets import make_classification from sklearn.model_selection import train_test_split from sklearn.svm import SVC import matplotlib.pyplot as plt X,y=make_classification(n_samples=300,n_features=2,random_state=22,n_redundant=0,n_informative=2,n_clusters_per_class=1,scale=100) plt.scatter(X[:,0],X[:,1]) plt.show() # X=preprocessing.scale(X) X_train,X_test,y_train,y_test=train_test_split(X,y,test_size=0.3) clf=SVC() clf.fit(X_train,y_train) print(clf.score(X_test,y_test))

    结果:0.5111111111111111 添加preprocessing.scale(X)后,结果:0.9222222222222223


    交叉验证(cross validation)

    validation_curve模块测试train和cross_validation

    前提:

    from sklearn.datasets import load_iris from sklearn.model_selection import train_test_split from sklearn.neighbors import KNeighborsClassifier iris=load_iris() data=iris.data label=iris.target X_train,X_test,y_train,y_test=train_test_split(data,label,test_size=0.3) for i in range(1,100): #n_neighbors即为k knn=KNeighborsClassifier(n_neighbors=i) knn.fit(X_train,y_train) print(i,knn.score(X_test,y_test))

    1 0.9555555555555556 2 0.9555555555555556 3 0.9555555555555556 4 0.9555555555555556 5 0.9555555555555556 6 0.9777777777777777 7 0.9555555555555556 8 1.0 9 0.9777777777777777 10 0.9777777777777777 11 0.9777777777777777 …

    可以看到当k等于8时是比较准确的预测的,但是这是非常不好的其实,因为我们的测试集是有限的非常少的

    这个时候就要用到交叉验证了(cross validation) 将训练集(train data)循环折叠,分成5组,然后取平均

    from sklearn.datasets import load_iris from sklearn.model_selection import train_test_split from sklearn.neighbors import KNeighborsClassifier # 可以获取交叉验证得分 from sklearn.model_selection import cross_val_score iris=load_iris() data=iris.data label=iris.target X_train,X_test,y_train,y_test=train_test_split(data,label,test_size=0.3) for i in range(1,100): knn=KNeighborsClassifier(n_neighbors=i) # 传入model X,y 折叠次数 判断精确度 score=cross_val_score(knn,X_train,y_train,cv=5,scoring='accuracy') # 返回每组测试的成绩 print(score)

    如果对score取平均score.mean()就得到我们想要的结果了: 为了更直观的看出区别,我们使用画图的方法,将其画出来:

    k_range=range(1,100) k_score=[] for k in k_range: knn=KNeighborsClassifier(n_neighbors=k) # 传入model X,y 折叠次数 判断精确度 loss=-cross_val_score(knn,data,label,cv=10,scoring='neg_mean_squared_error')#for regression 偏差 score=cross_val_score(knn,data,label,cv=10,scoring='accuracy')#for classfier # 返回每组测试的成绩 k_score.append(score.mean()) plt.plot(k_range,k_score) plt.show()

    想测试哪种model性能更好,可以在for循环中,改变model


    存储:

    训练好的model我们需要把它存储下来

    picklejoblib from sklearn.datasets import load_iris from sklearn.neighbors import KNeighborsClassifier knn=KNeighborsClassifier() X,y=load_iris() knn.fit(X,y) import pickle # 存储 with open('save/clf.pickle','wb') as f: pickle.dump(knn,f) with open('save/clf.pickle','rb') as f: pickle.load(f) from sklearn.externals import joblib # 存储 joblib.dump(knn,'save/clf.job') # 读取 joblib.load('save/clf.job')
    最新回复(0)