写点什么

数据预处理和特征工程 - 数据预处理 - 编码与哑变量 & 二值化与分段

  • 2022-11-11
    山东
  • 本文字数:3721 字

    阅读完需:约 12 分钟

处理分类型特征:编码与哑变量

多标签和特征在数据收集完毕的时候,都不是以数字来表现的。比如说,学历的取值可以是["小学",“初中”,“高中”,"大学"],付费方式可能包含["支付宝",“现金”,“微信”]等等。在这种情况下,为了让数据适应算法和库,我们必须将数据进行编码,即是说,将文字型数据转换为数值型。


LabelEncoder 标签专用,能够将分类转换为分类数值


LabelEncoder()# 啥也没有,作用就是把标签变成0-种类-1的值
复制代码


y = data.iloc[:,-1] # 要输入的是标签,不是特征矩阵,所以允许一维,也允许高维,例如多标签问题
le = LabelEncoder() # 实例化le = le.fit(y) # 导入数据label = le.transform(y) # transform接口调取结果np.unique(label) # 扔到set()里也行---array([0, 1, 2])
data.iloc[:,-1] = labeldata.head()---Age Sex Embarked Survived0 22.0 male S 01 38.0 female C 22 26.0 female S 23 35.0 female S 24 35.0 male S 0
np.unique(le.fit_transform(y))data.iloc[:,-1] = LabelEncoder().fit_transform(data.iloc[:,-1]) # 一行完成
le.classes_# 属性.classer_查看标签中究竟有多少类别---array(['No', 'Unknown', 'Yes'], dtype=object)
np.unique(le.inverse_transform(label)) # 逆转---array(['No', 'Unknown', 'Yes'], dtype=object)
复制代码


OrdinalEncoder:特征专用,能够将分类特征转换为分类数值


OrdinalEncoder(categories='auto', dtype=<class 'numpy.float64'>)# 一般默认,类似LabelEncoder
复制代码


from sklearn.preprocessing import OrdinalEncoder # 特征专用data_ = data.copy()data_.head()---Age  Sex  Embarked  Survived0  22.0  male  S  01  38.0  female  C  22  26.0  female  S  23  35.0  female  S  24  35.0  male  S  0
OrdinalEncoder().fit(data_.iloc[:,[1,2]]).categories_# OrdinalEncoder().fit(data_.iloc[:,1:-1]).categories_# iloc包括前不包括后---[array(['female', 'male'], dtype=object), array(['C', 'Q', 'S'], dtype=object)]
data_.iloc[:,1:-1] = OrdinalEncoder().fit_transform(data_.iloc[:,1:-1])data_.head()---Age Sex Embarked Survived0 22.0 1.0 2.0 01 38.0 0.0 0.0 22 26.0 0.0 2.0 23 35.0 0.0 2.0 24 35.0 1.0 2.0 0
np.unique(data_.loc[:,'Embarked'])---array([0., 1., 2.])
复制代码


OneHotEncoder:独热编码,创建哑变量刚才已经用 OrdinalEncoder 把分类变量 Sex 和 Embarked 都转换成数字对应的类别了。在舱门 Embarked 这一列中,我们使用代表了三个不同的舱门,然而这种转换不是完全正确的,0,1,2 之间有运算关系,但舱门显然没有,我们对于这些有不同性质的变量进行定义



然而在对特征进行编码的时候,这三种分类数据都会被我们转换为,这三个数字在算法看来,是连续且可以计算的,这三个数字相互不等,有大小,并且有着可以相加相乘的联系。所以算法会把舱门这样的分类特征,都误会成是分类特征。


OrdinalEncoder 可以用来处理有序变量,但对于名义变量,我们只有使用 OneHotEncoder 哑变量的方式来处理,才能够尽量向算法传达最准确的信息:



这样的变化,让算法能够彻底领悟,原来三个取值是没有可计算性质的,是“有你就没有我”的不等概念。在我们的数据中,性别和舱门,都是这样的名义变量。因此我们需要使用独热编码,将两个特征都转换为哑变量。


OneHotEncoder(    ['n_values=None', 'categorical_features=None', 'categories=None', 'sparse=True', "dtype=<class 'numpy.float64'>", "handle_unknown='error'"],)# 0.20以后不需要设置什么,默认就可以
复制代码


