import numpy as np
import matplotlib.pyplot as plt
from utils import *
%matplotlib inline
plt.rcParams["font.family"] = ["sans-serif","SimHei"]
plt.rcParams['axes.unicode_minus'] = False
def find_closest_centroids(X, centroids):
"""
计算每个样本所属的最近质心
参数:
X (ndarray): (m, n) 输入数据,m个样本,每个样本n个特征
centroids (ndarray): (k, n) k个质心的坐标
返回:
idx (array_like): (m,) 每个样本对应的最近质心的索引
"""
K = centroids.shape[0]
idx = np.zeros(X.shape[0], dtype=int)
for i in range(X.shape[0]):
distances = np.sqrt(np.sum((X[i] - centroids) ** 2, axis=1))
idx[i] = np.argmin(distances)
return idx
X = load_data()
initial_centroids = np.array([[3,3], [6,2], [8,5]])
idx = find_closest_centroids(X, initial_centroids)
print("X的形状为:",X.shape)
print("X.shape[0]的值为:",X.shape[0])
print("质心集合形状为:",initial_centroids.shape)
print("最近质心索引idx的形状为:", idx.shape)
print("前三个元素的最近质心索引为:", idx[:3])
from public_tests import *
find_closest_centroids_test(find_closest_centroids)
def compute_centroids(X, idx, K):
"""
根据每个质心所分配到的样本计算新的质心(取平均值)
参数:
X (ndarray): (m, n) 输入数据点
idx (ndarray): (m,) 每个样本对应的最近质心索引数组
K (int): 质心/聚类的数量
返回:
centroids (ndarray): (K, n) 计算得到的新质心
"""
m, n = X.shape
centroids = np.zeros((K, n))
for k in range(K):
samples = X[idx == k]
centroids[k] = np.mean(samples, axis=0)
return centroids
K = 3
centroids = compute_centroids(X, idx, K)
print("计算得到的质心为:", centroids)
compute_centroids_test(compute_centroids)
def run_kMeans(X, initial_centroids, max_iters=10, plot_progress=False):
"""
在数据矩阵X上运行K-Means算法,其中X的每一行是一个样本
"""
m, n = X.shape
K = initial_centroids.shape[0]
centroids = initial_centroids.copy()
previous_centroids = centroids.copy()
idx = np.zeros(m)
for i in range(max_iters):
print(f"K-Means迭代 {i}/{max_iters-1}")
idx = find_closest_centroids(X, centroids)
centroids = compute_centroids(X, idx, K)
plt.show()
return centroids, idx
X = load_data()
initial_centroids = np.array([[3,3],[6,2],[8,5]])
K = 3
max_iters = 10
centroids, idx = run_kMeans(X, initial_centroids, max_iters, plot_progress=True)
def kMeans_init_centroids(X, K):
"""
初始化K个质心,用于在数据集X上运行K-Means算法
参数:
X (ndarray): 数据点
K (int): 质心/聚类的数量
返回:
centroids (ndarray): 初始化的质心
"""
randidx = np.random.permutation(X.shape[0])
centroids = X[randidx[:K]]
return centroids
original_img = plt.imread('bird_small.png')
plt.imshow(original_img)
print("原始图像的形状为:", original_img.shape)
original_img = original_img / 255
X_img = np.reshape(original_img, (original_img.shape[0] * original_img.shape[1], 3))
K = 16
max_iters = 10
initial_centroids = kMeans_init_centroids(X_img, K)
centroids, idx = run_kMeans(X_img, initial_centroids, max_iters)
print("idx的形状:", idx.shape)
print("前五个像素的最近质心:", idx[:5])
X_recovered = centroids[idx, :]
X_recovered = np.reshape(X_recovered, original_img.shape)
fig, ax = plt.subplots(1, 2, figsize=(8, 8))
plt.axis('off')
ax[0].imshow(original_img * 255)
ax[0].set_title('原始图像')
ax[0].set_axis_off()
ax[1].imshow(X_recovered * 255)
ax[1].set_title(f'用{K}种颜色压缩后的图像')
ax[1].set_axis_off()
plt.show()