通过scikit-learn了解机器学习

Supervised Learning(有监督学习)

 

Machine Learning分为有监督学习与无监督学习,这个系列重在介绍有监督学习,即,通过告知算法有关Features和对应的输出Labels,然后当有新的feature数据时,做label预测。

 

环境搭建

 

首选Anaconda安装,Mac下可以用brew直接装。

 

通过Iris数据库管中窥豹

 

Iris是sklearn中内嵌的一组数据,可以用以学习通过特征值对鸢尾花进行分类。1

 

数据加载

 

from sklearn.datasets import load_iris

 

iris = load_iris()

 

X = iris.data # numpy.ndarray, Features的那些observation

 

y = iris.target # numpy.ndarray与data的一个label的一一对应

 

上面两个数据都是numpy中ndarray类型。ndarray作为类似于高代中的矩阵来表达数据,通过高效的C底层库,能比python内置类库更快地做大量数据处理。 iris.data.shape 的结果为 (150, 4),表面一共有150组数据(Observations),每组有4个数据(Features)。在金融领域的数据分析处理上,因为对于表操作得比较多,所以pandas(建立在numpy之上)也是使用比较多的库。

 

K-nearest neighbors (KNN) classification

 

对已有数据进行分类,当新的数据出现时,寻找已知数据中K个和新数据最接近的数据,然后通过这K个数据的label,得出新的数据应该分在哪个类型中。

 

from sklearn.neighbors import KNeighborsClassifier

 

knn = KNeighborsClassifier(n_neighbors=1)

 

knn.fit(X, y)

 

X_new = [[3, 5, 4, 2], [5, 4, 3, 2]]

 

knn.predict(X_new)

 

通过调用KNeighborsClassifier这个类,然后把一开始加载的数据通过fit()函数来适配,然后对于新的数据用predict来得出属于哪一类。这个里面的K值使用了1,不一定是最优的,那如何找到这个最优参数?

 

验证模型参数

 

对于模型进行验证,一种方法就是把数据进行分类,分成2类。然后寻找测试数据匹配度好的参数。有些过拟合的情况下,训练数据的拟合度很好,但到测试数据就悲剧了。

 

训练数据 (模型用以匹配)

 

测试数据 (模型用以测试其有效性)

 

其中,train_test_split可以自动完成这个分类工作,并且通过test_size自动划分百分之多少的数据作为测试数据。

 

from sklearn.model_selection import train_test_split # 注意,这个模块从0.20开始不存在于 sklearn.cross_validation了!

 

# STEP 1: split X and y into training and testing sets

 

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.4, random_state=4)

 

from sklearn.linear_model import LogisticRegression

 

# STEP 2: train the model on the training set

 

logreg = LogisticRegression()

 

logreg.fit(X_train, y_train)

 

# STEP 3: make predictions on the testing set

 

y_pred = logreg.predict(X_test)

 

# compare actual response values (y_test) with predicted response values (y_pred)

 

from sklearn import metrics

 

print(metrics.accuracy_score(y_test, y_pred))

 

上面例子用的模型是LogisticRegression,它对输入值会出现一个二元判断,可以理解为是或者否的判断。回到KNN的模型。可以有以下示例代码。

 

# try K=1 through K=25 and record testing accuracy

 

k_range = list(range(1, 26))

 

scores = []

 

for k in k_range:

 

knn = KNeighborsClassifier(n_neighbors=k)

 

knn.fit(X_train, y_train)

 

y_pred = knn.predict(X_test)

 

scores.append(metrics.accuracy_score(y_test, y_pred))

 

拿到的metrics评分,可以通过matplotlib.pyplot2绘画出来,以选择最合适的。

 

 

可以看到,一开始随着K的增加,测试数据的匹配在提高,但过多之后,反而下降了,那是作为对于过拟合的惩罚。从这个图表看,7到16和18都是不错的候选K值。

 

