使用sklearn進行數據挖掘系列文章:
- 1.使用sklearn進行數據挖掘-房價預測(1)
- 2.使用sklearn進行數據挖掘-房價預測(2)—划分測試集
- 3.使用sklearn進行數據挖掘-房價預測(3)—繪制數據的分布
- 4.使用sklearn進行數據挖掘-房價預測(4)—數據預處理
- 5.使用sklearn進行數據挖掘-房價預測(5)—訓練模型
- 6.使用sklearn進行數據挖掘-房價預測(6)—模型調優
在使用機器算法之前,我們先把數據做下預處理,先把特征和標簽拆分出來
housing = strat_train_set.drop("median_house_value",axis=1) #原始數據集並未發生改變
housing_labels=strat_train_set["median_house_value"].copy()
數據清洗###
大多數機器學習算法是不能在有缺失值的數據集上面運行的,而本數據集特征total_bedrooms是存在數據缺失現象的,所以就需要想辦法處理,有以下幾個思路:
- 1.將存在缺失數據的樣本去除掉
- 2.將存在缺失數據的特征去除掉
- 3.將缺失值用統一的值替換,如:均值、中值等
上面對應的操作:
housing.dropna(subset=["total_bedrooms"]) # 1.刪除樣本
housing.drop("total_bedrooms", axis=1) # 2.刪除特征,注意參數的用法和1不一樣
median = housing["total_bedrooms"].median()
housing["total_bedrooms"].fillna(median) # 3. 中值填充
如果采用的是方法3那么就需要將替換的值保存起來,在后續的工作中需要將它應用到測試集,以及可能添加的新數據。上面這個操作是使用pandas,sklearn提供了Imputer,同樣能夠很好解決缺失值問題,下面其用法
from sklearn.preprocessing import Imputer
imputer = Imputer(strategy="median")
housing_num = housing.drop("ocean_proximity", axis=1) #去除非數值類特征
imputer.fit(housing_num)
imputer提供了以下幾種填充策略
- If "mean", then replace missing values using the mean along the axis.
- If "median", then replace missing values using the median along the axis.
- If "most_frequent", then replace missing using the most frequent value along the axis.
通過statistics_ 查看填充的數值
>>imputer.statistics_
array([-118.51 , 34.26 , 29. , ..., 5.23228423,
0.20303137, 2.8176527 ])
再看一看pandas計算出來的中值
>>housing_num.median().values
array([-118.51 , 34.26 , 29. , ..., 5.23228423,
0.20303137, 2.8176527 ])
接下來就需要將計算得到的數值應用到數據集中
X = imputer.transform(housing_num)
>>type(X)
numpy.ndarray
最終得到的是結果是array類型,如果想轉為pandas類型
housing_tr = pd.DataFrame(X, columns=housing_num.columns)
上面我們把ocean_proximity這一特征去掉,所以這些操作是處理數值類型的特征,那么非數值類型的該如何處理呢?
處理標簽類特征###
決策樹、貝葉斯等分類器能夠處理標簽類特征,但很多算法是不能處理這類特征,需要轉換為數值類型,sklearn提供了LabelEncoder特征轉換方法
from sklearn.preprocessing import LabelEncoder
encoder = LabelEncoder()
housing_cat = housing["ocean_proximity"]
housing_cat_encoded = encoder.fit_transform(housing_cat)
>>housing_cat_encoded
array([0, 0, 4, ..., 1, 0, 3], dtype=int64)
上面是輸出編碼的結果,那么對應的0、1...是指的什么呢?
>>encoder.clases_
array(['<1H OCEAN', 'INLAND', 'ISLAND', 'NEAR BAY', 'NEAR OCEAN'], dtype=object)
通過類別號可以表示類別,還有一種方法能夠表示類別---one hot,該特征取的值位置為1,其余為0;當然sklearn也提供了實現方法OneHotEncoder
from sklearn.preprocessing import OneHotEncoder
encoder = OneHotEncoder()
housing_cat_1hot = encoder.fit_transform(housing_cat_encoded.reshape(-1,1))#返回的為稀疏矩陣
>>housing_cat_1hot.toarray()
array([[ 1., 0., 0., 0., 0.],
[ 1., 0., 0., 0., 0.],
[ 0., 0., 0., 0., 1.],
...,
[ 0., 1., 0., 0., 0.],
[ 1., 0., 0., 0., 0.],
[ 0., 0., 0., 1., 0.]])
note:housing_cat_encoded返回的為1D 數組,fit_transform需要傳入的為一個2D數組,需要先轉為列向量。
可以將上面encoder和one hot過程合並為一個
from sklearn.preprocessing import LabelBinarizer
encoder = LabelBinarizer()
housing_cat_1hot=encoder.fit_transform(housing_cat)
>>housing_cat_1hot #numpy array
array([[1, 0, 0, 0, 0],
[1, 0, 0, 0, 0],
[0, 0, 0, 0, 1],
...,
[0, 1, 0, 0, 0],
[1, 0, 0, 0, 0],
[0, 0, 0, 1, 0]])
自定義處理方法###
盡管sklearn提供了強大的數據處理功能,有些時候我們需要根據自己的需求自定義一些數據預處理方法,並且讓我們這些操作有着sklearnAPI相似的用法,我們所需要做的就是繼承BaseEstimator類,並覆寫三個方法fit,transform和fit_transform,第三個方法是前兩個的整合,如果不想覆寫fit_transform,可以繼承TransformerMixin(從類名稱就可以看出其作用)這個類
from sklearn.base import BaseEstimator, TransformerMixin
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):
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)
上面定義的類的功能是為原數據集添加新的特征,X[:,3]表示的是第4列所有數據,np.c_表示的是拼接數組。
另外sklearn是不能直接處理DataFrames的,那么我們需要自定義一個處理的方法將之轉化為numpy類型
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 #返回的為numpy array
特征縮放###
機器學習算法在縮放尺度不一樣的數據效果比較差,比就如房價數據集total_bedrooms的取值范圍為1~6445,而median_income的范圍是0.5~15,所以需要對特征進行縮放。
note:通常情況下Target特征不需縮放
有兩種縮放數據的方法
- min-max方式,對應的方法為
MinMaxScaler(self, feature_range=(0, 1), copy=True)
- standardization 標准化數據,對應的方法為
StandardScaler(self, copy=True, with_mean=True, with_std=True)
特征處理流程###
目前在數據預處理階段,我們需要對缺失值進行處理、特征組合和特征縮放。每一步的執行都有着先后順序,sklearn提供了Pipeline幫助順序完成轉換。
num_attribs = list(housing_num)#返回的為列名[col1,col2,....]
cat_attribs = ["ocean_proximity"]
num_pipeline = Pipeline([ #數值類型
('selector', DataFrameSelector(num_attribs)),
('imputer', Imputer(strategy="median")),
('attribs_adder', CombinedAttributesAdder()),
('std_scaler', StandardScaler()),
])
cat_pipeline = Pipeline([ #標簽類型
('selector', DataFrameSelector(cat_attribs)),
('cat_encoder', CategoricalEncoder(encoding="onehot-dense")),
])
上面定義的為分別處理數值類型和標簽類型的轉換流程,housing_num為DataFrame類型,list(DataFrame)的結果會是什么?返回的為列名字,不管你們信不信,反正我是信了。pandas真是太強大了。上面着兩個流程還可以再整合一起
from sklearn.pipeline import FeatureUnion
full_pipeline = FeatureUnion(transformer_list=[
("num_pipeline", num_pipeline),
("cat_pipeline", cat_pipeline),
])
housing_prepared = full_pipeline.fit_transform(housing)#最終的結果
今天就到這里把,工作了一天好困、眼疼,先發出去,明天再看看有沒有什么錯誤。
