0x00 scikit-learn Scikit-learn(以前称为scikits.learn)是一个用于Python编程语言的免费开源机器学习库。它广泛地支持各种分类、聚类以及回归分析方法比如支持向量机、随机森林、DBSCAN等等,由于其强大的功能、优异的拓展性以及易用性,目前受到了很多数据科学从业者的欢迎,也是业界相当著名的一个开源项目之一。
0x01 模型属性与功能 sklearn库中所有机器学习的模型对象中都有一些属性与功能,假设模型对象名为mod,那么就可以这样表示mod模型的一些属性与功能:
mod.coef_ x前的系数
mod.intercept_ 截距
mod.predict() 预测
mod.get_params() 定义的参数
mod.score(data_x,data_y) 用data_x做预测,用data_y做比较给模型打分
我们以上一篇中的线性回归模型为例查看一下这些属性:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 from sklearn import datasets from sklearn.linear_model import LinearRegression example_x,example_y = datasets.make_regression (n_samples=100 ,n_features=2 ,n_targets=1 ,noise=3 ) lr = LinearRegression() lr.fit (example_x,example_y)print (lr.coef_) print (lr.intercept_) print (lr.predict(example_x[:5 ,:]) )print (lr.get_params() )print (lr.score(example_x,example_y) )
可以从输出中看到:
lr.coef_输出一个list代表每一种特征前的系数
lr.intercept_输出截距
lr.predict()方法可以输入样本进行预测
lr.get_params()方法可以输出模型的配置信息
lr.score()方法通过对比预测的数据和原始标签对模型打分
0x02 标准化 在训练模型时,某些特征可能会在不同的样本中相差特别大,有一些异常大或者异常小的数据会对模型训练结果造成较大误差,并且数据分布很分散也会影响训练结果,所以一般在训练之前,我们都会对特征数值进行标准化。
基本的标准化流程是去除每个特征的平均值来转换数据使其居中,然后通过将非常数特征除以它们的标准差来对其进行缩放。
在scikit-learn库中,有用于预处理数据的模块sklearn.preprocessing,其中scale方法可以快速简便的实现上述标准化操作。用一段代码来尝试一下:
1 2 3 4 5 6 7 8 9 10 from sklearn import preprocessingimport numpy as np x_train = np.array ([[1 , -100 , 0.03 ], [-1, 500, -0.02] , [0.2, 200, 0.04] ], dtype=np.float 64) print(preprocessing.scale(x_train))
可以看到,数据都被标准化到很接近的位置,这样就更利于学习器训练了。
具体能产生多大的影响,我们可以通过datasets产生一组数据,对比直接训练和标准化之后训练的精度:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 from sklearn import preprocessingfrom sklearn.model_selection import train_test_splitfrom sklearn.datasets.samples_generator import make_classificationfrom sklearn.svm import SVC import matplotlib.pyplot as plt X, y = make_classification( n_samples =300, n_features =2, n_redundant =0, n_informative =2, n_clusters_per_class =1,scale=100) plt.scatter(X[:, 0], X[:, 1], c =y) plt.show() 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)) 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))
在这个程序中使用datasets中的make_classification方法产生拥有两个特征值的分类数据,然后就可以将两个特征值分别放在横轴和纵轴来观察数据分布
接着对比直接训练和标准化之后训练的精度,发现前后差距非常大。
标准化还有一种常用的方式那就是将特征取值规定到一个范围(默认0-1),只需将最开始代码中标准化函数改为:
1 2 min_max_scaler = preprocessing.MinMaxScaler()X_MinMax = min_max_scaler.fit_transform(x_train)
0x03 交叉验证 之前在机器学习的模型评估方法里面学过几种模型验证的方法,其中也提到了,学习器训练完成后仍然在训练集种测试实际上是一种错误的方法,因为这个学习器在自身的训练集上很容易得到一个很高的分数,但是对新样本无法预测出任何有用的信息,这种情况被称为过拟合。
所以为了避免这种情况,我们一般在验证的时候会将样本分为训练集和测试集,在之前的博客( http://next.uuzdaisuki.com/2018/07/24/机器学习-5-——模型评估方法/ )介绍了留数法、交叉验证法、自助法这几种方法来分割训练集与测试集。
前面的程序我们大多使用train_test_split方法将样本分为两部分,也就是留数法,那么这里就使用sklearn实现交叉验证法。
交叉验证法需要用到sklearn的cross_val_score模块,我们就在刚才svm分类算法的基础上写出交叉验证:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 from sklearn import preprocessingfrom sklearn.model_selection import train_test_splitfrom sklearn.datasets.samples_generator import make_classificationfrom sklearn.svm import SVC import matplotlib.pyplot as pltfrom sklearn.model_selection import cross_val_score X, y = make_classification( n_samples =300, n_features =2, n_redundant =0, n_informative =2, n_clusters_per_class =1,scale=100) plt.scatter(X[:, 0], X[:, 1], c =y) plt.show() X = preprocessing.scale(X) clf = SVC()scores =cross_val_score(clf,X,y,cv=10,scoring='accuracy')print (scores)print (scores.mean())
数据分布如图:
输出十组分别的分数和平均分数:
交叉验证因为抽取的测试集更随机化且全部抽到,所以平均后的评估得分更令人信服。
其中cross_val_score种的clf是模型,X样本特征,y是样本标签,cv是交叉验证的分组数量,scoring参数是计分指标,可以根据实际情况在官方文档选取合适的计分指标:
0x04 模型保存 在实际的机器学习运用中,训练用的样本量是十分大的,也就是说训练一个模型需要的时间开销非常大,我们要使用一个训练好的模型,每次都去重新训练一遍是不现实的,所以在训练好之后我们需要保存模型。
我们常用的存取模型方法有如下两种
使用pickle保存模型 第一种方法是使用pickle库保存和读取模型,以上一篇博客中的k近邻算法为例:
保存模型:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 from sklearn import datasetsfrom sklearn.neighbors import KNeighborsClassifierimport pickle iris = datasets.load_iris() iris_x = iris.data iris_y = iris.target knn = KNeighborsClassifier() knn.fit(iris_x,iris_y)file = open("model/knn.pickle" ,"wb" ) pickle.dump (knn,file )
然后当前程序目录中model子目录下就会产生一个knn.pickle的文件。
读取模型:
1 2 3 4 5 6 7 8 9 10 11 from sklearn import datasets import pickle iris = datasets.load_iris () iris_x = iris.data file = open("model/knn.pickle" ,"rb" ) knn=pickle.load (file) pred = knn.predict (iris_x[0:5] )print (pred)
读取模型时直接读取这个文件,就可以使用现有模型,在以上代码中使用这个模型预测了前五个数据,我们都知道鸢尾花数据集前五个样本分类都是0,将它们放在这个模型中预测输出,发现也都是0。
使用joblib保存模型 第二种方法是用sklearn的joblib模块保存,joblib库会自动多线程运行,所以在面对大数据的时候性能要优于pickle模块,但是joblib模块只能将文件保存在磁盘中,而且会产生多个文件。
保存模型:
1 2 3 4 5 6 7 8 9 10 11 12 from sklearn import datasetsfrom sklearn.neighbors import KNeighborsClassifierfrom sklearn.externals import joblib iris = datasets.load_iris() iris_x = iris.data iris_y = iris.target knn = KNeighborsClassifier() knn.fit(iris_x,iris_y) joblib.dump (knn,'model/knn.pkl' )
然后当前程序目录中model子目录下就会产生一个knn.pkl的文件,有时会产生多个文件,但是读取时只用读取第一个。
读取模型:
1 2 3 4 5 6 7 8 9 10 11 from sklearn import datasets from sklearn.externals import joblib iris = datasets.load_iris () iris_x = iris.data knn=joblib.load ('model/knn.pkl' ) pred = knn.predict (iris_x[0:5] )print (pred)
测试结果仍然成立。