单变量线性判别分析分类方法

2024-03-22 02:30

本文主要是介绍单变量线性判别分析分类方法,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

单变量线性判别分析分类方法

  • 单变量线性判别分析
    • 用贝叶斯方法进行分类
    • 单变量线性判别分析分类
    • 参数估计
    • 程序实现
    • 参考文献

单变量线性判别分析

用贝叶斯方法进行分类

线性判别分析(linear discriminant analysis, LDA)与贝叶斯分类方法的关系十分紧密。我们先来看怎么用贝叶斯方法进行分类。

假设我们有数据集 { ( X 1 , Y 1 ) , ( X 2 , Y 2 ) , ⋯ , } \{(X_1, Y_1), (X_2, \, Y_2), \cdots, \} {(X1,Y1),(X2,Y2),,}。这里 X X X 是自变量, Y Y Y 是因变量,或称为测量量、要预测的变量。 X i X_i Xi可以是一个多维的向量。我们想要把测量到的点(观察点) Y i Y_i Yi 分为 K K K 类中的一类。我们假设每一类的先验概率为 π k \pi_k πk,即如果我们没有其他信息,随机得抽取一个样本点,这个样本点属于第 k k k 类的概率就是 π k \pi_k πk。我们用 f k ( x ) = P ( X = x ∣ Y = k ) \displaystyle f_k (x) = \mathbb{P} (X = x \vert Y = k) fk(x)=P(X=xY=k) 来表示当观察点属于第 k k k 类时,自变量 X X X 的概率密度分布 (当 X X X 的取值为离散的时候,我们就用概率 P ( X = x ∣ Y = k ) \mathbb{P} (X = x \vert Y = k) P(X=xY=k)表示)。

于是,根据Bayes 公式,我们有
P ( Y = k ∣ X = x ) = P ( X = x , Y = k ) P ( X = x ) = P ( X = x , Y = k ) ∑ ℓ = 1 K P ( Y = ℓ ) P ( X = x ∣ Y = ℓ ) = π k f k ( x ) ∑ ℓ = 1 K π ℓ f ℓ ( x ) \begin{aligned} \mathbb{P} (Y = k \vert X = x) &= \frac{\mathbb{P} (X = x, Y = k)}{\mathbb{P} (X = x)} \\ &= \frac{\mathbb{P} (X = x, Y = k)}{\sum_{\ell = 1}^K \mathbb{P}(Y = \ell) \mathbb{P}(X = x \vert Y = \ell)} \\ &= \frac{\pi_k f_k (x) }{\sum_{\ell = 1}^K \pi_{\ell} f_{\ell} (x)} \end{aligned} P(Y=kX=x)=P(X=x)P(X=x,Y=k)==1KP(Y=)P(X=xY=)P(X=x,Y=k)==1Kπf(x)πkfk(x)

所以,根据 Bayes 公式,如果我们能够计算出 π k f k ( x ) ∑ ℓ = 1 K π ℓ f ℓ ( x ) \displaystyle \frac{\pi_k f_k (x) }{\sum_{\ell = 1}^K \pi_{\ell} f_{\ell} (x)} =1Kπf(x)πkfk(x) 的值,我们可以比较得出使得 π k f k ( x ) ∑ ℓ = 1 K π ℓ f ℓ ( x ) \displaystyle \frac{\pi_k f_k (x) }{\sum_{\ell = 1}^K \pi_{\ell} f_{\ell} (x)} =1Kπf(x)πkfk(x) 的值最大的那个类 k k k,从而将 X = x X = x X=x 这个数据分到第 k k k类中。为了方便起见,我们用 p k ( x ) p_k (x) pk(x) 来表示 P ( Y = k ∣ X = x ) \mathbb{P} (Y = k \vert X = x) P(Y=kX=x)

如果我们有预先的知识能让我们决定先验分布 π k \pi_k πk,我们可利用预先有的知识来确定 π k \pi_k πk。否则,我们就用样本的频数来估计 π k \pi_k πk。即 π k = n k / n \displaystyle \pi_k = n_k / n πk=nk/n。这里 n k n_k nk 是属于第 k k k 类的样本点的数目。 n n n 是总共的样本数。