虽然把数据分成多份能够对模型的匹配程度做验证,并惩罚那些过拟合的配置,但是牺牲了有限的数据,所以,下面有一种K-fold cross-validation的方法最大化地来利用数据,找到更合适的匹配参数。

 

Feature选择

 

有些feature关联性比较低,去除之后,反而能有更好地预测。这就需要一开始在fit()之前,对于X,把不需要的feature去除掉。如果之后得到的metrics.mean_squared_error3反而变小,说明匹配度提高。那这个feature去除ok。

 

K-fold cross-validation

 

K-fold cross-validation将原始数据均匀地分为K份,每一次将其中一份拿出来做测试数据4,其他参与模型训练,得到一个测试下的匹配值。如此做K次,则有K个测试匹配值,它们的平均值就是平均测试匹配值,平均值最小的模型所使用的参数,即是最佳参数。

 

from sklearn.model_selection import cross_val_score

 

# 10-fold cross-validation with K=5 for KNN (the n_neighbors parameter)

 

knn = KNeighborsClassifier(n_neighbors=5)

 

scores = cross_val_score(knn, X, y, cv=10, scoring=’accuracy’)

 

把模型knn传给cross_val_score并设置了K-fold的值为10,当然,cross_val_score也支持传自定义的cross-validation generator。返回值是K个测试匹配值的数组。

 

对于之前提到鸢尾花分类,可以更新为

 

# search for an optimal value of K for KNN

 

k_range = list(range(1, 31))

 

k_scores = []

 

for k in k_range:

 

knn = KNeighborsClassifier(n_neighbors=k)

 

scores = cross_val_score(knn, X, y, cv=10, scoring=’accuracy’)

 

k_scores.append(scores.mean())

 

通过绘图,得到如下匹配曲线

 

 

可见,K在13,18,20的情况下,返回值的匹配度最高。虽然数据的利用率高了,但是这个方法的操作代码比较冗余,缺少python的简洁美学。下面介绍更高效的处理方法。

 

自动寻找最佳匹配参数

 

采用GridSearchCV,它会遍历所以给予的参数,并告知最优解的参数。

 

from sklearn.grid_search import GridSearchCV

 

# define the parameter values that should be searched

 

k_range = list(range(1, 31))

 

param_grid = dict(n_neighbors=k_range)

 

# instantiate the grid

 

grid = GridSearchCV(knn, param_grid, cv=10, scoring=’accuracy’)

 

# fit the grid with data

 

grid.fit(X, y)

 

# examine the best model

 

print(grid.best_score_) # 0.98

 

print(grid.best_params_) # {‘n_neighbors’: 13}

 

print(grid.best_estimator_) # KNeighborsClassifier(algorithm=’auto’, leaf_size=30, metric=’minkowski’, metric_params=None, n_jobs=1, n_neighbors=13, p=2, weights=’uniform’)

 

如果调用 grid.predict则默认采用最优参数来预测,即上面K值为13来预测。

 

上面的例子只针对了k值调整,也就是说knn中的n_neighbors这一个参值。如果存在多个参数需要同时调整,可以在param_grid初始化的时候,一起在dict中设置,如

 

k_range = list(range(1, 31)) # 调整参数1

 

weight_options = [‘uniform’, ‘distance’] # 调整参数2

 

param_grid = dict(n_neighbors=k_range, weights=weight_options)

 

grid = GridSearchCV(knn, param_grid, cv=10, scoring=’accuracy’)

 

GridSearchCV会遍历所有的参数的所有组合,所以非常耗时。要减少遍历数,还有一种做法是采用 RandomizedSearchCV,它只会对组合的一个子集做验证。比如,用户可以通过n_iter=10限制只遍历10个子集。

 

ROC曲线

 

对于二分模型(binary classifier,比如上面提到过的LogisticRegression)预测的数据,比如说,给出某4个参数,预测是否是某种鸢尾花,那幺,需要知道这个结论的可信度有多少。这种可信度,可以从预测是或否的结果以及预测结果与实际结果对比这几个角度考虑。

 

