传统编程要求开发者明晰规定计算机执行任务的逻辑和条条框框的规则。然而,在机器学习的魔法领域,我们向计算机系统灌输了海量数据,让它在数据的奔流中领悟模式与法则,自主演绎未来,不再需要手把手的指点迷津。 机器学习,犹如三千世界的奇幻之旅,分为监督学习、无监督学习和强化学习等多种类型,各具神奇魅力。监督学习如大师传道授业,算法接收标签的训练数据,探索输入与输出的神秘奥秘,以精准预测未知之境。无监督学习则是数据丛林的探险者,勇闯没有标签的领域,寻找隐藏在数据深处的秘密花园。强化学习则是一场与环境的心灵对话,智能体通过交互掌握决策之术,追求最大化的累积奖赏。 机器学习,如涓涓细流,渗透各行各业。在图像和语音识别、自然语言处理、医疗诊断、金融预测等领域,它在智慧的浪潮中焕发生机,将未来的可能性绘制得更加丰富多彩。
聚类算法是一类无监督学习的算法,其目标是将数据集中的样本划分为若干个互不重叠的子集,每个子集被称为一个"簇",使得同一簇内的样本相似度较高,而不同簇之间的样本相似度较低。聚类的目标是在不事先知道数据的真实类别标签的情况下,发现数据中的内在结构和模式。 以下是一些常见的聚类算法:
这些聚类算法在不同场景和数据特性下有各自的优势和局限性,选择合适的算法取决于问题的性质和对结果的需求。聚类在图像分割、客户细分、异常检测等领域都有广泛的应用。
资源获取:关注公众号【科创视野】回复:机器学习实验
(1)加深对非监督学习的理解和认识;
(2)掌握基于距离的和基于密度的动态聚类算法的设计方法。
(1)安装机器学习必要库,如NumPy、Pandas、Scikit-learn等;
(2)配置环境用来运行 Python、Jupyter Notebook和相关库等内容。
1.选择一种聚类算法对鸢尾花做聚类; 2.读入要分类的数据; 3.设置初始聚类中心; 4.根据不同的聚类算法实现聚类; 5.显示聚类结果; 6.按照同样步骤实现学过的所有聚类算法。
在本次实验中,我使用了以下五种聚类方法来对数据进行分析和分类。其中,凝聚聚类算法(Agglomerative Clustering)是我自学的一种聚类方法。
1.K-means
K-means将数据分成K个簇,每个簇都以一个质心代表。该算法通过迭代的方式不断调整簇的质心位置,使得样本点到所属簇的质心的距离最小化。
2.K-means++
K-means++在选择初始质心时更加智能化。K-means++首先选择一个初始质心作为第一个簇的质心,然后根据距离选择下一个质心,直到选择完所有的质心。
3.K_medoids
K_medoids使用样本点作为簇的中心。与K-means算法不同,K_medoids选择的中心点必须是实际存在的样本点,而不仅仅是质心的位置。
4.DBScan
DBScan它将具有足够高密度的样本点划分为一个簇,并将低密度区域视为噪声。DBScan通过设置邻域半径和最小样本数来定义簇的形成条件。
5.凝聚聚类算法
凝聚聚类算法从每个样本点开始,逐步将最近的样本点聚合成簇,直到满足预设的聚类数目。凝聚聚类算法的特点是簇的形成是通过合并的方式进行的。
图1
运行结果
图2
实验代码:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
# 加载Iris数据集
def load_iris_data():
data = pd.read_csv("data/iris.csv") # 假设数据集保存在名为"iris.csv"的文件中
data = data.drop("Species", axis=1) # 移除类别列
return data.values
# 计算欧氏距离
def euclidean_distance(a, b):
return np.linalg.norm(a - b)
# 初始化聚类中心
def initialize_centers(data, k):
np.random.shuffle(data)
return data[:k]
# 分配样本点到最近的聚类中心
def assign_clusters(data, centers):
distances = np.zeros((len(data), len(centers)))
for i, sample in enumerate(data):
for j, center in enumerate(centers):
distances[i, j] = euclidean_distance(sample, center)
return np.argmin(distances, axis=1)
# 更新聚类中心
def update_centers(data, clusters, k):
centers = np.zeros((k, data.shape[1]))
for i in range(k):
cluster_samples = data[clusters == i]
if len(cluster_samples) > 0:
centers[i] = np.mean(cluster_samples, axis=0)
return centers
# K-means聚类算法
def k_means(data, k, max_iterations=100):
centers = initialize_centers(data, k)
for _ in range(max_iterations):
prev_centers = centers.copy()
clusters = assign_clusters(data, centers)
centers = update_centers(data, clusters, k)
if np.all(prev_centers == centers):
break
return clusters, centers
# 加载数据集
data = load_iris_data()
k = 3
clusters, centers = k_means(data, k)
# 绘制聚类结果
plt.scatter(data[:, 0], data[:, 1], c=clusters, cmap="viridis")
plt.scatter(centers[:, 0], centers[:, 1], marker="^", color="red", s=100, label="Centroids")
plt.xlabel("sepal length (cm)")
plt.ylabel("sepal width (cm)")
plt.title("K-means Clustering")
plt.legend()
plt.savefig("data/k-means聚类结果.png")
plt.show()
源码分析
该代码实现了K-means聚类算法对Iris数据集进行聚类,其中:
在k_means()函数中,首先使用initialize_centers()函数初始化聚类中心,然后进入迭代过程。每次迭代,首先将当前的聚类中心保存为prev_centers,然后使用assign_clusters()函数将样本点分配到最近的聚类中心,得到每个样本点所属的聚类索引。接下来,使用update_centers()函数根据每个聚类的样本点计算新的聚类中心。在每次迭代之后,检查当前的聚类中心是否与上一次迭代的聚类中心相同,如果相同,则说明聚类已经收敛,可以提前结束迭代。最终,返回聚类结果和最终的聚类中心。
图3
运行结果
图4
实验代码:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
# 加载Iris数据集
def load_iris_data():
data = pd.read_csv("data/iris.csv")
# 假设数据集保存在名为"iris.csv"的文件中
data = data.drop("Species", axis=1)
# 移除类别列
return data.values
# 计算欧氏距离
def euclidean_distance(a, b):
return np.linalg.norm(a - b)
# 初始化聚类中心
def initialize_centers(data, k):
centers = np.zeros((k, data.shape[1]))
# 创建一个k行,每行包含数据的特征数列的零数组,用于存储聚类中心
centers[0] = data[np.random.choice(range(len(data)))]
# 随机选择一个数据点作为第一个聚类中心
for i in range(1, k):
# 对于每个后续聚类中心,计算它与已选定的聚类中心之间的距离,并使用距离构建一个概率分布
distances = np.array([min([euclidean_distance(c, x) for c in centers[:i]]) for x in data])
probabilities = distances / np.sum(distances)
# 计算概率
centers[i] = data[np.random.choice(range(len(data)), p=probabilities)]
# 根据概率选择下一个聚类中心
return centers
# 分配样本点到最近的聚类中心
def assign_clusters(data, centers):
distances = np.zeros((len(data), len(centers)))
# 创建一个数组,存储每个样本点到每个聚类中心的距离
for i, sample in enumerate(data):
for j, center in enumerate(centers):
distances[i, j] = euclidean_distance(sample, center)
# 计算样本点到聚类中心的距离
return np.argmin(distances, axis=1)
# 返回每个样本点所属的最近的聚类索引
# 更新聚类中心
def update_centers(data, clusters, k):
centers = np.zeros((k, data.shape[1]))
# 创建一个k行,每行包含数据的特征数列的零数组,用于存储新的聚类中心
for i in range(k):
cluster_samples = data[clusters == i]
# 提取属于第i个聚类的样本点
if len(cluster_samples) > 0:
centers[i] = np.mean(cluster_samples, axis=0)
# 计算属于第i个聚类的样本点的均值作为新的聚类中心
return centers
# K-means++聚类算法
def k_means(data, k, max_iterations=100):
centers = initialize_centers(data, k)
# 初始化聚类中心
for _ in range(max_iterations):
prev_centers = centers.copy()
# 复制当前的聚类中心
clusters = assign_clusters(data, centers)
# 分配样本点到聚类中心
centers = update_centers(data, clusters, k)
# 更新聚类中心
if np.all(prev_centers == centers):
# 如果当前的聚类中心与上一轮的聚类中心相同,则停止迭代
break
return clusters, centers
# 返回最终的聚类结果和聚类中心
data = load_iris_data()
k = 3
clusters, centers = k_means(data, k)
# 绘制聚类结果
plt.scatter(data[:, 0], data[:, 1], c=clusters, cmap="viridis")
plt.scatter(centers[:, 0], centers[:, 1], marker="^", color="red", s=100, label="Centroids")
plt.xlabel("sepal length (cm)")
plt.ylabel("sepal width (cm)")
plt.title("K-means++ Clustering")
plt.legend()
plt.savefig("data/k-means++聚类结果.png")
plt.show()
源码分析
通过实现K-means++聚类算法,并对Iris数据集进行了聚类分析,最终生成散点图展示聚类结果。
图5
运行结果
图6
实验代码:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
# 导入Iris数据集
def load_iris_data():
data = pd.read_csv("data/iris.csv") # 假设数据集保存在名为"iris.csv"的文件中
data = data.drop("Species", axis=1) # 移除类别列
return data.values
# 曼哈顿距离
def manhattan_distance(a, b):
return np.sum(np.abs(a - b))
# 初始化聚类中心(Medoids)
def initialize_medoids(data, k):
medoids = np.zeros(k, dtype=int)
n = len(data)
indices = np.arange(n)
np.random.shuffle(indices)
medoids = indices[:k]
return medoids
# 分配样本点到最近的聚类中心
def assign_clusters(data, medoids):
clusters = np.zeros(len(data), dtype=int)
for i, point in enumerate(data):
distances = [manhattan_distance(point, data[m]) for m in medoids]
clusters[i] = np.argmin(distances)
return clusters
# 更新聚类中心(Medoids)
def update_medoids(data, clusters, medoids):
new_medoids = np.copy(medoids)
for i in range(len(medoids)):
cluster_points = data[clusters == i]
cluster_distances = np.zeros(len(cluster_points))
for j, point in enumerate(cluster_points):
other_distances = np.sum(manhattan_distance(point, other) for other in cluster_points)
cluster_distances[j] = other_distances
new_medoid_index = np.argmin(cluster_distances)
new_medoids[i] = np.where(clusters == i)[0][new_medoid_index]
return new_medoids
# K-medoids聚类算法
def k_medoids(data, k, max_iterations=100):
medoids = initialize_medoids(data, k)
clusters = assign_clusters(data, medoids)
for _ in range(max_iterations):
new_medoids = update_medoids(data, clusters, medoids)
new_clusters = assign_clusters(data, new_medoids)
if np.array_equal(clusters, new_clusters):
break
medoids = new_medoids
clusters = new_clusters
return clusters, medoids
# 加载Iris数据集
data = load_iris_data()
# 设置聚类的数量k
k = 3
# 运行K-medoids聚类算法
clusters, medoids = k_medoids(data, k)
# 绘制聚类结果
plt.scatter(data[:, 0], data[:, 1], c=clusters, cmap="viridis") # 绘制数据点,颜色根据聚类结果clusters来区分,使用颜色映射"viridis"
plt.scatter(data[medoids, 0], data[medoids, 1], c="red", marker="^") # 绘制聚类中心,使用红色的三角形表示
plt.xlabel("sepal length (cm)") # 设置x轴标签
plt.ylabel("sepal width (cm)") # 设置y轴标签
plt.title("K-medoids Clustering") # 设置图的标题为"K-medoids Clustering"
plt.savefig("data/k-medoids聚类结果.png") # 保存图像为文件
plt.show()
源码分析
图7
运行结果
图8
实验代码:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
# 导入Iris数据集
def load_iris_data():
data = pd.read_csv("data/iris.csv") # 假设数据集保存在名为"iris.csv"的文件中
data = data.drop("Species", axis=1) # 移除类别列
return data.values
# 欧氏距离
def euclidean_distance(a, b):
return np.linalg.norm(a - b)
# 寻找在给定点半径范围内的邻域数据点
def region_query(data, point_index, epsilon):
distances = np.linalg.norm(data - data[point_index], axis=1)
return np.where(distances <= epsilon)[0]
# 扩展簇,将邻域内的点添加到同一簇中
def expand_cluster(data, cluster_labels, point_index, neighbors, cluster_id, epsilon, min_samples):
cluster_labels[point_index] = cluster_id
i = 0
while i < len(neighbors):
neighbor_index = neighbors[i]
if cluster_labels[neighbor_index] == 0: # 未分类的点
cluster_labels[neighbor_index] = cluster_id
new_neighbors = region_query(data, neighbor_index, epsilon)
if len(new_neighbors) >= min_samples:
neighbors = np.concatenate((neighbors, new_neighbors))
i += 1
# DBSCAN聚类算法
def dbscan(data, epsilon, min_samples):
cluster_labels = np.zeros(len(data), dtype=int)
cluster_id = 0
for i in range(len(data)):
if cluster_labels[i] == 0: # 未分类的点
neighbors = region_query(data, i, epsilon)
if len(neighbors) < min_samples: # 边界点
cluster_labels[i] = -1
else: # 核心点
cluster_id += 1
expand_cluster(data, cluster_labels, i, neighbors, cluster_id, epsilon, min_samples)
return cluster_labels
# 加载Iris数据集
data = load_iris_data()
epsilon = 1 # 设置半径
min_samples = 1 # 设置每个类别的最小样本量
cluster_labels = dbscan(data, epsilon, min_samples)
# 绘制聚类结果
plt.scatter(data[:, 0], data[:, 1], c=cluster_labels, cmap="viridis") # 绘制数据点,颜色根据聚类结果cluster_labels来区分,使用颜色映射"viridis"
plt.xlabel("sepal length (cm)") # 设置x轴标签
plt.ylabel("sepal width (cm)") # 设置y轴标签
plt.title("DBSCAN Clustering") # 设置图的标题为"DBSCAN Clustering"
plt.savefig("data/DBScan聚类结果") # 保存图像为文件
plt.show() # 显示图像
源码分析
2.4.5 凝聚聚类算法
图9
运行结果
图10
实验代码:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.cluster import AgglomerativeClustering
# 导入Iris数据集
def load_iris_data():
data = pd.read_csv("data/iris.csv") # 假设数据集保存在名为"iris.csv"的文件中
data = data.drop("Species", axis=1) # 移除标签列
return data.values
# 加载Iris数据集
data = load_iris_data()
# 执行凝聚层次聚类
clustering = AgglomerativeClustering(n_clusters=3) # 创建AgglomerativeClustering对象并指定聚类个数为3
cluster_labels = clustering.fit_predict(data) # 对数据进行聚类并获取聚类标签
# 绘制聚类结果
plt.scatter(data[:, 0], data[:, 1], c=cluster_labels, cmap="viridis") # 绘制数据点,颜色根据聚类结果cluster_labels来区分,使用颜色映射"viridis"
plt.xlabel("sepal length (cm)") # 设置x轴标签
plt.ylabel("sepal width (cm)") # 设置y轴标签
plt.title("Agglomerative Clustering") # 设置图的标题为"Agglomerative Clustering"
plt.savefig("data/Agglomerative聚类结果.png") # 保存图像为文件
plt.show() # 显示图像
源码分析
这次实验如同踏足深邃的聚类算法探索之旅,涵盖了K-means、K-medoids、DBSCAN和凝聚聚类等引人瞩目的算法。
K-means通过不懈的迭代,将样本点巧妙地划分到K个簇中,并通过持续更新聚类中心的手法,不断提炼出聚类结果的精髓。虽然其简约高效,却对初始聚类中心的选择极为敏感,于是乎,K-means++以一种独特的方式改善了这一选择过程,从而显著提升了聚类的优越性。
K-medoids则以实际样本点为聚类中心,使得整个过程更为稳健,然而在处理大规模数据时,或许会面临着计算复杂度的考验。
DBSCAN以一种独特的方式通过密度可达关系扩展簇的规模,但对参数的选择显得尤为挑剔,需要谨慎斟酌,方可发挥其优势。
而凝聚聚类算法如同绘画一般,从每个样本点作为独立簇起步,逐渐融合最为相似的簇,从而呈现出层次化的聚类结果。然而,这一过程的计算复杂度较高,尤其在处理大规模数据时可能遭遇性能上的制约。
这次实验深刻地引领我步入这些算法的深邃世界,深刻理解它们的原理、特点和应用场景。在选择聚类算法时,需全面考虑数据的独特之处、规模的宏观因素、计算资源的稀缺与充足,以及对所需聚类结果形式的渴望等多重要素。同时,算法的效果不仅仅在于其自身,更在于恰如其分的参数选择,这是一个需要精心权衡的决定性因素。