回归问题常用的就是线性回归。在R中用的是lm(),而python中都封装在scikit-learn里。
一、数据准备
用的是书上的housing数据,如下图:
这个数据包含10个变量,一共有20640行,当然里面也有一些NA值。假如我们现在要研究median house value与哪些因素有关,并预测其值。对于这个问题,由于median house value是一个数值型变量,所以最适合用线性回归。
分割数据,创建训练集+测试集。
一般是按照80%和20%的比例划分数据,划分的方法包括随机抽样和分层抽样。
书中推荐的随机抽样函数:
import numpy as np
def split_train_test( data, test_ratio ):
shuffled_indices = np.random.permutation(len(data))
test_set_size = int(len(data) * test_ratio )
test_indices = shuffled_indices[ :test_set_size]
train_indices = shuffled_indices[test_set_size: ]
return data.iloc[train_indices], data.iloc[test_indices]
讲解一下上面的函数:len(data)输出data的行数,np.random.permutation()是根据括号里的数字随机生成随机序列,因此生成了洗牌后的指标shuffled indices。函数int()是数字转换为整数integer,去掉小数点,相反地,float是转换为浮点数值。值得一提的是,numpy的dataframe取值和R的dataframe有很大的不同,R中的dataframe取值的方法是data[1,2],而numpy的dataframe取值的方法是data.iloc[1,2],即以位置为索引选择数据。而data[ :2]则是取从第0行到第1行的数据,data.longjitude是取名为longjitude的一列。
所以整个函数的思路是:先将数据的实例(每行)重新洗牌,常规取80%作为训练集,20%作为测试集。在这里取0.2作为测试集test_set_size。然后取洗牌后的第0行到第20%行作为测试数据test_indices,取第20%行到100%行作为train_indices。随后返回两个数据集。
分层抽样
from sklearn.model_selection import StratifiedShuffleSplit
split = StratifiedShuffledSplit(n_splits=1, test_size=0.2, random_state=42)
for train_index, test_index in split,split(housing, housing['income_cat']):
strat_train_set = hosing.loc[train_index]
strat_test_set = housing.loc[test_index]
缺失值处理
缺失值常用的方法有三种:放弃这几行,放弃这个特征,填充缺失值。
书上这里示例的是用中位数填充缺失值
from sklearn.preprocessing import Imputer
imputer = Imputer(strategy = 'median')
转换器
对于文本或者类别变量,在R中可以用as.factor函数,在python中可以用df.astype(‘category’,categories,ordered)。而在这则可以用sklearn自带的转换器LabelEncoder()
from sklearn.preprocessing import LabelEncoder
encoder = LabelEncoder()
housing_cat = housing['ocean_proximity']
housing_cat_encoded = encoder.fit_transform(housing_cat)
上面的编码方法适合于有序分类变量,例如数值大小代表疾病严重程度。而书中推荐另一种无序分类变量的编码方法,即编码数值大小不代表任何意义。
这种编码方式是独热编码,1代表热,0代表冷,类似于binary。从因子向量变成独热向量用OneHotEncoder(),当然,也可以用LabelBinarizer()一步到位,将分类变量转换为独热变量。
encoder = LabelBinarizer() #替换上面的相应代码部分
fit()是用于估算的函数,transform()是用于转换的函数,返回的结果就是转换后的数据集。而fit_transform是先调用fit()然后调用transform,返回转换后的数据集。
自定义转换器
上面说了LabelEncoder和OneHotEncoder和LabelBinarizer三种转换器,下面分析下书中提供的一种自定义转换器:
from sklearn.base import BaseEstimator, TransformerMixin
rooms_ix, bedrooms_ix, population_ix, houshold_ix = 3,4,5,6
class CombinedAttributesAdder(BaseEstimator, TransformerMixin):
def _init_(self, add_bedrooms_per_room = True):
self.add_bedrooms_per_room = add_bedrooms_per_room
def fit(self, X, y=None):
return self
def transform(self, X, y=None):
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[ :, bedroom_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)
这个自定义的CombinedAttributesAdder()转换器有点长,我解释一下:rooms_ix就是rooms这个变量的索引值(对应着第四列的total_rooms,记得差一原则)。例如上文说的取某列,除了类似于R方法的df.iloc方法以外,还有df.ix就是根据索引值来取列或行。
然后定义了一个类,CombinedAttributesAdder。
特征缩放
目标值(即Y)通常是不需要特征缩放的,而X1,X2等等变量则需要。特征缩放包括2种,归一化和标准化。
归一化:将值减去最小值,再除以最大值最小值的差,最后结果值将介于0-1之间。归一化又称最小-最大缩放。用MinMaxScaler()转换器。
归一化的缺点是受异常值的影响大,尤其是最小值最大值的异常值,其影响更大。因为归一化是按照最小-最大的差值去归一的。
标准化:将值减去平均值再除以方差。将不用正态分布的数据,变成均之为0,方差为单位方差的标准正态分布图。这种方法受异常值的影响较小,因为不改变其分布形状,只是左右上下移动该分布的位置。用StandardScaler()转换器。
建立流水线
流水线就是一种管道,pipeline,能将传递过来的数据自动处理。一个典型的流水线:
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
num_pipeline = Pipeline([
('imputer', Imputer(strategy='median')),#将缺失值用中位数填充的流程
('attribs_adder', CombinedAttributesAdder()),#将
('std_scaler', StandardScaler()),
])