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

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

相关文章

golang中reflect包的常用方法

《golang中reflect包的常用方法》Go反射reflect包提供类型和值方法,用于获取类型信息、访问字段、调用方法等,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值... 目录reflect包方法总结类型 (Type) 方法值 (Value) 方法reflect包方法总结

C# 比较两个list 之间元素差异的常用方法

《C#比较两个list之间元素差异的常用方法》:本文主要介绍C#比较两个list之间元素差异,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录1. 使用Except方法2. 使用Except的逆操作3. 使用LINQ的Join,GroupJoin

MySQL查询JSON数组字段包含特定字符串的方法

《MySQL查询JSON数组字段包含特定字符串的方法》在MySQL数据库中,当某个字段存储的是JSON数组,需要查询数组中包含特定字符串的记录时传统的LIKE语句无法直接使用,下面小编就为大家介绍两种... 目录问题背景解决方案对比1. 精确匹配方案(推荐)2. 模糊匹配方案参数化查询示例使用场景建议性能优

关于集合与数组转换实现方法

《关于集合与数组转换实现方法》:本文主要介绍关于集合与数组转换实现方法,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1、Arrays.asList()1.1、方法作用1.2、内部实现1.3、修改元素的影响1.4、注意事项2、list.toArray()2.1、方

Python中注释使用方法举例详解

《Python中注释使用方法举例详解》在Python编程语言中注释是必不可少的一部分,它有助于提高代码的可读性和维护性,:本文主要介绍Python中注释使用方法的相关资料,需要的朋友可以参考下... 目录一、前言二、什么是注释?示例:三、单行注释语法:以 China编程# 开头,后面的内容为注释内容示例:示例:四

一文详解Git中分支本地和远程删除的方法

《一文详解Git中分支本地和远程删除的方法》在使用Git进行版本控制的过程中,我们会创建多个分支来进行不同功能的开发,这就容易涉及到如何正确地删除本地分支和远程分支,下面我们就来看看相关的实现方法吧... 目录技术背景实现步骤删除本地分支删除远程www.chinasem.cn分支同步删除信息到其他机器示例步骤

在Golang中实现定时任务的几种高效方法

《在Golang中实现定时任务的几种高效方法》本文将详细介绍在Golang中实现定时任务的几种高效方法,包括time包中的Ticker和Timer、第三方库cron的使用,以及基于channel和go... 目录背景介绍目的和范围预期读者文档结构概述术语表核心概念与联系故事引入核心概念解释核心概念之间的关系

在Linux终端中统计非二进制文件行数的实现方法

《在Linux终端中统计非二进制文件行数的实现方法》在Linux系统中,有时需要统计非二进制文件(如CSV、TXT文件)的行数,而不希望手动打开文件进行查看,例如,在处理大型日志文件、数据文件时,了解... 目录在linux终端中统计非二进制文件的行数技术背景实现步骤1. 使用wc命令2. 使用grep命令

Python中Tensorflow无法调用GPU问题的解决方法

《Python中Tensorflow无法调用GPU问题的解决方法》文章详解如何解决TensorFlow在Windows无法识别GPU的问题,需降级至2.10版本,安装匹配CUDA11.2和cuDNN... 当用以下代码查看GPU数量时,gpuspython返回的是一个空列表,说明tensorflow没有找到

XML重复查询一条Sql语句的解决方法

《XML重复查询一条Sql语句的解决方法》文章分析了XML重复查询与日志失效问题,指出因DTO缺少@Data注解导致日志无法格式化、空指针风险及参数穿透,进而引发性能灾难,解决方案为在Controll... 目录一、核心问题:从SQL重复执行到日志失效二、根因剖析:DTO断裂引发的级联故障三、解决方案:修复