scikit-learn 的编程接口

作者: Vector_Wan | 来源:发表于2019-08-24 11:40 被阅读16次

    scikit-learn 是一个著名的机器学习框架,它实现了很多数据挖掘算法、通用编程接口、标准化测试工具等等。

    这篇文章主要讲解使用 sklearn 的数据挖掘通用框架的搭建方法,还有一些使用接口的通用方法,以及自己实现一些接口。sklearn 提供的接口使用起来很相似,主要有以下三类。

    • 估计器 (Estimator):用于分类、聚类和回归分析。
    • 转换器(Transformer):用于数据预处理和数据转换。
    • 流水线(Pipeline):组合数据挖掘流程,便于再次使用。

    我们下面分别来说一说他们:

    1. 估计器

    估计器,或者有些人喜欢叫预测器(predicter),是一些由 sklearn 封装好的类,他们至少需要包括两个方法:

    • fit() :训练算法,设置内部参数。该函数接收训练集及其类别两个参数。返回一个训练好的模型对象。
    • predict() :参数为测试集。预测测试集类别,并返回一个包含测试集各条数据类别的数组。或者估计预测数值,同样返回一个包含测试集各条数据类别的数组。
    • score(): 参数为测试集数据,测试集标签,直接返回准确度

    下面我们来看一个例子,看看估计器是如何被使用的。数据可以从 http://archive.ics.uci.edu/ml/machine-learning-databases/ionosphere/ 里面的 Data Folder 处下载。这是一个二分类任务,最后一个值不是“g”就是“b”,表示数据的好坏,即是否提供了有价值的信息。

    首先导入必要的库

    import numpy as np
    import csv
    import os
    

    然后导入数据集,按照常规的做法我们将数据导入 X 中,将类别导入到 y 中。因为我们不需要做其他的分析,所以我们就直接导入到 numpy 数组中了。

    datafile = "D:\jupyter\sk-learn\dataset"
    data_filename = os.path.join(datafile, "ionosphere.data")
    X = np.zeros((351, 34), dtype='float')
    y = np.zeros((351,), dtype='bool')
    with open(data_filename, 'r') as input_file:
        reader = csv.reader(input_file)
        for i, row in enumerate(reader):
            data = [float(datum) for datum in row[:-1]]
            X[i] = data
            y[i] = row[-1] == 'g'
    

    接下来需要创建训练集和测试集。导入并运行 train_test_split 函数。

    from sklearn.model_selection import train_test_split
    X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=14)
    

    下面就是我们的估计器的使用,我们这次使用的估计器是基于 K 近邻的 KNeighborsClassifier

    from sklearn.neighbors import KNeighborsClassifier
    # 创建估计器
    estimator = KNeighborsClassifier()
    
    # 训练估计器
    estimator.fit(X_train, y_train)
    
    # 使用训练好的模型预测
    y_predicted = estimator.predict(X_test)
    
    # 计算准确度
    accuracy = np.mean(y_test == y_predicted)
    accuracy
    #    0.8636363636363636
    estimator.score(X_test, y_test)
    #    0.8636363636363636
    

    为了更加客观的评价模型的好坏,避免数据集选择对我们的影响,我们可以使用交叉验证的方法。scikit-learn 提供了几种交叉检验方法。有个辅助函数实现了上述交叉检验步骤,现在把它导进来。

    from sklearn.model_selection import cross_val_score
    
    scores = cross_val_score(estimator, X, y, scoring='accuracy', cv=10)
    average_accuracy = np.mean(scores) * 100
    print("The average accuracy is {0:.1f}%".format(average_accuracy))
    #    The average accuracy is 83.0%
    

    准确率还不是很高我们可以通过调整参数来提高准确度,那么如何选取参数呢,一个很直观的想法就是,测试一系列 n_neighbors 的值,比如从 1到 20,可以重复进行多次实验,观察不同的参数值所带来的结果之间的差异。

    avg_scores = []
    all_scores = []
    parameter_values = list(range(1, 21))
    for n_neighbors in parameter_values:
        estimator = KNeighborsClassifier(n_neighbors=n_neighbors)
        scores = cross_val_score(estimator, X, y, scoring='accuracy', cv=10)
        avg_scores.append(np.mean(scores))
        all_scores.append(scores)
    
    %matplotlib inline
    from matplotlib import pyplot as plt
    
    plt.plot(parameter_values, avg_scores, '-o')
    plt.show()
    

    从上图可以看到对于我们的这个问题似乎近邻数选择 2 是个不错的选择。

    estimator = KNeighborsClassifier(n_neighbors=2)
    estimator.fit(X_train, y_train)
    y_predicted = estimator.predict(X_test)
    accuracy = np.mean(y_test == y_predicted)
    accuracy
    #    0.9204545454545454
    

    2. 转换器

    如果说估计器是输入一组数据输出一个预测值,那么转换器就是输入一组数据,输出转化后的数据。

    正如它的名字一样,这类的接口常常被用于转化数据,比如说处理非数值型数据,抽取组合特征等等,一般来说估计器用于创建模型,转换器用于数据预处理

    一般来说转换器有下面三个方法:

    • fit() : 简单来说,就是求得训练集X的均值啊,方差啊,最大值啊,最小值啊这些训练集X固有的属性。可以理解为一个训练过程。
    • transform() : 在Fit的基础上,进行标准化,降维,归一化等操作(看具体用的是哪个工具,如PCA,StandardScaler等)
    • fit_transform() : fit_transform是fit和transform的组合,既包括了训练又包含了转换。

    transform()和fit_transform()二者的功能都是对数据进行某种统一处理(比如标准化~N(0,1),将数据缩放(映射)到某个固定区间,归一化,正则化等)

    fit_transform(trainData)对部分数据先拟合fit,找到该part的整体指标,如均值、方差、最大值最小值等等(根据具体转换的目的),然后对该trainData进行转换transform,从而实现数据的标准化、归一化等等。

    根据对之前部分trainData进行fit的整体指标,对剩余的数据(testData)使用同样的均值、方差、最大最小值等指标进行转换transform(testData),从而保证train、test处理方式相同。所以,一般都是这么用:

    from sklearn.preprocessing import StandardScaler
    sc = StandardScaler()
    sc.fit_tranform(X_train)
    sc.tranform(X_test)
    
    # 也可以这么写:
    sc.fit(X_train)
    sc.tranform(X_train)
    sc.tranform(X_test)
    

    如果fit_transfrom(trainData)后,使用fit_transform(testData)而不transform(testData),虽然也能归一化,但是两个结果不是使用的相同参数,sc.fit(X_train)计算出来一个基于训练集的参数,sc.fit(X_test)计算出来一个基于测试集的参数,有的时候我们并不希望这样做。

    下面我举一个关于使用转换器进行数据预处理的例子,我们还是使用之前的数据集,但是我们要先对它做一些破坏

    X_broken = np.array(X)
    # 每隔一行,就把第二个特征的值除以10
    X_broken[:,::2] /= 10
    
    scores = cross_val_score(estimator, X, y, scoring='accuracy' ,cv=10)
    print("The average accuracy for is {0:.1f}%".format(np.mean(scores) * 100))
    
    broken_scores = cross_val_score(estimator, X_broken, y, scoring='accuracy' ,cv=10)
    print("The 'broken' average accuracy for is {0:.1f}%".format(np.mean(broken_scores) * 100))
    #    The average accuracy for is 88.7%
    #   The 'broken' average accuracy for is 84.1%
    

    从之前的 88.7% 变成了 84.1%,这是由各个特征之间的数量差距太大造成的,我们把特征值转变到0到1之间就能解决这个问题。我们接下来用 MinMaxScaler 类进行基于特征的规范化。这个类可以把每个特征的值域规范化为0到1之间。最小值用0代替,最大值用1代替,其余值介于两者之间。

    我们在预处理器 MinMaxScaler 上调用转换函数。有些转换 器 要 求 像 训 练 分 类 器 那 样 先 进 行 训 练 , 但 是 MinMaxScaler 不 需 要 , 直 接 调 用 fit_transform() 函数,即可完成训练和转换。下面使用的是链式调用方法

    from sklearn.preprocessing import MinMaxScaler
    X_transformed = MinMaxScaler().fit_transform(X_broken)
    
    scores = cross_val_score(estimator, X, y, scoring='accuracy' ,cv=10)
    print("The average accuracy for is {0:.1f}%".format(np.mean(scores) * 100))
    
    broken_scores = cross_val_score(estimator, X_transformed, y, scoring='accuracy' ,cv=10)
    print("The 'broken' average accuracy for is {0:.1f}%".format(np.mean(broken_scores) * 100))
    
    The average accuracy for is 88.7%
    The 'broken' average accuracy for is 89.0%
    

    3. 流水线

    随着实验的增加,操作的复杂程度也在提高。我们可能需要切分数据集,对特征进行二值化处理,以特征或数据集中的个体为基础规范化数据,除此之外还可能需要其他各种操作。要跟踪记录所有这些操作可不容易,如果中间出点问题,先前实验的结果将很难再现。常见问题有落下步骤,数据转换错误,或进行了不必要的转换操作等。另一个问题就是代码的先后顺序。上一节,我们创建了 X_transformed 数据集,然后创建了一个新的估计器用于交叉检验。如果有多个步骤,就需要跟踪代码中对数据集进行的每一步操作。

    为了解决这种混乱的局面,我们可以使用流水线组织我们的代码。还是使用上面的例子,我们分为了两步:

    • (1) 用 MinMaxScaler 将特征取值范围规范到0~1。
    • (2) 指定 KNeighborsClassifier 分类器。
    from sklearn.pipeline import Pipeline
    # 创建流水线
    scaling_pipeline = Pipeline([('scale', MinMaxScaler()),
                                 ('predict', KNeighborsClassifier(n_neighbors=2))])
    
    # 运行流水线
    scores = cross_val_score(scaling_pipeline, X_broken, y,scoring='accuracy', cv=10)
    print("The pipeline scored an average accuracy for is {0:.1f}%".format(np.mean(scores) * 100))
    
    The pipeline scored an average accuracy for is 89.0%
    

    准确度跟上面分开写的一样,都是 89.0% 。

    相关文章

      网友评论

        本文标题:scikit-learn 的编程接口

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