目录
6.1 K-means聚类
K-means 是一种将输入数据划分成 k 个簇的简单的聚类算法。K-means 反复提炼初 始评估的类中心,步骤如下:
6.1.1 SciPy聚类包
在SciPy库中,scipy.cluster.vq
模块提供了K-means算法的实现。K-means是一种常见的聚类算法,其主要目标是将数据点分配到预定数量的簇中,使得簇内的数据点尽可能相似,而簇间的数据点尽可能不同。
实验代码:
import numpy as np
from scipy.cluster.vq import kmeans, vq
import matplotlib.pyplot as plt
# 生成测试数据
np.random.seed(42)
data = np.concatenate([
np.random.normal(loc=[1, 1], scale=0.5, size=(100, 2)),
np.random.normal(loc=[5, 5], scale=0.5, size=(100, 2)),
np.random.normal(loc=[8, 1], scale=0.5, size=(100, 2))
])
# 聚类数量
k = 3
# 计算K-means聚类的质心
centroids, distortion = kmeans(data, k)
# 将数据点分配到簇
code, distance = vq(data, centroids)
# 绘制结果
plt.figure(figsize=(8, 6))
plt.scatter(data[:, 0], data[:, 1], c=code, s=30, cmap='viridis')
plt.scatter(centroids[:, 0], centroids[:, 1], c='red', s=100, marker='x') # 质心
plt.title('K-means Clustering')
plt.xlabel('Feature 1')
plt.ylabel('Feature 2')
plt.show()
# 打印结果
print("质心位置:")
print(centroids)
print("失真度(Distortion):", distortion)
分析:
-
聚类效果:
- 上述代码生成了三类数据点,每类数据点在二维空间中分布。K-means聚类会将这些数据点分成三簇,并计算每簇的质心。
- 绘图中,数据点的颜色表示它们所属的簇,红色的“x”标记表示各簇的质心。
-
质心位置:
centroids
数组中包含了每个簇的质心位置。你可以通过这些质心了解每个簇的中心位置。
-
失真度:
distortion
是一个衡量聚类效果的指标,表示所有数据点到其最近质心的平均距离。较低的失真度意味着更好的聚类效果。
结果:
通过上述实验,可以观察到K-means算法如何将数据点分成不同的簇,并计算每个簇的质心。质心位置和失真度可以帮助评估聚类效果。此实验示例仅为基本的K-means应用,实际应用中可能需要进一步优化和调整参数,以适应不同的数据集和应用场景。
6.1.2 图像聚类
我们用 K-means 对这些字体图像进行聚类。
实验代码:
import numpy as np
import cv2
import os
from sklearn.cluster import KMeans
import matplotlib.pyplot as plt
# 设置图像文件夹路径和其他参数
image_folder = 'path_to_your_font_images'
image_size = (64, 64) # 统一图像大小
n_clusters = 5 # 设定簇的数量
# 读取和预处理图像
def load_and_preprocess_images(image_folder, image_size):
images = []
filenames = []
for filename in os.listdir(image_folder):
if filename.endswith('.png') or filename.endswith('.jpg'):
img_path = os.path.join(image_folder, filename)
img = cv2.imread(img_path, cv2.IMREAD_GRAYSCALE)
img = cv2.resize(img, image_size)
images.append(img.flatten())
filenames.append(filename)
return np.array(images), filenames
# 加载数据
images, filenames = load_and_preprocess_images(image_folder, image_size)
# 应用K-means聚类
kmeans = KMeans(n_clusters=n_clusters, random_state=0)
kmeans.fit(images)
labels = kmeans.labels_
# 可视化结果
def plot_clustered_images(images, labels, filenames, n_clusters, image_size):
fig, axes = plt.subplots(n_clusters, len(filenames) // n_clusters, figsize=(15, 10))
for i in range(n_clusters):
cluster_images = [images[j].reshape(image_size) for j in range(len(images)) if labels[j] == i]
for j in range(len(cluster_images)):
axes[i, j].imshow(cluster_images[j], cmap='gray')
axes[i, j].set_title(f'Cluster {i+1}')
axes[i, j].axis('off')
plt.tight_layout()
plt.show()
# 绘制聚类结果
plot_clustered_images(images, labels, filenames, n_clusters, image_size)
# 打印每个图像的簇标签
for filename, label in zip(filenames, labels):
print(f'{filename}: Cluster {label}')
分析:
-
数据加载和预处理:
load_and_preprocess_images()
函数从指定文件夹中读取图像,将每个图像转换为灰度图像,并调整大小为64x64像素。然后,将图像展平为一维特征向量,存储在images
数组中。
-
K-means聚类:
- 使用
KMeans
类对图像特征进行聚类。n_clusters
参数指定簇的数量。fit()
方法用于计算K-means模型,labels_
属性包含每个图像的簇标签。
- 使用
-
结果可视化:
plot_clustered_images()
函数用于绘制每个簇中的图像。每个簇的图像在一行中显示,便于查看相似图像的分组情况。
-
打印结果:
- 输出每个图像及其对应的簇标签,方便查看具体的聚类结果。
结果:
6.1.3 在主成分上可视化图像
用 40 个主成分数对字体图像进行 K-means 聚类:
- 加载和预处理数据:加载字体图像数据,并将其展平为特征向量。
- PCA降维:使用主成分分析(PCA)将数据降到 40 个主成分。
- K-means聚类:对降维后的数据进行 K-means 聚类。
- 可视化:将图像在前两个主成分上进行可视化,显示聚类结果。
实验代码:
import numpy as np
import matplotlib.pyplot as plt
from sklearn.decomposition import PCA
from sklearn.cluster import KMeans
from sklearn.datasets import fetch_olivetti_faces # 示例数据
# 1. 加载和预处理数据
data = fetch_olivetti_faces()
images = data.images
X = data.data # 展平后的图像数据
# 2. PCA降维
pca = PCA(n_components=40)
X_pca = pca.fit_transform(X)
# 3. K-means聚类
n_clusters = 10 # 假设有 10 个簇
kmeans = KMeans(n_clusters=n_clusters, random_state=42)
labels = kmeans.fit_predict(X_pca)
# 4. 可视化
def plot_pca_clusters(X_pca, labels, images, n_clusters):
plt.figure(figsize=(10, 8))
scatter = plt.scatter(X_pca[:, 0], X_pca[:, 1], c=labels, cmap='viridis', s=5)
plt.colorbar(scatter, label='Cluster')
plt.title('PCA of Font Images with K-means Clustering')
plt.xlabel('Principal Component 1')
plt.ylabel('Principal Component 2')
# 在主成分方向上显示示例图像
for i in range(n_clusters):
cluster_indices = np.where(labels == i)[0]
if len(cluster_indices) > 0:
example_idx = cluster_indices[0] # 选择该簇中的第一张图像
plt.figure(figsize=(2, 2))
plt.imshow(images[example_idx], cmap='gray')
plt.title(f'Cluster {i+1} Example')
plt.axis('off')
plt.show()
# 执行可视化
plot_pca_clusters(X_pca, labels, images, n_clusters)
分析:
-
PCA降维:将高维图像数据降到 40 个主成分,这使得 K-means 聚类可以在较低维度空间中进行。主成分提取了最重要的特征信息,有助于提高聚类效率和准确性。
-
K-means聚类:在 40 个主成分上应用 K-means 聚类将图像分为若干簇。通过选择适当的簇数(在示例中为 10),可以根据图像的特征进行分类。
-
可视化:将数据在前两个主成分上可视化,可以直观地看到不同簇的分布情况。展示每个簇的示例图像有助于理解聚类的结果和图像的特征。
结果:
-
主成分可视化:前两个主成分通常能捕捉到数据的主要结构。散点图将显示图像在主成分方向上的分布,颜色代表不同的簇。
-
簇的示例:每个簇的示例图像帮助识别每个簇的典型特征。通过观察这些示例图像,可以评估 K-means 聚类的效果以及是否达到了预期的分组。
6.1.4 像素聚类
将图像区域或像素合并成有意义的部分称为图像分割,
K-means 聚类是一种无监督学习算法,可以用于图像的像素聚类。在这种应用中,我们将图像视为一个像素的集合,每个像素可以用一个特征向量表示。我们可以将图像的每个像素点的颜色特征(通常是 RGB 颜色值)作为特征向量输入到 K-means 算法中,然后通过 K-means 聚类将这些像素点分成几个簇。这样,我们可以根据颜色特征将图像划分为几个区域,类似于图像分割。
实验代码:
import numpy as np
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
from sklearn.datasets import load_sample_image
# 1. 加载图像数据
image = load_sample_image("china.jpg") # 使用 sklearn 的示例图像
image = image / 255.0 # 归一化到 [0, 1] 范围
height, width, channels = image.shape
# 将图像转换为二维数组 (每行是一个像素的 RGB 值)
pixels = image.reshape(-1, 3)
# 2. 应用 K-means 聚类
n_clusters = 5 # 假设我们将图像分为 5 个簇
kmeans = KMeans(n_clusters=n_clusters, random_state=42)
labels = kmeans.fit_predict(pixels)
# 3. 重构图像
# 每个像素的颜色将被替换为其簇的中心颜色
segmented_image = kmeans.cluster_centers_[labels].reshape(height, width, channels)
# 4. 可视化结果
def plot_image_and_segments(original, segmented):
fig, ax = plt.subplots(1, 2, figsize=(12, 6))
ax[0].imshow(original)
ax[0].set_title("Original Image")
ax[0].axis('off')
ax[1].imshow(segmented)
ax[1].set_title("Segmented Image (K-means)")
ax[1].axis('off')
plt.show()
# 执行可视化
plot_image_and_segments(image, segmented_image)
分析:
-
K-means 聚类:在此实验中,我们将图像的每个像素表示为一个 RGB 颜色值,并将这些值作为 K-means 的输入。通过 K-means 算法将像素分为 5 个簇,表示图像中的主要颜色区域。
-
重构图像:聚类后,每个像素的颜色被替换为其所在簇的中心颜色。这样,图像的颜色信息被简化为几种主要的颜色,形成了聚类后的分割效果。
-
结果可视化:展示原始图像与 K-means 聚类后图像的对比。通过这种对比,可以观察到聚类的效果,了解算法如何将图像中的颜色区域分成若干簇。
结果:
- 原始图像:展示了图像的真实颜色和细节。
- 聚类后的图像:显示了图像经过 K-means 聚类后的效果。可以看到,图像的颜色被分成了几个主要的颜色区域。每个区域代表了一个簇,其颜色为该簇的中心颜色。
6.2 层次聚类
层次聚类(或凝聚式聚类)是另一种简单但有效的聚类算法,其思想是基于样本间成对距离建立一个简相似性树。层次聚类有若干优点。例如,利用树结构可以可视化数据间的关系,并显示这些簇 是如何关联的。在树中,一个好的特征向量可以给出一个很好的分离结果。另外一个优点是,对于给定的不同的阈值,可以直接利用原来的树,而不需要重新计算。
# 导入必要的库
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import make_blobs
from sklearn.cluster import AgglomerativeClustering
from scipy.cluster.hierarchy import dendrogram, linkage
from sklearn.metrics import silhouette_score
# 生成示例数据
X, _ = make_blobs(n_samples=300, centers=4, cluster_std=0.60, random_state=0)
# 绘制数据点
plt.scatter(X[:, 0], X[:, 1], s=50)
plt.title('Generated Data')
plt.xlabel('Feature 1')
plt.ylabel('Feature 2')
plt.show()
# 使用凝聚式聚类
def agglomerative_clustering(n_clusters):
model = AgglomerativeClustering(n_clusters=n_clusters)
model.fit(X)
return model
# 可视化凝聚式聚类结果
def plot_clusters(n_clusters):
model = agglomerative_clustering(n_clusters)
labels = model.labels_
plt.scatter(X[:, 0], X[:, 1], c=labels, s=50, cmap='viridis')
plt.title(f'Agglomerative Clustering (n_clusters={n_clusters})')
plt.xlabel('Feature 1')
plt.ylabel('Feature 2')
plt.show()
# 画出不同簇数的结果
for n_clusters in [2, 3, 4, 5]:
plot_clusters(n_clusters)
# 绘制层次树状图(dendrogram)
linked = linkage(X, 'ward')
plt.figure(figsize=(10, 7))
dendrogram(linked, orientation='top', distance_sort='descending', show_leaf_counts=True)
plt.title('Hierarchical Clustering Dendrogram')
plt.xlabel('Sample index')
plt.ylabel('Distance')
plt.show()
# 计算轮廓系数(Silhouette Score)以评估聚类效果
def calculate_silhouette_score(n_clusters):
model = agglomerative_clustering(n_clusters)
labels = model.labels_
score = silhouette_score(X, labels)
return score
# 打印不同簇数下的轮廓系数
for n_clusters in [2, 3, 4, 5]:
score = calculate_silhouette_score(n_clusters)
print(f'Silhouette Score for {n_clusters} clusters: {score:.2f}')
分析:
-
数据可视化:不同的簇数(2、3、4、5)下,聚类结果会有所不同。我们可以通过查看不同簇数下的聚类结果图来直观地了解数据如何被分组。
-
层次树状图:树状图展示了数据的层次结构。可以看到不同簇的合并过程,以及合并时的距离。
-
轮廓系数:轮廓系数是衡量聚类效果的指标。值的范围是[-1, 1],值越高,说明聚类效果越好。通过轮廓系数,我们可以选择最佳的簇数
结果:
6.3 谱聚类
谱聚类方法是一种有趣的聚类算法,与前面 K-means 和层次聚类方法截然不同。
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import fetch_olivetti_faces
from sklearn.metrics.pairwise import euclidean_distances
from sklearn.cluster import KMeans
from sklearn.preprocessing import normalize
from scipy.sparse.csgraph import laplacian
from sklearn.neighbors import kneighbors_graph
# 1. 加载数据
faces = fetch_olivetti_faces()
X = faces.data
n_samples, n_features = X.shape
# 2. 计算相似性矩阵
# 使用k邻近图来构建相似性矩阵
knn_graph = kneighbors_graph(X, n_neighbors=10, mode='connectivity', include_self=False)
similarity_matrix = (knn_graph.toarray() + knn_graph.T.toarray()) / 2 # 对称化
# 3. 构建图拉普拉斯矩阵
laplacian_matrix = laplacian(similarity_matrix, normed=True)
# 4. 计算特征值和特征向量
eigenvalues, eigenvectors = np.linalg.eigh(laplacian_matrix)
# 选择前k个特征向量
k = 40
X_reduced = eigenvectors[:, :k]
# 5. 使用k-means聚类
kmeans = KMeans(n_clusters=40, random_state=42)
labels = kmeans.fit_predict(X_reduced)
# 6. 可视化结果
# 由于结果是按照标签排序的,这里选择了一些代表性的图像来展示
fig, axes = plt.subplots(4, 10, figsize=(10, 4))
for i in range(4):
for j in range(10):
index = np.where(labels == i * 10 + j)[0]
if len(index) > 0:
img_index = index[0]
axes[i, j].imshow(faces.images[img_index], cmap='gray')
axes[i, j].axis('off')
plt.show()
分析:
-
数据准备:
- 加载了Olivetti人脸数据集,包含了4096张64x64像素的灰度图像,每张图像有4096个特征(像素值)。
-
构建相似性矩阵:
- 使用k邻近图(k=10)来构建图像之间的相似性矩阵,邻近图保留了数据点之间的局部结构信息。
-
构建拉普拉斯矩阵:
- 从相似性矩阵计算图的拉普拉斯矩阵,拉普拉斯矩阵用于捕捉数据的全局结构。
-
计算特征向量:
- 计算拉普拉斯矩阵的特征值和特征向量,并选择前40个特征向量作为新的数据表示。
-
聚类:
- 使用k-means算法对降维后的数据进行聚类,指定了40个聚类中心(与数据集中的类别数量一致)。
-
可视化:
- 通过可视化聚类结果中的一些代表性图像,可以观察到聚类效果。每个子图展示了一些被分到同一类别的图像
结果:
- 如果聚类效果较好,相同类别的图像应该在视觉上相似。
- 聚类的效果与k值选择密切相关,可以通过交叉验证等方法优化k值。
- 聚类的质量还依赖于相似性矩阵的构建和特征向量的选择。在实际应用中可能需要调整相似性矩阵的构建方法和特征向量的选择策略。