尽管 Scikit-Learn 提供了许多有用的转换器,你还是需要自己动手写转换器执行任务,比如自定义的清理操作,或属性组合。你需要让自制的转换器与 Scikit-Learn 组件(比如流水线)无缝衔接工作,因为 Scikit-Learn 是依赖鸭子类型的(而不是继承),你所需要做的是创建一个类并执行三个方法: fit() (返回 self ), transform() ,和 fit_transform() 。通过添加 TransformerMixin 作为基类,可以很容易地得到最后一个。另外,如果你添加 BaseEstimator 作为基类(且构造器中避免使用 *args 和 **kargs ),你就能得到两个额外的方法( get_params() 和 set_params() ),二者可以方便地进行超参数自动微调。例如,一个小转换器类添加了上面讨论的属性:(来自hands _On Machine Learning with Scikit_learn&TensorFlow
我们的原始数据格式:
上述数据的第3、4、5、6列数据分别是总共房间数、总共的床数、人口数、总共的家庭数,我们可以通过对这些数据变换得到更加细致的数据。比如可以算出每个家庭拥有的房间数、每个房间平均拥有的床数
首先我们需要使用sklearn中的TransformerMixin和BaseEstimator
import pandas as pd
from sklearn.base import BaseEstimator,TransformerMixin
total_rooms,total_bedrooms,population,household=3,4,5,6 #取出我们需要的属性列
class Attribute_Add(BaseEstimator,TransformerMixin): # 导入两个基类获得fit、transform方法
def __init__(self,bedrooms_per_room=None): # bedrooms_per_room=bedrooms_per_room为可选属性,同时我们设置了两个必选属性
self.bedrooms_per_room=bedrooms_per_room
def fit(self,x,y=None):
return self
def transform(self, x, y=None, ):
# x=inputdata,y=targetdata
#下面两个属性为我们必选合成属性
rooms_per_household = x[:,total_rooms] / x[:,household] # 求取每个房间平均的房间数
rooms_per_population = x[:,population] / x[:,total_rooms]# 求每个人拥有的平均房间数
if self.bedrooms_per_room:
bedrooms_per_room=x[:,total_rooms]/x[:,total_bedrooms] #bedrooms_per_room为可选的合成属性
return np.c_[x,rooms_per_househols,rooms_per_population,bedrooms_per_room]
else:
return np.c_[x,rooms_per_househols,rooms_per_population]
同理我们定义如下的转换器:get_data()、MyOneHotEncode、
class get_data(BaseEstimator,TransformerMixin):#获取数据表中数值数据或者是文本类型的数据,其中attributes为我们属性值列表
def __init__(self,attributes):
self.attributes=attributes;
def fit(self,x,y=None):
return self
def transform(self,x,y=None):
return x[self.attributes].values
class MyOneHotEncode(BaseEstimator,TransformerMixin):#将文本类型的数据转换成数值类型的数据,然后再转换成独热码
def __init__(self,data=None):
self.data=data
def fit(self,x,y=None):
return self
def transform(self,x,y=None):
encoder = LabelEncoder()
array1 = encoder.fit_transform(x)
onehotencode=OneHotEncoder()
tp=onehotencode.fit_transform(array1.reshape(-1,1))
#print(tp.toarray())
return tp.toarray()
from sklearn.pipeline import Pipeline #通俗理解就是前一个转换器的输出作为下一个转换的输入,依次对数据进行处理
from sklearn.pipeline import FeatureUnion #可以理解为多个流水线同时并行对数据操作,各个流水线工作互不影响
"""
sklearn 中的流水线处理数字数据
"""
num_attributes=list(housing_data.drop("ocean_proximity",axis=1))# ocean_proximity为非数值类型的数据,需要去除掉
num_pipeline=Pipeline([
('get_num',get_data(num_attributes)), # 获取数值类型数据
('imputer',Imputer(strategy="median")),#补全数据中的空值(用中位数填充空值)sklearn自带的Imputer # ( 需要导入,这里没有写出 from sklearm.preprocessing import Imputer)
('add_attributes',Attribute_Add()), #合成属性
('normalize',StandardScaler()), #数据标准化
])
"""
sklearn中的流水线处理非数字数据
"""
cat=["ocean_proximity"] # 非数值属性列
N_num_pipeline=Pipeline([
('get_char',get_data(cat)), #获取非数值数据
('label_bin',MyOneHotEncode()),转换成独热码
])
使用FeatureUnion来让两个流水线并行工作(from sklearn.pipline import FeatureUnion)
union_pipeline=FeatureUnion(transformer_list=[
("pipeline1",num_pipeline),
("pipeline2",N_num_pipeline),
])
tq=union_pipeline.fit_transform(housing_data) # 运行 得出的结果是一个简单numpy数组,我们可以将其转换成pd中DataFrame数据
#格式,方便我们查看
list=["rooms_per_househols","rooms_per_population","hot1","hot2","hot3","hot4","hot5"] #为新增的属性列增加名称
num_attributes.extend(list) # 与之前的属性列合并
final_data=pd.DataFrame(tq,columns=num_attributes) #转换成DataFrame
print(final_data) #显示数据
变量空间显示的数据