目录
1 无监督学习基础
无监督学习是机器学习中一个极其重要且富有挑战性的分支。与监督学习需要标注数据不同,无监督学习直接面对原始、未标注的数据,试图发现数据中隐藏的结构和规律。这就像是让计算机像人类一样,自主地从周围环境中学习和理解世界,而不需要老师的指导。
从数据的角度来看,无监督学习处理的是形如{x₁, x₂, ..., xₙ}的数据集,其中每个xᵢ是一个数据样本,可能是图像、文本、声音等任何形式。这些数据没有与之对应的标签y,这使得学习任务变得更具挑战性,因为系统需要自己定义什么是"相似"或"不同",什么样的模式是"有意义的"。
无监督学习主要解决三类问题:聚类、降维和密度估计。这些方法帮助我们理解数据的内在结构,发现数据中的隐藏模式,并降低数据的复杂度。
1.1 核心目标
模式发现。它试图找出数据中的规律性和结构,例如数据是否形成了天然的群组(聚类),数据是否存在某种周期性变化,或者数据是否具有某种特定的分布特征。这种发现对于理解数据的本质特征至关重要。
表示学习。无监督学习致力于找到数据的更好表示方式,可能是更紧凑的(降维),更有意义的(特征学习),或者更容易理解的形式。好的表示可以揭示数据的内在结构,并为后续的学习任务奠定基础。
生成建模。通过学习数据的概率分布,无监督学习可以生成与原始数据类似的新样本。这不仅需要理解数据的表面特征,还需要捕捉数据的深层统计规律。
1.2 理论基础
概率论为无监督学习提供了基本框架。我们经常需要估计数据的概率分布P(X),这可以通过参数化模型(如高斯混合模型)或非参数方法(如核密度估计)来实现。最大似然估计和贝叶斯推断是两个核心的概率建模工具。
信息论也在无监督学习中扮演重要角色。互信息(Mutual Information)可以用来度量特征之间的相关性,熵(Entropy)可以衡量数据的不确定性,KL散度(Kullback-Leibler Divergence)则可以度量两个分布之间的差异。
另一个重要的理论基础是流形学习。它假设高维数据实际上位于一个低维流形上,这为诸多降维算法提供了理论支撑。如,t-SNE和UMAP这样的算法就是基于这一思想设计的。
1.3 应用层面
评估问题:由于没有标准答案(标签),很难客观评价无监督学习的效果。我们通常需要设计特定的评估指标,如聚类的轮廓系数(Silhouette Coefficient)或重构误差等。
模型选择:如何确定模型的复杂度(如聚类的数量、降维的维度)往往需要启发式方法或交叉验证来解决。
可解释性:无监督学习发现的模式和结构需要领域专家的解释才能变得有意义。这种解释有时候具有主观性。
在数据预处理中,它可以用于特征工程、异常检测和数据清洗。 在探索性数据分析中,它帮助研究者理解数据的基本特征和结构。 在深度学习中,它可以用于预训练,帮助模型学习更好的特征表示。 在推荐系统中,它可以发现用户的兴趣模式和物品的相似关系。
2 聚类分析
聚类分析是数据挖掘和机器学习中的一个基础问题,其核心目标是将相似的数据对象自动分组到同一个簇中,而将不相似的对象分到不同簇中。这个看似简单的目标实际上涉及了许多深刻的问题,比如如何定义相似性,如何确定最优的簇的数量,以及如何处理不同形状和大小的簇等。
2.1 相似性度量
我们需要理解相似性度量这个基础概念。在聚类分析中,相似性(或距离)的定义直接影响聚类的结果。常用的距离度量包括:
欧氏距离:最常用的距离度量,表示空间中两点之间的直线距离。其数学表达式为: d(x,y) = √(Σ(xᵢ-yᵢ)²)
曼哈顿距离:表示在直角坐标系中两点之间的距离,计算为所有坐标差值的绝对值之和。 d(x,y) = Σ|xᵢ-yᵢ|
余弦相似度:主要用于高维空间中计算两个向量的夹角余弦值,特别适用于文本聚类。 cos(θ) = (x·y)/(||x||·||y||)
马哈拉诺比斯距离:考虑了数据的协方差结构,能够处理数据的尺度和相关性。
2.2 聚类算法
聚类是无监督学习中最基础也最常用的方法之一。它的目标是将相似的数据点分组到一起,形成多个群集。
2.2.1 K-均值聚类
划分式聚类方法是最基础的聚类方法之一,典型代表是K-means算法。这类方法通过迭代优化来最小化某个目标函数。K-means的优势在于简单直观、计算效率高,但缺点是需要预先指定簇的数量,且对初始值敏感,同时只能发现球形的簇。改进版本如K-medoids能够更好地处理离群点,而模糊C均值(Fuzzy C-means)则引入了软分配的概念。
K-均值是最简单也最广泛使用的聚类算法。其核心思想是通过迭代优化来最小化各个数据点到其所属类别中心的距离平方和。算法步骤如下:
- 随机选择K个中心点
- 重复以下步骤直到收敛:
- 将每个数据点分配到最近的中心点
- 重新计算每个类别的中心点位置
这里是一个简单的Python实现:
import numpy as np
from sklearn.cluster import KMeans
def simple_kmeans(X, n_clusters=3, max_iters=100):
# 随机初始化聚类中心
centroids = X[np.random.choice(X.shape[0], n_clusters, replace=False)]
for _ in range(max_iters):
# 计算每个点到所有中心的距离
distances = np.sqrt(((X - centroids[:, np.newaxis])**2).sum(axis=2))
# 分配类别
labels = np.argmin(distances, axis=0)
# 更新中心点
new_centroids = np.array([X[labels == k].mean(axis=0) for k in range(n_clusters)])
# 检查是否收敛
if np.all(centroids == new_centroids):
break
centroids = new_centroids
return labels, centroids
2.2.2 密度聚类:DBSCAN
密度基础的聚类方法,如DBSCAN(密度基于的带噪声的空间聚类应用)和OPTICS,能够发现任意形状的簇。这类方法基于密度连通性的概念,将密度相连的区域划分为一个簇。DBSCAN的主要优势在于:
- 不需要预先指定簇的数量
- 能够发现任意形状的簇
- 对噪声数据具有较强的鲁棒性
- 只需要两个参数:邻域半径ε和最小点数MinPts
实现步骤:
计算距离:计算所有点之间的距离,通常使用欧氏距离。
找出邻域点:对于每个点,找出其邻域内的点(距离小于
eps
的点)。确定核心点:找到所有邻域内点的数量大于等于
minPts
的核心点。扩展聚类:
选择一个未访问过的核心点,开始一个新的聚类。
使用广度优先搜索(BFS)扩展聚类,将邻域内的点加入聚类。
如果邻域点也是核心点,将其邻域内的点也加入队列。
标记噪声点:未被访问的点标记为噪声点。
import numpy as np
from collections import deque
def euclidean_distance(p1, p2):
"""计算两个点之间的欧氏距离"""
return np.sqrt(np.sum((p1 - p2) ** 2))
def dbscan(X, eps, minPts):
"""DBSCAN算法实现"""
n = X.shape[0]
visited = np.zeros(n, dtype=bool)
cluster_labels = np.full(n, -1, dtype=int)
cluster_id = 0
# 预计算所有点对的距离
dist_matrix = np.sqrt(((X[:, np.newaxis] - X) ** 2).sum(axis=2))
# 找出每个点的邻域内的点的索引
neighbors = [np.where(dist_matrix[i] <= eps)[0] for i in range(n)]
for i in range(n):
if not visited[i]:
visited[i] = True
if len(neighbors[i]) < minPts:
cluster_labels[i] = -1 # 噪声点
else:
# 开始一个新的聚类
cluster_labels[i] = cluster_id
queue = deque()
queue.extend(neighbors[i])
while queue:
current_point = queue.popleft()
if not visited[current_point]:
visited[current_point] = True
if len(neighbors[current_point]) >= minPts:
cluster_labels[current_point] = cluster_id
queue.extend(neighbors[current_point])
else:
cluster_labels[current_point] = -1 # 噪声点
cluster_id += 1
return cluster_labels
2.2.3 谱聚类
谱聚类则采用了完全不同的思路,它首先构建数据点之间的相似度图,然后利用图的拉普拉斯矩阵的特征向量来进行聚类。这种方法特别适合处理非球形簇,但计算复杂度较高,且参数选择较为困难。
import numpy as np
from sklearn.metrics.pairwise import rbf_kernel
from scipy.linalg import eigh
from sklearn.cluster import KMeans
def spectral_clustering(X, n_clusters, gamma=1.0, normalized=True):
# 计算相似度矩阵
S = rbf_kernel(X, gamma=gamma)
# 计算度矩阵
D = np.diag(np.sum(S, axis=1))
# 计算拉普拉斯矩阵
if normalized:
# 计算D的逆平方根
D_inv_sqrt = np.linalg.inv(np.sqrt(D))
# 计算归一化的拉普拉斯矩阵
L = np.eye(X.shape[0]) - np.dot(np.dot(D_inv_sqrt, S), D_inv_sqrt)
else:
# 计算未归一化的拉普拉斯矩阵
L = D - S
# 求解拉普拉斯矩阵的特征值和特征向量
eigvals, eigvecs = eigh(L)
# 获取最小的k个特征向量(排除第一个特征向量)
k = n_clusters
embedding = eigvecs[:, 1:k+1]
# 对特征向量进行L2归一化
embedding = embedding / np.linalg.norm(embedding, axis=1, keepdims=True)
# 使用KMeans进行聚类
kmeans = KMeans(n_clusters=k)
clusters = kmeans.fit_predict(embedding)
return clusters
在实际应用中,聚类分析面临着几个关键挑战:
- 簇的数量确定:虽然有肘部法则、轮廓系数等方法,但在实践中仍然较难确定最优的簇数。
- 聚类结果的评估:由于缺乏ground truth,需要使用内部指标(如轮廓系数、Davies-Bouldin指数)和外部指标(如互信息、兰德指数)来评估聚类质量。
- 高维数据的处理:在高维空间中,距离度量变得不那么有意义(维数灾难),需要结合降维技术或使用特殊的相似性度量。
- 大规模数据处理:某些算法(如层次聚类)在处理大规模数据时计算复杂度过高,需要使用近似算法或采样技术。
3 降维技术
降维技术是处理高维数据的重要工具,其核心目标是在保持数据重要特征的同时,将数据映射到更低维的空间。这个过程不仅能够减少数据的存储和计算开销,还能够帮助我们发现数据的本质结构,消除噪声,并实现数据的可视化。
从理论基础来看,降维技术基于一个重要假设:高维数据通常具有某种内在的低维结构。这就是所谓的"流形假设",即虽然数据表面上是高维的,但实际上可能位于一个低维流形上。这个理论基础启发了许多降维算法的设计。
3.1 线性
线性降维技术假设数据可以通过线性变换映射到低维空间。其中最经典的是主成分分析(PCA)。PCA的核心思想是找到数据方差最大的方向,将数据投影到这些方向上。从数学角度看,这等价于对数据协方差矩阵进行特征值分解:
- 首先中心化数据:X' = X - μ
- 计算协方差矩阵:S = (1/n)X'ᵀX'
- 求解特征值方程:SV = VΛ
- 选择最大的k个特征值对应的特征向量作为投影矩阵
PCA的优点是计算简单、理论清晰,而且保证了在均方误差意义下的最优性。但它也有局限性,主要是无法捕捉非线性关系。
另一个重要的线性降维方法是线性判别分析(LDA),虽然它通常用于监督学习,但其降维思想值得关注。LDA试图找到既能最大化类间距离又能最小化类内距离的投影方向。
PCA的Python实现:
import numpy as np
def pca(X, n_components):
# 中心化数据
X_centered = X - np.mean(X, axis=0)
# 计算协方差矩阵
cov_matrix = np.cov(X_centered.T)
# 计算特征值和特征向量
eigenvalues, eigenvectors = np.linalg.eigh(cov_matrix)
# 选择最大的n_components个特征向量
idx = eigenvalues.argsort()[::-1]
eigenvectors = eigenvectors[:, idx]
components = eigenvectors[:, :n_components]
# 投影数据
return np.dot(X_centered, components)
3.2 非线性
非线性降维技术则能够处理更复杂的数据结构。流行的方法包括:
t-SNE(t-distributed Stochastic Neighbor Embedding)是一种特别适合数据可视化的非线性降维技术。它的核心思想是:
- 在高维空间中用高斯分布描述点对之间的相似度
- 在低维空间中用t分布描述点对之间的相似度
- 通过最小化这两个分布之间的KL散度来优化低维表示
UMAP(Uniform Manifold Approximation and Projection)是近年来流行的降维方法,它基于黎曼几何和代数拓扑的理论,比t-SNE有更好的理论基础,而且计算效率更高。UMAP的特点是:
- 能够更好地保持数据的全局结构
- 计算速度快
- 理论基础扎实
- 可以处理大规模数据集
自编码器(Autoencoder)是一种基于神经网络的降维方法。它通过一个编码器将数据压缩到低维潜在空间,然后通过解码器重构原始数据。训练目标是最小化重构误差:
- 编码器:f(x) = z(将高维数据x映射到低维表示z)
- 解码器:g(z) = x'(将低维表示z重构为原始维度的数据x')
- 优化目标:min ||x - g(f(x))||²
3.3 降维技术面临关键问题
维度的选择:如何确定合适的目标维度是一个重要问题。常用的方法包括:
- 保持解释方差的比例(在PCA中)
- 观察重构误差的变化
- 使用交叉验证
计算效率:对于大规模数据集,某些降维方法(如t-SNE)的计算成本很高。解决方案包括:
- 使用近似算法
- 先用PCA降维,再应用非线性方法
- 采用批处理或流式处理
特征的可解释性:降维后的特征往往失去了原始的物理意义。为了提高可解释性,可以:
- 使用稀疏降维方法
- 分析特征的贡献度
- 结合领域知识进行解释
随着深度学习的发展,新的降维技术不断涌现,比如变分自编码器(VAE)和对抗自编码器(AAE)等。这些方法不仅能够学习数据的低维表示,还能够生成新的数据样本,为降维技术开辟了新的应用场景。
降维技术的选择需要根据具体问题来决定:
- 如果数据近似线性,且需要保持可解释性,选择PCA
- 如果主要目的是可视化,选择t-SNE或UMAP
- 如果需要处理非线性关系且有大量数据,考虑自编码器
- 如果需要生成能力,考虑VAE或AAE
4 概率密度估计
概率密度估计是统计学和机器学习中的一个基础问题,其目标是根据观测数据来推断随机变量的概率分布。这个问题的重要性体现在多个方面:它能帮助我们理解数据的生成过程,为异常检测提供基础,并且在生成模型中扮演着核心角色。
4.1 参数估计
参数密度估计假设数据来自某个特定的分布族(如高斯分布),估计问题就转化为确定分布的参数。最常用的参数估计方法包括:
最大似然估计(MLE)是最基础的方法,其核心思想是选择能够最大化观测数据出现概率的参数值。对于独立同分布的数据{x₁, ..., xₙ},似然函数为: L(θ) = ∏ᵢ p(xᵢ|θ)
通常我们会最大化对数似然: log L(θ) = Σᵢ log p(xᵢ|θ)
最大后验估计(MAP)则引入了参数的先验分布,通过贝叶斯定理结合先验知识和观测数据: θ_MAP = argmax_θ p(θ|X) ∝ p(X|θ)p(θ)
一个重要的参数模型是高斯混合模型(GMM),它假设数据由多个高斯分布的加权和生成: p(x) = Σₖ πₖ N(x|μₖ,Σₖ)
GMM的参数通常通过EM算法估计:
- E步:计算每个数据点属于各个组件的后验概率
- M步:更新组件的权重、均值和协方差矩阵
4.2 非参数估计
核密度估计(KDE)是最常用的非参数方法,它通过在每个数据点上放置一个核函数并求和来估计密度:
其中K是核函数,h是带宽参数。核函数的选择包括:
- 高斯核:K(u) = (1/√(2π))exp(-u²/2)
- Epanechnikov核:K(u) = (3/4)(1-u²),|u|≤1
- 矩形核:K(u) = 1/2,|u|≤1
以下是使用高斯核的简单实现:
import numpy as np
from scipy.stats import gaussian_kde
def simple_kde(X, x_grid, bandwidth=0.5):
n = len(X)
kde = np.zeros_like(x_grid)
for x_i in X:
# 使用高斯核
kde += np.exp(-0.5 * ((x_grid - x_i) / bandwidth)**2)
kde = kde / (n * bandwidth * np.sqrt(2 * np.pi))
return kde
带宽选择是KDE中的关键问题,常用方法有:
- Silverman's rule of thumb
- 交叉验证
- 自适应带宽方法
直方图方法是最简单的非参数估计方法,但在选择箱宽和起点时存在主观性。现代改进包括:
- 变宽直方图
- 平均移位直方图
- 自适应直方图
最近邻方法基于数据点的局部密度来估计概率密度,其思想是密度与最近邻点间距离成反比。
4.3 改进的估计
规范化流(Normalizing Flows)通过一系列可逆变换将简单分布(如标准正态分布)映射到复杂分布:
- 优势是可以精确计算似然
- 支持高效的采样
- 可以处理复杂的多峰分布
自回归模型将联合分布分解为条件分布的乘积: p(x₁,...,xₙ) = ∏ᵢ p(xᵢ|x₁,...,xᵢ₋₁)
这些方法在实践中面临几个关键挑战:
- 维度灾难:在高维空间中,数据变得稀疏,密度估计变得困难。解决方案包括:
- 降维预处理
- 使用结构化模型
- 采用深度学习方法
- 模型选择:如何选择合适的模型和参数是一个关键问题。常用方法包括:
- 交叉验证
- 信息准则(AIC、BIC)
- 模型平均
- 计算效率:某些方法(如KDE)在大规模数据集上计算开销大。改进方法包括:
- 使用快速算法(如FFT)
- 数据采样
- 并行计算
5 生成模型
生成模型是一类能够学习数据分布并生成与训练数据类似的新样本的模型。与判别模型不同,生成模型试图理解数据是如何产生的,它们学习的是联合概率分布P(X,Y)或数据的边缘分布P(X),这使得它们能够执行更丰富的任务,如数据生成、缺失值填补、异常检测等。
5.1 显式密度模型
显式密度模型直接定义并最大化数据的似然函数。这类模型包括:
变分自编码器(VAE)是一种重要的显式密度模型,它结合了神经网络和变分推断。VAE的核心思想是:
- 使用编码器网络将输入数据x映射到潜在空间的分布q(z|x)
- 使用解码器网络从潜在变量z重构数据p(x|z)
- 优化目标包括重构误差和KL散度: L = E[log p(x|z)] - KL(q(z|x)||p(z))
这个目标函数的两项分别确保了重构质量和潜在空间的规则性。
自回归模型通过因式分解来建模数据分布: p(x) = ∏ᵢ p(xᵢ|x₁,...,xᵢ₋₁)
典型的例如PixelRNN和PixelCNN,它们可以逐像素地生成图像,生成质量高但速度较慢。
规范化流(Normalizing Flows)通过一系列可逆变换将简单分布(如标准正态分布)转换为复杂分布。其优势在于:
- 精确的似然计算
- 快速的采样过程
- 可逆性保证
5.2 隐式密度模型
隐式密度模型不直接建模概率密度,而是通过采样过程来隐式地定义分布。最著名的代表是生成对抗网络(GAN):
GAN包含两个相互对抗的网络:
- 生成器G:试图生成逼真的样本
- 判别器D:试图区分真实样本和生成的样本
训练目标可以表示为极小极大博弈: min_G max_D E[log D(x)] + E[log(1-D(G(z)))]
GAN的发展催生了许多重要变体:
- DCGAN:将卷积神经网络引入GAN架构
- WGAN:使用Wasserstein距离改进训练稳定性
- StyleGAN:引入风格控制机制,生成质量显著提升
- Conditional GAN:允许控制生成过程
5.3 扩散模型
扩散模型是近年来发展最快的生成模型之一,它通过逐步添加和移除噪声来学习数据分布:
- 前向过程:逐步将数据转换为噪声
- 反向过程:学习去噪步骤
- 采样时通过迭代去噪生成数据
扩散模型的优势在于:
- 训练稳定
- 生成质量高
- 理论基础扎实
- 可以进行精确的似然计算
在实践应用中,生成模型面临几个关键挑战:
- 训练稳定性:特别是GAN的训练经常不稳定,解决方案包括:
- 改进损失函数设计
- 使用正则化技术
- 采用渐进式训练策略
- 模式崩溃:生成器可能只学习到数据分布的一小部分,解决方法包括:
- 使用多样性度量
- 改进网络架构
- 采用集成方法
- 评估指标:生成模型的评估特别困难,常用指标包括:
- Inception Score (IS)
- Fréchet Inception Distance (FID)
- Precision and Recall
- 人工评估