pytorch标签onehot编码_特征编码方法总结—part1

本文总结了PyTorch中处理类别特征的各种编码方法,包括labelencoder、onehotencoder、label_binarize、直方图编码、WOE编码、目标编码和均值编码。详细阐述了每种编码方式的原理、优缺点以及适用场景,特别是针对高基数类别特征的处理。
摘要由CSDN通过智能技术生成

最近又碰到了高基数类别特征的处理问题,正好也要把相关的解决方案添加到现有的线上机器学习系统里,这里总结一下以后免得又忘记了。

在特征工程里,特征编码是占比很重的一块,在kaggle的结构化数据比赛中,最终帮助选手胜利的关键因素之一往往是高级特征的构造和特征编码(很多时候特征编码也是在构造高级的特征),下面就来总结一下吧。

1、labelencoder 标签编码

如果是无序的非数值离散特征,一般直接用onehot独热编码了,有序的非数值离散特征才会用到标签编码,因为大部分算法是没有内置自动识别类别特征的功能的,所以需要做这么一步简单的转换,原理很easy了不用废话了,为了文章看起来完整才写的,使用labelencoder或者自己用字典来做映射即可。

2、onehotencoder 独热编码

针对类别特征,例如【男人,女人】,【晴天,雨天,阴天】,类别型特征,无序,最简单快捷的方式是通过独热编码转化为【0,1】或者【0,0,1】这样的形式,模型才能识别,同时也起到了扩充特征的作用(例如逻辑在特征进行onehot展开之后表达能力一般能够得到较好的提高)。sklearn的onehot,pandas的get_dummies或者自己用字典映射均可。

  • 优点:独热编码解决了分类器不好处理属性数据的问题,在一定程度上也起到了扩充特征的作用。它的值只有0和1,不同的类型存储在垂直的空间。
  • 缺点:1、当类别的数量很多时,特征空间会变得非常大。2、对于特定任务,例如词向量化,直接使用onehot的方式是无法考虑到词之间的交互关系的,onehot之后损失了部分信息。推而广之,如果特征之间是非独立的(比如上下文的词之间是存在交互关系,时间序列数据之间存在某些内在关系),就不能简单的使用onehot功能

3、label_binarize 二值化编码

举个例子就知道是干嘛用的了,比如特征为【晴天,雨天,阴天,雷暴】则特征转化为【是否晴天,是否雨天,是否阴天,是否雷暴】,用数字来表示【雷暴】就是[0,0,0,1],和onthot看起来很类似,很多时候不那么严格界定,其实等同于onehot,一般来说独热编码的结果是多个0和1个1组成的比如类别特征的处理,但是也存在处理之后出现多个1和多个0的情况,比如文本问题,whatever,不做严格区分,因为很多文章都不划分那么细,反正自己心里有数就行了,实现使用sklearn的label_binarize或者自己用字典来实现。

4、直方图编码与计数编码(count)

直方图编码,主要针对类别型特征与类别型标签的一种编码方式,还是举个例子来说明什么是直方图编码吧,最好理解了:

假设类别特征f1=【A,A,B,B,B,C,C】,对应的二分类标签为【0,1,0,1,1,0,0】,则我们是这样来计算类别特征f1中对应的类别的编码值的:

以A为例,类别特征f1的值为A的样本有两个,这两个样本的标签分别为【0,1】,则A被直方图编码为【1/2,1/2】=【0.5,0.5】(A的样本一共有2个所以分母为2,其中一个样本标签为1,一个样本标签为0),实际上就是计算取值为A的样本中,不同类别样本的比例,然后用这个比例来替换原始的类别标签,这里需要强调的是,无论是直方图编码还是我们后面要介绍的target encoding,本质上都是用类别特征的统计量来代替原来的类别值的,没什么神秘的地方,很好理解。

如法炮制,我们来对B进行类别编码,f1值为B的一共3个样本,其中一个样本标签为0,两个样本标签为1,所以B被编码为【1/3,2/3】,很好理解了。同样对于C,一共两个样本,并且两个样本标签均为0,则编码为【2/2,0】。