而线性判别分析,linear discriminant analysis (LDA) 就提供了一个估计 p k ( x ) p_k (x) pk(x) 的方法。下面我们就来介绍如何用 LDA 来进行贝叶斯公式的估计,从而对数据进行分类。

单变量线性判别分析分类

所谓单变量的线性判别分析,是指 X X X 只有一个变量,即 X X X 是一维的。我们假设 Y Y Y 可以取三个不同的类别。为了估计 p k ( x ) p_k (x) pk(x),我们须要对 f k ( x ) f_{k} (x) fk(x) 有一个估计。这里线性判别分析做了一个假设,即假设 f k ( x ) f_{k} (x) fk(x) 服从一个正态分布。回忆上文, f k ( x ) \displaystyle f_k (x) fk(x) 表示当观察点属于第 k k k 类时,自变量 X X X 的概率密度分布。根据这个假设,我们有
f k ( x ) = 1 2 π exp ⁡ ( − ( x − μ k ) 2 2 σ k 2 ) f_k (x) = \frac{1}{\sqrt{2 \pi}} \exp \left( - \frac{(x - \mu_k)^2}{2 \sigma_k^2} \right) fk(x)=2π 1exp(2σk2(xμk)2)

有了对 f k ( x ) f_k (x) fk(x) 的估计,我们便可以计算 p k ( x ) p_k (x) pk(x)。根据上面的公式,我们有 p k ( x ) = π k f k ( x ) ∑ ℓ = 1 K π ℓ f ℓ ( x ) \displaystyle p_k (x) = \frac{\pi_k f_k (x) }{\sum_{\ell = 1}^K \pi_{\ell} f_{\ell} (x)} pk(x)==1Kπf(x)πkfk(x)。代入 f k ( x ) f_{k} (x) fk(x) 的表达式,我们有
p k ( x ) = π k 1 2 π exp ⁡ ( − ( x − μ k ) 2 2 σ k 2 ) ∑ ℓ = 1 K π ℓ 1 2 π exp ⁡ ( − ( x − μ ℓ ) 2 2 σ ℓ 2 ) p_k (x) = \frac{\pi_k \frac{1}{\sqrt{2 \pi}} \exp \left( - \frac{(x - \mu_k)^2}{2 \sigma_k^2} \right)}{\sum_{\ell = 1}^K \pi_{\ell} \frac{1}{\sqrt{2 \pi}} \exp \left( - \frac{(x - \mu_\ell)^2}{2 \sigma_\ell^2} \right)} pk(x)==1Kπ2π 1exp(2σ2(xμ)2)πk2π 1exp(2σk2(xμk)2)

如果我们再做一个假设,假设 σ 1 2 = σ 2 2 = ⋯ = σ K 2 \displaystyle \sigma_1^2 = \sigma_2^2 = \cdots = \sigma_K^2 σ12=σ22==σK2。即对于不同类别的数据,它们对应的 X X X 的分布的方差是相同的。那么我们就有

p k ( x ) = π k 1 2 π exp ⁡ ( − ( x − μ k ) 2 2 σ 2 ) ∑ ℓ = 1 K π ℓ 1 2 π exp ⁡ ( − ( x − μ ℓ ) 2 2 σ 2 ) . (1) p_k (x) = \frac{\pi_k \frac{1}{\sqrt{2 \pi}} \exp \left( - \frac{(x - \mu_k)^2}{2 \sigma^2} \right)}{\sum_{\ell = 1}^K \pi_{\ell} \frac{1}{\sqrt{2 \pi}} \exp \left( - \frac{(x - \mu_\ell)^2}{2 \sigma^2} \right)}. \tag{1} pk(x)==1Kπ2π 1exp(2σ2(xμ)2)πk2π 1exp(2σ2(xμk)2).(1)

