活动介绍
file-type

Python版One-Hot编码手动实现详解

版权申诉

ZIP文件

5星 · 超过95%的资源 | 3KB | 更新于2025-01-01 | 155 浏览量 | 6 评论 | 3 下载量 举报 1 收藏
download 限时特惠:#14.90
知识点一:One-Hot编码的含义 One-Hot编码是一种将分类变量转换为机器学习算法可以理解的格式的技术。在One-Hot编码中,每个分类值都被转换成一个二进制向量,该向量的长度等于类别数,除了表示该分类的索引位置为1外,其余位置均为0。这种编码方式可以提高模型的性能,并解决某些算法中对类别数据无法处理的问题。 知识点二:One-Hot编码的应用场景 在实际应用中,One-Hot编码广泛应用于自然语言处理(NLP)、计算机视觉、数据挖掘等领域,特别是在处理离散特征时。由于机器学习模型无法直接处理字符串或非数值类型的数据,因此在输入模型之前,必须将这些非数值数据转换为数值型数据,One-Hot编码是其中一种常用的方法。 知识点三:手动实现One-Hot编码的步骤 手动实现One-Hot编码通常包含以下步骤: 1. 确定类别数据中所有可能的分类值。 2. 为每个分类创建一个长度等于类别总数的零向量。 3. 在对应分类值的索引位置上,将向量的该位置值置为1。 4. 将步骤3中得到的向量作为特征添加到数据集中。 5. 重复步骤2至4,直到数据集中的所有分类数据都转换为One-Hot编码形式。 知识点四:Python代码实现One-Hot编码 在Python中实现One-Hot编码,可以使用以下代码段作为参考: ```python import numpy as np def one_hot_encode(labels, n_classes): """ labels: 输入的标签列表 n_classes: 类别总数 返回: One-Hot编码后的矩阵 """ # 初始化结果矩阵,数据类型为整型 one_hot = np.zeros((len(labels), n_classes), dtype=int) # 将对应标签的位置设为1 one_hot[np.arange(len(labels)), labels] = 1 return one_hot # 示例 labels = [0, 1, 2, 1, 2] n_classes = 3 one_hot_encoded = one_hot_encode(labels, n_classes) print(one_hot_encoded) ``` 该函数`one_hot_encode`接受标签列表和类别总数,返回One-Hot编码后的矩阵。 知识点五:使用第三方库实现One-Hot编码 在实际开发中,由于手动实现较为繁琐,人们通常倾向于使用现成的库来快速实现One-Hot编码。例如,`pandas`库提供了`get_dummies`函数来处理数据框(DataFrame)中的类别变量。此外,`sklearn.preprocessing`中的`OneHotEncoder`类也可以用于将类别数据转换为One-Hot编码形式。 知识点六:One-Hot编码的注意事项 使用One-Hot编码时需要注意以下几点: 1. One-Hot编码可能会增加数据的维度,从而导致稀疏性问题,影响模型性能。 2. 对于类别值非常多的情况,One-Hot编码可能会导致数据稀疏和高维灾难,此时应考虑其他编码方法,如目标编码(Target Encoding)、标签编码(Label Encoding)等。 3. 当数据集中存在非常少的类别值时,One-Hot编码效果可能不是最优的。 知识点七:One-Hot编码与其他编码方法的比较 除了One-Hot编码,还有其他多种编码类别特征的方法,例如: 1. 标签编码(Label Encoding):将每个类别值直接转换为一个整数。 2. 二进制编码(Binary Encoding):将类别值编码为二进制形式,可以减少维度。 3. 哈希编码(Hashing Trick):通过哈希函数将类别值转换为固定长度的向量,但可能会有哈希冲突。 每种编码方法都有其适用场景和优缺点,选择合适的编码方法对于模型的性能至关重要。 知识点八:One-Hot编码的优化与改进 为了应对One-Hot编码所带来的高维稀疏问题,可以采用一些优化和改进方法,如: 1. 使用特征选择技术来减少特征的数量。 2. 应用降维技术,如主成分分析(PCA),来减少数据集的维度。 3. 采用嵌入式特征学习方法,例如在神经网络中嵌入层(Embedding Layer)来学习低维稠密的类别表示。 知识点九:One-Hot编码的实践示例 在实际项目中,手动实现One-Hot编码可以加深对编码过程的理解。例如,在处理文本数据时,可以通过手动编码将文本中的单词转换为机器学习模型可以接受的格式。以下是一个简单的实践示例: ```python # 假设有一个简单的文本数据集 texts = ['cat', 'dog', 'fish', 'dog', 'cat'] # 手动实现One-Hot编码 def one_hot_encode_texts(texts, vocabulary): """ texts: 输入的文本列表 vocabulary: 词汇表,包含了文本数据集中的所有单词 返回: 每个文本对应的One-Hot编码向量 """ one_hot_vectors = [] for text in texts: one_hot_vector = np.zeros(len(vocabulary)) word_index = vocabulary.index(text) one_hot_vector[word_index] = 1 one_hot_vectors.append(one_hot_vector) return one_hot_vectors # 构建词汇表 vocabulary = sorted(set(texts)) one_hot_vectors = one_hot_encode_texts(texts, vocabulary) print(one_hot_vectors) ``` 此示例展示了如何将文本数据集中的单词转换为One-Hot编码格式,为后续的机器学习处理提供便利。 知识点十:总结 One-Hot编码是处理类别特征的重要技术之一,它在数据预处理阶段扮演了关键角色。在Python中手动实现One-Hot编码不仅可以帮助我们更好地理解算法的内部逻辑,还可以在不依赖外部库的情况下,灵活地对数据进行处理。然而,在实践中,根据数据特性和模型需求,适当选择编码方法和处理策略,对模型的性能和效率具有显著的影响。