直方图编码实际上存在着比较多的问题,我们目前针对高基类特征的常用的目标编码或者均值编码实际上可以看作是在直方图编码之上的问题改进。

直方图编码存在以下问题:

1、没有考虑到类别特征中不同类别的数量的影响,举个例子,假设样本的某个类别特征为【A,A,A,A,A,A,B】,对应的标签为【0,0,0,1,1,1,0】,则根据直方图编码的公式得到的结果为A:【1/2,1/2】,B:【1,0】,然而这实际上对于A来说是很不公平的,因为B的样本数量太少,计算出来的结果根本不能算是明显的统计特征,而很可能是一种噪音,这实际上是一种非常“过拟合”的计算方式,因为一旦测试集中的样本有多个B之后,B的直方图编码的结果很可能发生非常大的变化;

2、假设没有1中出现的情况,所有的类别A,B的数量都比较均匀,直方图编码还是存在着一个潜在的隐患,直方图编码的计算非常依赖于训练集中的样本标签的分布情况,以f1特征的那个例子为例,实际上直方图这么计算的隐含的假设是潜在的所有的数据的在类别f1上的每一个类别计算出来的结果可以用训练集的结果来近似代替,简单说比如我在训练集中算出来A的直方图编码为【1/2,1/2】,即类别为A的样本中有一半标签0的样本,一半标签1的样本,那么一旦测试集的分布情况发生改变,或者是训练集本身的采样过程就是有偏的,则直方图编码的结果就是完全错误的,(比如全样本中,类别为A的样本其实只有10%是标签为0的,90%标签为1的,则这个时候A的直方图编码为【1/10,9/10】,训练集的产生可能是有偏的);

所以在可用的资料和kaggle比赛中很少有人会用到直方图编码,更多的使用target encoding和mean encoding。下面是简单的直方图编码的实现,因为不怎么用就懒得优化了。

def histogram_encoding(X,y):
    category=list(set(X))
    labels=list(set(y))
    data=pd.concat([X,pd.DataFrame(y)],axis=1)
    data.columns=['data','labels']
    dictionary={}
    for item in category:
        temp=data[data['data']==item]
        tp=temp['labels'].value_counts()
        if tp.shape[0]<len(labels):
            for label in labels:
                if label not in tp.index:
                    tp[label]=0
        nums=tp.tolist()
        sums=sum(nums)
        nums=[items*1.0/sums for items in nums] ### 这里sums如果-1就是one leave out的分类问题形式
        ##其实问题差别不是很大,数据量一般都是至少几十万的级别的这么一个数据点的删除与否没什么大影响
        dictionary[item]=nums
    hs_enc=X.copy()
    hs_enc=hs_enc.values.tolist()
    for i in range(len(hs_enc)):
        hs_enc[i]=dictionary[hs_enc[i]]
    return hs_enc,dictionary

而计数编码就更加简单了,以二分类问题为例,就是根据每一个类别特征的类别对二分类标签进行sum求和得到每个类别中样本标签为1的总数,一行搞定,不知道为什么这么简单的编码方式在比赛中效果这么好。。。:

df.groupby(['category'])['target'].transform(sum)

5、WOE编码

实际上这里细心一点就可以发现,woe编码仅仅针对于二分类问题,woe编码如下:

f491af11ef06ed63b260266df5d18e49.png

原理很简单就是根据woe的公式来计算即可。实际上woe编码的方法很容易就可以扩展到多类,后面会写。

单纯从woe的公式就可以看出woe编码存在的问题:

1、分母可能为0的问题;

2、类似于直方图编码,没有考虑到不同类别数量的大小,例如类别特征为【A,A,A,A,A,A,B】而标签为【0,0,0,1,1,1,1】这样的情况计算出来的woe明显对A这个类别不公平

3、应用局限性太大了,只能针对二分类问题,并且特征也必须为离散特征。

4、训练集计算的woe编码结果可能和测试集计算的woe编码结果存在较大差异(所有基于统计特征的编码方式的通病)

