无监督学习

返回机器学习

训练数据 只有特征 X、没有标签 y;目标通常是:发现簇结构压缩维度估计密度检测异常。下面示例以 scikit-learn 为主,与 监督学习特征工程 中的预处理习惯一致。


K-Means(划分式聚类)

思想:交替更新簇中心与样本指派,最小化簇内平方和(WCSS)。需 预先指定 K,对 初始中心特征尺度 敏感。

import numpy as np
from sklearn.cluster import KMeans
from sklearn.datasets import make_blobs
from sklearn.metrics import silhouette_score
from sklearn.preprocessing import StandardScaler
 
X, _ = make_blobs(n_samples=500, centers=4, n_features=2, random_state=42)
X = StandardScaler().fit_transform(X)
 
kmeans = KMeans(n_clusters=4, n_init="auto", random_state=42)
labels = kmeans.fit_predict(X)
 
print("inertia (WCSS):", kmeans.inertia_)
print("silhouette:", silhouette_score(X, labels))  # [-1,1],越大簇越分离
 
# 肘部法:扫 K 看 inertia 拐点(业务上需结合可解释性)
inertias = []
for k in range(2, 11):
    km = KMeans(n_clusters=k, n_init="auto", random_state=42).fit(X)
    inertias.append(km.inertia_)

DBSCAN(密度聚类)

思想:eps 邻域内样本数 ≥ min_samples 则为核心点,相连核心点形成簇;噪声点 label = -1。可发现非凸形状,不必定 K

from sklearn.cluster import DBSCAN
from sklearn.datasets import make_moons
from sklearn.preprocessing import StandardScaler
 
X, _ = make_moons(n_samples=300, noise=0.08, random_state=42)
X = StandardScaler().fit_transform(X)
 
db = DBSCAN(eps=0.25, min_samples=5)
labels = db.fit_predict(X)
 
n_clusters = len(set(labels)) - (1 if -1 in labels else 0)
n_noise = list(labels).count(-1)
print("clusters:", n_clusters, "noise:", n_noise)

eps 常结合 k-距离图 或对数据归一化后网格搜索;高维下距离含义变弱,需先做 筛选


层次聚类(Agglomerative)

自底向上合并簇,得到 树状图(dendrogram);适合中小规模、需要层级解释的场景。

import numpy as np
from sklearn.cluster import AgglomerativeClustering
from scipy.cluster.hierarchy import dendrogram, linkage
import matplotlib.pyplot as plt
 
rng = np.random.default_rng(0)
X = rng.normal(size=(80, 2))
 
Z = linkage(X, method="ward")  # 最小方差合并
# dendrogram(Z); plt.show()
 
labels = AgglomerativeClustering(n_clusters=3, linkage="ward").fit_predict(X)

高斯混合模型(GMM,软聚类)

每个样本对各簇有 隶属概率;可看作带隐变量的生成模型,也用于 密度估计 / 异常检测(低似然判异常)。

import numpy as np
from sklearn.datasets import make_blobs
from sklearn.mixture import GaussianMixture
 
X, _ = make_blobs(n_samples=400, centers=3, random_state=0)
 
gmm = GaussianMixture(n_components=3, covariance_type="full", random_state=0)
gmm.fit(X)
proba = gmm.predict_proba(X[:5])
print(proba.round(2))
 
logp = gmm.score_samples(X)          # 每个点 log 密度(越高越「正常」)
threshold = np.percentile(logp, 5)   # 经验:取最低 5% 当异常候选
outliers = np.where(logp < threshold)[0]

PCA(线性降维)

将数据投影到 方差最大的正交方向,用于去相关、可视化、降噪;新特征是原特征的线性组合。

from sklearn.decomposition import PCA
from sklearn.datasets import load_iris
 
X, y = load_iris(return_X_y=True)
pca = PCA(n_components=2)
Z = pca.fit_transform(X)
 
print("explained ratio:", pca.explained_variance_ratio_.round(3))
print("total variance kept:", pca.explained_variance_ratio_.sum().round(3))

TruncatedSVD 常用于稀疏矩阵(如 TF-IDF),与 LSA 文本主题相关。


流形学习(可视化为主)

t-SNE / UMAP:非线性嵌入,2D/3D 图很好看,但 低维坐标距离不宜当真实特征 再做距离分类或回归;论文里常只用来看簇是否分开。

from sklearn.manifold import TSNE
from sklearn.datasets import load_digits
 
X, y = load_digits(return_X_y=True)
X_sub = X[:600]
y_sub = y[:600]
 
Z = TSNE(n_components=2, random_state=42, init="pca", learning_rate="auto").fit_transform(X_sub)
# plt.scatter(Z[:, 0], Z[:, 1], c=y_sub, s=8, cmap="tab10"); plt.show()

聚类效果:轮廓 / CH / DB 指数

from sklearn.cluster import KMeans
from sklearn.datasets import load_iris
from sklearn.metrics import calinski_harabasz_score, davies_bouldin_score, silhouette_score
from sklearn.preprocessing import StandardScaler
 
X, _ = load_iris(return_X_y=True)
X = StandardScaler().fit_transform(X)
labels = KMeans(n_clusters=3, n_init="auto", random_state=0).fit_predict(X)
 
print("silhouette:", silhouette_score(X, labels).round(3))
print("Calinski-Harabasz:", calinski_harabasz_score(X, labels).round(1))
print("Davies-Bouldin:", davies_bouldin_score(X, labels).round(3))

DBSCAN 若有噪声点 -1,用 silhouette 前需剔除噪声或仅对核心簇计算;更常用 业务可解释性 + 稳定性(多次随机初始化) 共同决策 K。

与深度学习

自编码器、对比学习、聚类联合损失 等多在 深度学习 中展开;经典无监督仍是 EDA、表格冷启动、异常检测基线 的主力。


相关链接