Python中独热编码与虚拟变量

**

1、pandas内置函数虚拟变量(dummy variables)

**

虚拟变量,也叫哑变量和离散特征编码,可用来表示分类变量、非数量因素可能产生的影响。
① 离散特征的取值之间有大小的意义
例如:尺寸(L、XL、XXL)
离散特征的取值有大小意义的处理函数map
pandas.Series.map(dict)
参数 dict:映射的字典

② 离散特征的取值之间没有大小的意义

pandas.get_dummies
例如:颜色(Red,Blue,Green)
处理函数:
get_dummies(data,prefix=None,prefix_sep="_",dummy_na=False,columns=None,drop_first=False)

① data 要处理的DataFrame
② prefix 列名的前缀,在多个列有相同的离散项时候使用
③ prefix_sep 前缀和离散值的分隔符,默认为下划线,默认即可
④ dummy_na 是否把NA值,作为一个离散值进行处理,默认为不处理
⑤ columns 要处理的列名,如果不指定该列,那么默认处理所有列
⑥ drop_first 是否从备选项中删除第一个,建模的时候为避免共线性使用

import pandas

data = pandas.read_csv('D:\\PDA\\4.18\\data.csv',  encoding='utf8')
data['Education Level'].drop_duplicates()
"""
博士后    Post-Doc
博士      Doctorate
硕士      Master's Degree
学士      Bachelor's Degree
副学士    Associate's Degree
专业院校  Some College
职业学校  Trade School
高中      High School
小学      Grade School
"""
educationLevelDict = {
    'Post-Doc': 9,
    'Doctorate': 8,
    'Master\'s Degree': 7,
    'Bachelor\'s Degree': 6,
    'Associate\'s Degree': 5,
    'Some College': 4,
    'Trade School': 3,
    'High School': 2,
    'Grade School': 1
}
data['Education Level Map'] = data[
    'Education Level'
].map(
    educationLevelDict
)
data['Gender'].drop_duplicates()
dummies = pandas.get_dummies(
    data, 
    columns=['Gender'],
    prefix=['Gender'],
    prefix_sep="_",
    dummy_na=False,
    drop_first=False
)
dummies['Gender'] = data['Gender']

2、 sklearn 的二值化编码函数

所涉及到的几种 sklearn 的二值化编码函数:OneHotEncoder(), LabelEncoder(), LabelBinarizer(), MultiLabelBinarizer()

#coding=gbk
#几种sklearn 中的二值化编码函数,
import pandas as pd
import numpy as np
from sklearn.preprocessing import OneHotEncoder
from sklearn.preprocessing import LabelEncoder
from sklearn.preprocessing import LabelBinarizer
from sklearn.preprocessing import MultiLabelBinarizer
 
columns = ['pet','age','salary']
data = pd.DataFrame([['cat','dog','dog','fish'],[4,6,3,3],[4,5,1,1]])
data = data.T   #对二维数组进行转置
data.columns = columns
print(data)
#     pet age salary
# 0   cat   4      4
# 1   dog   6      5
# 2   dog   3      1
# 3  fish   3      1

(1)数值类型变量

