机器学习笔记之(1)——K邻近法

       接下来将会写一系列机器学习方面的博客,这些博客也是本人的学习笔记,其实之前本人已经把常见的机器学习算法都学过了( 或者说用过吧)但是放下一个月左右,又忘光光的。。。抓狂所以现在就打算复习一下之前所学的,顺便写下一系列的学习笔记方便以后回顾用。在学习机器学习各种算法的过程中呢,本人主要参考了以下的书籍(博客里面的内容也是根据本人看这些书籍摘抄以及个人思考)

  • 《机器学习实战》
  • 《Python机器学习》
  • 《机器学习Python实践》
  • 《Python机器学习算法》
  • 《Python大战机器学习》
  • 《Python与机器学习实战》

在学习机器学习的过程中本人是通过Python语言(Python被称为可执行伪代码,它的好处这里就不多说的hhh),用的是python3.6,主要使用开源的机器学习scikit-learn库,用的是WinPython(spyder 作为IDE),WinPython的优点就是不需要任何复杂的配置,直接上手就可以用(其实就是本人觉得配置windows下py的各种库好麻烦而且经常出错。。。。)至于学习机器学习和py其实是互补的,通过机器学习来提升py的水平,通过py来简单化实现机器学习,一举两得大笑

        这里说一点:对于Python而言,其唯一的不足就是性能的问题,py程序运行的效率不如c和java,但是在Python中提供了调用c和java的方法。


机器学习简介:

       所谓机器学习?机器学习就是把无序的数据转换成有用的信息,通过采用正确的特征来构建正确的模型,以完成既定的任务。故此机器学习有以下三大要素:

1、任务:监督学习(supervised learning),即有训练数据。监督学习分为:分类与回归。对于离散数据就是分类,将具有类别的、无序类标分配给各个新样本。分类又分为二分类多分类;连续的数据就是回归(预测),回归分析。

         非监督学习(unsupervised learning),即无训练数据。无监督学习有:聚类、密度估计、数据降维。将数据集合分成由类似的对象组成的多个类的过程就称为聚类;将寻找描述数据统计值的过程称之为密度估计。聚类,将数据划分为有意义的小的组别(簇,cluster);而簇之间的相似程度就是密度估计算法。数据降维即减少数据特征的维度。

          半监督学习,即监督学习和无监督学习的融合。

2、模型:就是你采用什么样的机器学习模型,如什么样的分类器。可以理解为各式各样的机器学习算法。机器学习算法可以划分为参数化模型与非参数化模型。当采用参数化模型时,需要我们通过训练数据估计参数,并通过学习得到一个模式,以便于在没有原始训练数据的情况下对新的数据点进行分类操作。如:感知器,逻辑斯蒂回归和线性支持向量机等。非参数化模型无法通过一组固定的参数来进行表征,而且参数的数量也会随着训练数据的增加而递增。如:决策树,核SVM,KNN。

3、特征:就是描述数据用的。特征构造、特征空间的映射(重构)。个人觉得,在机器学习的运用过程中,最重要的就是特征提取与选择。机器学习的算法(模型)大多数都是拿来主义(可能是本人水平较低,对机器学习的运用都是拿来主义),充其量就是调参。而重中之重就是如何选取合适的特征来运用机器学习算法。机器学习算法应该是属于一个工具,而特征的提取与选择,决定了你应该用哪一种工具(哪种算法)。身边大多数做机器学习项目的同学,主要都是用算法,项目的过程重点是特征的处理。

强化学习

推荐系统——就是连接用户与信息的桥梁,一方面帮助用户从海量数据中找到感兴趣的信息,另一方面将有价值的信息传递给潜在用户。

深度学习——传统的机器学习算法都是利用浅层的结构,这些结构一般包含最多一到两层的非线性特征变换。所以传统的机器学习属于“浅度”的

分类性能的评价——列联表或混淆矩阵覆盖图(ROC图)

机器学习中的几个关键词:

假设空间——就是模型在数学上的“适用场合”。

泛化能力——就是模型在未知数据上的表现

数据集、样本。每个样本的属性称为特征。特征取的具体值称为特征值。特征和样本所张成的空间称为特征空间和样本空间。模型的输出空间为标签空间或类别空间。

训练集、测试集、交叉验证集(用于调整模型具体参数的)。