from sklearn.preprocessing import OneHotEncoderX = data.iloc[:,1:-1]X.info()---<class 'pandas.core.frame.DataFrame'>Int64Index: 889 entries, 0 to 890Data columns (total 2 columns):Sex         889 non-null objectEmbarked    889 non-null objectdtypes: object(2)memory usage: 20.8+ KB
enc = OneHotEncoder(categories='auto').fit(X) # 注意不能有空值# categorties:每个特征中有几个类别,输入类别数量列表,或者默认categories='auto'自动匹配,不需要填写result = enc.transform(X).toarray()# enc.tranfrom(X)生成稀疏矩阵对象result# 这五列,男女各占一列,舱门SCQ各占一列---array([[0., 1., 0., 0., 1.], [1., 0., 1., 0., 0.], [1., 0., 0., 0., 1.], ..., [1., 0., 0., 0., 1.], [0., 1., 1., 0., 0.], [0., 1., 0., 1., 0.]])
OneHotEncoder(categories='auto').fit_transform(X).toarray()# 一步到位
enc.inverse_transform(result)# 也可以还原---array([['male', 'S'], ['female', 'C'], ['female', 'S'], ..., ['female', 'S'], ['male', 'C'], ['male', 'Q']], dtype=object)
enc.get_feature_names() # 稀疏矩阵中每个列代表什么# 第一项代表哪个哑变量,第二项代表该变量的取值是什么---array(['x0_female', 'x0_male', 'x1_C', 'x1_Q', 'x1_S'], dtype=object)
# axis=1代表跨行合并,增宽,axis=1代表跨列合并,增长newdata = pd.concat([data,pd.DataFrame(result)],axis=1)newdata.head()---Age Sex Embarked Survived 0 1 2 3 40 22.0 male S No 0.0 1.0 0.0 0.0 1.01 38.0 female C Yes 1.0 0.0 1.0 0.0 0.02 26.0 female S Yes 1.0 0.0 0.0 0.0 1.03 35.0 female S Yes 1.0 0.0 0.0 0.0 1.04 35.0 male S No 0.0 1.0 0.0 0.0 1.0
newdata.drop(['Sex','Embarked'],axis=1,inplace=True)# 第一个参数删除的索引,axis=1删除列newdata.columns = ['Age','Survived','Female','Male','Embarked_C','Embarked_Q','Embarked_S']newdata.head()---
Age Survived Female Male Embarked_C Embarked_Q Embarked_S0 22.0 No 0.0 1.0 0.0 0.0 1.01 38.0 Yes 1.0 0.0 1.0 0.0 0.02 26.0 Yes 1.0 0.0 0.0 0.0 1.03 35.0 Yes 1.0 0.0 0.0 0.0 1.04 35.0 No 0.0 1.0 0.0 0.0 1.0
复制代码



使用类 sklearn.preprocessing.LabelBinarizer 可以对做哑变量,许多算法都可以处理多标签问题(比如说决策树),但是这样的做法在现实中不常见,因此我们在这里就不赘述了。

处理连续型特征:二值化与分段

Binarizer,根据阈值将数据二值化(将特征值设置为 0 或 1),用于处理连续型变量。大于阈值的值映射为 1,而小于或等于阈值的值映射为 0。默认阈值为 0


Binarizer(threshold=0.0, copy=True)# threshold:阈值,默认为0
复制代码


from sklearn.preprocessing import Binarizer # 连续型变量才能分箱data_2 = data.copy()data_2.head()---Age  Sex  Embarked  Survived0  22.0  male  S  No1  38.0  female  C  Yes2  26.0  female  S  Yes3  35.0  female  S  Yes4  35.0  male  S  No
X = data_2.iloc[:,0].values.reshape(-1,1)# 类为特征专用,所以不能使用一维数组
transformer = Binarizer(threshold=30).fit_transform(X)transformer[:5,:]---array([[0.], [1.], [0.], [1.], [1.]])
data_2.iloc[:,0] = transformer
复制代码


BinsDiscretizer,连续型变量划分为多个分类变量的类,能够将连续型变量排序后按顺序分箱后编码。


KBinsDiscretizer(n_bins=5, encode='onehot', strategy='quantile')# n_bins:每个特征中分箱的个数,默认5,一次会被运用到所有导入的特征# encode:编码的方式,默认“onehot” ,做哑变量,之后返回一个稀疏矩阵,每一列是一个特征中的一个类别,含有该类别的样本表示为1,不含的表示为0 ;“ordinal”,每个特征的每个箱都被编码为一个整数,返回每一列是一个特征,每个特征下含有不同整数编码的箱的矩阵 # strategy:用来定义箱宽的方式,默认"quantile" 表示等位分箱,即每个特征中的每个箱内的样本数量都相同;"uniform",表示等宽分箱,即每个特征中的每个箱的最大值之间的差为 (特征.max() - 特征.min())/(n_bins) 
复制代码


from sklearn.preprocessing import KBinsDiscretizerX = data.iloc[:,0].values.reshape(-1,1)est = KBinsDiscretizer(n_bins=3,encode='ordinal',strategy='uniform').fit_transform(X)# 'ordinal'一个特征一列,等宽分箱set(est.ravel())---{0.0, 1.0, 2.0}
est[:5,:]---array([[0.], [1.], [0.], [1.], [1.]])
est = KBinsDiscretizer(n_bins=3,encode='onehot',strategy='uniform').fit_transform(X).toarray()# 独热编码生成稀疏矩阵对象,所以要toarray()est[:5,:]---array([[1., 0., 0.], [0., 1., 0.], [1., 0., 0.], [0., 1., 0.], [0., 1., 0.]])
复制代码


DataFrame 对象需要 iloc 或者 loc 索引,ndarray 对象不能用 iloc、loc,直接用[]索引即可


视频作者:菜菜TsaiTsai链接:【技术干货】菜菜的机器学习sklearn【全85集】Python进阶_哔哩哔哩_bilibili


发布于: 刚刚阅读数: 4
用户头像

一个烟台人 2022-09-14 加入

还未添加个人简介

评论

发布
暂无评论
数据预处理和特征工程-数据预处理-编码与哑变量 & 二值化与分段_Python_烧灯续昼2002_InfoQ写作社区