对于给定的 X = x X = x X=x,我们找出使得 p k ( x ) p_k (x) pk(x) 最大的那一 k k k 类,就把 x x x 划分到第 k k k 类。

分析公式(1),可以发现分母 ∑ ℓ = 1 K π ℓ 1 2 π exp ⁡ ( − ( x − μ ℓ ) 2 2 σ 2 ) \displaystyle \sum_{\ell = 1}^K \pi_{\ell} \frac{1}{\sqrt{2 \pi}} \exp \left( - \frac{(x - \mu_\ell)^2}{2 \sigma^2} \right) =1Kπ2π 1exp(2σ2(xμ)2) 是与 k k k 无关的。从而我们只需要找到使得分子 π k 1 2 π exp ⁡ ( − ( x − μ k ) 2 2 σ 2 ) \displaystyle \pi_k \frac{1}{\sqrt{2 \pi}} \exp \left( - \frac{(x - \mu_k)^2}{2 \sigma^2} \right) πk2π 1exp(2σ2(xμk)2) 最大的那个 k k k 即可。对分子求对数,我们有
arg max ⁡ k ( p k ( x ) ) = arg max ⁡ k δ k ( x ) = arg max ⁡ k ( log ⁡ ( π k ) + x ⋅ μ k σ 2 − μ k 2 2 σ 2 ) (2) \begin{aligned} \argmax_{k} \left( p_k(x) \right) &= \argmax_{k} \delta_k(x) \\ &= \argmax_k \left( \log(\pi_k) +\frac{x \cdot \mu_k}{\sigma^2} - \frac{\mu_k^2}{2 \sigma^2} \right) \\ \tag{2} \end{aligned} kargmax(pk(x))=kargmaxδk(x)=kargmax(log(πk)+σ2xμk2σ2μk2)(2)

由于 δ k ( x ) \delta_k(x) δk(x) 关于 x x x 是线性的,所以我们称之为线性判别分析。

具体地说,如果我们要比较第一类( k = 1 k = 1 k=1) 和第二类 ( k = 2 k =2 k=2),我们代入表达式(2),来看什么情况下 p 1 ( x ) p_1(x) p1(x) p 2 ( x ) p_2(x) p2(x) 大。这里先假设 μ 1 < μ 2 \mu_1 < \mu_2 μ1<μ2,并且我们假设所有类别的先验概率都是一样的,即 π 1 = π 2 = ⋯ = π K \pi_1 = \pi_2 = \cdots = \pi_K π1=π2==πK
p 1 ( x ) > p 2 ( x ) ⟺ x ⋅ μ 1 σ 2 − μ 1 2 2 σ 2 > x ⋅ μ 2 σ 2 − μ 2 2 2 σ 2 ⟺ x ⋅ ( μ 1 − μ 2 ) > 1 2 ( μ 1 2 − μ 2 2 ) ⟺ x < 1 2 ( μ 1 + μ 2 ) \begin{aligned} p_1(x) > p_2(x) &\Longleftrightarrow \frac{x \cdot \mu_1}{\sigma^2} - \frac{\mu_1^2}{2\sigma^2} > \frac{x \cdot \mu_2}{\sigma^2} - \frac{\mu_2^2}{2\sigma^2} \\ &\Longleftrightarrow x \cdot (\mu_1 - \mu_2) > \frac{1}{2} (\mu_1^2 - \mu_2^2) \\ &\Longleftrightarrow x < \frac{1}{2} (\mu_1 + \mu_2) \end{aligned} p1(x)>p2(x)σ2xμ12σ2μ12>σ2xμ22σ2μ22x(μ1μ2)>21(μ12μ22)x<21(μ1+μ2)

也就是说,当 x x x 的值小于 μ 1 \mu_1 μ1 μ 2 \mu_2 μ2 的平均值时, x x x 就划分为第一类;反之当 x x x 的值大于 μ 1 \mu_1 μ1 μ 2 \mu_2 μ2 的平均值时,就划分为第二类。

