基本概念:
在机器学习的分类任务中,经常存在一个特征有多个分类变量值,例如在kaggle中的Titanic比赛数据中,Embarked的值有S,C,Q。此时,为了进行算法训练,需要 对离散型数据进行onehot编码处理,常见的处理方法有两种:
pd.dummies()
或pd.factorize()
进行独热编码;OneHotEncoder()
方法进行独热编码。onehot的优点:
1、能够处理非连续型数值特征;
2、在一定程度上扩充了特征(例如:性别本身是一个特征,经过one hot编码以后,就变成了男或女两个特征。);
3、将离散特征的取值扩展到了欧式空间(离散特征的某个取值就对应欧式空间的某个点,在回归,分类,聚类等机器学习算法中,特征之间距离的计算或相似度的计算是非常重要的,而我们常用的距离或相似度的计算都是在欧式空间的相似度计算,计算余弦相似性,基于的就是欧式空间。);
4、将离散型特征使用one-hot编码,可以让特征之间的距离计算更加合理,相当于做了归一化处理;
当一个feature有10几种甚至几百种取值可能的话,使用get_summies是将造成DataFrame的特征列数量激增。
例如:feature1取值有[“a”,“b”,…“z”]26中可能的话,显然用哑变量pd.get_dummies() 就将把这一个feature变为26列。明显增加了数据的稀疏性,并且没有意义(视情况而定)。此时使用pd.factorize()会将原特征列分解为0-25种数字。同时1列字符串经过变换后仍是一列,不会造成数据集臃肿。
factorize()对每一个类别映射一个ID,这种映射最后只生成一个特征;
然而,dummy()映射后生成多个特征。
核心功能:
为了较方便地对离散型特征进行one-hot编码,即:使用pd.get_dummies( )将定性变量转换为 Dummy 变量,仅适用于:出现少数几个独立变量的情形。
语法格式:
pandas.get_dummies(data, prefix=None, prefix_sep='_', dummy_na=False, columns=None, sparse=False, drop_first=False, dtype=None)
参数说明:
data:可以是数组类型,Series类型或DataFrame类型;
prefix:可以字符串,字符串列表,或字符串的字典类型,默认为None。将data的列名映射到prefix的字符串或者字典;
columns: 指要编码的DataFrame中的列名称list-like类型,默认None。 如果columns=None,则将转换DataFrame中dtype为 object 或 category dtype 的所有列。
drop_first:布尔型,默认为False,指是否删除第一列;
典型范例:
import pandas as pd
import numpy as np
#例1:传入series
s=pd.Series(list('abca'))
print(s)
>>>
0 a
1 b
2 c
3 a
dtype: object
s0=pd.get_dummies(s)
print(s0)
>>>
a b c
0 1 0 0
1 0 1 0
2 0 0 1
3 1 0 0
#例2:传入DataFrame
df=pd.DataFrame({'A':['a','b','a'],'B':['b','a','c'],
'C':[1,2,3]})
print(df)
>>>
A B C
0 a b 1
1 b a 2
2 a c 3
print(df.info())
>>>
Data columns (total 3 columns):
A 3 non-null object
B 3 non-null object
C 3 non-null int64
dtypes: int64(1), object(2)
# 默认columns=None,DataFrame中dtype为object或 category dtype的所有列将被转化为demmies类型,其他类型不变。
df0=pd.get_dummies(df,prefix=['col1','col2'])
print(df0) # C列为int型,故不会被转为dummies类型
>>>
C col1_a col1_b col2_a col2_b col2_c
0 1 1 0 0 1 0
1 2 0 1 1 0 0
2 3 1 0 0 0 1
核心功能:
使用pandas.factorize( )可以创建一些数字,来表示分类变量(categorical variable) 或 枚举型(enumerated type)变量。具体而言:factorize函数可以将Series中的标称型数据映射称为一组数字,相同的标称型映射为相同的数字。对每一个类别映射一个ID,最后factorize只生成一个特征,不像dummies生成多个特征。适用于:出现较多独立变量的情形。
语法格式:
pandas.factorize(values, sort=False, order=None, na_sentinel=-1, size_hint=None)
参数说明:
values:sequence(序列类型),一维序列。 在分解之前,不是pandas对象的序列被强制转换为ndarray。
sort:表示是否对unique进行排序。bool类型,默认为False,若sort = True,将对uniques进行排序,并对标签进行洗牌,以便保持关系。
na_sentinel:用于标记“not found”的值。int类型,默认-1;
size_hint:用于提示哈希表sizer。int类型,可选参数;
返回值:包含labels和uniques的两个ndarray,其中,labels为uniques的索引;当values为分类变量时,uniques是唯一的不重复类别标识。
典型范例:
labels,uniques=pd.factorize(['b','b','a','c','b']) # 不排序
print(labels)
>>>
array([0, 0, 1, 2, 0], dtype=int64)
print(uniques)
>>>
array(['b', 'a', 'c'], dtype=object)
labels,uniques=pd.factorize(['b','b','a','c','b'],sort=True) # 排序
print(labels)
array([1, 1, 0, 2, 1], dtype=int64)
print(uniques)
array(['a', 'b', 'c'], dtype=object)
#例3
sf_df_last['号码归属省']=pd.factorize(sf_df_last['号码归属省'])[0] #效果见图1
one-hot是将每个feature的取值个数作为one-hot后的长度,对应的位置0/1的值根据原数据在此位置取值的有/无来确定的,并不是每个feature的max取值的长度编号。如此,可以节约矩阵one-hot后的规模。
import pandas as pd
from sklearn.preprocessing import OneHotEncoder
from sklearn.preprocessing import LabelEncoder
from sklearn.preprocessing import LabelBinarizer
from sklearn.preprocessing import MultiLabelBinarizer
testdata=pd.DataFrame({'pet':['cat','dog','dog','fish'],
'age':[4,6,3,3],'salary':[4,5,1,1]})
print(testdata)
>>>
pet age salary
0 cat 4 4
1 dog 6 5
2 dog 3 1
3 fish 3 1
>>>
#把他们全都二值化,进行 one-hot 编码.
OneHotEncoder(sparse=False).fit_transform(testdata.age) #报错
>>>ValueError: Expected 2D array, got 1D array instead:
# 从 Warning 信息中得知,原因是 sklearn 的新版本中,OneHotEncoder 的输入必须是 2-D array,而 testdata.age 返回的 Series 本质上是 1-D array,所以要改成
OneHotEncoder(sparse=False).fit_transform(testdata[['age']]) #正确
# testdata[[‘age’]]的取值是:0,4,6所以对这个三个值进行one-hot化,第一行:[4]===>得到one-hot:[0,1,0]
>>>
array([[0., 1., 0.],
[0., 0., 1.],
[1., 0., 0.],
[1., 0., 0.]])
可以用同样的方法对 salary 进行 OneHotEncoder, 然后将结果用 numpy.hstack()
把两者拼接起来得到变换后的结果。
a1=OneHotEncoder(sparse=False).fit_transform(testdata[['age']])
>>>a1
array([[0., 1., 0.],
[0., 0., 1.],
[1., 0., 0.],
[1., 0., 0.]])
a2=OneHotEncoder(sparse=False).fit_transform(testdata[['salary']])
>>>a2
array([[0., 1., 0.],
[0., 0., 1.],
[1., 0., 0.],
[1., 0., 0.]])
final_ouput=np.hstack((a1,a2))
>>>final_ouput
array([[0., 1., 0., 0., 1., 0.],
[0., 0., 1., 0., 0., 1.],
[1., 0., 0., 1., 0., 0.],
[1., 0., 0., 1., 0., 0.]])
有时候我们除了得到最终编码结果,还想知道结果中哪几列属于 age 的二值化编码,哪几列属于 salary 的,这时候我们可以通过 OneHotEncoder() 自带的 feature_indices_
来实现这一要求,比如这里 feature_indices_ 的值是[0, 3, 6],表明 第[0:3]列是age的二值化编码,[3:6]是salary的。更多细节请参考 sklearn 文档。
所涉及到的几种 sklearn 的二值化编码函数:OneHotEncoder(), LabelEncoder(), LabelBinarizer(), MultiLabelBinarizer()
get_dummies的优势:
get_dummies的劣势:
参考链接:
https://blog.csdn.net/wl_ss/article/details/78508500