```python
OneHotEncoder(sparse = False).fit_transform(testdata[['age']])

注意: one-hot化是每个feature的取值个数作为one-hot后的长度,对应的位置0/1的值是原数据在此位置取值的有无.不是取值的max的长度编号:如这个最大为6,按照one-hot的定义是testdata[[‘age’]]=[4]–>one-hot后:[0,0,0,1,0,0]但定义直观理解是这样的,但在工程实现这样没必要,只针对有值得取值编码就可以,节约矩阵one-hot后的规模而且效果一样;
可以用同样的方法对 salary 进行 OneHotEncoder, 然后将结果用 numpy.hstack() 把两者拼接起来得到变换后的结果

a1 = OneHotEncoder(sparse = False).fit_transform( testdata[['age']] )
a2 = OneHotEncoder(sparse = False).fit_transform( testdata[['salary']])
final_output = numpy.hstack((a1,a2))

有时候我们除了得到最终编码结果,还想知道结果中哪几列属于 age 的二值化编码,哪几列属于 salary 的,这时候我们可以通过 OneHotEncoder() 自带的 feature_indices_ 来实现这一要求,比如这里 feature_indices_ 的值是[0, 3, 6],表明 第[0:3]列是age的二值化编码,[3:6]是salary的。更多细节请参考 sklearn 文档

#1. OneHotEncoder 独热编码的使用
#True 则返回一个array, False 则返回matrix矩阵
onehot_age = OneHotEncoder(sparse=False).fit_transform(data[['age']]) 
 
print(data['age'].shape)    #(4,)
print(data[['age']].shape)  #(4, 1)
#由于 OneHotEncoder 的编码必须是 2-D array ,而data.age 即 data['age']返回的是 1-D array,所以要改成上述的双中括号
print(onehot_age)
# [[0. 1. 0.]
#  [0. 0. 1.]
#  [1. 0. 0.]
#  [1. 0. 0.]]
 
onehot_salary = OneHotEncoder(sparse= False)._fit_transform(data[['salary']])   #两个输出都是一样的
output = np.hstack((onehot_age, onehot_salary))  #记住括号是双括号,使其在列上合并
print(output)
# [[0. 1. 0. 0. 1. 0.]
#  [0. 0. 1. 0. 0. 1.]
#  [1. 0. 0. 1. 0. 0.]
#  [1. 0. 0. 1. 0. 0.]]
# onehot_pet = OneHotEncoder(sparse=False).fit_transform(data[['pet']]) 不能直接对字符串的类别进行编码
test = OneHotEncoder(sparse=False).fit_transform(data[['age','salary']])
print(test) #可以同时输入两个特征值,可以接受多列输入
# [[0. 1. 0. 0. 1. 0.]
#  [0. 0. 1. 0. 0. 1.]
#  [1. 0. 0. 1. 0. 0.]
#  [1. 0. 0. 1. 0. 0.]]

**

(2)、对付字符串型类别变量

**
遗憾的是OneHotEncoder无法直接对字符串型的类别变量编码,也就是说OneHotEncoder().fit_transform(testdata[[‘pet’]])这句话会报错(不信你试试)。已经有很多人在 stackoverflow 和 sklearn 的 github issue 上讨论过这个问题,但目前为止的 sklearn 版本仍没有增加OneHotEncoder对字符串型类别变量的支持,所以一般都采用曲线救国的方式:

  • 方法一 先用 LabelEncoder() 转换成连续的数值型变量,再用 OneHotEncoder() 二值化
  • 方法二 直接用 LabelBinarizer() 进行二值化
    然而要注意的是,无论 LabelEncoder() 还是 LabelBinarizer(),他们在 sklearn 中的设计初衷,都是为了解决标签 y的离散化,而非输入X, 所以他们的输入被限定为 1-D array,这恰恰跟OneHotEncoder() 要求输入 2-D array 相左。所以我们使用的时候要格外小心,否则就会出现上面array([[ 1., 1., 1., 1.]])那样的错误.
#方法一: LabelEncoder() + OneHotEncoder()
a = LabelEncoder().fit_transform(testdata['pet'])
OneHotEncoder( sparse=False ).fit_transform(a.reshape(-1,1)) # 注意: 这里把 a 用 reshape 转换成 2-D array
 
#方法二: 直接用 LabelBinarizer()
 
LabelBinarizer().fit_transform(testdata['pet'])

正因为LabelEncoder和LabelBinarizer设计为只支持 1-D array,也使得它无法像上面 OneHotEncoder 那样批量接受多列输入,也就是说LabelEncoder().fit_transform(testdata[[‘pet’, ‘age’]])会报错。

#2,对字符串类型二值化
#方法1 使用 LabelEncoder + OneHotEncoder
le_pet = LabelEncoder().fit_transform(data.pet)
print(le_pet)   #[0 1 1 2]
print(le_pet.shape) # (4,) 是一维数组
print(le_pet.reshape(-1,1).shape) # (4, 1) 将其转换成 4 行 1列
oe_pet = OneHotEncoder(sparse=False).fit_transform(le_pet.reshape(-1,1))
print(oe_pet)
# [[1. 0. 0.]
#  [0. 1. 0.]
#  [0. 1. 0.]
#  [0. 0. 1.]]
 
#方法2 直接使用 labelBinarizer ,设计是为了解决y 的离散化的
lb_pet = LabelBinarizer().fit_transform(data.pet)
print(lb_pet)   #同样可以得到同样的输出,只是 dtype 不相同
# [[1 0 0]
#  [0 1 0]
#  [0 1 0]
#  [0 0 1]]
 
print('-----')
mb = MultiLabelBinarizer().fit_transform(data[['age','salary']].values)
print(mb)
# [[0 0 1 0 0]
#  [0 0 0 1 1]
#  [1 1 0 0 0]
#  [1 1 0 0 0]]

(3)、尝试虚拟变量

pd.get_dummies(testdata,columns=testdata.columns)

get_dummies的优势:

  • 1.本身就是 pandas 的模块,所以对 DataFrame 类型兼容很好.
  • 2.无论你的列是字符型还是数字型都可以进行二值编码.
  • 3.能根据用户指定,自动生成二值编码后的变量名.
    这么看来,我们找到最完美的解决方案了? No!get_dummies千般好,万般好,但毕竟不是 sklearn 里的transformer类型,所以得到的结果得手动输入到 sklearn 里的相应模块,也无法像 sklearn 的transformer一样可以输入到pipeline中 进行流程化地机器学习过程。更重要的一点.

注意: get_dummies 不像 sklearn 的 transformer一样,有 transform方法,所以一旦测试集中出现了训练集未曾出现过的特征取值,简单地对测试集、训练集都用 get_dummies 方法将导致数据错误。

#使用 pandas 自带的 get_dummies 函数
gd = pd.get_dummies(data, columns = columns)
print(gd)
#  pet_cat  pet_dog  pet_fish  age_3  age_4  age_6  salary_1  salary_4  \ .....
# 0        1        0         0      0      1      0         0         1   
# 1        0        1         0      0      0      1         0         0   
# 2        0        1         0      1      0      0         1         0   
# 3        0        0         1      1      0      0         1         0 

你可能感兴趣的:(Python,机器学习)