如果我们有多余两个的类别的数目( K > 2 K > 2 K>2),我们须要计算 p 1 ( x ) , p 2 ( x ) , ⋯ , p K ( x ) p_1(x), \, p_2(x), \cdots, \, p_K(x) p1(x),p2(x),,pK(x),找到使 p k ( x ) p_k(x) pk(x) 最大的那个 k k k

参数估计

实际问题中,大多数情况下我们是不知道 μ 1 , μ 2 , ⋯ , μ K \mu_1, \mu_2, \cdots, \, \mu_K μ1,μ2,,μK 以及 σ 2 \sigma^2 σ2 的,这就要求我们对 μ 1 , μ 2 , ⋯ , μ K \mu_1, \mu_2, \cdots, \, \mu_K μ1,μ2,,μK 以及 σ 2 \sigma^2 σ2 作出估计。
我们用如下方法进行估计 [1]:
μ ^ k = 1 n k ∑ i : y i = k x i σ ^ 2 = 1 n − K ∑ k = 1 K ∑ i : y i = k ( x i − μ ^ k ) 2 \begin{aligned} \hat{\mu}_k &= \frac{1}{n_k} \sum_{i: y_i = k} x_i \\ \hat{\sigma}^2 &= \frac{1}{n - K} \sum_{k = 1}^K \sum_{i: y_i = k} (x_i - \hat{\mu}_k)^2 \end{aligned} μ^kσ^2=nk1i:yi=kxi=nK1k=1Ki:yi=k(xiμ^k)2

这里 n n n 是样本点的个数, n k n_k nk 是第 k k k 类的样本点的数目。

程序实现

假设 K = 3 K =3 K=3,我们的样本数据来自于三个不同的正态分布,如下图所示:
在这里插入图片描述
黑色的虚线和红色的虚线分别代表根据LDA 的线性判别公式得到的分类边界(decision boundary)。

我们根据三个不同的正态分布生成样本数据点。

num_points_each_category = 10
x1_sample = np.random.normal(mu_vec[0], 1, (num_points_each_category, 1)) 
x2_sample = np.random.normal(mu_vec[1], 1, (num_points_each_category, 1))
x3_sample = np.random.normal(mu_vec[2], 1, (num_points_each_category, 1))
x1_label = np.zeros((num_points_each_category, 1)) + 1 # generate the label value for category 1
x2_label = np.zeros((num_points_each_category, 1)) + 2 # generate the label value for category 2
x3_label = np.zeros((num_points_each_category, 1)) + 3 # generate the label value for category 3# Make x_i of shape (num_points_each_category, 2), with x_i[:,0] being the data value 
# and x_i[:,1] the category label
x1 = np.hstack((x1_sample, x1_label))
x2 = np.hstack((x2_sample, x2_label))
x3 = np.hstack((x3_sample, x3_label))# Combine them into one ndarray
sample = np.vstack((x1, x2, x3))

sample 的 shape 为 ( m m m, 2)。这里 m m m 是所有数据点的个数。样本点生成之后,我们可以根据一下程序对样本点进行分类。