相关推荐

filetype

import numpy as np import matplotlib.pyplot as plt import torch from torch import nn, optim # 设置字体为Times New Roman plt.rcParams["font.family"] = "Times New Roman" plt.rcParams["axes.labelsize"] = 12 plt.rcParams["axes.titlesize"] = 14 # 辅助函数:将整数转换为one-hot编码向量 def one_hot(a, M): onehot = np.zeros(M) onehot[a] = 1 return onehot def normalization(x, P): c = torch.mean(x**2) # 计算当前信号功率 return torch.sqrt(P / c) * x # 缩放信号以达到目标功率 def awgn(x, sigma2): noise_t = np.sqrt(sigma2)*torch.randn(x.shape) return torch.add(x, noise_t) class Mapper(nn.Module): """ 映射器网络(带隐藏层) """ def __init__(self): super().__init__() self.lin1 = nn.Linear(32, 32) self.lin2 = nn.Linear(32, 32) self.lin3 = nn.Linear(32, 2) def forward(self, y): return self.lin3(self.lin2(self.lin1(y))) class Demapper(nn.Module): """ 解映射器网络(带隐藏层) """ def __init__(self): super().__init__() self.lin1 = nn.Linear(2, 32) self.lin2 = nn.Linear(32, 32) self.lin3 = nn.Linear(32, 32) def forward(self, y): return self.lin3(self.lin2(self.lin1(y))) # 生成训练数据(one-hot编码) M = 32 n = 10000 a = np.random.choice(range(M), size= n) # 随机生成消息索引 onehot = np.array([one_hot(a[i], M) for i in range(n)]) # 转换为one-hot编码 # 转换为PyTorch张量 onehot_t = torch.tensor(onehot).float() # 输入特征(one-hot编码) a_t = torch.tensor(a) # 目标标签(消息索引) a_t = a_t.type(torch.LongTensor) # 转换为长整型(用于交叉熵损失) # 损失函数(交叉熵损失) loss_fn = nn.CrossEntropyLoss() P = 1 SNRdBs = np.array([5,10,15]) SNRs = 10**(SNRdBs/10) # 转换为线性值 # 初始化网络 mapper = Mapper() demap = Demapper() # 训练循环(针对不同SNR) for (k,snr) in enumerate(SNRs): sigma2 = P/snr # 训练循环(针对不同SNR) print(f'---SNR = {SNRdBs[k]} dB---') # 优化器(同时优化映射器和解映射器) optimizer = optim.Adam(list(mapper.parameters()) + list(demap.parameters()), lr=0.01) # 训练循环 for j in range(10001): xhat = mapper(onehot_t) # 映射器生成星座点 xhat = normalization(xhat, P) # 归一化信号功率 yhat = awgn(xhat, sigma2) # 通过AWGN信道 l = demap(yhat) # 解映射器预测消息概率 # 计算损失和反向传播 loss = loss_fn(l, a_t) # 交叉熵损失 optimizer.zero_grad() # 梯度清零 loss.backward() # 反向传播 optimizer.step() # 参数更新 # 每500次迭代打印损失 if j % 500 == 0: # 将损失转换为比特(除以log2) print(f'epoch {j}: Loss = {loss.detach().numpy()/np.log(2) :.4f} dB') # 提前终止条件 if loss < 1e-3: break # 可视化学习到的星座图 a_plot = np.arange(M) # 所有可能的消息索引 onehot_plot = np.array([one_hot(a_plot[i], M) for i in range(M)]) # one-hot编码 learned_x = mapper(torch.tensor(onehot_plot).float()) # 生成星座点 learned_x = normalization(learned_x, P).detach().numpy() # 归一化并转为numpy print("learned_x[0:15,0]:", learned_x[0:15,0]) print("learned_x[16:31,0]:", learned_x[16:31,0]) print("learned_x[0:15,1]:", learned_x[0:15,1]) print("learned_x[16:31,1]:", learned_x[16:31,1]) plt.scatter(learned_x[:,0], learned_x[:,1]) plt.title(f'32QAM, SNR = {SNRdBs[k]} dB') plt.grid() plt.show() 请将代码中的功率归一化修改为幅度归一化,并保证任意两个星座点之间的距离不过小,尽可能保证其在接收端不被误判决