泛化能力用于衡量相应学习方法学习到的模型在整个样本空间上的表现。分为过拟合和欠拟合。

对于过拟合,可以选择合适的假设空间来规避。也可以通过交叉验证,让我们知道过拟合的程度,从而帮助我们选择合适的模型。


KNN算法介绍:

简单地说,K-近邻算法(k-Nearest Neighbor)采用测量不同特征之间的距离来进行分类。是最简单的机器学习算法。它的工作原理是:存在一个样本数据集(训练样本集),并且样本集中的每个数据都有标签(分类好的,每一个数据对应的类别已知)。输入没有标签的新数据后(测试数据),将新数据的每个特征与样本集中数据对应的特征进行比较,然后算法提取样本集中特征最相似数据(最近邻)的分类标签。一般来说,只选择样本数据集中前k个最相似的数据。然后根据这K个最相似的数据中出现次数最多的分类,作为新数据的分类(投票法)如下图所示。


直观理解是:给定一个训练数据集,对于新的输入实例,在训练集中找到与该实例最邻近的k个实例。这k个实例的多数属于哪个类别,则该输入实例就划分为哪个类别。所以其不具有显示学习过程,只是利用训练数据集对特征向量空间进行划分,并作为分类的“模型”。在scikit-learn中,如果几个邻近数据的距离相同,则判定为在训练数据集中位置靠前的那些样本的类别。

KNN是基于实例的学习,使用算法时必须保存全部数据集。

k值的减少意味着模型整体变复杂,容易发生过拟合。

KNN算法要求数据的所有特征都可以做可比较的量化。

在KNN中,通过计算对象间距离来作为各个对象之间的非相似性指标,避免了对象之间的匹配问题,距离一般使用欧氏距离或曼哈顿距离;同时,KNN通过依据k个对象中占优势的类别进行决策,而不是通过单一的对象类别决策。

KNN算法也称为惰性学习。就是它仅仅对训练数据集有记忆功能,并不是从训练集中学习到一个判别函数。基于记忆的学习算法优点在于分类器可以快速适应新的训练数据,但是计算的复杂度会随着样本数量增大而线性增长。

由于维度灾难(curse of dimensionality)的原因,使得KNN算法易于过拟合。维度灾难是指:对于一个样本数量大小稳定的训练数据集,随着其特征数量的增加,样本中有具体值的特征数量变得极其稀疏(大多数特征的取值为空)。直观地说,可以认为即使是最近邻的样本,在高维空间中的实际距离也是非常远的,因此难以给出一个合适的类标判定。

一般通过正则化来避免过拟合,不过,正则化不适用于决策树和KNN等算法,可以使用特征选择和降维等技术来帮其避免维度灾难。


python代码如下:

#KNN分类代码
import numpy as np#科学计算包NumPy
from sklearn import neighbors,datasets,cross_validation



###############################################################################
#创建分类模型所使用的数据集(使用sklearn中的手写识别数据集digit)。用于分类的数据
#返回为: 一个元组,依次为:训练样本集、测试样本集、训练样本的标记、测试样本的标记
def load_classification_data():
    digits=datasets.load_digits() # 使用 scikit-learn 自带的手写识别数据集 Digit Dataset
    X_train=digits.data
    y_train=digits.target
    return cross_validation.train_test_split(X_train, y_train,test_size=0.25,random_state=0,stratify=y_train) 
    #见后面补充
    #给定数据集X和类别标签y,将数据集按一定比例随机切分为训练集和测试集。进行分层采样拆分,测试集大小占 1/4
    '''
    
    train_test_split是交叉验证中常用的函数,功能是从样本中随机的按比例选取train data和testdata,形式为:
    X_train,X_test, y_train, y_test =cross_validation.train_test_split(train_data,train_target,test_size=0.4, random_state=0)
    参数解释:
    train_data:所要划分的样本特征集
    train_target:所要划分的样本结果
    test_size:样本占比,如果是整数的话就是样本的数量.测试集的大小。
    random_state:是随机数的种子。
    
    随机数种子:其实就是该组随机数的编号,在需要重复试验的时候,保证得到一组一样的随机数。
    比如你每次都填1,其他参数一样的情况下你得到的随机数组是一样的。但填0或不填,每次都会不一样。
    
    随机数的产生取决于种子,随机数和种子之间的关系遵从以下两个规则:
    种子不同,产生不同的随机数;种子相同,即使实例不同也产生相同的随机数。
    
    还有一个参数是stratify,它是为了保持split前类的分布。
    
    '''



