Python 机器学习 基础 之 无监督学习 【预处理 / 缩放】的简单说明

Python 机器学习 基础 之 无监督学习 【预处理 / 缩放】的简单说明

目录

Python 机器学习 基础 之 无监督学习 【预处理 / 缩放】的简单说明

一、简单介绍

二、无监督学习

1、无监督学习的类型

附录

一、参考文献


一、简单介绍

Python是一种跨平台的计算机程序设计语言。是一种面向对象的动态类型语言,最初被设计用于编写自动化脚本(shell),随着版本的不断更新和语言新功能的添加,越多被用于独立的、大型项目的开发。Python是一种解释型脚本语言,可以应用于以下领域: Web 和 Internet开发、科学计算和统计、人工智能、教育、桌面界面开发、软件开发、后端开发、网络爬虫。

Python 机器学习是利用 Python 编程语言中的各种工具和库来实现机器学习算法和技术的过程。Python 是一种功能强大且易于学习和使用的编程语言,因此成为了机器学习领域的首选语言之一。Python 提供了丰富的机器学习库,如Scikit-learn、TensorFlow、Keras、PyTorch等,这些库包含了许多常用的机器学习算法和深度学习框架,使得开发者能够快速实现、测试和部署各种机器学习模型。

Python 机器学习涵盖了许多任务和技术,包括但不限于:

  1. 监督学习:包括分类、回归等任务。
  2. 无监督学习:如聚类、降维等。
  3. 半监督学习:结合了有监督和无监督学习的技术。
  4. 强化学习:通过与环境的交互学习来优化决策策略。
  5. 深度学习:利用深度神经网络进行学习和预测。

通过 Python 进行机器学习,开发者可以利用其丰富的工具和库来处理数据、构建模型、评估模型性能,并将模型部署到实际应用中。Python 的易用性和庞大的社区支持使得机器学习在各个领域都得到了广泛的应用和发展。

二、无监督学习

无监督学习包括没有已知输出、没有老师指导学习算法的各种机器学习。在无监督学习中,学习算法只有输入数据,并需要从这些数据中提取知识。

无监督学习是一种机器学习范式,其目标是从未标记的数据中发现隐藏的结构、模式或关系,而无需提供标签或目标变量。与监督学习不同,无监督学习不依赖于已知的输出来进行训练,而是通过对数据本身的特征进行学习和分析来发现数据的内在结构。

无监督学习任务通常可以分为以下几类:

  1. 聚类(Clustering):将数据集中的样本分成不同的组(即簇),使得同一组内的样本之间的相似度较高,而不同组之间的相似度较低。常见的聚类算法包括 K-Means、层次聚类、DBSCAN 等。

  2. 降维(Dimensionality Reduction):将高维数据映射到低维空间,同时尽可能地保留数据的原始特征信息。降维可以帮助去除数据中的噪声和冗余信息,简化模型的复杂度,加速训练过程,并提高模型的泛化能力。常见的降维算法包括主成分分析(PCA)、 t-分布邻域嵌入(t-SNE)等。

  3. 关联规则学习(Association Rule Learning):从大规模数据集中发现物品之间的关联关系,例如购物篮分析中的购买行为、网页浏览中的点击行为等。关联规则学习的典型算法是 Apriori 算法。

  4. 密度估计(Density Estimation):通过对数据集进行建模,估计数据点在特征空间中的密度分布。这对于异常检测和异常值识别等任务非常有用。常见的密度估计方法包括高斯混合模型(Gaussian Mixture Model)和核密度估计(Kernel Density Estimation)等。

  5. 生成对抗网络(Generative Adversarial Networks,GANs):一种生成式无监督学习方法,通过训练两个神经网络(生成器和判别器),实现从随机噪声中生成逼真的数据样本,如图像、音频等。

无监督学习在许多领域都有广泛的应用,包括数据挖掘、模式识别、自然语言处理、图像处理、推荐系统等。它可以帮助我们更好地理解数据的结构和特征,发现数据中的规律和潜在关系,并为后续的分析和决策提供支持。

1、无监督学习的类型

本节将研究两种类型的无监督学习:数据集变换与聚类。

数据集的无监督变换 (unsupervised transformation)是创建数据新的表示的算法,与数据的原始表示相比,新的表示可能更容易被人或其他机器学习算法所理解。无监督变换的一个常见应用是降维(dimensionality reduction),它接受包含许多特征的数据的高维表示,并找到表示该数据的一种新方法,用较少的特征就可以概括其重要特性。降维的一个常见应用是为了可视化将数据降为二维。

