机器学习建模时处理的都是数值类型的数据,然而实际工作中获取的数据往往会包含非数值类型的数据,其中最常见的就是文本类型的数据,例如,性别中的“男”和“女”,处理时可以用查找、替换的思路,分别转换为数字1和0。但如果类别有很多,又该如何处理呢?本节就来介绍Python中两种常用的非数值类型数据处理方法——Get_dummies哑变量处理和Label Encoding编号处理。
1、 Get_dummies哑变量处理
哑变量也叫虚拟变量,通常取值为0或1,上面提到的将性别中的“男”和“女”分别转换成数字1和0就是哑变量最经典的应用。
在Python中,通常利用pandas库中的get_dummies()函数进行哑变量处理,它不仅可以处理“男”和“女”这种只有两个分类的简单问题,还可以处理含有多个分类的问题。下面通过两个示例演示get_dummies()函数的基本用法。
1.简单的示例:“男”和“女”的数值转换
import pandas as pd
df = pd.DataFrame({'客户编号': [1,2,3], '性别': ['男','女','男']})
df
接着用get_dummies()函数对文本类型的数据进行处理,代码如下。get_dummies()函数的第1个参数为表格名称,第2个参数为需要处理的列的名称。
df = pd.get_dummies(df,columns=['性别'])
df
然现在已经将文本类型的数据转换成了数字,但是“性别_女”和“性别_男”这两列存在多重共线性,即知道其中一列的内容,就能知道另一列的内容,用公式来表达就是:性别_男=1-性别_女。
df = df.drop(columns='性别_女')
df
df = df.rename(columns={"性别_男":"性别"})
df
2.稍复杂的示例:房屋朝向的数值转换
df = pd.DataFrame({"房屋编号":[1,2,3,4,5],"朝向":['东','南','西','北','南']})
df
用get_dummies()函数构造哑变量,代码如下。
df = pd.get_dummies(df,columns=["朝向"])
df
上表同样存在多重共线性(即根据3个朝向的数字就能判断第4个朝向的数字是0还是1),因此需要从新构造出来的4个哑变量中删去1个,假设删去“朝向_西”列,代码如下。
df = df.drop(columns='朝向_西')
df
这样便通过哑变量处理将分类变量转化为数值变量,为后续构建模型打好了基础。构造哑变量容易产生高维数据。
2、Label Encoding编号处理
除了使用get_dummies()函数进行非数值类型数据处理外,还可以使用LabelEncoding进行编号处理,具体来说,是使用LabelEncoder()函数将文本类型的数据转换成数字。下面简单演示如何对不同的城市名称做编号处理,演示代码如下。
df = pd.DataFrame({"编号":[1,2,3,4,5],"城市":["北京","上海","广州","深圳","北京"]})
df
通过如下代码即可将“城市”列的文本内容转换为不同的数字。
from sklearn.preprocessing import LabelEncoder as ln
le = ln()
label = le.fit_transform(df["城市"])
第1行代码从Scikit-Learn库的preprocessing模块中引入LabelEncoder()函数;
第2行代码将LabelEncoder()函数赋给变量le;
第3行代码用fit_transform()函数将待转化的列传入模型中进行拟 合,并将结果赋给变量label,打印输出label的结果如下。
array([1, 0, 2, 3, 1])
可以看到,“北京”被转换成数字1,“上海”被转换成数字0,“广州”被转换成数字2,“深圳”被转换成数字3。通过如下代码可以用转换结果替换原来的列内容。
df["城市"] = label
df
上述示例中使用Label Encoding处理后产生了一个奇怪的现象:上海和广州的平均值是北京,这个现象其实是没有现实意义的,这也是Label Encoding的一个缺点——可能会产生一些没有意义的关系。不过树模型(如决策树、随机森林及XGBoost等集成算法)能很好地处理这种转化,因此对于树模型来说,这种奇怪的现象是不会影响结果的。
3、 pandas库中的replace()函数
LabelEncoder()函数生成的数字是随机的,如果想按特定内容进行替换,可以使用replace()函数。这两种处理方式对于建模效果不会有太大影响。还是用之前的演示数据来进行讲解。
df = pd.DataFrame({"编号":[1,2,3,4,5],"城市":["北京","上海","广州","深圳","北京"]})
df
在使用replace()函数之前,先利用value_counts()函数查看“城市”列有哪些内容需要替换(因为有时数据量很大,通过人眼判断可能会遗漏某些内容),代码如下。
df["城市"].value_counts()
从上述结果可知,需要替换的是“北京”“上海”“深圳”“广州”这4个词。这里用replace()函数按“北上广深”的顺序进行数字编号,代码如下。
df["城市"] = df["城市"].replace({"北京":0,"上海":1,"广州":2,"深圳":3})
df
可以看到,LabelEncoder()函数是对文本内容进行随机编号,而用replace()函数可将文本内容替换成自定义的值。不过当分类较多时,还需要先用value_counts()函数获取每个分类的名称,步骤会稍微烦琐一些。
4、总结
Get_dummies的优点是它的值只有0和1,缺点是当类别的数量很多时,特征维度会很高,此时可以配合使用下一章要讲解的PCA(主成分分析)来减少维度。如果类别数量不多,可以优先考虑使用Get_dummies,其次考虑使用Label Encoding或replace()函数;但如果是基于树模型的机器学习模型,用LabelEncoding也没有太大关系。