**
**
虚拟变量,也叫哑变量和离散特征编码,可用来表示分类变量、非数量因素可能产生的影响。
① 离散特征的取值之间有大小的意义
例如:尺寸(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']
所涉及到的几种 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()
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的优势:
注意: 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