无监督变换的另一个应用是找到“构成”数据的各个组成部分。这方面的一个例子就是对文本文档集合进行主题提取。这里的任务是找到每个文档中讨论的未知主题,并学习每个文档中出现了哪些主题。这可以用于追踪社交媒体上的话题讨论,比如选举、枪支管制或流行歌手等话题。

与之相反,聚类算法 (clustering algorithm)将数据划分成不同的组,每组包含相似的物项。思考向社交媒体网站上传照片的例子。为了方便你整理照片,网站可能想要将同一个人的照片分在一组。但网站并不知道每张照片是谁,也不知道你的照片集中出现了多少个人。明智的做法是提取所有的人脸,并将看起来相似的人脸分在一组。但愿这些人脸对应同一个人,这样图片的分组也就完成了。

无监督学习的一个主要挑战就是评估算法是否学到了有用的东西。无监督学习算法一般用于不包含任何标签信息的数据,所以我们不知道正确的输出应该是什么。因此很难判断一个模型是否“表现很好”。例如,假设我们的聚类算法已经将所有的侧脸照片和所有的正面照片进行分组。这肯定是人脸照片集合的一种可能的划分方法,但并不是我们想要的那种方法。然而,我们没有办法“告诉”算法我们要的是什么,通常来说,评估无监督算法结果的唯一方法就是人工检查。

因此,如果数据科学家想要更好地理解数据,那么无监督算法通常可用于探索性的目的,而不是作为大型自动化系统的一部分。无监督算法的另一个常见应用是作为监督算法的预处理步骤。学习数据的一种新表示,有时可以提高监督算法的精度,或者可以减少内存占用和时间开销。

在开始学习“真正的”无监督算法之前,我们先简要讨论几种简单又常用的预处理方法。虽然预处理和缩放通常与监督学习算法一起使用,但缩放方法并没有用到与“监督”有关的信息,所以它是无监督的。

上一章我们学到,一些算法(如神经网络和 SVM)对数据缩放非常敏感。因此,通常的做法是对特征进行调节,使数据表示更适合于这些算法。通常来说,这是对数据的一种简单的按特征的缩放和移动。

在无监督学习中,预处理和缩放是非常重要的步骤,用于准备数据以便进行后续的分析和建模。预处理和缩放的目的是消除数据中的噪声、处理异常值、统一数据的尺度等,从而提高模型的性能和效果。

以下是常见的无监督学习中的预处理和缩放技术:

  1. 特征缩放(Feature Scaling):对数据的特征进行缩放,使得它们具有相似的尺度和范围。这有助于加速优化算法的收敛速度,并确保不同特征对模型的影响权重是相等的。常见的特征缩放方法包括:

    • 标准化(Standardization):将特征的数值缩放到均值为0,方差为1的标准正态分布。可以使用 StandardScaler 类来实现。
    • 归一化(Normalization):将特征的数值缩放到0到1的范围内,通常适用于具有明确边界的特征。可以使用 MinMaxScaler 类来实现。
  2. 处理缺失值(Handling Missing Values):如果数据中存在缺失值,需要进行处理。一种常见的方法是填充缺失值,可以使用平均值、中位数、众数等进行填充。

  3. 异常值检测与处理(Outlier Detection and Handling):检测和处理数据中的异常值,以避免它们对模型的影响。可以使用基于统计方法、距离方法、密度方法等来识别异常值,并根据实际情况选择舍弃、替换或调整异常值。

  4. 特征工程(Feature Engineering):通过创建新的特征、组合特征、转换特征等方式,改进原始特征的表示,从而提高模型的性能和泛化能力。

  5. 降维(Dimensionality Reduction):将高维数据映射到低维空间,以减少数据的复杂度和噪声,并提高模型的效率和泛化能力。常见的降维技术包括主成分分析(PCA)、t-分布邻域嵌入(t-SNE)等。

在无监督学习任务中,合适的预处理和缩放技术可以帮助提高模型的稳定性、准确性和泛化能力,从而更好地挖掘数据中的模式和结构。

下面的代码(图 3-1)给出了一个简单的例子:

import mglearn
import matplotlib.pyplot as plt

mglearn.plots.plot_scaling()

