符号型数据的 NB 算法

该博客介绍了朴素贝叶斯算法的基础知识,包括其独立性假设和贝叶斯定理的应用。通过一个天气数据集展示了如何计算条件概率和类别分布,并使用Laplacian平滑处理零概率问题。博主提供了Java代码实现,包括数据读取、类别分布和条件概率计算,以及最终的分类预测。通过运行代码,得出预测准确率。

学习来源:日撸 Java 三百行(51-60天,kNN 与 NB)

第 58 天: 符号型数据的 NB 算法

朴素贝叶斯算法(Naive Bayes,NB)是一种是基于贝叶斯定理与特征条件独立假设的分类算法。

数据集
数据集中共有Outlook、Temperature、Humidity、Windy、Play 五个属性,每个属性有多个值,如属性Outlook有Sunny、 Overcast、Rain三个可选取的值。这里我们选用Outlook、Temperature、Humidity、Windy等四个属性作为条件属性。

@relation weather
@attribute Outlook {Sunny, Overcast, Rain}
@attribute Temperature {Hot, Mild, Cool}
@attribute Humidity {High, Normal, Low}
@attribute Windy {FALSE, TRUE}
@attribute Play {N, P}
@data
Sunny,Hot,High,FALSE,N
Sunny,Hot,High,TRUE,N
Overcast,Hot,High,FALSE,P
Rain,Mild,High,FALSE,P
Rain,Cool,Normal,FALSE,P
Rain,Cool,Normal,TRUE,N
Overcast,Cool,Normal,TRUE,P
Sunny,Mild,High,FALSE,N
Sunny,Cool,Normal,FALSE,P
Rain,Mild,Normal,FALSE,P
Sunny,Mild,Normal,TRUE,P
Overcast,Mild,High,TRUE,P
Overcast,Hot,Normal,FALSE,P
Rain,Mild,High,TRUE,N

算法思想
通过某对象的先验概率,利用贝叶斯公式计算出其后验概率,即该对象属于某一类的概率,最后选择具有最大后验概率的类作为该对象所属的类。

独立性假设
X = x 1 ∧ x 2 ∧ x 3 ∧ . . . ∧ x m X=x_1∧x_2∧x_3∧...∧x_m X=x1x2x3...xm表示一个条件的组合,如: O u t l o o k = s u n n y ∧ T e m p e r a t u r e = h o t ∧ H u m i d d i t y = h i g h ∧ W i n d y = F A L S E Outlook=sunny∧Temperature=hot∧Humiddity=high∧Windy=FALSE Outlook=sunnyTemperature=hotHumiddity=highWindy=FALSE,令 D i D_i Di表示一个事件, 如: P l a y = n o Play = no Play=no. 根据条件概率的式子可知:
在这里插入图片描述

假设各个条件之间是相互独立的,则有:
在这里插入图片描述
综合 (2)(3) 式可得:
在这里插入图片描述
在这里插入图片描述
(4)式中的 P ( D i ∣ x ) P(D_i|x) P(Dix)表示在条件组合x下发生 D i D_i Di的概率。其中分母 P ( x ) P(x) P(x)是计算不了的,但是针对我们分类的目标,在不同类别的分母都一致的情况下,可以只比较分子。因此我们可得出哪个类别的相对概率高, 就可预测为该类的预测方案。即最大后验概率的类别作为该对象所属的类别。预测方案如下所示:
在这里插入图片描述
k表示类别数,这里的k为2,因为属性Play只有yes和no两个值;
a r g m a x argmax argmax 表示哪个类别的相对概率高, 我们就预测为该类别。

Laplacian 平滑
在预测方案的连乘因子 P ( x j ∣ D i ) P(x_j|D_i) P(xjDi)中, 可能不存在满足 D i D_i Di的情况下发生 x j x_j xj的样本,因此该事件概率可能为0。连乘因子只要有一个为 0, 则乘积一定为 0。因此为了解决该问题, 我们要想办法让这个因子不要取 0 值。

为解决零概率的问题,我们采用Laplacian 平滑的方法:

P L ( x j ∣ D i ) = n P ( x j ∣ D i ) + 1 n P ( D i ) + v j P^L(x_j|D_i)=\frac{nP(x_j|D_i)+1}{nP(D_i)+v_j} PL(xjDi)=nP(Di)+vjnP(xjDi)+1

其中,n是样本总数, v j v_j vj是第j个属性取值的个数。

对于 P ( D i ) P(D_i) P(Di)也需要进行平滑:

P L ( D i ) = n P ( D i ) + 1 n + k P^L(D_i)=\frac{nP(D_i)+1}{n+k} PL(Di)=n+knP(Di)+1

其中n是样本总数,k是类别数。

Laplacian 平滑的优化目标为:
在这里插入图片描述

算法步骤:
1.读入weather.arff中的数据。
2.设置数据集类型为符号型。
3.计算类的分布
3.1计算每个类别对应的样本数,即 D i D_i Di的数量,因为Play属性只有no和yes两个值,所以i可取1、2。
3.2计算每个类别的先验概率,即计算每个类别对应的样本数占比, P ( D i ) = D i / n u m I n s t a n c e s P(D_i)=D_i/numInstances P(Di)=Di/numInstances,numInstances为总样本数。
3.3根据3.2计算的 P ( D i ) P(D_i) P(Di)来计算经过 Laplacian 平滑后的类的分布,即 P L ( D i ) P^L(D_i) PL(Di)
4.计算条件概率
4.1计算每个类别的每个属性的每个值所对应的样本数,用三维数组存储。
4.2通过4.1得出的三维数组和3.2得到的类的分布来计算经过 Laplacian 平滑后的条件概率。
5.通过 Laplacian 平滑的优化目标来分类,找到使目标函数最大的 D i D_i Di,则该类别就是待预测对象所属的类别。
6.计算预测准确度。
代码:

package machine_learning;

import java.io.FileReader;
import java.util.Arrays;
import weka.core.*;

/**
 * @Description: The Naive Bayes algorithm.
 * @author: Xin-Yu Li
 * @time: May 8(th),2022
 */
public class NaiveBayes {
	private class GaussianParamters {
		double mu;
		double sigma;

		public GaussianParamters(double paraMu, double paraSigma) {
			mu = paraMu;
			sigma = paraSigma;
		}// Of the constructor

		public String toString() {
			return "(" + mu + ", " + sigma + ")";
		}// Of toString
	}// Of GaussianParamters

	Instances dataset;
	int numClasses;
	int numInstances;
	int numConditions;
	
	int[] predicts;
	double[] classDistribution;
	double[] classDistributionLaplacian;
	double[][][] conditionalCounts;
	double[][][] conditionalProbabilitiesLaplacian;

	GaussianParamters[][] gaussianParameters;

	int dataType;
	public static final int NOMINAL = 0;
	public static final int NUMERICAL = 1;

	public NaiveBayes(String paraFilename) {
		dataset = null;
		try {
			FileReader fileReader = new FileReader(paraFilename);
			dataset = new Instances(fileReader);
			fileReader.close();
		} catch (Exception ee) {
			System.out.println("Cannot read the file: " + paraFilename + "\r\n" + ee);
			System.exit(0);
		} // Of try

		dataset.setClassIndex(dataset.numAttributes() - 1);
		numConditions = dataset.numAttributes() - 1;
		numInstances = dataset.numInstances();
		numClasses = dataset.attribute(numConditions).numValues();
	}// Of the constructor

	public void setDataType(int paraDataType) {
		dataType = paraDataType;
	}// Of setDataType

	public void calculateClassDistribution() {
		classDistribution = new double[numClasses];
		classDistributionLaplacian = new double[numClasses];

		double[] tempCounts = new double[numClasses];
		for (int i = 0; i < numInstances; i++) {
			int tempClassValue = (int) dataset.instance(i).classValue();
			tempCounts[tempClassValue]++;
		} // Of for i

		for (int i = 0; i < numClasses; i++) {
			classDistribution[i] = tempCounts[i] / numInstances;
			classDistributionLaplacian[i] = (tempCounts[i] + 1) / (numInstances + numClasses);
		} // Of for i

		System.out.println("Class distribution: " + Arrays.toString(classDistribution));
		System.out.println("Class distribution Laplacian: " + Arrays.toString(classDistributionLaplacian));
	}// Of calculateClassDistribution

