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

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

相关文章

Linux换行符的使用方法详解

《Linux换行符的使用方法详解》本文介绍了Linux中常用的换行符LF及其在文件中的表示,展示了如何使用sed命令替换换行符,并列举了与换行符处理相关的Linux命令,通过代码讲解的非常详细,需要的... 目录简介检测文件中的换行符使用 cat -A 查看换行符使用 od -c 检查字符换行符格式转换将

SpringBoot实现数据库读写分离的3种方法小结

《SpringBoot实现数据库读写分离的3种方法小结》为了提高系统的读写性能和可用性,读写分离是一种经典的数据库架构模式,在SpringBoot应用中,有多种方式可以实现数据库读写分离,本文将介绍三... 目录一、数据库读写分离概述二、方案一:基于AbstractRoutingDataSource实现动态

Java中的String.valueOf()和toString()方法区别小结

《Java中的String.valueOf()和toString()方法区别小结》字符串操作是开发者日常编程任务中不可或缺的一部分,转换为字符串是一种常见需求,其中最常见的就是String.value... 目录String.valueOf()方法方法定义方法实现使用示例使用场景toString()方法方法

Java中List的contains()方法的使用小结

《Java中List的contains()方法的使用小结》List的contains()方法用于检查列表中是否包含指定的元素,借助equals()方法进行判断,下面就来介绍Java中List的c... 目录详细展开1. 方法签名2. 工作原理3. 使用示例4. 注意事项总结结论:List 的 contain

macOS无效Launchpad图标轻松删除的4 种实用方法

《macOS无效Launchpad图标轻松删除的4种实用方法》mac中不在appstore上下载的应用经常在删除后它的图标还残留在launchpad中,并且长按图标也不会出现删除符号,下面解决这个问... 在 MACOS 上,Launchpad(也就是「启动台」)是一个便捷的 App 启动工具。但有时候,应

SpringBoot日志配置SLF4J和Logback的方法实现

《SpringBoot日志配置SLF4J和Logback的方法实现》日志记录是不可或缺的一部分,本文主要介绍了SpringBoot日志配置SLF4J和Logback的方法实现,文中通过示例代码介绍的非... 目录一、前言二、案例一:初识日志三、案例二:使用Lombok输出日志四、案例三:配置Logback一

Python实现无痛修改第三方库源码的方法详解

《Python实现无痛修改第三方库源码的方法详解》很多时候,我们下载的第三方库是不会有需求不满足的情况,但也有极少的情况,第三方库没有兼顾到需求,本文将介绍几个修改源码的操作,大家可以根据需求进行选择... 目录需求不符合模拟示例 1. 修改源文件2. 继承修改3. 猴子补丁4. 追踪局部变量需求不符合很

mysql出现ERROR 2003 (HY000): Can‘t connect to MySQL server on ‘localhost‘ (10061)的解决方法

《mysql出现ERROR2003(HY000):Can‘tconnecttoMySQLserveron‘localhost‘(10061)的解决方法》本文主要介绍了mysql出现... 目录前言:第一步:第二步:第三步:总结:前言:当你想通过命令窗口想打开mysql时候发现提http://www.cpp

Mysql删除几亿条数据表中的部分数据的方法实现

《Mysql删除几亿条数据表中的部分数据的方法实现》在MySQL中删除一个大表中的数据时,需要特别注意操作的性能和对系统的影响,本文主要介绍了Mysql删除几亿条数据表中的部分数据的方法实现,具有一定... 目录1、需求2、方案1. 使用 DELETE 语句分批删除2. 使用 INPLACE ALTER T

MySQL INSERT语句实现当记录不存在时插入的几种方法

《MySQLINSERT语句实现当记录不存在时插入的几种方法》MySQL的INSERT语句是用于向数据库表中插入新记录的关键命令,下面:本文主要介绍MySQLINSERT语句实现当记录不存在时... 目录使用 INSERT IGNORE使用 ON DUPLICATE KEY UPDATE使用 REPLACE