###############################################################################
#在scikit——learn中,提供了一个KNeighborsClassifier类来实现KNN分类模型
def test_KNeighborsClassifier(*data):
    '''
    test(*args)* 的作用其实就是把序列 args 中的每个元素,当作位置参数传进去。
    比如上面这个代码,如果 args 等于 (1,2,3) ,那么这个代码就等价于 test(1, 2, 3) 
    '''
    x_train,x_text,y_train,y_test=data
    clf=neighbors.KNeighborsClassifier()
    clf.fit(x_train,y_train)#对模型进行训练
    print("Training Score:%f"%clf.score(x_train,y_train))#返回在(X_train,y_train)上的准确率
    print("Testing Score:%f"%clf.score(x_text,y_test))#返回在(X_test,y_test)上的准确率



###############################################################################
#测试分类性能
x_train,x_text,y_train,y_test=load_classification_data()
test_KNeighborsClassifier(x_train,x_text,y_train,y_test)   

结果如下图所示:


可以看出,KNN对于测试集的分类准确率达到98%,对于训练集的分类准确率达99.1%。下面给出KNN回归的代码:

KNN分类的策略为:待预测样本点最近邻的k个训练样本点中出现次数最多的分类作为该待预测样本点的类别。而KNN回归的策略为:将待预测样本点最近邻的k个训练样本点的平均值作为该待预测样本点的值。

#KNN回归代码
import numpy as np#科学计算包NumPy
from sklearn import neighbors,datasets,cross_validation



###############################################################################
#在scikit——learn中,提供了一个KNeighborsRegressor类来实现KNN回归模型
def test_KNeighborsClassifier(*data):
    x_train,x_text,y_train,y_test=data
    regr=neighbors.KNeighborsRegressor()
    regr.fit(x_train,y_train)#对模型进行训练
    print("Training Score:%f"%regr.score(x_train,y_train))#返回在(X_train,y_train)上的准确率
    print("Testing Score:%f"%regr.score(x_text,y_test))#返回在(X_test,y_test)上的准确率



###############################################################################
#创建回归模型使用的数据集。在一个sin(x)基础上添加噪声生成的
#输入参数为数据集大小
#输出为:一个元组,依次为:训练样本集、测试样本集、训练样本的标记、测试样本的标记
def create_regression_data(n):
    x=5*np.random.rand(n,1)#创建一个n*1的数组,其元素是0~1之间的随机数
    y=np.sin(x).ravel()#ravel()的作用是将多维数组变为1维数组。见后面补充
    y[::5] += 1 * (0.5 - np.random.rand(int(n/5))) # 每隔 5 个样本就在样本的值上添加噪音
    return cross_validation.train_test_split(x, y,test_size=0.25,random_state=0)# 进行简单拆分,测试集大小占 1/4


###############################################################################
#测试
x_train,x_text,y_train,y_test=create_regression_data(1000)
test_KNeighborsClassifier(x_train,x_text,y_train,y_test)

结果如图所示:


KNN对于训练集的预测得分为0.97611,对于测试集的预测得分为0.962432


对于上述代码的补充如下:

对于sklearn.cross_validation.train_test_split()这个函数,可以参考

