K均值聚类
一种无监督学习算法。用来把一组数据点分成K个不同的簇。主要目的是最小化簇内平方误差和。对数据点需要找最近的簇,对簇需要求得对点距离的平均值,然后更新簇。
K均值聚类是生成式还是判别式方法?
生成式方法,因为它试图学习生成数据的概率分布,不断更新新数据。
KNN VS. K-means
KNN算法是监督式学习算法,用于分类和回归,K-means是无监督学习算法,用于聚类。
主成分分析
数据降维技术。将高维空间的主要数据映射到低维空间方便计算。
LDA VS. PCA
都是降维用的。但是LDA是监督学习算法,用来分类。PCA是无监督学习算法,用于数据探索和可视化。
奇异值分解(SVD)
将一个矩阵分解成3个矩阵乘积。用来图像压缩,自然语言处理。
A = UΣV^T。
其中,U 和 V 是正交矩阵,Σ 是对角矩阵
特征人脸方法(Eigenface)
将人脸图像投影到低维空间,提取出最有区分性的特征,再把测试人脸也投影,来测试人脸身份。
潜在语义分析 (LSA)
把语言提取成一些矩阵和特殊值,用来判断不同语言的相似度,用来检索和分类用的,有可能查重网站利用的就是这种技术。
期望最大化算法(EM)
用于求解包含隐变量的概率模型参数的最大似然估计。
K-means是最简单的EM算法?
不完全,他们都有迭代的E步和M步最大化期望,但是算法不一样,目标函数也不同。
编程实现EM算法
main:
import matplotlib.pyplot as plt
from generate_data import generate_data
from em_algorithm import EMAlgorithm
# 生成测试数据集
X = generate_data(n_samples=300)
# 设置模型参数
n_clusters = 3
max_iter = 100
# 创建 EM 算法实例
em_algo = EMAlgorithm(n_clusters=n_clusters, max_iter=max_iter)
# 运行 EM 算法
em_algo.fit(X)
# 显示聚类结果
plt.scatter(X[:, 0], X[:, 1], c=em_algo.labels_)
plt.show()
EMAlgorithm:
import numpy as np
class EMAlgorithm:
def __init__(self, n_clusters, max_iter):
"""
初始化 EM 算法。
Parameters
----------
n_clusters : int
聚类数量。
max_iter : int
最大迭代次数。
"""
self.n_clusters = n_clusters
self.max_iter = max_iter
self.labels_ = None
self.mu_ = None
self.sigma_ = None
self.pi_ = None
def _initialize_params(self, X):
"""
初始化模型参数。
Parameters
----------
X : ndarray of shape (n_samples, n_features)
数据集。
"""
n_samples, n_features = X.shape
# 初始化均值向量、协方差矩阵和权重系数
self.mu_ = np.zeros((self.n_clusters, n_features))
self.sigma_ = np.zeros((self.n_clusters, n_features, n_features))
self.pi_ = np.ones(self.n_clusters) / self.n_clusters
# 从数据集中随机选取数据点作为聚类中心
indices = np.random.choice(n_samples, size=self.n_clusters, replace=False)
self.mu_ = X[indices]
# 初始化协方差矩阵
for k in range(self.n_clusters):
self.sigma_[k] = np.eye(n_features)
def _e_step(self, X):
"""
执行 E 步骤。
Parameters
----------
X : ndarray of shape (n_samples, n_features)
数据集。
Returns
-------
resp : ndarray of shape (n_samples, n_clusters)
每个数据点属于每个聚类的概率。
"""
n_samples = X.shape[0]
resp = np.zeros((n_samples, self.n_clusters))
for k in range(self.n_clusters):
diff = X - self.mu_[k]
exponent = np.sum(diff @ np.linalg.inv(self.sigma_[k]) * diff, axis=1)
resp[:, k] = self.pi_[k] * np.exp(-0.5 * exponent)
resp /= np.sum(resp, axis=1, keepdims=True)
return resp
def _m_step(self, X, resp):
"""
执行 M 步骤。
Parameters
----------
X : ndarray of shape (n_samples, n_features)
数据集。
resp : ndarray of shape (n_samples, n_clusters)
每个数据点属于每个聚类的概率。
"""
n_samples = X.shape[0]
n_features = X.shape[1]
# 计算每个聚类的权重系数
self.pi_ = np.sum(resp, axis=0) / n_samples
# 计算每个聚类的均值向量
for k in range(self.n_clusters):
self.mu_[k] = np.sum(resp[:, k].reshape(-1, 1) * X, axis=0) / np.sum(resp[:, k])
# ... 省略其他代码 ...
def fit(self, X):
"""
使用 EM 算法拟合模型。
Parameters
----------
X : ndarray of shape (n_samples, n_features)
数据集。
"""
self._initialize_params(X)
for i in range(self.max_iter):
resp = self._e_step(X)
self._m_step(X, resp)
# 计算对数似然函数值
ll = self._log_likelihood(X)
print(f"Iteration {i+1}/{self.max_iter}: log-likelihood = {ll}")
# 预测数据点属于哪个聚类
self.labels_ = np.argmax(self._e_step(X), axis=1)
def _log_likelihood(self, X):
"""
计算对数似然函数值。
Parameters
----------
X : ndarray of shape (n_samples, n_features)
数据集。
Returns
-------
ll : float
对数似然函数值。
"""
n_samples = X.shape[0]
ll = 0
for k in range(self.n_clusters):
diff = X - self.mu_[k]
exponent = np.sum(diff @ np.linalg.inv(self.sigma_[k]) * diff, axis=1)
ll += np.sum(np.log(self.pi_[k]) - 0.5 * np.log(np.linalg.det(self.sigma_[k])) - 0.5 * exponent)
return ll / n_samples
Gmm:
import numpy as np
from scipy.stats import multivariate_normal
class GaussianMixtureModel:
def __init__(self, k, max_iter=100, tol=1e-4):
"""
初始化高斯混合模型。
Parameters
----------
k : int
聚类数。
max_iter : int, optional
最大迭代次数,默认为 100。
tol : float, optional
收敛阈值,默认为 1e-4。
"""
self.k = k
self.max_iter = max_iter
self.tol = tol
def fit(self, X):
"""
对数据集进行参数估计。
Parameters
----------
X : ndarray of shape (n_samples, n_features)
数据集。
Returns
-------
self
"""
n_samples, n_features = X.shape
# 初始化模型参数
self.pi = np.ones(self.k) / self.k
self.mu = X[np.random.choice(n_samples, self.k, replace=False)]
self.sigma = np.array([np.eye(n_features)] * self.k)
# 迭代更新模型参数
for i in range(self.max_iter):
# E 步:计算后验概率
gamma = np.zeros((n_samples, self.k))
for j in range(self.k):
gamma[:, j] = self.pi[j] * multivariate_normal.pdf(X, mean=self.mu[j], cov=self.sigma[j])
gamma /= gamma.sum(axis=1, keepdims=True)
# M 步:更新模型参数
pi_prev = self.pi.copy()
mu_prev = self.mu.copy()
sigma_prev = self.sigma.copy()
self.pi = gamma.mean(axis=0)
self.mu = gamma.T.dot(X) / gamma.sum(axis=0, keepdims=True).T
for j in range(self.k):
X_centered = X - self.mu[j]
self.sigma[j] = (X_centered.T * gamma[:, j]).dot(X_centered) / gamma[:, j].sum()
# 判断是否收敛
pi_diff = np.abs(self.pi - pi_prev).max()
mu_diff = np.abs(self.mu - mu_prev).max()
sigma_diff = np.abs(self.sigma - sigma_prev).max()
if pi_diff < self.tol and mu_diff < self.tol and sigma_diff < self.tol:
break
return self
def predict(self, X):
"""
对数据集进行预测。
Parameters
----------
X : ndarray of shape (n_samples, n_features)
数据集。
Returns
-------
labels : ndarray of shape (n_samples,)
预测标签。
"""
n_samples = X.shape[0]
# 计算后验概率
gamma = np.zeros((n_samples, self.k))
generate_data:
import numpy as np
def generate_data(n_samples):
"""
生成测试数据集。
Parameters
----------
n_samples : int
数据点数量。
Returns
-------
X : ndarray of shape (n_samples, 2)
数据集。
"""
np.random.seed(0)
# 生成高斯分布
mu1 = [0, 0]
sigma1 = [[1, 0], [0, 1]]
mu2 = [3, 3]
sigma2 = [[1, 0], [0, 1]]
mu3 = [0, 3]
sigma3 = [[1, 0], [0, 1]]
X1 = np.random.multivariate_normal(mu1, sigma1, n_samples // 3)
X2 = np.random.multivariate_normal(mu2, sigma2, n_samples // 3)
X3 = np.random.multivariate_normal(mu3, sigma3, n_samples // 3)
X = np.concatenate([X1, X2, X3])
# 打乱数据集的顺序
np.random.shuffle(X)
return X
运行结果如下:
代码当然不是我写的,只是为了体会算法模型的实现,我还没有成长到这一步,呜呜。