首先我们调个包,使用到的是注明scikit-learn contrib分支中的category_encoders:

from category_encoders import *
import pandas as 
### 回答1: PyTorch中可以使用torch.nn.functional.one_hot()函数实现one-hot编码。该函数的输入是一个张量,输出是一个one-hot编码的张量。 具体实现方法如下: ```python import torch # 定义一个需要进行one-hot编码的张量 x = torch.tensor([1, 2, , 3]) # 计算one-hot编码 one_hot = torch.nn.functional.one_hot(x) # 输出结果 print(one_hot) ``` 输出结果为: ``` tensor([[, 1, , ], [, , 1, ], [1, , , ], [, , , 1]]) ``` 其中,输入张量x的每个元素都被转换为一个one-hot编码的向量,向量的长度等于x中不同元素的个数。例如,在上面的例子中,x中有4个不同的元素,因此每个one-hot编码的向量的长度为4。如果x中有n个不同的元素,那么每个one-hot编码的向量的长度就为n。 ### 回答2: PyTorch 是一个深度学习框架,支持张量(tensor)计算以及梯度优化。在 PyTorch 中实现 one-hot 编码非常简单。具体实现过程为: 首先,将需要进行 one-hot 编码的数组或列表使用 PyTorch 的 tensor() 函数转换为张量。例如: data = torch.tensor([1, 2, 3, 0, 1]) 其次,使用 PyTorch 的 nn.functional.one_hot() 函数进行 one-hot 编码处理。其输入参数为数据张量,以及需要指定编码向量的长度,即包含的类别数目。例如: one_hot = torch.nn.functional.one_hot(data, num_classes=4) 最后,通过 one_hot 的 shape 属性获取输出的编码向量的维度,即查看是否正确进行了编码。例如: print(onehot.shape) # 输出: torch.Size([5, 4]) 在此基础上,我们可以将这个 one_hot 张量转换为 numpy 数组进行后续操作。实际上,PyTorch 的张量并不需要专门转换为 numpy 数组,而是通过 PyTorch 的支持,使用自带的函数计算并进行后续处理,方便实用。 总之,在 PyTorch 中实现 one-hot 编码非常简单,只需要利用 PyTorch 提供的 nn.functional.one_hot() 函数即可。同时,PyTorch 的张量也提供了非常丰富的计算和操作方法,可用于各种深度学习模型的实现。 ### 回答3: 在机器学习和深度学习领域中,经常需要将类别型变量转换为数值型变量。而将分类变量转换为数值型变量的方式之一就是使用one-hot编码PyTorch提供了一个简单的方法实现one-hot编码。 首先,创建一个列表,其中包含将要进行预测的所有类别。例如:['cat', 'dog', 'bird']。 然后,使用PyTorch的torch.eye()函数。该函数将返回一个矩阵,其中对角线元素均为1,其他元素均为0。函数签名为:`torch.eye(n, m=None, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False) -> Tensor`,其中n为行数,m为列数。默认情况下,当m为None时,torch.eye()函数返回一个n*n的方阵。 为了使用torch.eye()函数实现one-hot编码,需要将一个列表转换为一个张量,要求每个类别都是一个数字。例如,将['cat', 'dog', 'bird']转化为[0, 1, 2]。然后使用如下的代码实现one-hot编码: ``` import torch categories = ['cat', 'dog', 'bird'] cat_tensor = torch.tensor([0]) dog_tensor = torch.tensor([1]) bird_tensor = torch.tensor([2]) one_hot = torch.eye(len(categories)) print(one_hot[cat_tensor]) # tensor([1., 0., 0.]) print(one_hot[dog_tensor]) # tensor([0., 1., 0.]) print(one_hot[bird_tensor]) # tensor([0., 0., 1.]) ``` 这样,一个类别将被编码为在one-hot张量中对应位置为1,其余位置为0的向量。每个向量大小相同,维数等于类别数,这样对于每个类别,都可以由该类别对应的索引所得到的one-hot向量来表示。 总之,pytorch实现one-hot编码非常简单,只需使用torch.eye()函数即可。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值