(http://scikit-learn.org/stable/modules/generated/sklearn.cross_validation.train_test_split.html)

np.sin(x).ravel()中,ravel的效果如下:


还有一个类似的函数为flatten(),两者的区别可参考博客:https://blog.csdn.net/lanchunhui/article/details/50354978


给出另外一个程序:

#KNN分类算法
import numpy as np



###############################################################################
#画图的函数
from matplotlib.colors import ListedColormap
import matplotlib.pyplot as plt
def plot_decision_regions(X, y, classifier, test_idx=None, resolution=0.02):

    # setup marker generator and color map
    markers = ('s', 'x', 'o', '^', 'v')
    colors = ('red', 'blue', 'lightgreen', 'gray', 'cyan')
    cmap = ListedColormap(colors[:len(np.unique(y))])#通过ListedColormap来定义一些颜色和标记号,并通过颜色列表生成了颜色示例图
    # plot the decision surface
    #对两个特征的最大值最小值做了限定(使用两个特征来训练感知器)
    x1_min, x1_max = X[:, 0].min() - 1, X[:, 0].max() + 1
    x2_min, x2_max = X[:, 1].min() - 1, X[:, 1].max() + 1
    #利用meshgrid函数,将最大值、最小值向量生成二维数组xx1和xx2
    xx1, xx2 = np.meshgrid(np.arange(x1_min, x1_max, resolution), np.arange(x2_min, x2_max, resolution))
    #创建一个与数据训练集中列数相同的矩阵,以预测多维数组中所有对应点的类标z
    Z = classifier.predict(np.array([xx1.ravel(), xx2.ravel()]).T)
    Z = Z.reshape(xx1.shape)#将z变换为与xx1和xx2相同维度
    #使用contourf函数,对于网格数组中每个预测的类以不同的颜色绘制出预测得到的决策区域
    plt.contourf(xx1, xx2, Z, alpha=0.3, cmap=cmap)
    plt.xlim(xx1.min(), xx1.max())
    plt.ylim(xx2.min(), xx2.max())

    for idx, cl in enumerate(np.unique(y)):
        plt.scatter(x=X[y == cl, 0], 
                    y=X[y == cl, 1],
                    alpha=0.8, 
                    c=colors[idx],
                    marker=markers[idx], 
                    label=cl, 
                    edgecolor='black')

    # highlight test samples
    if test_idx:
        # plot all samples
        X_test, y_test = X[test_idx, :], y[test_idx]

        plt.scatter(X_test[:, 0],
                    X_test[:, 1],
                    c='',
                    edgecolor='black',
                    alpha=1.0,
                    linewidth=1,
                    marker='o',
                    s=100, 
                    label='test set')



###############################################################################
#训练集与测试集的获取,采用鸢尾花数据集
from sklearn import datasets
iris=datasets.load_iris()
x=iris.data[:,[2,3]]
y=iris.target

#对数据集进行划分
from sklearn.cross_validation import train_test_split
#采用scikit-learn中的cross_validation模块中的train_test_split()函数,随机将iris数据特征矩阵x与类标向量y按照3:7划分为测试数据集和训练数据集
x_train,x_test, y_train, y_test =train_test_split(x,y,test_size=0.3, random_state=0)

#为了优化性能,对特征进行标准化处理
from sklearn.preprocessing import StandardScaler
sc=StandardScaler()
sc.fit(x_train)#通过fit方法,可以计算训练数据中每个特征的样本均值和方差
x_train_std=sc.transform(x_train)#通过调用transform方法,可以使用前面获得的样本均值和方差来对数据做标准化处理
x_test_std=sc.transform(x_test)



###############################################################################
#KNN分类器
from sklearn.neighbors import KNeighborsClassifier
knn=KNeighborsClassifier(n_neighbors=6,p=2,metric='minkowski')#输入参数为,k值;欧拉距离;指定距离度量('minkowski'距离.闵可夫斯基距离)
knn.fit(x_train_std,y_train)
print("Training Score:%f"%knn.score(x_train_std,y_train))#返回在(X_train,y_train)上的准确率
print("Testing Score:%f"%knn.score(x_test_std,y_test))#返回在(X_test,y_test)上的准确率

x_combined_std = np.vstack((x_train_std, x_test_std))#将数组垂直排列成多个子数组的列表。
y_combined = np.hstack((y_train, y_test))# 按水平顺序(列)顺序堆栈数组。
plot_decision_regions(X=x_combined_std, y=y_combined, classifier=knn, test_idx=range(105, 150))
plt.xlabel('petal length [standardized]')
plt.ylabel('petal width [standardized]')
plt.legend(loc='upper left')
plt.show()

得到的结果如图所示:


将KNN算法中的k设定为6,图中获得了相对平滑的决策边界。KNN中,正确的k值是过拟合与欠拟合的关键。

程序中,闵可夫斯基距离定义为:

欧氏距离公式:

 

在KNN算法中,除了k值为关键外,还有p值(即距离函数的形式)。可以参考《Python大战机器学习》一书中,第四章对这两个参数的分析。

好,KNN算法的学习笔记告一段落,后续如果在应用过程有新的体会的话,会及时更新本博客奋斗



  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值