	public void calculateConditionalProbabilities() {
		conditionalCounts = new double[numClasses][numConditions][];
		conditionalProbabilitiesLaplacian = new double[numClasses][numConditions][];

		for (int i = 0; i < numClasses; i++) {
			for (int j = 0; j < numConditions; j++) {
				int tempNumValues = (int) dataset.attribute(j).numValues();
				conditionalCounts[i][j] = new double[tempNumValues];
				conditionalProbabilitiesLaplacian[i][j] = new double[tempNumValues];
			} // Of for j
		} // Of for i

		int[] tempClassCounts = new int[numClasses];
		for (int i = 0; i < numInstances; i++) {
			int tempClass = (int) dataset.instance(i).classValue();
			tempClassCounts[tempClass]++;
			for (int j = 0; j < numConditions; j++) {
				int tempValue = (int) dataset.instance(i).value(j);
				conditionalCounts[tempClass][j][tempValue]++;
			} // Of for j
		} // Of for i

		for (int i = 0; i < numClasses; i++) {
			for (int j = 0; j < numConditions; j++) {
				int tempNumValues = (int) dataset.attribute(j).numValues();
				for (int k = 0; k < tempNumValues; k++) {
					conditionalProbabilitiesLaplacian[i][j][k] = (conditionalCounts[i][j][k] + 1)/ (tempClassCounts[i] + tempNumValues);
				} // Of for k
			} // Of for j
		} // Of for i

		System.out.println("Conditional probabilities: " + Arrays.deepToString(conditionalCounts));
	}// Of calculateConditionalProbabilities

	public void classify() {
		predicts = new int[numInstances];
		for (int i = 0; i < numInstances; i++) {
			predicts[i] = classify(dataset.instance(i));
		} // Of for i
	}// Of classify

	public int classify(Instance paraInstance) {
		if (dataType == NOMINAL) {
			return classifyNominal(paraInstance);
		} 
		else
			return -1;
	}// Of classify

	public int classifyNominal(Instance paraInstance) {
		double tempBiggest = -10000;
		int resultBestIndex = 0;
		for (int i = 0; i < numClasses; i++) {
			double tempClassProbabilityLaplacian = Math.log(classDistributionLaplacian[i]);
			double tempPseudoProbability = tempClassProbabilityLaplacian;
			for (int j = 0; j < numConditions; j++) {
				int tempAttributeValue = (int) paraInstance.value(j);

				tempPseudoProbability += Math.log(conditionalCounts[i][j][tempAttributeValue])- tempClassProbabilityLaplacian;
			} // Of for j

			if (tempBiggest < tempPseudoProbability) {
				tempBiggest = tempPseudoProbability;
				resultBestIndex = i;
			} // Of if
		} // Of for i

		return resultBestIndex;
	}// Of classifyNominal
	
	public double computeAccuracy() {
		double tempCorrect = 0;
		for (int i = 0; i < numInstances; i++) {
			if (predicts[i] == (int) dataset.instance(i).classValue()) {
				tempCorrect++;
			} // Of if
		} // Of for i

		double resultAccuracy = tempCorrect / numInstances;
		return resultAccuracy;
	}// Of computeAccuracy

	public static void testNominal() {
		System.out.println("Hello, Naive Bayes. I only want to test the nominal data.");
		String tempFilename = "C:\\Users\\LXY\\Desktop\\weather.arff";

		NaiveBayes tempLearner = new NaiveBayes(tempFilename);
		tempLearner.setDataType(NOMINAL);
		tempLearner.calculateClassDistribution();
		tempLearner.calculateConditionalProbabilities();
		tempLearner.classify();

		System.out.println("The accuracy is: " + tempLearner.computeAccuracy());
	}// Of testNominal

	public static void main(String[] args) {
		testNominal();
	}// Of main
}// Of class NaiveBayes

运行截图:
在这里插入图片描述