filetype

深度学习——基于卷积神经网络的手写数字识别,实验要求模型构建 2.1 数据预处理 使用MNIST手写数字数据集(包含60000训练样本和10000测试样本,图像尺寸为28×28像素,灰度图)。对数据进行以下预处理: ● 数据归一化:将像素值缩放到[0,1]范围。 ● 数据增强(可选):随机旋转、平移图像,增加模型泛化能力。 ● 标签编码:将数字标签转换为one-hot编码。 2.2 模型选择与训练 采用卷积神经网络模型,结构如下: (1)卷积层1:32个5×5卷积核,步长为1,ReLU激活函数。 (2)池化层1:2×2最大池化,步长为2。 (3)卷积层2:64个5×5卷积核,步长为1,ReLU激活函数。 (4)池化层2:2×2最大池化,步长为2。 (5)全连接层1:128个神经元,ReLU激活函数。 (6)输出层:10个神经元(对应0-9数字),Softmax激活函数。 (7)损失函数:交叉熵损失。 (8)优化器:Adam优化器,学习率0.001。 (9)训练参数:批次大小(batch size)为128,训练轮数(epochs)为10。 2.3 参数调优 通过网格搜索或手动调整,优化超参数(如学习率、批次大小、卷积核数量)。例如,调整学习率至0.0005可提升准确率。 2.4 效果评估 ● 训练过程可视化:绘制训练集与验证集的准确率、损失曲线。 ● 测试集评估:计算测试集准确率、精确率、召回率、F1-score等指标。 ● 混淆矩阵:分析模型对不同数字的识别能力。 写出相应的代码,以及运行结果

filetype