class LDA:def __init__(self, num_categories, pi_vector, mu_vector, variance):"""num_categories is the number of total categories. vairance is the common distribution variance for all categories.pi_vector is the vector containing the prior distribution forall categories. len(pi_vector) = num_categoriesmu_vector is the vector containing the mean value for eachcategory. len(mu_vector) = num_categories."""self.num_categories = num_categoriesself.variance = varianceself.pi_vector = pi_vectorself.mu_vector = mu_vectorself.estimated_mu_vector = []self.estimated_variance = 0def discriminantFormula(self, x, pi_k, mu_k, var):"""Calculate the value of the \delta_k(x) function given x. The meaning of \delta_k(x) function isdefined in the text. pi_k is the prior distribution for the kth category.mu_k is the mean value of the kth category."""delta_k_at_x = x * mu_k / var + \np.log(pi_k) - (mu_k ** 2) / (2 * var)return delta_k_at_xdef find_best_k(self, x, using_estimated_mu_and_var=True):"""Find the best category that makes \delta_k(x) the largest.x is the value of the sample data point."""cur_max = -float('inf')candi = -1for i in range(self.num_categories):if using_estimated_mu_and_var:cur = self.discriminantFormula(x, self.pi_vector[i], self.estimated_mu_vector[i], self.estimated_variance)else:cur = self.discriminantFormula(x, self.pi_vector[i], self.mu_vector[i], self.variance)if cur > cur_max:candi = icur_max = curreturn candi + 1 # we add 1 because the index starts from 0def get_estimation_mu_variance(self, sample):"""In reality we need to estimate the mu_vector and the commonvariance from the sample. sample has a dimension of (m, 2). m is the total number of data points. sample[:,0] is the valueof the data points, sample[:,1] is the category label for each data point (the label starts from 1). """m = sample.shape[0]mu_estimated = [0 for _ in range(self.num_categories)]variance_total = 0for i in range(self.num_categories):category_i_data = sample[sample[:,1] == (i + 1)]mu_estimated[i] = np.mean(category_i_data[:,0])variance_total += np.sum((category_i_data[:,0] - mu_estimated[i]) ** 2)variance_estimated = variance_total / (m - self.num_categories)self.estimated_mu_vector= mu_estimatedself.estimated_variance = variance_estimatedreturn (mu_estimated, variance_estimated)def calculate_accuracy(self, sample: 'np.ndarray', using_estimated_mu_and_var=True):"""We calculate the accuracy of the LDA classification method. Heresample is an np.ndarray type with the dimension (m, 2). m is the total number of points in sample. """m = sample.shape[0]predicted = [-1 for _ in range(m)]for i in range(m):cur_predicted = self.find_best_k(sample[i, 0], using_estimated_mu_and_var)predicted[i] = cur_predictedreturn np.sum(np.array(predicted) == sample[:,1]) / m

对样本 sample 进行分析如下。

a = LDA(num_categories=3, pi_vector=[1/3, 1/3, 1.3], mu_vector=mu_vec, variance=1)
estimated_mu_vector, estimated_variance = a.get_estimation_mu_variance(sample)
a.calculate_accuracy(sample, using_estimated_mu_and_var=True)

最终作图如下:

plt.figure(figsize=(10, 8))
plt.plot(x1[:,0], np.zeros(num_points_each_category), 's', x2[:,0], np.zeros(num_points_each_category), 'v',x3[:,0], np.zeros(num_points_each_category), 'o', markerfacecolor='none', markersize=20, markeredgewidth=2)
# plt.scatter(x2_sample, np.zeros(10), 'v', markerfacecolor='none', markersize=20, linewidth=8)
# plt.scatter(x3_sample, np.zeros(10), 'o', markerfacecolor='none', markersize=20, linewidth=8)
plt.vlines(1, -0.1, 0.1, color='red',linestyles='--', linewidth=4)
plt.vlines(-1, -0.1, 0.1, color='black',linestyles='--', linewidth=4)
plt.vlines(np.mean([estimated_mu_vector[1], estimated_mu_vector[2]]), -0.1, 0.1, color='red',linestyles='-', linewidth=4)
plt.vlines(np.mean([estimated_mu_vector[0], estimated_mu_vector[1]]), -0.1, 0.1, color='black',linestyles='-', linewidth=4)
plt.ylim(-0.1, 0.1)
plt.xlabel(r"x", fontsize=36)
#plt.ylabel("$y$", fontsize=36)
plt.xticks(fontsize=24)
plt.yticks([])

在这里插入图片描述
图中虚线为根据理论的样本分布函数期望计算得到的分类边界,实线则为根据实际样本点计算得到的分类边界。有了边界值,如果在给我们一个样本点 x x x,我们就可以根据分类边界对 x x x 进行分类。

参考文献

[1] An introduction to statistical learning: with applications in R, Gareth James, Daniela Witten, Trevor Hastie, and Robert Tibshirani, Springer.

这篇关于单变量线性判别分析分类方法的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/834341

相关文章