plt.tight_layout()
plt.savefig('Images/01PreprocessingAndScaling-01.png', bbox_inches='tight')
plt.show()
图 3-1:对数据集缩放和预处理的各种方法

在图 3-1 中,第一张图显示的是一个模拟的有两个特征的二分类数据集。第一个特征(x 轴)位于 10 到 15 之间。第二个特征(y 轴)大约位于 1 到 9 之间。

接下来的 4 张图展示了 4 种数据变换方法,都生成了更加标准的范围。scikit-learn 中的 StandardScaler 确保每个特征的平均值为 0、方差为 1,使所有特征都位于同一量级。但这种缩放不能保证特征任何特定的最大值和最小值。RobustScaler 的工作原理与 StandardScaler 类似,确保每个特征的统计属性都位于同一范围。但 RobustScaler 使用的是中位数和四分位数 ( 对于一组数字来说,中位数指的是这样的数值 x :有一半数值小于 x ,另一半数值大于 x 。较小四分位数指的是这样的数值 x :有四分之一的数值小于 x 。较大四分位数指的是这样的数值 x :有四分之一的数值大于 x) ,而不是平均值和方差。这样 RobustScaler 会忽略与其他点有很大不同的数据点(比如测量误差)。这些与众不同的数据点也叫异常值 (outlier),可能会给其他缩放方法造成麻烦。

与之相反,MinMaxScaler 移动数据,使所有特征都刚好位于 0 到 1 之间。对于二维数据集来说,所有的数据都包含在 x 轴 0 到 1 与 y 轴 0 到 1 组成的矩形中。

最后,Normalizer 用到一种完全不同的缩放方法。它对每个数据点进行缩放,使得特征向量的欧式长度等于 1。换句话说,它将一个数据点投射到半径为 1 的圆上(对于更高维度的情况,是球面)。这意味着每个数据点的缩放比例都不相同(乘以其长度的倒数)。如果只有数据的方向(或角度)是重要的,而特征向量的长度无关紧要,那么通常会使用这种归一化。

前面我们已经看到不同类型的变换的作用,下面利用 scikit-learn 来应用这些变换。我们将使用第 2 章见过的 cancer 数据集。通常在应用监督学习算法之前使用预处理方法(比如缩放)。举个例子,比如我们想要将核 SVM(SVC )应用在 cancer 数据集上,并使用 MinMaxScaler 来预处理数据。首先加载数据集并将其分为训练集和测试集(我们需要分开的训练集和数据集来对预处理后构建的监督模型进行评估):

from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split
cancer = load_breast_cancer()

X_train, X_test, y_train, y_test = train_test_split(cancer.data, cancer.target,
                                                    random_state=1)
print(X_train.shape)
print(X_test.shape)

提醒一下,这个数据集包含 569 个数据点,每个数据点由 30 个测量值表示。我们将数据集分成包含 426 个样本的训练集与包含 143 个样本的测试集。

与之前构建的监督模型一样,我们首先导入实现预处理的类,然后将其实例化:

from sklearn.preprocessing import MinMaxScaler

scaler = MinMaxScaler()

然后,使用 fit 方法拟合缩放器(scaler),并将其应用于训练数据。对于 MinMaxScaler 来说,fit 方法计算训练集中每个特征的最大值和最小值。与第 2 章中的分类器和回归器(regressor)不同,在对缩放器调用 fit 时只提供了 X_train ,而不用 y_train :

scaler.fit(X_train)

为了应用刚刚学习的变换(即对训练数据进行实际缩放 ),我们使用缩放器的 transform 方法。在 scikit-learn 中,每当模型返回数据的一种新表示时,都可以使用 transform 方法:

# 变换数据
X_train_scaled = scaler.transform(X_train)
# 在缩放之前和之后分别打印数据集属性
print("transformed shape: {}".format(X_train_scaled.shape))
print("per-feature minimum before scaling:\n {}".format(X_train.min(axis=0)))
print("per-feature maximum before scaling:\n {}".format(X_train.max(axis=0)))
print("per-feature minimum after scaling:\n {}".format(
    X_train_scaled.min(axis=0)))
print("per-feature maximum after scaling:\n {}".format(
    X_train_scaled.max(axis=0)))
