分类与预测

作者: Alex_杨策 | 来源:发表于2018-10-03 23:39 被阅读0次

    常见的分类算法

    感知机

    感知机是神经网络以及支持向量机的基础。通过w*x + b = 0这样一条直线将二维空间划分为两个区域,落在这两个区域中的点被归为正类和负类。
    感知机的学习策略是通过极小化下面的损失函数来选取最终的直线:


    Figure_0.png

    该损失函数表达的含义是误分类点到分离平面的总距离和。也就是说,误分类点越少越好,误分类点离分离平面的总距离和越小越好。

    实现感知机分类模型:
    先导入一个示例数据集,然后画出该数据集的图像。

    In [1]: from matplotlib import pyplot as plt
    In [2]: import pandas as pd
    
    
    In [3]: data = pd.read_csv("two_class_data.csv", header=0)
    
    In [4]: x = data['x']
    In [5]: y = data['y']
    In [6]: c = data['class']
    
    In [7]: plt.scatter(x, y, c=c)
    Out[7]: <matplotlib.collections.PathCollection at 0x231ca41d9b0>
    
    In [8]: plt.show()
    

    可以看到这个数据集是一个拥有明显二分类特征的数据集。

    Figure_1.png

    然后使用Scikit-learn提供的感知机方法来对上面的数据集进行分类效果测试。

    In [1]: from matplotlib import pyplot as plt
    In [2]: import pandas as pd
    
    In [3]: from sklearn.model_selection import train_test_split
    In [4]: from sklearn.linear_model import Perceptron
    
    
    In [5]: # 导入数据
    In [6]: data = pd.read_csv("two_class_data.csv", header=0)
    
    In [7]: # 定义特征变量和目标变量
    In [8]: feature = data[['x', 'y']].values
    In [9]: target = data['class'].values
    
    In [10]: # 对数据集进行切分,70%为训练集,30%为测试集。
    In [13]: x_train, x_test, y_train, y_test = train_test_split(feature, target, test_size=0.3, random_state=50)
    
    In [14]: # 构建模型
    In [15]: model = Perceptron()
    
    In [16]: # 训练模型
    In [18]: model.fit(x_train, y_train)
    C:\Users\yc\Anaconda3\lib\site-packages\sklearn\linear_model\stochastic_gradient.py:128: FutureWarning: max_iter and tol parameters have been added in <class 'sklearn.linear_model.perceptron.Perceptron'> in 0.19. If both are left unset, they default to max_iter=5 and tol=None. If tol is not None, max_iter defaults to max_iter=1000. From 0.21, default max_iter will be 1000, and default tol will be 1e-3.
      "and default tol will be 1e-3." % type(self), FutureWarning)
    Out[18]:
    Perceptron(alpha=0.0001, class_weight=None, eta0=1.0, fit_intercept=True,
          max_iter=None, n_iter=None, n_jobs=1, penalty=None, random_state=0,
          shuffle=True, tol=None, verbose=0, warm_start=False)
    
    In [19]: # 预测
    In [20]: results = model.predict(x_test)
    
    In [21]: # 以默认样式绘制训练数据
    In [22]: plt.scatter(x_train[:, 0], x_train[:, 1], alpha=0.3)
    Out[22]: <matplotlib.collections.PathCollection at 0x1d02094a470>
    
    In [23]: # 以方块样式绘制测试数据
    In [24]: plt.scatter(x_test[:, 0], x_test[:, 1], marker=',', c=y_test)
    Out[24]: <matplotlib.collections.PathCollection at 0x1d020963f60>
    
    In [25]: # 将预测结果用标签样式标注在测试数据左上方
    In [26]: for i, txt in enumerate(results):
        ...:     plt.annotate(txt, (x_test[:, 0][i], x_test[:, 1][i]))
        ...:
    
    In [27]: plt.show()
    

    测试集中有两个数据被错误分类。绿色的方框被标记为了C2。


    Figure_2.png

    还可以导出分类评估的数据:

    In [29]: print(model.score(x_test, y_test))
    0.990196078431
    

    这里如此高的分类正确率,很大程度上是因为示例数据很好。感知机作为一种十分基础的方法,在实际数据分类和预测中并不常用。因为,实战过程中的数据肯定没有示例数据呈现出的线性可分性。
    这并不意味着感知机不重要。理解感知机,可以更好地理解后面的支持向量机算法和神经网络算法。

    支持向量机(SVM)

    支持向量机是一种非常常用的,适用性非常广的分类方法。与感知机不同的是,支持向量机不仅可以用于线性分类,还可以用于非线性分类。支持向量机引入了最大间隔的思想来划定分割平面。
    通过支持向量机来重新对刚刚使用过的感知机的数据进行分类:
    只需要更改两行代码,分别是导入支持向量机SVC和使用SVC构建模型。

    In [30]: from matplotlib import pyplot as plt
    In [31]: import pandas as pd
    
    In [32]: from sklearn.model_selection import train_test_split
    In [33]: from sklearn.svm import SVC
    
    In [34]: data = pd.read_csv("two_class_data.csv", header=0)
    
    In [35]: # 定义特征变量和目标变量
    In [36]: feature = data[['x', 'y']].values
    In [37]: target = data['class'].values
    
    In [38]: # 对数据集进行切分,70%为训练集,30%为测试集。
    In [39]: x_train, x_test, y_train, y_test = train_test_split(feature, target, test_s
        ...: ize=0.3, random_state=50)
    
    In [40]: # 构建模型
    In [41]: model = SVC()
    
    In [42]: # 训练模型
    In [43]: model.fit(x_train, y_train)
    Out[43]:
    SVC(C=1.0, cache_size=200, class_weight=None, coef0=0.0,
      decision_function_shape='ovr', degree=3, gamma='auto', kernel='rbf',
      max_iter=-1, probability=False, random_state=None, shrinking=True,
      tol=0.001, verbose=False)
    
    In [44]: # 预测
    In [45]: results = model.predict(x_test)
    
    In [46]: # 以默认样式绘制训练数据
    In [47]: plt.scatter(x_test[:, 0], x_test[:, 1], marker=',', c=y_test)
    Out[47]: <matplotlib.collections.PathCollection at 0x1d020fce9b0>
    
    In [48]: # 将预测结果用标签样式标注在测试数据左上方
    In [49]: for i, txt in enumerate(results):
        ...:     plt.annotate(txt, (x_test[:, 0][i], x_test[:, 1][i]))
        ...:
    
    In [50]: plt.show()
    

    测试结果如下图:


    Figure_3.png

    正确率已经达到100%。

    除了线性分类,支持向量机还通过引入核函数来解决非线性分类的问题。

    在将特征映射到高维空间的过程中,常常会用到多种核函数,包括:线性核函数,多项式核函数,高斯经向基核函数等。其中最常用的就是高斯径向基核函数,也简称为RBF核。

    通过支持向量机完成一个非线性分类的任务。
    zoo.csv叫动物园数据集,总共有18列,第一列为动物名称,最后一列为动物分类。


    data

    数据集中间的16列为动物特征,比如:是否有毛发,是否下蛋。除了腿的数量为数值型,其余特征列均为布尔型数据。数据集中的动物共有7类,通过最后一列的数字表示。

    用支持向量机完成这个非线性分类任务。导入csv文件。定义其中16列为特征,最后一列为目标值。

    import pandas as pd
    
    from sklearn.model_selection import train_test_split
    from sklearn.svm import SVC
    from sklearn.decomposition import PCA
    
    data = pd.read_csv("zoo.csv", header=0)
    
    feature = data.iloc[:, 1:17].values
    target = data['type'].values
    
    x_train, x_test, y_train, y_test = train_test_split(feature, target, test_size=0.3, random_state=50)
    
    model = SVC()
    model.fit(x_train, y_train)
    result = model.predict(x_test)
    
    print(model.score(x_test, y_test))
    

    测试集的正确分类率为0.867

    0.866666666667
    

    16个特征参与运算,但得出的正确率并不高。主要原因为数据集太小了,才100行。

    由于存在16个特征,所以无法进行可视化,有一种叫作PCA`降维的方法,它的作用是缩减特征的数量,从而更方便可视化呈现。

    import pandas as pd
    from matplotlib import pyplot as plt
    
    from sklearn.model_selection import train_test_split
    from sklearn.svm import SVC
    from sklearn.decomposition import PCA
    
    data = pd.read_csv("zoo.csv", header=0)
    
    feature = data.iloc[:, 1:17].values
    target = data['type'].values
    
    pca = PCA(n_components=2)
    feature_pca = pca.fit_transform(feature)
    
    x_train, x_test, y_train, y_test = train_test_split(feature_pca, target, test_size=0.3, random_state=50)
    
    model = SVC()
    model.fit(x_train, y_train)
    results = model.predict(x_test)
    
    print(model.score(x_test, y_test))
    
    plt.scatter(x_train[:, 0], x_train[:, 1], alpha=0.3)
    plt.scatter(x_test[:, 0], x_test[:, 1], marker=',', c=y_test)
    
    for i, txt in enumerate(results):
        plt.annotate(txt, (x_test[:, 0][i], x_test[:, 1][i]))
        
    plt.show()
    

    当特征降为2维时,就可以通过平面图画出来了。


    Figure_4.png
    0.833333333333
    

    这里得出的准确度变成了0.833,比之前的0.867还要低。原因是特征数量减少了,影响了准确度。

    K - 近邻法(KNN)

    k 近邻时一种十分常用的分类方法。KNN中的三个关键要素:
    1.K值的大小。K值一般通过测试数据交叉验证来选择。
    2.距离的度量。新数据与最近邻数据之间的距离计算方式,有欧式距离或者曼哈顿距离等。
    3.分类决策规则。KNN的决策规则为多数表决,即新数据属于圆圈中占比最大的一类。

    使用一个由3种类别构成的数据集测试,并将KNN的决策边界绘制出来。

    import numpy as np
    import pandas as pd
    from matplotlib import pyplot as plt
    from matplotlib.colors import ListedColormap
    
    from sklearn.model_selection import train_test_split
    from sklearn.neighbors import KNeighborsClassifier
    
    
    data = pd.read_csv('c:/Users/yc/Desktop/data05/three_class_data.csv', header=0)
    
    feature = data[['x', 'y']].values
    target = data['class'].values
    
    x_train, x_test, y_train, y_test = train_test_split(feature, target, test_size=0.3, random_state=50)
    
    model = KNeighborsClassifier()
    model.fit(x_train, y_train)
    
    results = model.predict(x_test)
    print(model.score(x_test, y_test))
    
    # 绘制决策边界等高线图
    cm0 = plt.cm.Oranges
    cm1 = plt.cm.Greens
    cm2 = plt.cm.Reds
    cm_color = ListedColormap(['red', 'yellow'])
    
    x_min, x_max = data['x'].min() - .5, data['x'].max() + .5
    y_min, y_max = data['y'].min() - .5, data['y'].max() + .5
    
    xx, yy = np.meshgrid(np.arange(x_min, x_max, .1),
                         np.arange(y_min, y_max, .1))
    
    Z0 = model.predict_proba(np.c_[xx.ravel(), yy.ravel()])[:, 0]
    Z1 = model.predict_proba(np.c_[xx.ravel(), yy.ravel()])[:, 1]
    Z2 = model.predict_proba(np.c_[xx.ravel(), yy.ravel()])[:, 2]
    
    Z0 = Z0.reshape(xx.shape)
    Z1 = Z1.reshape(xx.shape)
    Z2 = Z2.reshape(xx.shape)
    
    plt.contourf(xx, yy, Z0, cmap=cm0, alpha=.9)
    plt.contourf(xx, yy, Z1, cmap=cm0, alpha=.5)
    plt.contourf(xx, yy, Z2, cmap=cm0, alpha=.4)
    
    # 绘制训练集和测试集
    plt.scatter(x_train[:, 0], x_train[:, 1], c=y_train, cmap=cm_color)
    plt.scatter(x_test[:, 0], x_test[:, 1], c=y_test, cmap=cm_color, edgecolors='black')
    plt.show()
    
    

    由于示例数据集界线清晰,所以分类的正确率为100%。KNN的决策边界:


    Figure_5.png

    图中,颜色越深的地方代表属于某一类别的可能性越高。

    决策树和随机森林

    除了支持向量机和KNN之外,决策树和随机森林也是非常不错的分类方法。

    在决策分析中,可以用决策树形象地展示决策过程,而决策数中,就是类似于if-then规则的集合。

    在用决策进行分类时,从跟节点出发,对实例的特征进行测试,然后将其分别分给不同的子节点。然后对子节点重复上面的步骤,最终所有的实例被分给叶节点中。

    执行决策树算法,一般分为三步:

    1. 特征选项。

    特性选择及选择判断规则。一般情况下,依据3种指标来选择特征,分别是信息增益,信息增益比,以及基尼指数。

    其中依据增益来选择特征,是一种来源于信息论和概率统计中的方法。通过判断某一特征对决策树前后影响的信息差值,从而选出最关键的特征。这种依据信息增益来选择特征的算法,也被称作ID3算法。

    信息增益在划分训练数据特征时,容易偏向取值较多的特征。于是改进了 ID3 算法,通过信息增益比值来选择,发展出了 C4.5 算法。除此之外,还有一种叫 CART 的生成算法,它利用了基尼指数最小化的原则。

    2. 数的生成。

    选择完特征之后,通过这些特征来生成一颗完整的决策树。生成的原则是,所有训练数据都能分配到相应的叶节点。

    3. 数的剪枝。

    一颗完整的决策树,使得训练数据得到有效的划分。但是完整的决策树往往对于测试数据的效果并不好。因为出现了过度拟合的问题。过度拟合,指模型对训练数据的效果很好,但是对测试数据的效果差,泛化能力较弱。

    解决决策树过度拟合的方法是对决策树进行剪枝。剪枝,也就是去掉一些叶节点。剪枝并不是随意乱剪,它的依据是,剪枝前和剪枝后的决策树整体损失函数最小。

    对于决策树的演示,用到了著名的鸢尾花 iris 数据集。

    iris是机器学习领域一个非常经典的分类数据集,它总共包含150行数据。每一行数据由4 个特征值及一个目标值组成。其中 4` 个特征值分别为:萼片长度、萼片宽度、花瓣长度、花瓣宽度。而目标值及为三种不同类别的鸢尾花,分别为:Iris Setosa,Iris Versicolour,Iris Virginica。

    iris 数据集无需导入 csv 文件,作为常用的基准数据集之一,sklearn 提供了相应的导入方法。输出数据看一看。

    from sklearn import datasets
    
    
    # 载入数据集
    iris = datasets.load_iris()
    print(iris.data, iris.target)
    

    部分输出:

    [[ 5.1  3.5  1.4  0.2]
     [ 4.9  3.   1.4  0.2]
     [ 4.7  3.2  1.3  0.2]
     [ 4.6  3.1  1.5  0.2]
     [ 5.   3.6  1.4  0.2]
     [ 5.4  3.9  1.7  0.4]
     [ 4.6  3.4  1.4  0.3]
     [ 5.   3.4  1.5  0.2]
     ········
    
    [ 6.2  3.4  5.4  2.3]
     [ 5.9  3.   5.1  1.8]] [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
     0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
     1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2
     2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
     2 2]
    

    构建 iris 分类决策树。

    from sklearn.datasets import load_iris
    from sklearn import tree
    
    import graphviz
    
    
    # 导入数据
    iris = load_iris()
    
    # 建立模型
    model = tree.DecisionTreeClassifier()
    
    # 模拟训练
    clf = model.fit(iris.data, iris.target)
    

    完成模型训练,就建立起一颗决策树了。通过 graphviz 模块,将决策树绘制出来。

    from sklearn.datasets import load_iris
    from sklearn import tree
    
    
    # 导入数据
    iris = load_iris()
    
    # 建立模型
    model = tree.DecisionTreeClassifier()
    
    # 模拟训练
    clf = model.fit(iris.data, iris.target)
    
    dot_data = tree.export_graphviz(clf, out_file=None,
                                    feature_names=iris.feature_names,
                                    class_names=iris.target_names,
                                    filled=True,rounded=True,
                                    special_characters=True)
    graph = graphviz.Source(dot_data)
    graph
    
    Figure_6.png

    随机森林与决策树不同的地方在于,它不只是一棵树,而是建立一堆树。与决策树不同,随机森林每次只从全部数据集中随机抽取一部分数据用于生成树。随机森林在生成树的时候不会剪枝。

    随机森林优点很多,它可以处理大量的数据;可以在特征不均衡时,依然维持较高的准确度;随机森林学习速度快,一般情况下,比单纯应用决策树要好。

    使用随机森林和决策树算法针对上面的 iris 数据集进行分类,比较准确度。

    from sklearn.datasets import load_iris
    from sklearn.tree import DecisionTreeClassifier
    from sklearn.ensemble import RandomForestClassifier
    
    
    # 导入数据
    iris = load_iris()
    
    x_train = iris.data[:120]
    x_test = iris.data[120:]
    
    y_train = iris.target[:120]
    y_test = iris.target[120:]
    
    # 建立模型
    model_tree = DecisionTreeClassifier(random_state=10)
    model_random = RandomForestClassifier(random_state=10)
    
    # 训练模型并验证
    model_tree.fit(x_train, y_train)
    s1 = model_tree.score(x_test, y_test)
    
    model_random.fit(x_train, y_train)
    s2 = model_random.score(x_test, y_test)
    
    print('DecisionTree:', s1)
    print('RandomForest:', s2)
    

    结果显示,随机森林的正确分类率比决策数高 10 个百分点。

    DecisionTree: 0.7333333333333333
    RandomForest: 0.8333333333333334
    

    相关文章

      网友评论

        本文标题:分类与预测

        本文链接:https://www.haomeiwen.com/subject/koyzoftx.html