import pandas as pd
data = pd.read_csv('vertebrate.csv',header='infer')
data
header='infer'
:此参数指示pandas应该从CSV文件的第一行推断列名。换句话说,CSV文件的第一行被视为包含列名的标题。
data['Class'] = data['Class'].replace(['fishes','birds','amphibians','reptiles'],'non-mammals')
data
这段代码对data
中的'Class'列进行了替换操作。具体来说,它使用replace
方法将'fishes'、'birds'、'amphibians'和'reptiles'这些值替换为'non-mammals'。这意味着将这些类别中的动物都重新分类为非哺乳动物。
pd.crosstab([data['Warm-blooded'],data['Gives Birth']],data['Class'])
使用 Pandas交叉表 来检查“Warm-blooded”和“Gives Birth”属性与类别标签(是否为哺乳动物)之间的关系。
使用这两个属性就可以将哺乳动物与非哺乳动物区分开,因为它们的属性值的每种组合只会产生属于同一类的实例。 例如,哺乳动物可以被识别为温血且胎生的脊椎动物
Name
(名称): 动物的名称Warm-blooded
(恒温): 是否是温血动物Gives Birth
(胎生): 是否是胎生动物Aquatic Creature
(水生生物): 是否是水生生物Aerial Creature
(空中生物): 是否是空中生物Has Legs
(有腿): 是否有腿Hibernates
(冬眠): 是否冬眠
这种关系也可以使用决策树分类器来推导,如下小节中的示例所示。
决策树分类器 Decision Tree Classifier
使用不同的“不纯度度量”策略训练决策树,并进行测试;使用不同的“最大深度”训练决策树,并进行测试
数据(iris.data)训练决策树并进行测试;可以将该数据的80%作为训练集,20%作为测试集
思考:
1.观察使用不同配置的决策树的运行结果并进行分析。
2.观察决策树在鸢尾花数据上的表现并进行分析。
from sklearn import tree
Y = data['Class']
# 从data中去掉Name和Class作为输入特征X
X = data.drop(['Name','Class'],axis=1)
clf = tree.DecisionTreeClassifier(criterion='entropy',max_depth=3)
clf = clf.fit(X, Y)
前面的命令将从脊椎动物数据集中提取预测变量(X)和目标类别(Y)属性,并使用熵作为分裂标准的不纯度度量(impurity measure)来创建决策树分类器。 Python sklearn库中的决策树类还支持使用 “gini” 作为不纯度度量。 上面的决策树分类器的最大深度被限制为3。接下来,使用fit()函数在标记的数据上训练分类器。我们可以绘制训练分类器后获得的结果决策树。
import pydotplus
from IPython.display import Image
dot_data = tree.export_graphviz(clf, feature_names=X.columns, class_names=['mammals','non-mammals'], filled=True,
out_file=None)
graph = pydotplus.graph_from_dot_data(dot_data)
Image(graph.create_png())
这段代码使用pydotplus
和IPython.display
库,结合scikit-learn
的tree
模块,来可视化决策树模型。
-
tree.export_graphviz
: 这个函数用于生成决策树的可视化描述,它接受多个参数,包括:clf
: 这是你的决策树分类器(DecisionTreeClassifier)的实例。feature_names
: 特征的名称列表,用于标识决策树上的每个节点。class_names
: 目标类别的名称列表,用于标识每个类别。filled=True
: 这个参数表示是否要用颜色填充决策树节点,颜色的深浅表示类别的纯度或不纯度。out_file=None
: 这个参数表示不将可视化描述写入文件,而是返回该描述。
-
pydotplus.graph_from_dot_data
: 这个函数将export_graphviz
生成的DOT格式的数据转换为图形,它接受一个DOT格式的字符串并返回一个pydotplus.graphviz.Dot
对象。 -
最后,通过
Image(graph.create_png())
将图形显示在Jupyter Notebook中。graph.create_png()
将返回图形的PNG格式的二进制数据,Image
则将其显示在Notebook中。
要使这段代码工作,确保你已经正确安装了pydotplus
、IPython
和scikit-learn
。在运行代码之前,确保你已经拟合了一个决策树分类器(clf
)并且你的特征矩阵(X
)和目标向量是正确的。
创建了一个包含测试数据的DataFrame testData
,其中列的顺序与原始数据的列相同。这个DataFrame 包含了一些动物的特征,如 Warm-blooded
、Gives Birth
、Aquatic Creature
、Aerial Creature
、Has Legs
和 Hibernates
,以及它们的类别 (Class
)。
我还把之前鸢尾花的数据训练了一下。
import pydotplus
from sklearn.tree import DecisionTreeClassifier, export_graphviz
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier
from sklearn.metrics import accuracy_score, classification_report
from IPython.display import Image
# 加载数据
iris_data = pd.read_csv('iris.csv')
# 将特征和标签分开
X = iris_data.drop('species', axis=1)
y = iris_data['species']
# 划分数据集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# 初始化并训练决策树模型
clf = DecisionTreeClassifier()
clf.fit(X_train, y_train)
# 可视化决策树
dot_data = export_graphviz(clf, out_file=None,
feature_names=iris_data.columns[:-1].tolist(),
class_names=iris_data['species'].unique(),
filled=True, rounded=True, special_characters=True)
graph = pydotplus.graph_from_dot_data(dot_data)
# 保存决策树图像
graph.write_png('decision_tree.png')
# 在Notebook中显示决策树图像
Image(graph.create_png())
接下来,我们使用决策树对以下测试示例进行分类。
testData = [['gila monster',0,0,0,0,1,1,'non-mammals'],
['platypus',1,0,0,0,1,1,'mammals'],
['owl',1,0,0,1,1,0,'non-mammals'],
['dolphin',1,1,1,0,0,0,'mammals']]
testData = pd.DataFrame(testData, columns=data.columns)
testData
显示如下:
这些数据与我们的原始数据类似,但是是用于测试模型的新数据。可以使用训练好的模型(例如 clf
)对这些数据进行预测,然后评估模型在测试数据上的性能。
testY = testData['Class']
testX = testData.drop(['Name','Class'],axis=1)
predY = clf.predict(testX)
predictions = pd.concat([testData['Name'],pd.Series(predY,name='Predicted Class')], axis=1)
predictions
创建了一个 testY
Series,其中包含测试数据的实际类别(ground truth),而 testX
DataFrame 包含了测试数据的特征。接着,使用训练好的决策树模型 clf
对 testX
进行预测,得到了预测的类别 predY
。
最后,将测试数据的名称('Name' 列)和模型的预测类别('Predicted Class' 列)合并成一个DataFrame predictions
。这个DataFrame显示了每个动物的名称以及模型对其类别的预测。
这个DataFrame显示了每个动物的真实类别和模型的预测类别,可以用来评估模型在测试数据上的性能。如果真实类别和预测类别匹配,说明模型对这些样本的预测是正确的。
除了鸭嘴兽(platypus)是卵生哺乳动物外,分类器可以正确预测测试示例的类别标签。 我们可以根据测试数据的结果计算分类器的准确性,如下例所示。
from sklearn.metrics import accuracy_score
print('Accuracy on test data is %.2f' % (accuracy_score(testY, predY)))
Accuracy on test data is 0.75
模型过拟合 Model Overfitting
为了说明模型过度拟合的问题,我们考虑一个二维数据集,其中包含1500个带类别标签(class label)的实例,每个实例被分配给两个类别(0或1)中的一个。每个类别的实例生成如下:
1. 来自类别1的实例是由3个高斯分布的混合生成的,其中,这三个高斯分布分别以[6,14],[10,6]和[14 14]为中心。
2. 来自类别0的实例由正方形区域中的均匀分布生成,该正方形区域的边长等于20。
import numpy as np
import matplotlib.pyplot as plt
from numpy.random import random
%matplotlib inline
N = 1500
mean1 = [6, 14]
mean2 = [10, 6]
mean3 = [14, 14]
cov = [[3.5, 0], [0, 3.5]] # diagonal covariance
np.random.seed(50)
X = np.random.multivariate_normal(mean1, cov, int(N/6))
X = np.concatenate((X, np.random.multivariate_normal(mean2, cov, int(N/6))))
X = np.concatenate((X, np.random.multivariate_normal(mean3, cov, int(N/6))))
X = np.concatenate((X, 20*np.random.rand(int(N/2),2)))
Y = np.concatenate((np.ones(int(N/2)),np.zeros(int(N/2))))
plt.plot(X[:int(N/2),0],X[:int(N/2),1],'r+',X[int(N/2):,0],X[int(N/2):,1],'k.',ms=4)
因此,整体上这行代码绘制了一个散点图,其中红色加号表示第一类别的数据,黑色点表示第二类别的数据。这种表示方式是为了在散点图中区分不同的类别。
N
是生成的数据点总数。mean1
、mean2
、mean3
是三个正态分布的均值。cov
是一个对角协方差矩阵,用于生成正态分布的数据- 使用
np.random.multivariate_normal
生成带有不同均值的正态分布数据。 np.concatenate
用于将生成的数据合并成一个数组- 有三个均值
mean1
、mean2
、mean3
,每个均值生成250
个数据点,总共生成750
个数据点。 -
plt.plot(X[:int(N/2), 0], X[:int(N/2), 1], 'r+', ...)
:- 绘制红色加号 (
'r+'
) 的点,表示第一类别的数据。 X[:int(N/2), 0]
表示取前半部分数据的第一列,即 x 坐标。X[:int(N/2), 1]
表示取前半部分数据的第二列,即 y 坐标。
- 绘制红色加号 (
-
plt.plot(..., X[int(N/2):, 0], X[int(N/2):, 1], 'k.', ms=4)
:- 绘制黑色点 (
'k.'
),表示第二类别的数据。 X[int(N/2):, 0]
表示取后半部分数据的第一列,即 x 坐标。X[int(N/2):, 1]
表示取后半部分数据的第二列,即 y 坐标。
- 绘制黑色点 (
-
ms=4
表示设置点的大小(marker size)为4
。
在此示例中,我们保留了80%的数据用于训练,其余20%的数据用于测试。 然后,我们将使用具有不同最大深度(从2到50)的决策树拟合训练集,并将其在测试集上的精度绘制出来。
#########################################
# Training and Test set creation
#########################################
from sklearn.model_selection import train_test_split
X_train, X_test, Y_train, Y_test = train_test_split(X, Y, test_size=0.8, random_state=1)
from sklearn import tree
from sklearn.metrics import accuracy_score
#########################################
# Model fitting and evaluation
#########################################
maxdepths = [2,3,4,5,6,7,8,9,10,15,20,25,30,35,40,45,50]
trainAcc = np.zeros(len(maxdepths))
testAcc = np.zeros(len(maxdepths))
index = 0
for depth in maxdepths:
clf = tree.DecisionTreeClassifier(max_depth=depth)
clf = clf.fit(X_train, Y_train)
Y_predTrain = clf.predict(X_train)
Y_predTest = clf.predict(X_test)
trainAcc[index] = accuracy_score(Y_train, Y_predTrain)
testAcc[index] = accuracy_score(Y_test, Y_predTest)
index += 1
#########################################
# Plot of training and test accuracies
#########################################
plt.plot(maxdepths,trainAcc,'ro-',maxdepths,testAcc,'bv--')
plt.legend(['Training Accuracy','Test Accuracy'])
plt.xlabel('Max depth')
plt.ylabel('Accuracy')
其他分类技术 Alternative Classification Techniques
除决策树分类器外,Python sklearn库还支持其他分类技术。 在本节中,我们提供示例来说明如何将k最近邻分类器、线性分类器(逻辑回归和支持向量机)以及集成方法(增强boosting,装袋bagging和随机森林random forest)应用于上一节的二维数据上。
3.4.1 K最近邻分类器 K-Nearest neighbor classifier
在这种方法中,将基于与测试实例最接近的 *k* 个训练实例的多数类来预测其实例标签。 最近邻居的数量 *k* 以及距离度量策略是用户必须提供的超参数。默认情况下,我们可以使用欧几里得距离(它等价于指数因子p=2的Minkowski距离):
from sklearn.neighbors import KNeighborsClassifier
import matplotlib.pyplot as plt
%matplotlib inline
numNeighbors = [1, 5, 10, 15, 20, 25, 30]
trainAcc = []
testAcc = []
for k in numNeighbors:
clf = KNeighborsClassifier(n_neighbors=k, metric='minkowski', p=2)
clf.fit(X_train, Y_train)
Y_predTrain = clf.predict(X_train)
Y_predTest = clf.predict(X_test)
trainAcc.append(accuracy_score(Y_train, Y_predTrain))
testAcc.append(accuracy_score(Y_test, Y_predTest))
plt.plot(numNeighbors, trainAcc, 'ro-', numNeighbors, testAcc,'bv--')
plt.legend(['Training Accuracy','Test Accuracy'])
plt.xlabel('Number of neighbors')
plt.ylabel('Accuracy')
3.4.2 线性分类器 Linear Classifiers
from sklearn import linear_model
from sklearn.svm import SVC
C = [0.01, 0.1, 0.2, 0.5, 0.8, 1, 5, 10, 20, 50]
LRtrainAcc = []
LRtestAcc = []
SVMtrainAcc = []
SVMtestAcc = []
for param in C:
clf = linear_model.LogisticRegression(C=param)
clf.fit(X_train, Y_train)
Y_predTrain = clf.predict(X_train)
Y_predTest = clf.predict(X_test)
LRtrainAcc.append(accuracy_score(Y_train, Y_predTrain))
LRtestAcc.append(accuracy_score(Y_test, Y_predTest))
clf = SVC(C=param,kernel='linear')
clf.fit(X_train, Y_train)
Y_predTrain = clf.predict(X_train)
Y_predTest = clf.predict(X_test)
SVMtrainAcc.append(accuracy_score(Y_train, Y_predTrain))
SVMtestAcc.append(accuracy_score(Y_test, Y_predTest))
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12,6))
ax1.plot(C, LRtrainAcc, 'ro-', C, LRtestAcc,'bv--')
ax1.legend(['Training Accuracy','Test Accuracy'])
ax1.set_xlabel('C')
ax1.set_xscale('log')
ax1.set_ylabel('Accuracy')
ax2.plot(C, SVMtrainAcc, 'ro-', C, SVMtestAcc,'bv--')
ax2.legend(['Training Accuracy','Test Accuracy'])
ax2.set_xlabel('C')
ax2.set_xscale('log')
ax2.set_ylabel('Accuracy')
3.4.3 非线性支持向量机 Nonlinear Support Vector Machine
from sklearn.svm import SVC
C = [0.01, 0.1, 0.2, 0.5, 0.8, 1, 5, 10, 20, 50]
SVMtrainAcc = []
SVMtestAcc = []
for param in C:
clf = SVC(C=param,kernel='rbf',gamma='auto')
clf.fit(X_train, Y_train)
Y_predTrain = clf.predict(X_train)
Y_predTest = clf.predict(X_test)
SVMtrainAcc.append(accuracy_score(Y_train, Y_predTrain))
SVMtestAcc.append(accuracy_score(Y_test, Y_predTest))
plt.plot(C, SVMtrainAcc, 'ro-', C, SVMtestAcc,'bv--')
plt.legend(['Training Accuracy','Test Accuracy'])
plt.xlabel('C')
plt.xscale('log')
plt.ylabel('Accuracy')
3.4.4 集成方法 Ensemble Methods
集成分类器根据训练数据构建一组基础分类器,并通过对每个基础分类器做出的预测进行投票来执行分类。 在此示例中,我们考虑了三种集成分类器:装袋(bagging)、增强(boosting)和随机森林(random forest)。
在下面的示例中,我们使用每种集成方法将500个基本分类器拟合到二维数据集。 基本分类器是一个最大深度为10的决策树。
from sklearn import ensemble
from sklearn.tree import DecisionTreeClassifier
numBaseClassifiers = 500
maxdepth = 10
trainAcc = []
testAcc = []
clf = ensemble.RandomForestClassifier(n_estimators=numBaseClassifiers)
clf.fit(X_train, Y_train)
Y_predTrain = clf.predict(X_train)
Y_predTest = clf.predict(X_test)
trainAcc.append(accuracy_score(Y_train, Y_predTrain))
testAcc.append(accuracy_score(Y_test, Y_predTest))
clf = ensemble.BaggingClassifier(DecisionTreeClassifier(max_depth=maxdepth),n_estimators=numBaseClassifiers)
clf.fit(X_train, Y_train)
Y_predTrain = clf.predict(X_train)
Y_predTest = clf.predict(X_test)
trainAcc.append(accuracy_score(Y_train, Y_predTrain))
testAcc.append(accuracy_score(Y_test, Y_predTest))
clf = ensemble.AdaBoostClassifier(DecisionTreeClassifier(max_depth=maxdepth),n_estimators=numBaseClassifiers)
clf.fit(X_train, Y_train)
Y_predTrain = clf.predict(X_train)
Y_predTest = clf.predict(X_test)
trainAcc.append(accuracy_score(Y_train, Y_predTrain))
testAcc.append(accuracy_score(Y_test, Y_predTest))
methods = ['Random Forest', 'Bagging', 'AdaBoost']
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12,6))
ax1.bar([1.5,2.5,3.5], trainAcc)
ax1.set_xticks([1.5,2.5,3.5])
ax1.set_xticklabels(methods)
ax2.bar([1.5,2.5,3.5], testAcc)
ax2.set_xticks([1.5,2.5,3.5])
ax2.set_xticklabels(methods)