赞
踩
线性判别分析(Linear Discriminant Analysis,LDA)是一种用于分类和降维的方法。其目标是寻找一个线性组合,使得不同类别的数据在新的维度上具有最大的可分性。
计算类内散度矩阵和类间散度矩阵:
计算矩阵 S W − 1 S B S_W^{-1}S_B SW−1SB 的特征值和特征向量:
选择特征值最大的特征向量:
将数据投影到新的坐标轴上:
S W = ∑ i = 1 c ∑ x ∈ D i ( x − m i ) ( x − m i ) T S_W = \sum_{i=1}^{c} \sum_{\mathbf{x} \in D_i} (\mathbf{x} - \mathbf{m}_i)(\mathbf{x} - \mathbf{m}_i)^T SW=i=1∑cx∈Di∑(x−mi)(x−mi)T
其中, c c c 是类别数, D i D_i Di 是第 i i i 个类别的数据集, m i \mathbf{m}_i mi 是第 i i i 个类别的均值向量。
类内散度矩阵 S W S_W SW 描述了同一类别内部数据点的分散程度。以下是一个具体的例子来说明这一点。
假设我们有两个类别的数据集,每个类别包含若干二维数据点。
类内散度矩阵 S W S_W SW 由两个类别的散度矩阵 S 1 S_1 S1 和 S 2 S_2 S2 相加得到:
S W = S 1 + S 2 S_W = S_1 + S_2 SW=S1+S2
其中, S 1 S_1 S1 和 S 2 S_2 S2 分别是类别 1 和类别 2 的散度矩阵:
S 1 = ∑ x ∈ 类别1 ( x − m 1 ) ( x − m 1 ) T S_1 = \sum_{\mathbf{x} \in \text{类别1}} (\mathbf{x} - \mathbf{m}_1)(\mathbf{x} - \mathbf{m}_1)^T S1=x∈类别1∑(x−m1)(x−m1)T
S 2 = ∑ x ∈ 类别2 ( x − m 2 ) ( x − m 2 ) T S_2 = \sum_{\mathbf{x} \in \text{类别2}} (\mathbf{x} - \mathbf{m}_2)(\mathbf{x} - \mathbf{m}_2)^T S2=x∈类别2∑(x−m2)(x−m2)T
例如,对于类别 1 中的一个点 ( 1 , 2 ) (1, 2) (1,2),进行外积运算,其贡献到 S 1 S_1 S1 的部分是:
(
x
−
m
1
)
(
x
−
m
1
)
T
=
[
1
−
2
2
−
2.67
]
[
1
−
2
2
−
2.67
]
=
[
−
1
−
0.67
]
[
−
1
−
0.67
]
=
[
1
0.67
0.67
0.45
]
类似地,我们会计算类别 1 中其他点的贡献,以及类别 2 中所有点的贡献,然后将这些矩阵相加得到 S W S_W SW。
外积运算能生成一个方阵,这个方阵的每个元素代表了数据点在各个维度上的分散情况。具体来说:
因此,通过外积运算,我们能够获得一个全面的描述数据点分散情况的矩阵。
import numpy as np # 假设数据集 class1 = np.array([[1, 2], [2, 3], [3, 3]]) # 类别1的数据点 class2 = np.array([[6, 8], [7, 8], [8, 9]]) # 类别2的数据点 # 计算每个类别的均值向量 mean1 = np.mean(class1, axis=0) mean2 = np.mean(class2, axis=0) # 计算类内散度矩阵 S_W = np.zeros((2, 2)) # 初始化类内散度矩阵 for x in class1: S_W += np.outer((x - mean1), (x - mean1)) for x in class2: S_W += np.outer((x - mean2), (x - mean2)) print("类内散度矩阵 S_W:", S_W)
S B = ∑ i = 1 c N i ( m i − m ) ( m i − m ) T S_B = \sum_{i=1}^{c} N_i (\mathbf{m}_i - \mathbf{m})(\mathbf{m}_i - \mathbf{m})^T SB=i=1∑cNi(mi−m)(mi−m)T
其中, N i N_i Ni 是第 i i i 个类别中的样本数量, m \mathbf{m} m 是所有样本的全局均值向量。
类间散度矩阵( S B S_B SB)用于描述不同类别之间的数据点的分散程度。它关注的是类别的均值向量之间的差异,而不是类别内部的数据点。
假设我们有两个类别的数据集,每个类别包含若干二维数据点。
类间散度矩阵计算的是不同类别的均值向量之间的差异。对于上面的例子,我们首先计算总体均值向量 m \mathbf{m} m:
m = 所有数据点的均值 \mathbf{m} = \text{所有数据点的均值} m=所有数据点的均值
然后,对于每个类别,我们计算它的均值向量与总体均值向量之间的差,然后进行外积运算,并乘以该类别中的样本数量。例如,对于类别 1:
S B 1 = N 1 ( m 1 − m ) ( m 1 − m ) T S_{B1} = N_1 (\mathbf{m}_1 - \mathbf{m})(\mathbf{m}_1 - \mathbf{m})^T SB1=N1(m1−m)(m1−m)T
类似地,我们计算类别 2 的贡献 S B 2 S_{B2} SB2。类间散度矩阵 S B S_B SB 是这些矩阵的总和:
S B = S B 1 + S B 2 S_B = S_{B1} + S_{B2} SB=SB1+SB2
使用外积计算类间散度矩阵可以帮助我们捕捉不同类别间均值向量的差异。外积运算产生的矩阵描述了这些差异在各个维度上的分布情况。
从数学的角度来看,这种加权方式保证了在优化过程中,大类别的特征不会被小类别的特征所掩盖。
在计算特征值和特征向量时,这种加权方法有助于突出那些在数据集中占据主导地位的类别特征,从而在降维后的特征空间中实现有效的类别分离。
import numpy as np # 假设数据集 class1 = np.array([[1, 2], [2, 3], [3, 3]]) # 类别1的数据点 class2 = np.array([[6, 8], [7, 8], [8, 9]]) # 类别2的数据点 # 计算每个类别的均值向量和总体均值向量 mean1 = np.mean(class1, axis=0) mean2 = np.mean(class2, axis=0) overall_mean = np.mean(np.concatenate((class1, class2)), axis=0) # 计算类间散度矩阵 S_B = np.zeros((2, 2)) S_B += len(class1) * np.outer((mean1 - overall_mean), (mean1 - overall_mean)) S_B += len(class2) * np.outer((mean2 - overall_mean), (mean2 - overall_mean)) print("类间散度矩阵 S_B:", S_B)
在线性判别分析(LDA)中,计算 S W − 1 S B S_W^{-1}S_B SW−1SB 的特征值和特征向量是核心步骤。这一步骤的目的是为了找到最佳的数据投影方向,以最大化类间散度同时最小化类内散度。
通过计算 S W − 1 S B S_W^{-1}S_B SW−1SB 的特征值和特征向量,我们能够确定数据降维的最佳方向,这有助于提高分类的准确性和效率。
import numpy as np # 假设 S_W 是类内散度矩阵,S_B 是类间散度矩阵 # 计算 S_W 的逆矩阵 S_W_inv = np.linalg.inv(S_W) # 计算乘积矩阵 S_W^{-1}S_B S_W_inv_S_B = np.dot(S_W_inv, S_B) # 计算特征值和特征向量 eigenvalues, eigenvectors = np.linalg.eig(S_W_inv_S_B) # 对特征值进行排序,并选择对应的特征向量 indices = np.argsort(eigenvalues)[::-1] top_eigenvectors = eigenvectors[:, indices[:n_components]]
线性判别分析(LDA)是一种常用于降维和分类的统计方法。以下是对LDA算法的Python实现进行详细解释。
np.linalg.pinv(S_W)
)来处理
S
W
S_W
SW 可能不可逆的情况。num_components
个特征向量作为投影方向。np.linalg.qr
)对特征向量进行正交化处理。#X代表数据特征数组,y代表类别(标签),num_components代表降维数量 def lda(X, y, num_components,orth=1): class_means = {} for label in np.unique(y): class_means[label] = np.mean(X[y == label], axis=0) overall_mean = np.mean(X, axis=0) # 类内散布矩阵 S_W S_W = np.zeros((X.shape[1], X.shape[1])) for label, mean_vec in class_means.items(): S_W += np.dot((X[y == label] - mean_vec).T, (X[y == label] - mean_vec)) # 类间散布矩阵 S_B S_B = np.zeros((X.shape[1], X.shape[1])) for label, mean_vec in class_means.items(): n = X[y == label].shape[0] mean_diff = (mean_vec - overall_mean).reshape(X.shape[1], 1) S_B += n * (mean_diff).dot(mean_diff.T) eigenvalues, eigenvectors = np.linalg.eigh(np.linalg.pinv(S_W).dot(S_B)) idx = np.argsort(eigenvalues)[::-1] eigenvectors = eigenvectors[:, idx] eigenvectors = eigenvectors[:, :num_components] # 正交化鉴别向量 if orth==0: print("unorth vector") return eigenvectors.T else : q, r = np.linalg.qr(eigenvectors) return q.T # 返回正交化的鉴别向量
class_means[label] = np.mean(X[y == label], axis=0)
这行代码是线性判别分析(LDA)算法中的一个关键步骤,它用于计算每个类别的均值向量。具体来说,这行代码的作用和意义如下:
np.mean
函数沿着特定的轴(axis=0)计算均值。对于一个给定的类别(标记为 label
),这行代码首先筛选出所有属于这个类别的数据点(X[y == label]
),然后计算这些点在每个特征维度上的平均值。
数学表示为:
m label = 1 N label ∑ x ∈ D label x \mathbf{m}_{\text{label}} = \frac{1}{N_{\text{label}}} \sum_{\mathbf{x} \in D_{\text{label}}} \mathbf{x} mlabel=Nlabel1x∈Dlabel∑x
其中,
D
label
D_{\text{label}}
Dlabel 是属于类别 label
的数据点集合,
N
label
N_{\text{label}}
Nlabel 是这个集合中的数据点数量,
m
label
\mathbf{m}_{\text{label}}
mlabel 是计算得到的均值向量。
S_W += np.dot((X[y == label] - mean_vec).T, (X[y == label] - mean_vec))
这段代码是线性判别分析(LDA)算法中用于计算类内散度矩阵 S W S_W SW 的关键部分。以下是对这部分代码的详细解释。
这部分代码的主要目的是计算类内散度矩阵 S W S_W SW,它度量了数据集中每个类别内部数据点的分散程度。
for label, mean_vec in class_means.items():
循环遍历每个类别。label
是类别标签,mean_vec
是该类别的均值向量。X[y == label] - mean_vec
。X[y == label]
筛选出属于当前类别 label
的所有数据点,mean_vec
是该类别的均值向量。np.dot((X[y == label] - mean_vec).T, (X[y == label] - mean_vec))
。S_W
中,以便对所有类别执行相同的操作。类内散度矩阵的计算公式是:
S W = ∑ i = 1 c ∑ x ∈ D i ( x − m i ) ( x − m i ) T S_W = \sum_{i=1}^{c} \sum_{\mathbf{x} \in D_i} (\mathbf{x} - \mathbf{m}_i)(\mathbf{x} - \mathbf{m}_i)^T SW=i=1∑cx∈Di∑(x−mi)(x−mi)T
其中, c c c 是类别数, D i D_i Di 是第 i i i 个类别的数据集, m i \mathbf{m}_i mi 是第 i i i 个类别的均值向量。
这个计算过程实际上是在评估每个类别内部数据点相对于其均值向量的分散情况。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。