Nginx设置连接超时并进行测试的方法步骤

《Nginx设置连接超时并进行测试的方法步骤》在高并发场景下,如果客户端与服务器的连接长时间未响应,会占用大量的系统资源,影响其他正常请求的处理效率,为了解决这个问题,可以通过设置Nginx的连接... 目录设置连接超时目的操作步骤测试连接超时测试方法:总结:设置连接超时目的设置客户端与服务器之间的连接

Java判断多个时间段是否重合的方法小结

《Java判断多个时间段是否重合的方法小结》这篇文章主要为大家详细介绍了Java中判断多个时间段是否重合的方法,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录判断多个时间段是否有间隔判断时间段集合是否与某时间段重合判断多个时间段是否有间隔实体类内容public class D

Python使用国内镜像加速pip安装的方法讲解

《Python使用国内镜像加速pip安装的方法讲解》在Python开发中,pip是一个非常重要的工具,用于安装和管理Python的第三方库,然而,在国内使用pip安装依赖时,往往会因为网络问题而导致速... 目录一、pip 工具简介1. 什么是 pip?2. 什么是 -i 参数?二、国内镜像源的选择三、如何

IDEA编译报错“java: 常量字符串过长”的原因及解决方法

《IDEA编译报错“java:常量字符串过长”的原因及解决方法》今天在开发过程中,由于尝试将一个文件的Base64字符串设置为常量,结果导致IDEA编译的时候出现了如下报错java:常量字符串过长,... 目录一、问题描述二、问题原因2.1 理论角度2.2 源码角度三、解决方案解决方案①:StringBui

Linux使用nload监控网络流量的方法

《Linux使用nload监控网络流量的方法》Linux中的nload命令是一个用于实时监控网络流量的工具,它提供了传入和传出流量的可视化表示,帮助用户一目了然地了解网络活动,本文给大家介绍了Linu... 目录简介安装示例用法基础用法指定网络接口限制显示特定流量类型指定刷新率设置流量速率的显示单位监控多个

Java覆盖第三方jar包中的某一个类的实现方法

《Java覆盖第三方jar包中的某一个类的实现方法》在我们日常的开发中,经常需要使用第三方的jar包,有时候我们会发现第三方的jar包中的某一个类有问题,或者我们需要定制化修改其中的逻辑,那么应该如何... 目录一、需求描述二、示例描述三、操作步骤四、验证结果五、实现原理一、需求描述需求描述如下:需要在

JavaScript中的reduce方法执行过程、使用场景及进阶用法

《JavaScript中的reduce方法执行过程、使用场景及进阶用法》:本文主要介绍JavaScript中的reduce方法执行过程、使用场景及进阶用法的相关资料,reduce是JavaScri... 目录1. 什么是reduce2. reduce语法2.1 语法2.2 参数说明3. reduce执行过程

C#中读取XML文件的四种常用方法

《C#中读取XML文件的四种常用方法》Xml是Internet环境中跨平台的,依赖于内容的技术,是当前处理结构化文档信息的有力工具,下面我们就来看看C#中读取XML文件的方法都有哪些吧... 目录XML简介格式C#读取XML文件方法使用XmlDocument使用XmlTextReader/XmlTextWr

C++初始化数组的几种常见方法(简单易懂)

《C++初始化数组的几种常见方法(简单易懂)》本文介绍了C++中数组的初始化方法,包括一维数组和二维数组的初始化,以及用new动态初始化数组,在C++11及以上版本中,还提供了使用std::array... 目录1、初始化一维数组1.1、使用列表初始化(推荐方式)1.2、初始化部分列表1.3、使用std::

oracle DBMS_SQL.PARSE的使用方法和示例

《oracleDBMS_SQL.PARSE的使用方法和示例》DBMS_SQL是Oracle数据库中的一个强大包,用于动态构建和执行SQL语句,DBMS_SQL.PARSE过程解析SQL语句或PL/S... 目录语法示例注意事项DBMS_SQL 是 oracle 数据库中的一个强大包,它允许动态地构建和执行