最小距离分类器
最小距离分类器(Minimum Distance Classifier)是一种简单的分类算法,它基于计算数据点到不同类别中心的距离来进行分类。它通常用于二维或多维数据的分类。基本步骤包括:
- 计算每个类别的中心点:对于给定的训练数据,计算每个类别的中心点,即该类别所有点的平均值。
- 计算距离:对于一个新的数据点,计算它到每个类别中心点的距离。
- 分类决策:将新的数据点分类到与其最近的类别中心点所代表的类别。
算法实现
假设我们有两个类别的数据,我们将使用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=1∑n(xi1−xi2)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=(x1−x2)2+(y1−y2)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)是衡量向量大小的一种方法。简单来说,范数是一个函数,它将一个向量映射到一个非负值(即范数值),这个值可以被理解为该向量的“长度”或“大小”。
不同类型的范数可以通过不同的方式来计算向量的大小。以下是一些常见的范数:
- 欧几里得范数(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} ∥x∥2=x12+x22+⋯+xn2
这相当于在二维或三维空间中测量直线距离。
- 1-范数(Manhattan norm):表示为 ( |\mathbf{x}|_1 ),是向量元素绝对值之和:
∥ x ∥ 1 = ∣ x 1 ∣ + ∣ x 2 ∣ + ⋯ + ∣ x n ∣ \|\mathbf{x}\|_1 = |x_1| + |x_2| + \cdots + |x_n| ∥x∥1=∣x1∣+∣x2∣+⋯+∣xn∣
在几何上,这相当于在网格中沿轴测量距离(如在城市街道中行走的距离)。
- 无穷范数(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∣)
- 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}} ∥x∥p=(∣x1∣p+∣x2∣p+⋯+∣xn∣p)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])
完成了以下任务:
-
迭代唯一标签:
for label in unique_labels
部分遍历unique_labels
中的每个标签。unique_labels
是一个数组,包含了训练数据中所有不同的类别标签。 -
筛选特定类别的向量:
train_vectors[train_labels == label]
是一个条件索引表达式,用于从train_vectors
中选择出所有类别标签为label
的数据点。train_vectors
是一个包含训练数据特征向量的数组,而train_labels
是一个相应的标签数组。 -
计算平均向量:
.mean(axis=0)
计算上述筛选出来的向量的平均值。axis=0
表示沿数组的第一个轴(通常是列)计算均值,即对每个特征维度进行平均。 -
创建包含所有平均向量的数组:最后,列表推导式
[...]
创建了一个新的数组,其中每个元素都是一个类别的平均向量,然后用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
是一个非常有用的工具,尤其是在需要找出数组中最小值位置的场景中。它在数据分析和科学计算中经常被使用。