ROC曲线,就是在x轴标记,如果实际分类为是的情形下,模型将其错误地标示为是的概率(False Positive Rate)。而y轴则为,如果实际分类是是的情形下,模型也标示是是的概率(True Positive Rate)。

 

 

图中的示例图,红色为是,蓝色为否,模型有一个判断点,右边都认为是是,左边的都认为是否,那存在FPR和TPR,ROC曲线上的红点就是这个模型的判断点。

 

在FPR上,它值偏小,说明大多数错误的被过滤掉。正确性能保证。

 

在TPR上,它值偏大,说明大多数正确的被识别出,准确性能保证。

 

如果判断点右移到底,红点会左移到底,这时候,所有的数据都被判断为否,那幺,FPR为0,即,没有一个错误的被判断为正确,正确性最高。但是,TPR也变为0,导致没有一个正确的被识别出,准确性完全丢失。

 

可见,只有存在一些模糊过度的阶段,即图中蓝色与红色有交汇,那判断输出必然存在一个模糊的阶段,所以需要ROC曲线对其准确性和正确性做评估。对于一个理想的判断点,这个和你的业务决策相关联,你需要FPR尽量小(->0),还是TPR要尽量大(->1)?

 

如果蓝色图像和红色图像近乎重叠,那幺ROC曲线也近似于对角线,这个情形下,判断的准确性和瞎猜没啥区别。

 

X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0)

 

logreg = LogisticRegression()

 

logreg.fit(X_train, y_train)

 

y_pred_class = logreg.predict(X_test)

 

# IMPORTANT: first argument is true values, second argument is predicted values

 

confusion = metrics.confusion_matrix(y_test, y_pred_class)

 

TP = confusion[1, 1]

 

TN = confusion[0, 0]

 

FP = confusion[0, 1]

 

FN = confusion[1, 0]

 

print(metrics.recall_score(y_test, y_pred_class)) # TPR:(TP / float(TP + FN))

 

print(FP / float(TN + FP)) # FPR

 

y_pred_prob = logreg.predict_proba(X_test)[:, 1]

 

import matplotlib.pyplot as plt

 

fpr, tpr, thresholds = metrics.roc_curve(y_test, y_pred_prob)

 

plt.plot(fpr, tpr)

 

plt.xlim([0.0, 1.0])

 

plt.ylim([0.0, 1.0])

 

plt.title(‘ROC curve for diabetes classifier’)

 

plt.xlabel(‘False Positive Rate (1 – Specificity)’)

 

plt.ylabel(‘True Positive Rate (Sensitivity)’)

 

plt.grid(True)

 

plt.show()

 

绘制出图像如下

 

 

对于曲线,需要计算下面的面积(Area Under Curve),面积越大越优。计算方式是

 

# IMPORTANT: first argument is true values, second argument is predicted probabilities

 

print(metrics.roc_auc_score(y_test, y_pred_prob))

 

当然,也可以用老朋友cross_validation来找最优配置模型

cross_val_score(logreg, X, y, cv=10, scoring=’roc_auc’).mean()

注意

 

本文中的中文语言不确定对应的术语,可能存在不准确的情况。

 

这个是经典的Machine Learning入门示例,在《Building Machine Learning Systems with Python》一书中,就专门有一章以这个展开。

 

在绘图上,还可以采用seaborn,它封装了matplotlib。

 

原文中使用了线性模型LinearRegression,对其提到3种验证准确率的方式,metrics.mean_absolute_error,metrics.mean_squared_error 和 np.sqrt(metrics.mean_squared_error()) 这3种。

 

sklearn有个专门的KFold类,可以通过 from sklearn.cross_validation import KFold 引用。

发表评论

电子邮件地址不会被公开。 必填项已用*标注