简单的最小距离分类器

最小距离分类器

最小距离分类器(Minimum Distance Classifier)是一种简单的分类算法,它基于计算数据点到不同类别中心的距离来进行分类。它通常用于二维或多维数据的分类。基本步骤包括:

  1. 计算每个类别的中心点:对于给定的训练数据,计算每个类别的中心点,即该类别所有点的平均值。
  2. 计算距离:对于一个新的数据点,计算它到每个类别中心点的距离。
  3. 分类决策:将新的数据点分类到与其最近的类别中心点所代表的类别。

算法实现

假设我们有两个类别的数据,我们将使用Python来实现这个分类器。首先,我会逐步说明每个步骤的代码实现,然后提供完整的代码。

步骤 1: 计算每个类别的中心点

首先,我们需要计算每个类别的中心点。这可以通过对每个类别中所有点的坐标求平均值来实现。在Python中,我们可以使用numpy库来方便地进行数学运算。

import numpy as np

# 假设class1和class2是两个类别的数据点,格式为二维数组
class1 = np.array([[1, 2], [3, 4], [5, 6]])  # 类别1的数据点
class2 = np.array([[7, 8], [9, 10], [11, 12]])  # 类别2的数据点

# 计算每个类别的中心点
center1 = np.mean(class1, axis=0)
center2 = np.mean(class2, axis=0)

在上面的代码中,np.mean函数计算了给定数组的平均值。axis=0参数意味着我们在列方向(即每个维度)上进行平均

步骤 2: 计算距离

接下来,我们需要计算一个新数据点到每个类别中心点的距离。欧氏距离(Euclidean distance)是两点间距离的常用计算方法。其公式表示为:

Euclidean Distance = ∑ i = 1 n ( x i 1 − x i 2 ) 2 \text{Euclidean Distance} = \sqrt{\sum_{i=1}^{n} (x_{i1} - x_{i2})^2} Euclidean Distance=i=1n(xi1xi2)2

其中 x i 1 x_{i1} xi1 x i 2 x_{i2} xi2 分别是两个点在第 i i i 维的坐标值, n n n 是维度数。

对于二维空间(例如,平面上的两个点),公式简化为:

Distance = ( x 1 − x 2 ) 2 + ( y 1 − y 2 ) 2 \text{Distance} = \sqrt{(x_1 - x_2)^2 + (y_1 - y_2)^2} Distance=(x1x2)2+(y1y2)2

其中, x 1 , y 1 x_1, y_1 x1,y1是第一个点的坐标, x 2 , y 2 x_2, y_2 x2,y2 是第二个点的坐标。

在Python中,我们可以这样计算:

# 假设new_point是新的数据点
new_point = np.array([4, 5])

# 计算到每个类别中心点的距离
distance_to_center1 = np.linalg.norm(new_point - center1)
distance_to_center2 = np.linalg.norm(new_point - center2)

这里np.linalg.norm函数用于计算向量的欧氏距离,np.linalg.norm 函数是 NumPy 库中的一个函数,用于计算向量的范数。在数学上,向量的范数是对向量的长度或大小的一种度量。在 Python 的 NumPy 库中,np.linalg.norm 函数常被用来计算向量(或高维数组)的欧几里得范数(Euclidean norm),也就是常说的欧氏距离。

基本用法

numpy.linalg.norm(x, ord=None, axis=None, keepdims=False)

  • x:输入的数组。
  • ord:范数的类型。默认为 None,这时候计算的是2-范数,即欧氏距离。
  • axis:如果指定,则沿着这个轴计算范数。
  • keepdims:如果设置为 True,则输出的维度和输入相同,否则可能会减少维度。
计算欧氏距离

当使用默认参数调用时,np.linalg.norm 计算的是向量的 2-范数,即欧氏距离。例如,计算向量 (3, 4) 的欧氏距离(长度)。

向量的范数

向量的范数(Norm of a vector)是衡量向量大小的一种方法。简单来说,范数是一个函数,它将一个向量映射到一个非负值(即范数值),这个值可以被理解为该向量的“长度”或“大小”。

不同类型的范数可以通过不同的方式来计算向量的大小。以下是一些常见的范数:

  1. 欧几里得范数(Euclidean norm,或 2-范数):这是最常用的范数,表示为 ( |\mathbf{x}|_2 )。对于一个向量 ( \mathbf{x} ),其欧几里得范数是向量各元素平方和的平方根,计算公式为:

∥ x ∥ 2 = x 1 2 + x 2 2 + ⋯ + x n 2 \|\mathbf{x}\|_2 = \sqrt{x_1^2 + x_2^2 + \cdots + x_n^2} x2=x12+x22++xn2

这相当于在二维或三维空间中测量直线距离。

  1. 1-范数(Manhattan norm):表示为 ( |\mathbf{x}|_1 ),是向量元素绝对值之和:

∥ x ∥ 1 = ∣ x 1 ∣ + ∣ x 2 ∣ + ⋯ + ∣ x n ∣ \|\mathbf{x}\|_1 = |x_1| + |x_2| + \cdots + |x_n| x1=x1+x2++xn

在几何上,这相当于在网格中沿轴测量距离(如在城市街道中行走的距离)。

  1. 无穷范数(Infinity norm):表示为 ( |\mathbf{x}|_\infty ),是向量所有元素的绝对值中的最大值:

∥ x ∥ ∞ = max ⁡ ( ∣ x 1 ∣ , ∣ x 2 ∣ , … , ∣ x n ∣ ) \|\mathbf{x}\|_\infty = \max(|x_1|, |x_2|, \ldots, |x_n|) x=max(x1,x2,,xn)

  1. p-范数:表示为 ( |\mathbf{x}|_p ),是向量元素绝对值的 p 次方之和的 1/p 次幂:

∥ x ∥ p = ( ∣ x 1 ∣ p + ∣ x 2 ∣ p + ⋯ + ∣ x n ∣ p ) 1 p \|\mathbf{x}\|_p = \left( |x_1|^p + |x_2|^p + \cdots + |x_n|^p \right)^{\frac{1}{p}} xp=(x1p+x2p++xnp)p1当 ( p = 2 ) 时,p-范数就是欧几里得范数。

向量范数在数学、物理学和工程学等多个领域都有广泛应用,尤其是在解决涉及空间和距离的问题时。

计算其他类型的范数

通过改变 ord 参数的值,np.linalg.norm 可以用来计算不同类型的范数。例如,ord=1 计算的是 1-范数(也称为曼哈顿距离),ord=np.inf 计算的是无穷范数。

在矩阵和多维数组上使用

np.linalg.norm 也可以用于矩阵或多维数组。通过 axis 参数,您可以指定沿哪个轴计算范数。例如,在一个二维数组中,axis=0 会沿着列计算范数,而 axis=1 会沿着行计算范数。

# 计算矩阵每行的欧氏距离
import numpy as np

matrix = np.array([[1, 2], [3, 4]])
norms = np.linalg.norm(matrix, axis=1)

# 输出结果
print(norms)
步骤 3: 分类决策

最后,我们将新的数据点分类到最近的类别中心点所代表的类别。

# 分类决策
if distance_to_center1 < distance_to_center2:
    print("New point belongs to Class 1")
else:
    print("New point belongs to Class 2")

完整代码

将上述步骤合并,我们得到完整的最小距离分类器实现:

import numpy as np

# 类别数据
class1 = np.array([[1, 2], [3, 4], [5, 6]])
class2 = np.array([[7, 8], [9, 10], [11, 12]])

# 计算类别中心点
center1 = np.mean(class1, axis=0)
center2 = np.mean(class2, axis=0)

# 新数据点
new_point = np.array([4, 5])

# 计算距离
distance_to_center1 = np.linalg.norm(new_point - center1)
distance_to_center2 = np.linalg.norm(new_point - center2)

# 分类决策
if distance_to_center1 < distance_to_center2:
    print("New point belongs to Class 1")
else:
    print("New point belongs to Class 2")

以下是用最小距离分类器处理人像识别

数据输入

from PIL import Image
import numpy as np
from sklearn.decomposition import PCA
from sklearn.datasets import fetch_lfw_people
import matplotlib.pyplot as plt

