监督学习
当我们想要根据给定输入预测某个结果,并且还有输入、输出对的示例时,都应该使用监督学习。
我们的目标是对从未见过的新数据作出准确预测。
监督机器学习问题主要有两种,分别叫作分类(classification)与回归(regression)。
分类问题的目标是预测类别标签(class label),这些标签来自预定义的可选列表。
回归任务的目标是预测一个连续值,编程术语叫作浮点数(floating-pointnumber),数学术语叫作实数(real number)
两个任务的区别就是输出数据是否存在连续性。
泛化:在监督学习中,我们想要在训练数据上构建模型,然后能够对没见过的新数据(这些新数据与训练集具有相同的特性)做出准确预测。如果一个模型能够对没见过的数据做出准确预测,我们就说它能够从训练集泛化(generalize)到测试集。
过拟合:构建一个对现有信息量来说过于复杂的模型。在训练集上表现很好,但不能够泛化到测试集。
欠拟合:与过拟合相反,那么你可能无法抓住数据的全部内容以及数据中的变化,你的模型在训练集上的表现就很差,测试集更差。
我们的模型越复杂,在训练数据上的预测结果就越好。但是,如果我们的模型过于复杂,我们开始过多关注训练集中每个单独的数据点,模型就不能很好地泛化到新数据上。
模型复杂度与训练精度和测试精度之间的权衡
我们学习中往往使用的是固定数据数目的数据集,但是现实生活中,收集更多的数据我们往往能够得到更多的信息,来帮助我们预测,更多的数据可能比模型调整参数更重要。
1、模拟二分类数据集forge数据集
生成数据集
X, y=mglearn.datasets.make_forge()
#数据集绘图
mglearn.discrete_scatter(X[:,0], X[:, 1], y)
plt.legend(["Class 0","Class 1"],loc=4)#生成图例的位置
plt.xlabel("First feature")
plt.ylabel("Second feature")
print("X.shape:{}".format(X.shape))
数据集可视化
可以看出这个数据集有26个数据点和2个特征
2、使用模拟数据集wave来说明回归算法
我们用模拟的wave数据集来说明回归算法。wave数据集只有一个输入特征和一个连续的目标变量(或响应),后者是模型想要预测的对象。下面绘制的图像中单一特征位于x轴,回归目标(输出)位于y轴
X, y=mglearn.datasets.make_wave(n_samples=40)
plt.plot(X, y, 'o')
plt.ylim(-3, 3)#设置刻度
plt.xlabel("Feature")
plt.ylabel("Target")
http://t.csdn.cn/8RIFchttp://t.csdn.cn/8RIFc
从低微数据集了解到的特征不一定适用于高维数据集
3、威斯康星州乳腺癌数据集(简称cancer)
里面记录了乳腺癌肿瘤的临床测量数据。每个肿瘤都被标记为“良性”(benign,表示无害肿瘤)或“恶性”(malignant,表示癌性肿瘤),其任务是基于人体组织的测量数据来学习预测肿瘤是否为恶性
from sklearn.datasets import load_breast_cancer#使用scikit-learn模块的load breast caner函数加载数据
cancer= load_breast_cancer()
print("cancer.keys():n{}".format(cancer.keys()))
print("shape of cancer data:{}".format(cancer.data.shape))#数据含有的数据点数,每个数据点含有的特征数
print("sample count per class:n{}".format({n: v for n, v in zip(cancer.target_names, np.bincount(cancer.target))}))
#打印被标记为良性、恶性的数据点数目
了解np.bincount
http://t.csdn.cn/jS3hjhttp://t.csdn.cn/jS3hj
包含在scikit-learn中的数据集通常被保存为Bunch对象,里面包含真实数据以及一些数据集信息。关于Bunch对象,你只需要知道它与字典很相似,而且还有一个额外的好处,就是你可以用点操作符来访问对象的值(比如用bunch.key来代替bunch['key'])
print("Feature names:n{}".format(cancer.feature_names))#打印特征名
print("cancer.DESCR:n{}".format(cancer.DESCR))#打印cancer.DESCR了解更多信息
4、波士顿房价数据集(回归数据集)
from sklearn.datasets import load_boston#加载数据集
boston=load_boston()
print("data shape:{}".format(boston.data.shape))#打印数据集数据形状
同时也可以自行阅读DESCR属性来了解数据集的更多信息。
对于我们的目的而言,我们需要扩展这个数据集,输入特征不仅包括这13个测量结果,还包括这些特征之间的乘积(也叫交互项)。换句话说,我们不仅将犯罪率和公路可达性作为特征,还将犯罪率和公路可达性的乘积作为特征。像这样包含导出特征的方法叫作特征工程(feature engineering)。这个导出的数据集可以用load extended boston函数加载。
X, y=mglearn.datasets.load_extended_boston()
print("X.shape:{}".format(X.shape))
最初的13个特征加上这13个特征两两组合(有放回)得到的91个特征,一共有104个特征.
5、k近邻
k近邻分类
最简单版本只考虑一个最近邻,也就是与我们想要预测的数据点最近的训练数据点,预测结果就是这个训练数据点的已知输出。
在gorge数据集上应用
mglearn.plots.plot_knn_classification(n_neighbors=1)
单一最近邻模型对forge数据集的预测结果
mglearn.plots.plot_knn_classification(n_neighbors=3)
3近邻模型对forge数据集的预测结果
选择占据多数的作为预测结果。
我们发现在这样与单一近邻不同。
这样的方法适用于二分类,也适用于多分类数据集。
通过skikit-learn来应用k近邻算法
#将数据集分为训练集和测试集,以便评估泛化性能
from sklearn.model_selection import train_test_split
X, y=mglearn.datasets.make_forge()
X_train, X_test, y_train, y_test=train_test_split(X, y, random_state=0)
#导入类并将其实例化,此时可以设定k的参数
from sklearn.neighbors import KNeighborsClassifier
clf=KNeighborsClassifier(n_neighbors=3)
#利用训练集对这个分类器进行拟合,对于KNeighborsClassifier来说就是保存数据集,以便预测时计算与邻居之间的距离。
clf.fit(X_train, y_train)
#调用predict方法来对测试数据进行预测,对于每个测试集中的每个数据点,都要计算出它在训练集中的最近邻,然后找出其中出现次数最多的类别
print("test set predictions:{}".format(clf.predict(X_test)))
#为了评估模型泛化能力好坏,我们可以对测试数据和测试标签调用score方法
print("test set accuracy:{:.2f}".format(clf.score(X_test, y_test)))
print("Test set score:{:.2f}".format(np.mean(clf.predict(X_test)==y_test)))
6、分析KNeighborsClassifier
对于二维数据集,我们还可以在xy平面上画出所有可能的测试点的预测结果。我们根据平面中每个点所属的类别对平面进行着色。这样可以查看决策边界(decisionboundary),即算法对类别0和类别1的分界线。下列代码分别将1个、3个和9个邻居三种情况的决策边界可视化。
fig, axes = plt.subplots(1, 3, figsize=(10, 3))
for n_neighbors, ax in zip([1, 3, 9], axes):
#fit方法返回对象本身,所以我们可以将实例化和拟合放在一行代码中
clf = KNeighborsClassifier(n_neighbors=n_neighbors).fit(X, y)
mglearn.plots.plot_2d_separator(clf, X, fill=True, eps=0.5, ax=ax, alpha=.4)
mglearn.discrete_scatter(X[:, 0], X[:, 1], y, ax=ax)
ax.set_title("{} neighbor(s)".format(n_neighbors))
ax.set_xlabel("feature 0")
ax.set_ylabel("feature 1")
axes[0].legend(loc=3)
随着邻居个数增多,决策边界越来越平滑,更平滑的边界意味着更简单的模型。
即使用更少的邻居对应更高的模型复杂度,更多的邻居对应更低的模型复杂度。
考虑极端情况,邻居个数等于测试集中所有数据点的个数,那么每个测试点的邻居都完全相同,所有预测结果也完全相同。
7、模型复杂度和泛化能力之间的关系
from sklearn.datasets import load_breast_cancer
cancer=load_breast_cancer()
X_train,X_test,y_train,y_test=train_test_split(cancer.data, cancer.target,stratify=cancer.target, random_state=66)
training_accuracy=[]
test_accuracy=[]
#n_neighbors取值1-10
neighbors_settings=range(1,11)
for n_neighbors in neighbors_settings:
#构建模型
clf=KNeighborsClassifier(n_neighbors=n_neighbors)
clf.fit(X_train,y_train)
#记录训练集精度
training_accuracy.append(clf.score(X_train, y_train))
#记录泛化精度
test_accuracy.append(clf.score(X_test, y_test))
plt.plot(neighbors_settings,training_accuracy, label="training_accuracy")
plt.plot(neighbors_settings,test_accuracy, label="test accuracy")
plt.ylabel("accuracy")
plt.xlabel("n_neighbors")
plt.legend()
#plt.show()
仅考虑单一近邻时,训练集上的预测结果十分完美。但随着邻居个数的增多,模型变得更简单,训练集精度也随之下降。单一邻居时的测试集精度比使用更多邻居时要低,这表示单一近邻的模型过于复杂。与之相反,当考虑10个邻居时,模型又过于简单,性能甚至变得更差。最佳性能在中间的某处,邻居个数大约为6



