有监督算法 & 无监督算法
有监督学习和无监督学习是机器学习中的两种主要类型的学习算法,分别用于不同的任务。下面我通过具体的例子来生动地说明这两者的区别:
有监督学习
定义:有监督学习是一种机器学习方法,其中模型在训练阶段接收标注好的数据,即每个训练样本都有一个对应的标签。模型的目标是学会从输入数据中预测这些标签。
例子:假设你有一组动物的图片,每张图片都有一个标签,标签是“猫”或“狗”。你可以用这些图片来训练一个有监督学习模型。模型在训练时会看到图片和它们的标签,并且学习到什么样的特征可以区分猫和狗。例如,模型可能会学习到猫的耳朵通常是尖的,而狗的耳朵可能是圆的。训练完成后,你可以给模型一张新的图片,模型会根据它所学的特征来预测这张图片是猫还是狗。
应用:垃圾邮件过滤器、疾病预测(比如根据病人的症状预测是否患有某种疾病)、情感分析(根据文本内容预测情感倾向)。
无监督学习
定义:无监督学习是一种机器学习方法,其中模型在训练阶段接收的只是未标注的数据,即没有预先定义好的标签。模型的目标是从这些数据中发现潜在的结构或模式。
例子:假设你有一组不同类型的客户的购买记录,但你不知道他们的具体群体或类别。你可以使用无监督学习中的聚类算法(比如K-means算法)来对这些客户进行分组。模型会分析每个客户的购买行为,并将类似的客户归为同一类。通过这种方式,你可以发现潜在的客户群体,例如“高消费群体”、“中等消费群体”和“低消费群体”,这些群体是模型自动发现的,而不是事先定义好的。
应用:市场细分(发现不同的客户群体)、异常检测(识别数据中的异常点,比如信用卡欺诈检测)、主题建模(从文档中自动提取主题)。
这两种方法都非常强大,适用于不同的任务和数据类型。选择哪种方法通常取决于你是否有标签数据以及你的具体目标。
K-最近邻(K-Nearest Neighbors, KNN)算法是一种简单且直观的监督学习算法,广泛用于分类和回归任务。其基本思想是通过计算样本点之间的距离来进行分类或预测。
KNN算法
KNN 算法的基本步骤
-
选择参数 K:选择一个正整数 K,表示在做分类时考虑最近的 K 个邻居。
-
计算距离:对于待分类的样本,计算它与训练集中所有样本的距离。常用的距离度量包括欧氏距离、曼哈顿距离等。
-
选择最近邻居:找到距离待分类样本最近的 K 个邻居。
-
进行分类或预测:
- 分类:根据这 K 个邻居中出现频率最高的类别来确定待分类样本的类别。
- 回归:计算这 K 个邻居的目标值的平均值(或加权平均值),作为待预测样本的目标值。
示例
问题:假设你正在开发一个基于花瓣和花萼长度来分类鸢尾花(Iris)品种的系统。你有一个包含鸢尾花数据集的训练集,每个样本包括花瓣长度、花瓣宽度、花萼长度和花萼宽度,还有对应的花品种标签(如 Setosa, Versicolor, Virginica)。
步骤:
-
选择参数 K:假设我们选择 K = 3,即在分类时考虑最近的 3 个邻居。
-
计算距离:对于每个待分类的鸢尾花样本,计算它与训练集中所有样本的距离。例如,可以使用欧氏距离来计算。
-
选择最近邻居:假设我们有一个待分类的鸢尾花样本(花瓣长度为 4.5 cm,花瓣宽度为 1.5 cm)。我们计算它与训练集中所有样本的距离,并找到最近的 3 个邻居。
-
进行分类:
- 假设最近的 3 个邻居分别属于 Setosa、Versicolor 和 Setosa。
- 由于 Setosa 出现了 2 次,Versicolor 出现了 1 次,最终根据 KNN 算法,待分类的样本将被分类为 Setosa。
优点和缺点
优点:
- 简单直观,易于理解和实现。
- 不需要模型训练,因为它是一个懒惰学习算法(即所有计算都在预测时完成)。
缺点:
- 计算复杂度高,对于大数据集,预测时间可能很长。
- 对噪声敏感,尤其是在特征空间中有大量噪声时。
- 选择合适的 K 值可能需要经验或交叉验证。
KNN 是一种非常直观且有效的算法,尤其适用于中小规模的数据集和需要解释的场景。
伪代码
以下是 K-最近邻(KNN)算法的伪代码实现,适用于分类任务。伪代码包括了 KNN 的主要步骤:选择 K 值、计算距离、选择最近邻居和进行分类。
function KNN(training_data, test_point, K):
# training_data 是一个包含训练样本的集合,每个样本包含特征和标签
# test_point 是需要分类的测试样本
# K 是选择的邻居数量
# 1. 计算所有训练样本到测试样本的距离
distances = []
for each sample in training_data:
distance = calculate_distance(sample.features, test_point.features)
distances.append((distance, sample.label))
# 2. 根据距离对训练样本进行排序
sorted_distances = sort_by_distance(distances)
# 3. 选择距离最近的 K 个样本
nearest_neighbors = select_first_K(sorted_distances, K)
# 4. 统计 K 个邻居中每个类别的出现次数
class_count = {}
for each neighbor in nearest_neighbors:
label = neighbor.label
if label not in class_count:
class_count[label] = 0
class_count[label] += 1
# 5. 根据出现次数最多的类别确定测试样本的类别
predicted_label = find_most_frequent_class(class_count)
return predicted_label
# 辅助函数
function calculate_distance(features1, features2):
# 计算两个特征向量之间的欧氏距离
sum_squared = 0
for i = 0 to length(features1) - 1:
sum_squared += (features1[i] - features2[i])^2
return sqrt(sum_squared)
function sort_by_distance(distances):
# 对距离进行排序
return sort(distances, by_distance)
function select_first_K(sorted_distances, K):
# 选择前 K 个最近的样本
return sorted_distances[0:K]
function find_most_frequent_class(class_count):
# 找到出现次数最多的类别
max_count = -1
most_frequent_class = None
for each class_label, count in class_count:
if count > max_count:
max_count = count
most_frequent_class = class_label
return most_frequent_class
KMeans算法
K-means 算法是一种常见的无监督学习算法,主要用于数据聚类任务。其目标是将数据集分成 K 个簇(cluster),使得每个簇中的数据点尽可能地相似,而不同簇之间的数据点尽可能地不同。K-means 算法基于数据点的特征,自动地将数据分组。
K-means 算法的基本步骤
-
选择 K 值:选择要分成的簇的数量 K。
-
初始化簇中心:随机选择 K 个数据点作为初始簇中心(centroids)。
-
分配簇:
- 将每个数据点分配到距离最近的簇中心。
- 这个步骤基于某种距离度量(通常是欧氏距离)来确定。
-
更新簇中心:
- 对于每个簇,计算该簇内所有数据点的均值,并将该均值作为新的簇中心。
-
重复步骤 3 和 4:
- 继续分配簇和更新簇中心,直到簇中心不再变化或变化非常小(收敛)。
示例
问题:假设你有一组关于学生的考试成绩数据,包括数学和英语两个科目的分数。你希望将这些学生分成 K 个簇,以发现不同的学习群体。
步骤:
-
选择 K 值:假设我们选择 K = 3,即将学生分成 3 个群体。
-
初始化簇中心:
- 随机选择 3 个学生的数学和英语分数作为初始簇中心。例如,初始簇中心可能是 (80, 70), (60, 50), 和 (90, 85)。
-
分配簇:
- 对于每个学生,根据其数学和英语分数计算与每个簇中心的距离,并将学生分配到距离最近的簇中心。例如,一个学生的分数是 (75, 65),他可能会被分配到与簇中心 (80, 70) 距离最近的簇。
-
更新簇中心:
- 计算每个簇内学生数学和英语分数的均值,并将这些均值作为新的簇中心。例如,如果簇 1 包含学生 (70, 60), (80, 70), 和 (75, 65),则簇 1 的新簇中心将是这三个点的均值。
-
重复步骤 3 和 4:
- 根据新的簇中心重新分配学生,更新簇中心,并重复直到簇中心稳定。
优点和缺点
优点:
- 算法简单,易于理解和实现。
- 对大数据集效果良好,计算速度较快。
缺点:
- 需要预先指定 K 值,选择不合适的 K 值可能影响聚类效果。
- 对初始簇中心选择敏感,可能会导致局部最优解。
- 对离群点和噪声敏感。
K-means 是一种非常流行且实用的聚类算法,尤其适用于数据集中簇的数量已知或容易确定的情况。
伪代码
以下是 K-means 算法的伪代码实现,适用于数据聚类任务。伪代码包括了 K-means 的主要步骤:初始化簇中心、分配簇、更新簇中心和迭代直到收敛。
function KMeans(data, K, max_iterations):
# data 是待聚类的数据集
# K 是选择的簇的数量
# max_iterations 是最大迭代次数
# 1. 随机初始化 K 个簇中心
centroids = initialize_centroids(data, K)
for iteration = 1 to max_iterations:
# 2. 分配每个数据点到最近的簇中心
clusters = assign_clusters(data, centroids)
# 3. 更新簇中心
new_centroids = update_centroids(data, clusters, K)
# 4. 检查收敛条件(簇中心是否变化)
if centroids_equal(new_centroids, centroids):
break
centroids = new_centroids
return clusters, centroids
# 辅助函数
function initialize_centroids(data, K):
# 从数据集中随机选择 K 个样本作为初始簇中心
return random_samples(data, K)
function assign_clusters(data, centroids):
# 为每个数据点分配到最近的簇中心
clusters = []
for each point in data:
distances = [calculate_distance(point, centroid) for each centroid in centroids]
nearest_centroid_index = find_index_of_min(distances)
clusters.append(nearest_centroid_index)
return clusters
function update_centroids(data, clusters, K):
# 根据每个簇中的数据点计算新的簇中心
new_centroids = []
for k = 0 to K-1:
points_in_cluster = [data[i] for i = 0 to length(data)-1 if clusters[i] == k]
new_centroid = calculate_mean(points_in_cluster)
new_centroids.append(new_centroid)
return new_centroids
function calculate_distance(point1, point2):
# 计算两个点之间的欧氏距离
sum_squared = 0
for i = 0 to length(point1) - 1:
sum_squared += (point1[i] - point2[i])^2
return sqrt(sum_squared)
function centroids_equal(centroids1, centroids2):
# 判断两个簇中心是否相等(收敛条件)
for i = 0 to length(centroids1) - 1:
if calculate_distance(centroids1[i], centroids2[i]) > tolerance:
return false
return true
function calculate_mean(points):
# 计算点集的均值
num_points = length(points)
dimensions = length(points[0])
mean = [0] * dimensions
for each point in points:
for d = 0 to dimensions - 1:
mean[d] += point[d]
for d = 0 to dimensions - 1:
mean[d] /= num_points
return mean