运行结果:
transformed shape: (426, 30)
per-feature minimum before scaling:
 [6.981e+00 9.710e+00 4.379e+01 1.435e+02 5.263e-02 1.938e-02 0.000e+00
 0.000e+00 1.060e-01 5.024e-02 1.153e-01 3.602e-01 7.570e-01 6.802e+00
 1.713e-03 2.252e-03 0.000e+00 0.000e+00 9.539e-03 8.948e-04 7.930e+00
 1.202e+01 5.041e+01 1.852e+02 7.117e-02 2.729e-02 0.000e+00 0.000e+00
 1.566e-01 5.521e-02]
per-feature maximum before scaling:
 [2.811e+01 3.928e+01 1.885e+02 2.501e+03 1.634e-01 2.867e-01 4.268e-01
 2.012e-01 3.040e-01 9.575e-02 2.873e+00 4.885e+00 2.198e+01 5.422e+02
 3.113e-02 1.354e-01 3.960e-01 5.279e-02 6.146e-02 2.984e-02 3.604e+01
 4.954e+01 2.512e+02 4.254e+03 2.226e-01 9.379e-01 1.170e+00 2.910e-01
 5.774e-01 1.486e-01]
per-feature minimum after scaling:
 [0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.
 0. 0. 0. 0. 0. 0.]
per-feature maximum after scaling:
 [1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.
 1. 1. 1. 1. 1. 1.]

变换后的数据形状与原始数据相同,特征只是发生了移动和缩放。你可以看到,现在所有特征都位于 0 到 1 之间,这也符合我们的预期。

为了将 SVM 应用到缩放后的数据上,还需要对测试集进行变换。这可以通过对 X_test 调用 transform 方法来完成:

# 对测试数据进行变换
X_test_scaled = scaler.transform(X_test)
# 在缩放之后打印测试数据的属性
print("per-feature minimum after scaling:\n{}".format(X_test_scaled.min(axis=0)))
print("per-feature maximum after scaling:\n{}".format(X_test_scaled.max(axis=0)))

你可以发现,对测试集缩放后的最大值和最小值不是 1 和 0,这或许有些出乎意料。有些特征甚至在 0~1 的范围之外!对此的解释是,MinMaxScaler (以及其他所有缩放器)总是对训练集和测试集应用完全相同的变换。也就是说,transform 方法总是减去训练集的最小值,然后除以训练集的范围,而这两个值可能与测试集的最小值和范围并不相同。

为了让监督模型能够在测试集上运行,对训练集和测试集应用完全相同的变换是很重要的。如果我们使用测试集的最小值和范围,下面这个例子(图 3-2)展示了会发生什么:

from sklearn.datasets import make_blobs
# 构造数据
X, _ = make_blobs(n_samples=50, centers=5, random_state=4, cluster_std=2)
# 将其分为训练集和测试集
X_train, X_test = train_test_split(X, random_state=5, test_size=.1)

# 绘制训练集和测试集
fig, axes = plt.subplots(1, 3, figsize=(13, 4))
axes[0].scatter(X_train[:, 0], X_train[:, 1],
                c=mglearn.cm2(0), label="Training set", s=60)
axes[0].scatter(X_test[:, 0], X_test[:, 1], marker='^',
                c=mglearn.cm2(1), label="Test set", s=60)
axes[0].legend(loc='upper left')
axes[0].set_title("Original Data")

# 利用MinMaxScaler缩放数据
scaler = MinMaxScaler()
scaler.fit(X_train)
X_train_scaled = scaler.transform(X_train)
X_test_scaled = scaler.transform(X_test)

# 将正确缩放的数据可视化
axes[1].scatter(X_train_scaled[:, 0], X_train_scaled[:, 1],
                c=mglearn.cm2(0), label="Training set", s=60)
axes[1].scatter(X_test_scaled[:, 0], X_test_scaled[:, 1], marker='^',
                c=mglearn.cm2(1), label="Test set", s=60)
axes[1].set_title("Scaled Data")

# 单独对测试集进行缩放
# 使得测试集的最小值为0,最大值为1
# 千万不要这么做!这里只是为了举例
test_scaler = MinMaxScaler()
test_scaler.fit(X_test)
X_test_scaled_badly = test_scaler.transform(X_test)

# 将错误缩放的数据可视化
axes[2].scatter(X_train_scaled[:, 0], X_train_scaled[:, 1],
                c=mglearn.cm2(0), label="training set", s=60)
axes[2].scatter(X_test_scaled_badly[:, 0], X_test_scaled_badly[:, 1],
                marker='^', c=mglearn.cm2(1), label="test set", s=60)
