参考内容
特征放缩(Feature scaling)
数据处理与管道通信模型
报错Error message: fit_transform() takes 2 positional arguments but 3 were given的解决方法
此部分建议编写函数来执行:
- 函数可以在任何数据集上方便地重现这些转换
- 逐渐建立的一个转换函数库,可以在以后的项目中重复使用
- 可以在实时系统(live system)中使用这些函数转换数据后,再喂给算法
- 可以轻易地尝试多种数据转换,找到效果最好的转换的组合
目录
一、将数据集分成独立的输入集和输出集
二、数据清理
三、处理文本和分类属性
四、自定义转换器
五、特征缩放
六、pipeline
一、将数据集分成独立的输入集和输出集
创建训练集的副本,同时将输入集(预测器)X与输出集(标签)Y分开。
housing = strain_train_set.drop("median_house_value", axis = 1)
#生成没有“median_house_value”这一属性的输入集X
housing_labels = strat_train_set["median_house_value"].copy()
#生成以“median_house_value”这一属性为标签的输出集Y
- 输入集(预测器)X
- 输出集(标签)Y
二、数据清理
(1)处理缺失值的常用方法
需要清理的数据主要类型:残缺数据、错误数据、重复数据
数据清洗方法:
- 不完整数据:经验推导,平均最大最下,甚至概率估计,或建立回归模型,插值法等;
- 错误值检测:异常点检测,偏差分析,规则库等 ;
- 重复值:将重复记录合并、清楚。
前面在研究数据的时候有发现"total_bedrooms"属性有部分数据缺失,所以需要解决这个问题。常见的选择是:
- 放弃这些相应的地区,dropna()
housing.dropna(subset = ["total_bedrooms"])
- 去掉整个属性,drop()
housing.drop("total_bedrooms", axis = 1)
- 进行赋值(0、平均值、中位数),fillna()
median = housing["total_bedrooms"].median()
housing["total_bedrooms"].fillna(median)#将缺失值设置为中位数
(2)用imputer处理缺失值
这里选择用Scikit-Learn提供的imputer处理缺失值,使用属性的中位数替换属性的缺失值来创建imputer实例:
from sklearn.impute import SimpleImputer
imputer = SimpleImputer(strategy = "median")
因为只有数值属性才能算出中位数,所以需要创建一份不包括“ocean_proximity”这一文本属性的数据副本,接着将imputer实例适配到训练集:
housing_num = housing.drop("ocean_proximity", axis = 1)
imputer.fit(housing_num)#将imputer实例适配到训练集
上面的操作只是计算了每个属性的中位数值,并将结果保存在imputer实例变量statistics_中,验证如下:
imputer.statistics_
housing_num.median().values
为了保证其他属性也没有缺失值,这个将imputer应用于所有数值属性:
X = imputer.transform(housing_num)
将转换后得到的一个Numpy数组放回Pandas DataFrame中:
housing_str = pd.DataFrame(X, columns = housing_num.columns)
三、处理文本和分类属性
(1)将文本转化成数字
前面的部分只对数值属性求了中位数。对于机器学习算法来说,会更容易理解数字,因此,先将文本标签转化成数字。
from sklearn.preprocessing import LabelEncoder
encoder = LabelEncoder()
housing_cat = housing["ocean_proximity"]
housing_cat_encoded = encoder.fit_transform(housing_cat)
housing_cat_encoded
(2)将类别编码成独热向量
但是单纯的转换成数字属性可能会让机器学习算法误会他们之间的相似度。因此给每个类别创建一个二进制的属性(独热编码:只有一个属性为1(热),其它均为0(冷)):
from sklearn.preprocessing import OneHotEncoder
encoder = OneHotEncoder()
housing_cat_1hot = encoder.fit_transform(housing_cat_encoded.reshape(-1,1))
housing_cat_1hot
此时输出的是一个Scipy稀疏矩阵,调用toarray()方法可以转换成密集的Numpy数组。
注意:fit_transform()操作的对象是一个二维数组,但housing_cat_encoded是一个一维数组,因此使用reshape进行重塑,-1表示“未指定”。
(3)一次性完成将文本变成独热向量
from sklearn.preprocessing import LabelBinarizer
encoder=LabelBinarizer(sparse_output=True)#默认是sparse_output=False,会生成一个Numpy数组
housing_cat_1hot=encoder.fit_transform(housing_cat)
housing_cat_1hot
四、自定义转换器
(1)消除重尾现象(通过属性结合实现)
针对此项目,可用属性结合的方式消除重尾现象。但这一方法并不适用于所有数据情况,所有针对消除重尾的方法,scikit-learn中并没有具体的模块可以完成这一步。
因此,我们需要自定义一个转换器来实现这一过程。
from sklearn.base import BaseEstimator, TransformerMixin
# column index
rooms_ix, bedrooms_ix, population_ix, household_ix = 3, 4, 5, 6
class CombinedAttributesAdder(BaseEstimator, TransformerMixin):
def __init__(self, add_bedrooms_per_room = True): # no *args or **kargs
self.add_bedrooms_per_room = add_bedrooms_per_room
def fit(self, X, y=None):
return self # nothing else to do
def transform(self, X, y=None):#其输入参数和返回值均是numpy.array类型
rooms_per_household = X[:, rooms_ix] / X[:, household_ix]
population_per_household = X[:, population_ix] / X[:, household_ix]
if self.add_bedrooms_per_room:
bedrooms_per_room = X[:, bedrooms_ix] / X[:, rooms_ix]
return np.c_[X, rooms_per_household, population_per_household,
bedrooms_per_room]
else:
return np.c_[X, rooms_per_household, population_per_household]
attr_adder = CombinedAttributesAdder(add_bedrooms_per_room=False)
housing_extra_attribs = attr_adder.transform(housing.values)
一个转换器类除了fit和transform方法之外,还需要有
fit_transform()
方法。但通过继承TransformerMixin
类,此处可不用添加该方法。
通过继承BaseEstimator
类,对于此自定义类的构造器,也无需添加*args
或**kargs
参数。
(2)Numpy数组转换器
from sklearn.base import BaseEstimator,TransformerMixin
# creat a class to select numerical or categorical columns
# since sklearn doesn't handle DataFrames yet
class DataFrameSelector(BaseEstimator,TransformerMixin):
def __init__(self,attribute_names):
self.attribute_names=attribute_names
def fit(self,X,y=None):
return self
def transform(self,X):
return X[self.attribute_names].values
(3)定义一个三参数的MyLabelBinarizer
针对报错:Error message: fit_transform() takes 2 positional arguments but 3 were given.
from sklearn.base import TransformerMixin #gives fit_transform method for free
class MyLabelBinarizer(TransformerMixin):
def __init__(self, *args, **kwargs):
self.encoder = LabelBinarizer(*args, **kwargs)
def fit(self, x, y=0):
self.encoder.fit(x)
return self
def transform(self, x, y=0):
return self.encoder.transform(x)
五、特征缩放
我们收集到的数据一般需要保证其数量级上统一。
(1)Min-Max scaling(最小最大放缩)
将值缩放使其最终范围归于0到1之间。
from sklearn.preprocessing import MinMaxScaler
(2)Z-score standardization(均值标准化)
均值标准化受异常值影响比较小,支持向量机,逻辑回归,人工神经网络中常用。
from sklearn.preprocessing import StandardScaler
StandardScaler(copy=True,with_mean=True,with_std=True)
from sklearn.preprocessing import scale
(3)Mean normalization(均值归一化处理)
(4)Scaling to unit length(缩放到单位向量)
from sklearn.preprocessing import Normalizer
六、pipeline
对于此项目训练集数据的处理,是先将其分为数值部分和标签部分。其中数值部分,将先后进行清理、消除重尾、缩放的处理;标签部分将进行编码处理。
这一过程中,数据就仿佛是水流、转换器就仿佛是管道,数据先分流成两部分,其中每部分都将流经一个或多个管道。流经多个管道时,数据从前一级转换器流入,输出的结果再流入下一级转换器中。将所有管道按照特定的顺序,或先后、或并排进行组合,最终得到的就是管道通信模型(pipeline)。
利用此特性,上述的处理过程可以通过如下代码集中处理和简化。
(1)生成转换列表
数据处理过程中,存在许多数据转换步骤,我们需要按照一定的顺序进行执行,sklearn提供了类——Pipeline来完成一系列转换。
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
num_pipeline = Pipeline([
('imputer', Imputer(strategy="median")), #'imputer':数据填充
('attribs_adder', CombinedAttributesAdder()), #'attribs_adder':加入新的特征
('std_scaler', StandardScaler()), #'std_scaler':数值型数据的特征缩放
])
housing_num_tr = num_pipeline.fit_transform(housing_num)
- pipline构造器定义的步骤顺序:除了最后一个估算器,其余都要是转换器。
- 转换器用.transform()方法;估算器用.fit()方法;没法保证先.transform()方法、后.fit()方法时,可以直接调用.fit_transform()方法。
- 当调用流水线fit()方法的时候:会对所有的转换器顺序调用fit_transform()方法,将每次调用的输出作为参数传递给下一个调用,一直到最后的一个估计器,只执行fit方法。
(2)将转换加入到单个流水线中
利用 DataFrameSelector将生成的housing框架转换成NumPy数组(用自定义数组转换器那部分的代码)
# from sklearn.pipeline import FeatureUnion
from sklearn.compose import ColumnTransformer
#利用ColumnTransformer可将多个管道并排,以达到分流处理的目的。
num_attribs = list(housing_num)
cat_attribs = ["ocean_proximity"]
num_pipeline = Pipeline([
('selector', DataFrameSelector(num_attribs)),
('imputer', SimpleImputer(strategy = "median")),
('attribs_adder', CombinedAttributesAdder()),
('std_scaler', StandardScaler()),
])
cat_pipeline = Pipeline([
('selector', DataFrameSelector(cat_attribs)),
('label_binarizer',MyLabelBinarizer()),
])
# full_pipeline = FeatureUnion(transformer_list=[
# ("num_pipeline", num_pipeline),
# ("cat_pipeline", cat_pipeline),
# ])
full_pipeline = ColumnTransformer([
('num_pipeline', num_pipeline, num_attribs),
('cat_pipeline', cat_pipeline, cat_attribs),
])
housing_prepared = full_pipeline.fit_transform(housing)
housing_prepared