其中P PP为真实值,Q QQ为预测值。2、计算交叉熵的步骤:1)步骤说明:①将predict_scores进行softmax运算,将运算结果记为pred_scores_soft;②将pred_scores_soft进行log运算,将运算结果记为pred_scores_soft_log;③将pred_scores_soft_log与真实值进行计算处理。思路即:s c o r e s → s o f t m a x → l o g → c o m p u t e scores\to softmax\to log\to computescores→softmax→log→compute2)举一个例子对计算进行说明:P 1 = [ 1 0 0 0 0 ] P_1=[10000][10000]P 1​ =[ 1​ 0​ 0​ 0​ 0​ ]Q 1 = [ 0.4 0.3 0.05 0.05 0.2 ] Q_1=[0.40.30.050.050.2][0.40.30.050.050.2]Q 1​ =[ 0.4​ 0.3​ 0.05​ 0.05​ 0.2​ ]H ( p , q ) = − ∑ i P ( i ) log ⁡ Q ( i ) = − ( 1 ∗ l o g 0.4 + 0 ∗ l o g 0.3 + 0 ∗ l o g 0.05 + 0 ∗ l o g 0.05 + 0 ∗ l o g 0.2 ) = − l o g 0.4 ≈ 0.916 H\left( {p,q} \right) = - \sum\limits_i {P\left( i \right)\log Q\left( i \right)}=-(1*log0.4+0*log0.3+0*log0.05+0*log0.05+0*log0.2) \\=-log0.4 \approx 0.916H(p,q)=− i∑​ P(i)logQ(i)=−(1∗log0.4+0∗log0.3+0∗log0.05+0∗log0.05+0∗log0.2)=−log0.4≈0.916如果Q 2 = [ 0.98 0.01 0 0 0.01 ] Q_2=[0.980.01000.01][0.980.01000.01]Q 2​ =[ 0.98​ 0.01​ 0​ 0​ 0.01​ ]则H ( p , q ) = − ∑ i P ( i ) log ⁡ Q ( i ) = − ( 1 ∗ l o g 0.98 + 0 ∗ l o g 0.01 + 0 ∗ l o g 0.05 + 0 ∗ l o g 0 + 0 ∗ l o g 0.01 ) = − l o g 0.98 ≈ 0.02 H\left( {p,q} \right) = - \sum\limits_i {P\left( i \right)\log Q\left( i \right)}=-(1*log0.98+0*log0.01+0*log0.05+0*log0+0*log0.01) \\=-log0.98 \approx 0.02H(p,q)=− i∑​ P(i)logQ(i)=−(1∗log0.98+0∗log0.01+0∗log0.05+0∗log0+0∗log0.01)=−log0.98≈0.02由H ( p , q ) H(p,q)H(p,q)的计算结果和直观地观察Q 1 Q_1Q 1​ 和Q 2 Q_2Q 2​ 与P 1 P_1P 1​ 的相似度,均可看出Q 2 Q_2Q 2​ 比Q 1 Q_1Q 1​ 更近似于P 1 P_1P 1​ 。二、官方文档的说明在PyTorch的官方中文文档中F.cross_entropy()的记录如下:torch.nn.functional.cross_entropy(input, target, weight=None, size_average=True)1该函数使用了 log_softmax 和 nll_loss,详细请看CrossEntropyLoss常用参数:参数名 shape 注input (N,C) C是类别的个数target N 0 <= targets[i] <= C-1三、自己的困惑在官方文档说明中,对于target参数的说明为,torch.shape为torch.Size([N]),0 <= targets[i] <= C-1。我的困惑是:网络计算输出并送入函数中的input的torch.shape为torch.Size([N,C]),它的torch.shape并不会因为softmax和log的操作而改变,但是target的torch.shape为torch.Size([N]),是一个标量而不是一个矩阵,那么如何按照上面的例子中的运算方法进行交叉熵的计算?例如:import torchimport torch.nn.functional as Fpred_score = torch.tensor([[13., 3., 2., 5., 1.], [1., 8., 20., 2., 3.], [1., 14., 3., 5., 3.]])print(pred_score)pred_score_soft = F.softmax(pred_score, dim=1)print(pred_score_soft)pred_score_soft_log = pred_score_soft.log()print(pred_score_soft_log)1234567891011它的结果为:tensor([[13., 3., 2., 5., 1.], [ 1., 8., 20., 2., 3.], [ 1., 14., 3., 5., 3.]])tensor([[9.9960e-01, 4.5382e-05, 1.6695e-05, 3.3533e-04, 6.1417e-06], [5.6028e-09, 6.1442e-06, 9.9999e-01, 1.5230e-08, 4.1399e-08], [2.2600e-06, 9.9984e-01, 1.6699e-05, 1.2339e-04, 1.6699e-05]])tensor([[-4.0366e-04, -1.0000e+01, -1.1000e+01, -8.0004e+00, -1.2000e+01], [-1.9000e+01, -1.2000e+01, -6.1989e-06, -1.8000e+01, -1.7000e+01], [-1.3000e+01, -1.5904e-04, -1.1000e+01, -9.0002e+00, -1.1000e+01]])123456789如何与一个标量target进行计算?四、分析F.Cross_entropy(input, target)函数中包含了s o f t m a x softmaxsoftmax和l o g loglog的操作,即网络计算送入的input参数不需要进行这两个操作。例如在分类问题中,input表示为一个torch.Size([N, C])的矩阵,其中,N NN为样本的个数,C CC是类别的个数,input[i][j]可以理解为第i ii个样本的类别为j jj的Scores,Scores值越大,类别为j jj的可能性越高,就像在代码块中所体现的那样。同时,一般我们将分类问题的结果作为lable表示时使用one-hot embedding,例如在手写数字识别的分类问题中,数字0的表示为[ 1 0 0 0 0 0 0 0 0 0 ][1000000000][1000000000][ 1​ 0​ 0​ 0​ 0​ 0​ 0​ 0​ 0​ 0​ ]数字3的表示为[ 0 0 0 1 0 0 0 0 0 0 ][0001000000][0001000000][ 0​ 0​ 0​ 1​ 0​ 0​ 0​ 0​ 0​ 0​ ]在手写数字识别的问题中,我们计算l o s s lossloss的方法为l o s s = ( y − y ^ ) 2 loss=(y-\hat y)^2loss=(y− y^​ ) 2 ,即求y yy的embedding的矩阵减去pred_probability矩阵的结果矩阵的范数。但是在这里,交叉熵的计算公式为H ( p , q ) = − ∑ i P ( i ) log ⁡ Q ( i ) H\left( {p,q} \right) = - \sum\limits_i {P\left( i \right)\log Q\left( i \right)}H(p,q)=− i∑​ P(i)logQ(i)其中P PP为真实值概率矩阵,Q QQ为预测值概率矩阵。那么如果P PP使用one-hot embedding的话,只有在i ii为正确分类时P ( i ) P(i)P(i)才等于1 11,否则,P ( i ) P(i)P(i)等于0。例如在手写数字识别中,数字3的one-hot表示为[ 0 0 0 1 0 0 0 0 0 0 ][0001000000][0001000000][ 0​ 0​ 0​ 1​ 0​ 0​ 0​ 0​ 0​ 0​ ]对于交叉熵来说,H ( p , q ) = − ∑ i P ( i ) l o g Q ( i ) = − P ( 3 ) l o g Q ( 3 ) = − l o g Q ( 3 ) H(p,q)=- \sum\limits_iP(i)logQ(i)=-P(3)logQ(3)=-logQ(3)H(p,q)=− i∑​ P(i)logQ(i)=−P(3)logQ(3)=−logQ(3)发现H ( p , q ) H(p,q)H(p,q)的计算不依赖于P PP矩阵,而仅仅与P PP的真实类别的i n d e x indexindex有关五、总结所以,我的理解是,在one-hot编码的前提下,在pytorch代码中target不需要以one-hot形式表示,而是直接用scalar,scalar的值则是真实类别的index。所以交叉熵的公式可表示为:

资源评论
用户头像
东郊椰林放猪散仙
2025.05.30
新手友好,可以帮助理解One-Hot编码背后的逻辑。
用户头像
shashashalalala
2025.05.22
内容简洁明了,适合想要深入了解编码原理的读者。
用户头像
weixin_35780426
2025.05.01
此文档为Python手动实现One-Hot编码的教程,适合初学者学习。
用户头像
李多田
2025.04.02
代码示例丰富,易于理解和实践。🎊
用户头像
恽磊
2025.02.18
对于学习机器学习预处理步骤很有帮助。
用户头像
城北伯庸
2025.01.24
提供了一种Python编程中常见编码方式的实现方法。
WuGenQiang
  • 粉丝: 420
上传资源 快速赚钱