<think> 嗯,我现在需要解决用户关于AMR语音压缩算法输出数据定义的问题。首先,我需要回顾之前的对话历史,确保符合系统级指令,比如正确使用LaTeX格式和中文回答。用户之前提到了站内引用,但引用内容可能不直接相关,所以应该专注于用户当前的问题。 用户的问题集中在AMR输出数据的结构上。我需要回忆AMR的基本原理,尤其是编码后的帧结构。AMR有多种模式,每种有不同的帧长度和编码参数,例如AMR-NB有8种比特率。输出数据应该是由帧组成的序列,每帧包含头部和有效载荷。 接下来,考虑帧头的组成。RFC 4867文档是关键,它规定了RTP打包时的结构。每个帧以P帧头和FT字段开始,后面是编码数据。还要注意Q比特、P比特的作用,以及帧尾的填充比特可能影响对齐。 然后,帧内容的细节部分,比如LPC系数、自适应码本、固定码本等参数如何打包成比特流。不同模式下的比特分配差异需要说明,例如12.2kbps模式使用244比特,而4.75kbps只有95比特。这里可能需要用LaTeX展示表格结构,但用户要求行内公式,所以表格可能需要简化或描述。 另外,用户可能需要知道文件存储格式,比如3GPP定义的.amr文件结构。文件头中的魔术号和单声道描述,以及帧头的同步字和帧类信息。这部分需要和实时传输的RTP包结构区分开,但用户的问题更偏向数据定义本身,两者都需要涵盖。 还要注意错误处理部分,如NO_DATA帧的定义,这在传输中很重要。同时,比特顺序(MSB优先)和填充位的处理容易被忽略,需要明确说明。 最后,生成相关问题时要覆盖AMR的应用场景、解码过程、参数配置等,确保问题有针对性。检查LaTeX是否正确使用,例如帧长公式$L = \frac{\text{比特率}}{50}$用行内格式,独立公式如表格用$$...$$单独成段,但用户示例中没有表格,可能需要描述代替。 需要确保引用RFC 4867和3GPP TS 26.101标准,并在回答末尾添加引用标识。确认所有技术细节准确,比如比特字段长度、帧类值的范围(0-7对应有效负载,8-15保留)。避免混淆AMR-NB和WB,用户的问题明确是AMR,通常指窄带。 </think> AMR(Adaptive Multi-Rate)语音压缩算法的输出数据是经过编码的二进制比特流,其结构遵循严格的帧格式标准。以下是关键定义和技术细节: ### 一、输出数据结构 1. **基本单元** 输出数据以**帧(Frame)**为基本单位,每帧对应**20ms**的原始语音信号采样。帧长度取决于编码比特率(AMR-NB支持8种比特率:4.75-12.2 kbps)。 2. **帧结构** 每帧包含两部分: ```plaintext +----------------+-------------------+ | 帧头 (1 byte) | 有效载荷 (N字节) | +----------------+-------------------+ ``` - **帧头(Header)** 包含控制信息(详见RFC 4867[^1]): - `P` (1 bit):负载填充标志(0=无填充,1=填充) - `FT` (4 bits):帧类(Frame Type),取值0-7对应AMR模式(如FT=7表示12.2kbps) - `Q` (1 bit):帧质量指示(0=受损,1=完整) - 保留位 (2 bits) - **有效载荷(Payload)** 编码后的语音参数比特流,长度$L$由比特率$R$决定: $$ L = \left\lceil \frac{R \times 20}{1000} \right\rceil \ \text{(比特)} $$ 例如12.2kbps模式:$L = \lceil 12.2 \times 20 \rceil = 244$比特 = 30.5字节 → 向上取整为**31字节**。 ### 二、有效载荷内容 AMR采用**代数码本激励线性预测(ACELP)**编码,有效载荷包含: 1. **LPC系数**:线性预测系数(转换为LSF量化索引) 2. **自适应码本**:基音延迟和增益参数 3. **固定码本**:激励脉冲位置和符号 4. **增益控制**:量化增益系数 > ⚠️ 不同比特率的参数比特分配不同(如4.75kbps仅95比特) ### 三、存储/传输格式 1. **文件存储(.amr格式)** 文件头固定6字节:`0x23 0x21 0x41 0x4D 0x52 0x0A`("#!AMR\n") ```hex 00000000: 23 21 41 4D 52 0A 04 25 04 A5 85 31 ... // 示例AMR文件头 ``` 后续每帧前有1字节帧头:`0bPFTQRRRR`(P/Q/R定义同前) 2. **实时传输(RTP协议)** 按RFC 4867[^1]封装: - 首字节:`0bF|FT|Q|P`(F=0表示正常帧) - 第二字节:帧序号(可选) - 后续接有效载荷 ### 四、特殊帧类 | FT值 | 含义 | 载荷长度 | |------|---------------|----------| | 8-14 | 保留 | 0字节 | | 15 | `NO_DATA`帧 | 0字节 | > 用于网络丢包时的占位帧[^1] ### 五、比特顺序规则 - **大端序(Big-endian)**:所有字段高位比特(MSB)在先 - **字节对齐**:载荷不足8比特倍数时补0(如4.75kbps帧补1个0) --- ### 相关问题 1. AMR-NB与AMR-WB的输出数据结构有何差异? 2. 如何解析AMR文件的帧头中的`FT`字段? 3. AMR解码器如何处理`NO_DATA`帧? 4. 为什么AMR编码需要20ms的帧长度? [^1]: IETF RFC 4867 - _RTP Payload Format for AMR and AMR-WB_, 2007. [^2]: 3GPP TS 26.101 - _Adaptive Multi-Rate (AMR) speech codec frame structure_.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值