创建分类器
**简介:**分类是指利用数据的特性将其分类成若干类型的过程。分类与回归不同,回归的输出是实数。监督学习分类器就是用带标记的训练数 据建立一个模型,然后对未知的数据进行分类。
分类器可以实现分类功能的任意算法,最简单的分类器就是简单的数学函数。其中有二元(binary)分类器,将数据分成两类,也可多元(multiclass)分类器,将数据分成两个以上的类型。解决分类问题的数据手段都倾向于解决二元分类问题,可通过不同形式对其进行扩展,进而解决多元分类。
1、建立简单分类器
1import numpy as np 2import matplotlib.pyplot as plt 3 4# 准备数据 5X = np.array([[3,1], [2,5], [1,8], [6,4], [5,2], [3,5], [4,7], [4,-1]]) 6y = [0, 1, 1, 0, 0, 1, 1, 0] 7# 根据y的值分类X,取值范围为0~N-1,N表示有N个类 8class_0=np.array([X[i] for i in range(len(X)) if y[i]==0]) 9class_1=np.array([X[i] for i in range(len(X)) if y[i]==1]) 10# 将点画出 11plt.figure() 12plt.scatter(class_0[:,0],class_0[:,1],color='red',marker='s') 13plt.scatter(class_1[:,0],class_1[:,1],color='black',marker='x') 14# 创建y=x的直线 15line_x=range(10) 16line_y=line_x 17plt.plot(line_x,line_y,color='blue',linewidth=3) 18plt.show()
2、逻辑回归分类器
逻辑回归是一种分类方法,给定一组数据点,需要建立一个可以在类之间绘制线性边界的模型。就可以对训练数据派生的一组方程进行求解来提取边界。
1import numpy as np 2from sklearn import linear_model 3import matplotlib.pyplot as plt 4 5# 准备数据 6X = np.array([[4, 7], [3.5, 8], [3.1, 6.2], [0.5, 1], [1, 2], [1.2, 1.9], [6, 2], [5.7, 1.5], [5.4, 2.2]]) 7y = np.array([0, 0, 0, 1, 1, 1, 2, 2, 2]) 8 9# 初始化一个逻辑分类回归器 10classifier=linear_model.LogisticRegression(solver='liblinear',C=10000)#solver设置求解系统方程的算法类型,C表示正则化强度,越小表强度越高,C越大,各个类型的边界更优。 11 12#训练分类器 13classifier.fit(X,y) 14 15# 定义画图函数 16def plot_classifier(classifier,X,y): 17 # 获取x,y的最大最小值,并设置余值 18 x_min,x_max=min(X[:,0])-1.0,max(X[:,0]+1.0) 19 y_min,y_max=min(X[:,1])-1.0,max(X[:,1]+1.0) 20 # 设置网格步长 21 step_size=0.01 22 # 设置网格 23 x_values,y_values=np.meshgrid(np.arange(x_min,x_max,step_size),np.arange(y_min,y_max,step_size)) 24 # 计算出分类器的分类结果 25 mesh_output=classifier.predict(np.c_[x_values.ravel(),y_values.ravel()]) 26 mesh_output=mesh_output.reshape(x_values.shape) 27 # 画图 28 plt.figure() 29 #选择配色方案 30 plt.pcolormesh(x_values,y_values,mesh_output,cmap=plt.cm.gray) 31 # 画点 32 plt.scatter(X[:,0],X[:,1],c=y,s=80,edgecolors='black',linewidths=1,cmap=plt.cm.Paired) 33 # 设置图片取值范围 34 plt.xlim(x_values.min(),x_values.max()) 35 plt.ylim(y_values.min(),y_values.max()) 36 # 设置x与y轴 37 plt.xticks((np.arange(int(min(X[:, 0]) - 1), int(max(X[:, 0]) + 1), 1.0))) 38 plt.yticks((np.arange(int(min(X[:, 1]) - 1), int(max(X[:, 1]) + 1), 1.0))) 39 plt.show() 40 41# 画出数据点和边界 42plot_classifier(classifier,X,y)
3、朴素贝叶斯分类去
用贝叶斯定理进行建模的监督学习分类器。 下面举个例子,虽然这个例子没有区分训练集和测试集,一般情况最好还是区分一下。
1from sklearn.naive_bayes import GaussianNB 2 3# 准备数据 4input_file = 'data_multivar.txt' 5X = [] 6y = [] 7with open(input_file, 'r') as f: 8 for line in f.readlines(): 9 data = [float(x) for x in line.split(',')] 10 X.append(data[:-1]) 11 y.append(data[-1]) 12 13X = np.array(X) 14y = np.array(y) 15# 建立朴素贝叶斯分类器 16classifier_gaussiannb=GaussianNB() 17classifier_gaussiannb.fit(X,y) 18y_pre=classifier_gaussiannb.predict(X) 19# 计算分类器的准确性 20accuracy=100.0*(y==y_pre).sum()/X.shape[0] 21print('结果:',accuracy) 22# 画出数据和边界 23plot_classifier(classifier_gaussiannb,X,y)
4、将数据集分割成训练集和数据集
分割训练集和测试集,更好的评估模型
1from sklearn.naive_bayes import GaussianNB 2from sklearn import cross_validation 3 4# 准备数据 5input_file = 'data_multivar.txt' 6X = [] 7y = [] 8with open(input_file, 'r') as f: 9 for line in f.readlines(): 10 data = [float(x) for x in line.split(',')] 11 X.append(data[:-1]) 12 y.append(data[-1]) 13 14X = np.array(X) 15y = np.array(y) 16x_train,x_test,y_train,y_test=cross_validation.train_test_split(X,y,test_size=0.25,random_state=5)# 测试数据占25%, 17# 建立朴素贝叶斯分类器 18classifier_gaussiannb=GaussianNB() 19classifier_gaussiannb.fit(x_train,y_train) 20y_test_pre=classifier_gaussiannb.predict(x_test) 21# 计算分类器的准确性 22accuracy=100.0*(y_test==y_test_pre).sum()/x_test.shape[0] 23print('结果:',accuracy) 24# 画出数据和边界 25plot_classifier(classifier_gaussiannb,x_test,y_test_pre)
5、用交叉验证检验模型准确性
为了能让模型更加稳定,还需要用数据的不同子集进行反复验证,若只是对特定的子集进行微调,会造成过度拟合。
5.1 性能指标
概念:
- 精度(precision):被正确分类的样本数量占分类器分类出的总分类样本数量的百分比。
- 召回率(recall):被正确分类的样本数量占某分类总样本数量的百分比。
良好的机器学习模型需要保持两个指标能够同事处于合理高度,所以引入F1得分指标,是精度和召回率的合成指标,实际上是精度和召回率的调和均值(harmonic mean),公式如下:
F1得分=2_精度_召回率/(精度+召回率)
代码实现交叉验证:
1 num_validations = 5 2 # 正确率 3 accuracy = cross_validation.cross_val_score(classifier_gaussiannb,X, y, scoring='accuracy', cv=num_validations) 4 print("Accuracy: " + str(round(100*accuracy.mean(), 2)) + "%") 5 # F1 6 f1 = cross_validation.cross_val_score(classifier_gaussiannb,X, y, scoring='f1_weighted', cv=num_validations) 7 print("F1: " + str(round(100*f1.mean(), 2)) + "%") 8 # 精度 9 precision = cross_validation.cross_val_score(classifier_gaussiannb,X, y, scoring='precision_weighted', cv=num_validations) 10 print("Precision: " + str(round(100*precision.mean(), 2)) + "%") 11 # 召回率 12 recall = cross_validation.cross_val_score(classifier_gaussiannb,X, y, scoring='recall_weighted', cv=num_validations) 13 print("Recall: " + str(round(100*recall.mean(), 2)) + "%") 14 # 画出数据和边界 15 plot_classifier(classifier_gaussiannb,x_test,y_test_pre)
6、混淆矩阵可视化
混淆矩阵(confusion matrix)是理解分类模型性能的数据表,它有助于我们理解如何把测试数据分成不同的类。当向对算法进行调优时,就需要在 对算法做出改变之前了解数据的错误分类情况。有些分类效果比其他分类效果差,混淆矩阵可以帮我们理解。
1from sklearn.metrics import confusion_matrix 2 3# 显示混淆矩阵 4def plot_confusion_matrix(confusion_mat): 5 plt.imshow(confusion_mat,interpolation='nearest',cmap=plt.cm.gray) 6 plt.colorbar() 7 tick_marks=np.arange(4) 8 plt.xticks(tick_marks,tick_marks) 9 plt.yticks(tick_marks,tick_marks) 10 plt.show() 11 12y_true = [1, 0, 0, 2, 1, 0, 3, 3, 3] 13y_pred = [1, 1, 0, 2, 1, 0, 1, 3, 3] 14confusion_mat=confusion_matrix(y_true,y_pred) 15plot_confusion_matrix(confusion_mat)
7、提取性能报告
可直接使用上面的scikit-learn打印精度、召回率和F1得分。但是如果不需要单独计算各个指标,可用该函数直接从模型中提取所有统计值。
1# 提取性能报告 2from sklearn.metrics import classification_report 3 4target_names = ['Class-0', 'Class-1', 'Class-2', 'Class-3'] 5print(classification_report(y_true,y_pred,target_names=target_names))
8、根据汽车特征评估质量
使用随机森林分类器,用一个包含汽车多种细节的数据集,分类吧汽车的质量分成4中:不达标、达标、良好、优秀。代码如下:
1from sklearn import preprocessing 2from sklearn.ensemble import RandomForestClassifier 3 4# 准备数据 5input_file = 'car.data.txt' 6 7X = [] 8count = 0 9with open(input_file, 'r') as f: 10 for line in f.readlines(): 11 data = line[:-1].split(',') # line[:-1]表示line中最后一个换行删除 12 X.append(data) 13 14X = np.array(X) 15 16# 使用标记编将字符串转化为数值 17label_encoder = [] 18X_encoder = np.empty(X.shape) 19print(X[0]) 20for i, item in enumerate(X[0]): # 由于相同的信息是以列的形式显示,所以应该按列进行标记编码 21 label_encoder.append(preprocessing.LabelEncoder()) # 初始化每列的标记编码器 22 X_encoder[:, i] = label_encoder[-1].fit_transform(X[:, i]) # 未标记编码 23 24X = X_encoder[:, :-1].astype(int) # 将所有数据的除最后一列作为X,最后一列作为y 25y = X_encoder[:, -1].astype(int) 26 27# 训练随机森林分类器 28params = {'n_estimators': 200, 'max_depth': 8, 'random_state': 7} # 跟上章监督学习中的随机森林回归的参数一个意思: 29# n_estimators指评估器的数量,则决策树数量,min_samples_split指决策树分裂一个节点需要用到的最小数据样本量 30classifier = RandomForestClassifier(**params) 31classifier.fit(X, y) 32 33# 进行交叉验证 34from sklearn import model_selection 35 36# model_selection 将之前的sklearn.cross_validation, sklearn.grid_search 和 sklearn.learning_curve模块组合到一起 37 38accuracy = model_selection.cross_val_score(classifier, X, y, scoring='accuracy', cv=3) 39print('accuracy:', str(round(accuracy.mean(), 2)) + '%') 40 41# 对某条信息进行分类 42input_data = ['low', 'low', '4', 'more', 'big', 'med'] 43input_data_encoded = [-1] * len(input_data) 44 45for i, item in enumerate(input_data): 46 labels=[] 47 labels.append(input_data[i])# 转换形式,否则下行会报错 48 input_data_encoded[i] = int(label_encoder[i].transform(labels)) 49 50input_data_encoder = np.array(input_data_encoded) 51output_class = classifier.predict(input_data_encoder) # 预测 52print('结果:', label_encoder[-1].inverse_transform(output_class)[0]) # 最后一个编码器是结果
9、生成验证曲线
在第8节中使用了n_estimators和max_depth参数,而这两个被称为超参数(hyperparameters),分类器的性能取决于这两个参数的值,而这节就是使用验证曲线理解训练得分情况。(其他参数可不变),实例如下:
1from sklearn.model_selection import validation_curve 2 3classifier=RandomForestClassifier(max_depth=4,random_state=7) 4parameter_grid=np.linspace(25,200,8).astype(int) 5train_scores,validation_scores=validation_curve(classifier,X,y,'n_estimators',parameter_grid,cv=5)#对n_estimators参数进行验证 6print('training scores:',train_scores) 7print('validation scores:',validation_scores) 8 9plt.figure() 10plt.plot(parameter_grid,100*np.average(train_scores,axis=1),color='black') 11plt.show() 12 13classifier=RandomForestClassifier(n_estimators=20,random_state=7) 14parameter_grid=np.linspace(2,10,5).astype(int) 15train_scores,validation_scores=validation_curve(classifier,X,y,'max_depth',parameter_grid,cv=5)#max_depth 16print('training scores:',train_scores) 17print('validation scores:',validation_scores) 18 19plt.figure() 20plt.plot(parameter_grid,100*np.average(train_scores,axis=1),color='black') 21plt.show()
10、生成学习曲线
学习曲线可帮助我们理解训练数据集大小对机器学习模型的影响,当遇到计算能力限制时,这点十分有用,实例如下:
1from sklearn.model_selection import learning_curve 2 3classifier=RandomForestClassifier(random_state=7) 4parameter_grid=np.array([200,500,800,1100]) 5train_size,train_scores,validation_scores=learning_curve(classifier,X,y,train_sizes=parameter_grid,cv=5)#cv表示五折交叉验证 6print('train_scores:',train_scores) 7print('validation_scores:',validation_scores) 8 9plt.figure() 10plt.plot(parameter_grid,100*np.average(train_scores,axis=1),color='black') 11plt.show()
ps:虽然训练数据集的规模越小,仿佛精确度越高,但是它很容易造成过拟合问题。但是若选择较大的数据集,又会消耗更多资源,所以应综合考虑。
11、估算收入阶层
这里使用朴素贝叶斯分类器。这里的方法和第8节的一样,只是多了数字和字符串的混合编码,所以一些代码注释可查看上方第8节。
1# 1、读取数据 2input_file='adult.data.txt' 3X=[] 4 5countLess=0 6countMore=0 7countAll=20000 8 9with open(input_file,'r') as f: 10 for line in f.readlines(): 11 if '?' not in line: 12 data=line[:-1].split(', ') 13 # 2、若大部分点都属于同一个类型,则分类器会倾向于该类型,所以应该选出大于50k与小于等于50k各10000 14 if data[-1]=='<=50K' and countLess<countAll: 15 X.append(data) 16 countLess=countLess+1 17 elif data[-1]=='>50K' and countMore<countAll: 18 X.append(data) 19 countMore=countMore+1 20 if countMore>=countAll and countLess>=countAll: 21 break; 22 23X=np.array(X) 24from sklearn import preprocessing 25# 3、对数据进行编码 26label_encoder=[] 27for i,item in enumerate(X[0]): 28 if item.isdigit(): 29 X[:,i]=X[:,i] 30 else: 31 label_encoder.append(preprocessing.LabelEncoder()) 32 X[:,i]=label_encoder[-1].fit_transform(X[:,i]) 33 34y=X[:,-1].astype(int) 35X=X[:,:-1].astype(int) 36# 4、将数据分成训练和测试 37 38from sklearn.model_selection import train_test_split 39from sklearn.model_selection import cross_val_score 40from sklearn.naive_bayes import GaussianNB 41X_train,X_test,y_train,y_test=train_test_split(X,y,test_size=0.25,random_state=5) 42# 5、训练数据 43classifier_gaussiannb=GaussianNB() 44classifier_gaussiannb.fit(X_train,y_train) 45y_test_pred=classifier_gaussiannb.predict(X_test) 46# 6、提取性能指标 47f1=cross_val_score(classifier_gaussiannb,X,y,scoring='f1_weighted',cv=5) 48print('f1:',str(round(f1.mean()*100,2))+'%') 49# 7、预测新的值 50input_data = ['39', 'State-gov', '77516', 'Bachelors', '13', 'Never-married', 'Adm-clerical', 'Not-in-family', 'White', 'Male', '2174', '0', '40', 'United-States'] 51count=0 52input_data_encoder=[-1]*len(input_data) 53for i,item in enumerate(input_data): 54 if item.isdigit(): 55 input_data_encoder[i]=int(input_data[i]) 56 else: 57 labels = [] 58 labels.append(input_data[i]) 59 input_data_encoder[i]=int(label_encoder[count].transform(labels)) 60 count=count+1 61 62result=classifier_gaussiannb.predict(input_data_encoder) 63result=label_encoder[-1].inverse_transform(result) 64print('resutl:',result)