axes[2].set_title("Improperly Scaled Data")

for ax in axes:
    ax.set_xlabel("Feature 0")
    ax.set_ylabel("Feature 1")

plt.tight_layout()
plt.savefig('Images/01PreprocessingAndScaling-02.png', bbox_inches='tight')
plt.show()
图 3-2:对左图中的训练数据和测试数据同时缩放的效果(中)和分别缩放的效果(右)

第一张图是未缩放的二维数据集,其中训练集用圆形表示,测试集用三角形表示。第二张图中是同样的数据,但使用 MinMaxScaler 缩放。这里我们调用 fit 作用在训练集上,然后调用 transform 作用在训练集和测试集上。你可以发现,第二张图中的数据集看起来与第一张图中的完全相同,只是坐标轴刻度发生了变化。现在所有特征都位于 0 到 1 之间。你还可以发现,测试数据(三角形)的特征最大值和最小值并不是 1 和 0。

第三张图展示了如果我们对训练集和测试集分别进行缩放会发生什么。在这种情况下,对训练集和测试集而言,特征的最大值和最小值都是 1 和 0。但现在数据集看起来不一样。测试集相对训练集的移动不一致,因为它们分别做了不同的缩放。我们随意改变了数据的排列。这显然不是我们想要做的事情。

再换一种思考方式,想象你的测试集只有一个点。对于一个点而言,无法将其正确地缩放以满足 MinMaxScaler 的最大值和最小值的要求。但是,测试集的大小不应该对你的处理方式有影响。

快捷方式与高效的替代方法

通常来说,你想要在某个数据集上 fit 一个模型,然后再将其transform 。这是一个非常常见的任务,通常可以用比先调用 fit 再调用 transform 更高效的方法来计算。对于这种使用场景,所有具有 transform 方法的模型也都具有一个 fit_transform 方法。下面是使用 StandardScaler 的一个例子:

from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
# 依次调用fit和transform(使用方法链)
X_scaled = scaler.fit(X).transform(X)
# 结果相同,但计算更加高效
X_scaled_d = scaler.fit_transform(X)

虽然 fit_transform 不一定对所有模型都更加高效,但在尝试变换训练集时,使用这一方法仍然是很好的做法。

现在我们回到 cancer 数据集,观察使用 MinMaxScaler 对学习 SVC 的作用(这是一种不同的方法,实现了与第 2 章中相同的缩放)。首先,为了对比,我们再次在原始数据上拟合 SVC:

from sklearn.svm import SVC

X_train, X_test, y_train, y_test = train_test_split(cancer.data, cancer.target,
                                                    random_state=0)

svm = SVC(C=100)
svm.fit(X_train, y_train)
print("Test set accuracy: {:.2f}".format(svm.score(X_test, y_test)))

下面先用 MinMaxScaler 对数据进行缩放,然后再拟合 SVC :

# 使用0-1缩放进行预处理
scaler = MinMaxScaler()
scaler.fit(X_train)
X_train_scaled = scaler.transform(X_train)
X_test_scaled = scaler.transform(X_test)

# 在缩放后的训练数据上学习SVM
svm.fit(X_train_scaled, y_train)

# 在缩放后的测试集上计算分数
print("Scaled test set accuracy: {:.2f}".format(
    svm.score(X_test_scaled, y_test)))

正如我们上面所见,数据缩放的作用非常显著。虽然数据缩放不涉及任何复杂的数学,但良好的做法仍然是使用 scikit-learn 提供的缩放机制,而不是自己重新实现它们,因为即使在这些简单的计算中也容易犯错。

你也可以通过改变使用的类将一种预处理算法轻松替换成另一种,因为所有的预处理类都具有相同的接口,都包含 fittransform 方法:

# 利用零均值和单位方差的缩放方法进行预处理
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
scaler.fit(X_train)
X_train_scaled = scaler.transform(X_train)
X_test_scaled = scaler.transform(X_test)

# 在缩放后的训练数据上学习SVM
svm.fit(X_train_scaled, y_train)

# 在缩放后的测试集上计算分数
print("SVM test accuracy: {:.2f}".format(svm.score(X_test_scaled, y_test)))

附录

一、参考文献

参考文献:[德] Andreas C. Müller [美] Sarah Guido 《Python Machine Learning Basics Tutorial》

  • 11
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

仙魁XAN

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值