我们会探讨如下主题:
《特征工程入门与实践》-特征构建
为了进行演示,本章会使用我们自己创建的数据集,以便展示不同的数据等级和类型。我们先设置数据的DataFrame。
用Pandas创建要使用的DataFrame,这也是Pandas的主要数据结构。这样做的优点是可以用很多属性和方法操作数据,从而对数据进行符合逻辑的操作,以深入了解我们使用的数据,以及如何最好地构建机器学习模型。
(1) 首先导入Pandas:
import pandas as pd
(2) 然后就可以设置DataFrame X了。我们用Pandas的DataFrame方法创建表格数据结构(带行和列的表格)。这个方法可以接受不同类型的数据(例如,NumPy数组和字典等)。在本例中,我们传入一个字典,其键是列标题、值是列表,每个列表代表一列:
X = pd.DataFrame({
'city':['tokyo', None, 'london', 'seattle', 'sanfrancisco','tokyo'],
'boolean':['yes', 'no', None, 'no', 'no', 'yes'],
'ordinal_column':['somewhat like', 'like', 'somewhat like', 'like',
'somewhat like', 'dislike'],
'quantitative_column':[1, 11, -.5, 10, None, 20]})
print(X)
利用Pandas DataFrame的isnull方法查看缺失值。这个方法返回一个布尔值对象,表示数据是否为空。然后调用sum方法查看哪列缺失数据:
X.isnull().sum()
boolean 1
city 1
ordinal_column 0
quantitative_column 1
dtype: int64
可以看见,有3列存在缺失值。接下来当然要填充这些值。
scikit-learn的Imputer类,用于填充数值数据,有一个most_frequent方法可以用在定性数据上,但是只能处理整数型的分类数据。
我们要写一个自己的转换器,也就是一个填充每列缺失值的方法。这些转换器对转换数据帮助很大,而且可以进行Pandas和scikit-learn不支持的操作。
为此,需要找出定性列city列中最常见的类别。
注意,要对这个列使用value_counts
方法。这样会返回一个对象,由高到低包含列中的各个元素——第一个元素就是最常出现的。
我们只需要对象中的第一个元素:
# 寻找city列中最常见的元素
X['city'].value_counts().index[0]
>>>>
'tokyo'
tokyo是最频繁出现的城市。我们知道了用tokyo来填充。fillna
函数可以指定填充缺失值的方式:
# 用最常见的值填充city列
X['city'].fillna(X['city'].value_counts().index[0])
city列现在是这样的:
0 tokyo
1 tokyo
2 london
3 seattle
4 san francisco
5 tokyo
Name: city, dtype: object
对另一个列boolean依然存在缺失值。我们不再使用同样的方法,而是构建一个自定义填充器,用来处理分类数据的填充。
回顾一下机器学习流水线:
我们可以用流水线按顺序应用转换和最终的预测器;
流水线的中间步骤只能是转换,这意味着它们必须实现fit和transform方法;
最终的预测器只需要实现fit方法。
流水线的目的是将几个可以交叉验证的步骤组装在一起,并设置不同的参数。在为每个需要填充的列构建好自定义转换器后,就可以把它们传入流水线,一口气转换好数据。
首先,用scikit-learn的TransformerMixin
基类创建我们的自定义分类填充器。这个转换器会作为流水线的一环,实现fit
和transform
方法。
代码仔细讲解:
from sklearn.base import TransformerMixin
#初始化这个自定义的类
class CustomCategoryImputer(TransformerMixin):
def __init__(self, cols=None): #__init__方法对属性进行了初始化
self.cols = cols #初始化一个实例属性self.cols(就是我们指定为参数的列)
def transform(self, df):
X = df.copy()
for col in self.cols:
X[col].fillna(X[col].value_counts().index[0],inplace=True)
return X
def fit(self, *_):
return self
1.scikit-learn的TransformerMixin
类,它包括一个.fit_transform
方法,会调用我们创建的.fit
和.transform
方法。这能让我们的转换器和scikit-learn的转换器保持结构一致。
2.现在可以构建fit和transform方法了:
def transform(self, df):
X = df.copy()
for col in self.cols:
X[col].fillna(X[col].value_counts().index[0],inplace=True)
return X
def fit(self, *_):
return self
我们的fit方法只有return self一句话,和scikit-learn的标准.fit
方法相同。
# 在列上应用自定义分类填充器
cci = CustomCategoryImputer(cols=['city', 'boolean'])
fit_transform
函数:cci.fit_transform(X)
自定义定量填充器
我们使用的结构和自定义分类填充器类似。主要的区别在于,此处用scikit-learn的Imputer类实现一个自定义的转换器,对列进行转换:
# 按名称对列进行转换的填充器
from sklearn.preprocessing import Imputer
class CustomQuantitativeImputer(TransformerMixin):
def __init__(self, cols=None, strategy='mean'):
self.cols = cols
self.strategy = strategy
def transform(self, df):
X = df.copy()
impute = Imputer(strategy=self.strategy)
for col in self.cols:
X[col] = impute.fit_transform(X[[col]])
return X
def fit(self, *_):
return self
对于CustomQuantitativeImputer
,我们添加了一个strategy
参数,指定如何填充定量数据里的缺失值。这里用均值填充缺失值,依然使用transform和fit方法。
还是用fit_transform
函数填充数据,这次我们指定要填充的列和strategy:
cqi = CustomQuantitativeImputer(cols=['quantitative_column'],
strategy='mean')
cqi.fit_transform(X)
也可以不分别调用并用fit_transform
拟合转换CustomCategoryImputer
和CustomQuantitativeImputer
,而是把它们放在流水线中。方法如下所示。
(1) 写import语句:
# 从sklearn导入Pipeline
from sklearn.pipeline import Pipeline
(2) 导入自定义填充器:
imputer = Pipeline([('quant', cqi), ('category', cci)])
imputer.fit_transform(X)
定类等级的编码
主要方法是将分类数据转换为虚拟变量(dummy variable),有两种选择:
在深入探讨之前,我们先研究一下什么是虚拟变量。
虚拟变量的取值是1或0,代表某个类别的有无。虚拟变量是定性数据的代理,或者说是数值的替代。
考虑一个简单的工资回归分析问题。假设给定了性别(定性数据)和工龄(定量数据)。为了考察性别对工资的影响,我们用虚拟变量:female = 0代表男性,female = 1代表女性。
当使用虚拟变量时,需要小心虚拟变量陷阱。虚拟变量陷阱的意思是,自变量有多重共线性或高度相关。简单地说,这些变量能依据彼此来预测。在这个例子中,如果设置female和male两个虚拟变量,它们都可以取值为1或0,那么就出现了重复的类别,陷入了虚拟变量陷阱。我们可以直接推断female = 0代表男性。
为了避免虚拟变量陷阱,我们需要忽略一个常量或者虚拟类别。被忽略的虚拟变量可以作为基础类别,和其他变量进行比较。
回到数据集中,用第一种选择将分类数据编码成虚拟变量。Pandas有个很方便