#数据集
label=1
j=1
train_data=[]
train_label=[]
test_data=[]
test_label=[]
for p in range(40):
    for i in range(10):
        num_strings = 10

        # 使用字符串格式化生成列表
        path_string= f"{j:03d}"
        path="ORL/orl"+path_string+".bmp"
        j+=1
        image=Image.open(path)
        image_vector=np.array(image).flatten()
        if i<5:
            train_data.append(image_vector)
            train_label.append(p+1)
        else:
            test_data.append(image_vector)
            test_label.append(p+1)
train_data=np.array(train_data)
train_label=np.array(train_label)
test_data=np.array(test_data)
test_label=np.array(test_label)
print(test_data.shape)
# unique_labels = np.unique(train_label)
# mean_vectors = np.array([train_data[train_label == label].mean(axis=0) for label in unique_labels])
# print(mean_vectors)
# print(mean_vectors.shape)

最小分类实现:

def nearest_mean_classifier(train_vectors, train_labels, test_vectors):
    """最小距离分类器"""
    unique_labels = np.unique(train_labels)
    mean_vectors = np.array([train_vectors[train_labels == label].mean(axis=0) for label in unique_labels])

    predictions = []
    for test_vector in test_vectors:
        # 计算与每个类的平均向量之间的欧氏距离
        distances = np.linalg.norm(mean_vectors - test_vector, axis=1)

        # 返回距离最近的类
        predicted_label = unique_labels[np.argmin(distances)]
        predictions.append(predicted_label)

    return np.array(predictions)


predict_label=nearest_mean_classifier(train_data,train_label,test_data)
print(predict_label)
print(test_label)

代码解释

代码 mean_vectors = np.array([train_vectors[train_labels == label].mean(axis=0) for label in unique_labels]) 完成了以下任务:

  1. 迭代唯一标签for label in unique_labels 部分遍历 unique_labels 中的每个标签。unique_labels 是一个数组,包含了训练数据中所有不同的类别标签。

  2. 筛选特定类别的向量train_vectors[train_labels == label] 是一个条件索引表达式,用于从 train_vectors 中选择出所有类别标签为 label 的数据点。train_vectors 是一个包含训练数据特征向量的数组,而 train_labels 是一个相应的标签数组。

  3. 计算平均向量.mean(axis=0) 计算上述筛选出来的向量的平均值。axis=0 表示沿数组的第一个轴(通常是列)计算均值,即对每个特征维度进行平均。

  4. 创建包含所有平均向量的数组:最后,列表推导式 [...] 创建了一个新的数组,其中每个元素都是一个类别的平均向量,然后用 np.array(...) 将这个列表转换成 NumPy 数组。

应用场景

这种计算方式通常用于准备数据,以便进行如最小距离分类等算法的训练和预测。通过计算每个类别的平均向量,可以得到每个类别在特征空间中的“中心点”,这对于后续的分类决策非常有用。

函数解释

np.argmin 是 NumPy 库中的一个函数,用于找出数组中最小元素的索引。当你有一个由数值组成的数组时,np.argmin 会返回这个数组中最小元素的索引。

基本用法

在最基本的形式中,np.argmin 只需要一个数组作为输入:

  • a:输入的数组。
  • axis:沿着指定的轴找最小值的索引。如果不指定,np.argmin 将会在整个数组中查找。

示例:找出一维数组中最小元素的索引

考虑一个简单的一维数组,np.argmin 会返回数组中的最小值(1)首次出现在索引位置 1。

示例:在二维数组中使用 np.argmin

np.argmin 也可以在多维数组中使用,并且可以指定轴。对于一个二维数组,你可以分别找到每列的最小元素索引或每行的最小元素索引。

import numpy as np

# 一维数组示例
arr = np.array([3, 1, 4, 1, 5, 9, 2])
index_of_min = np.argmin(arr)
print("Index of min in one-dimensional array:", index_of_min)

# 二维数组示例
arr_2d = np.array([[3, 1, 4], [1, 5, 9], [2, 6, 5]])
index_of_min_col = np.argmin(arr_2d, axis=0)  # 每列的最小元素索引
index_of_min_row = np.argmin(arr_2d, axis=1)  # 每行的最小元素索引
print("Index of min in each column:", index_of_min_col)
print("Index of min in each row:", index_of_min_row)

结论

np.argmin 是一个非常有用的工具,尤其是在需要找出数组中最小值位置的场景中。它在数据分析和科学计算中经常被使用。

你可能感兴趣的:(python,机器学习,计算机视觉,分类算法)