



類別較多的時(shí)候,獨(dú)熱編碼性能不好,可能會(huì)造成類數(shù)的爆炸,可以預(yù)先進(jìn)行粗分,再接著往下分類。
獨(dú)熱編碼的矩陣是稀疏矩陣。

# 人工智能數(shù)據(jù)源下載地址:https://video.mugglecode.com/data_ai.zip,下載壓縮包后解壓即可(數(shù)據(jù)源與上節(jié)課相同)
# -*- coding: utf-8 -*-
"""
任務(wù):房屋價(jià)格預(yù)測(cè)
"""
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn.preprocessing import OneHotEncoder, MinMaxScaler
import numpy as np
DATA_FILE = './data_ai/house_data.csv'
# 使用的特征列
NUMERIC_FEAT_COLS = ['sqft_living', 'sqft_above', 'sqft_basement', 'long', 'lat']
CATEGORY_FEAT_COLS = ['waterfront']
def process_features(X_train, X_test):
"""
特征預(yù)處理
"""
# 1. 對(duì)類別型特征做one-hot encoding
encoder = OneHotEncoder(sparse=False)
encoded_tr_feat = encoder.fit_transform(X_train[CATEGORY_FEAT_COLS])
encoded_te_feat = encoder.transform(X_test[CATEGORY_FEAT_COLS])
# 2. 對(duì)數(shù)值型特征值做歸一化處理
scaler = MinMaxScaler()
scaled_tr_feat = scaler.fit_transform(X_train[NUMERIC_FEAT_COLS])
scaled_te_feat = scaler.transform(X_test[NUMERIC_FEAT_COLS])
# 3. 特征合并
X_train_proc = np.hstack((encoded_tr_feat, scaled_tr_feat))
X_test_proc = np.hstack((encoded_te_feat, scaled_te_feat))
return X_train_proc, X_test_proc
def main():
"""
主函數(shù)
"""
house_data = pd.read_csv(DATA_FILE, usecols=NUMERIC_FEAT_COLS + CATEGORY_FEAT_COLS + ['price'])
X = house_data[NUMERIC_FEAT_COLS + CATEGORY_FEAT_COLS]
y = house_data['price']
# 分割數(shù)據(jù)集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=1/3, random_state=10)
# 建立線性回歸模型
linear_reg_model = LinearRegression()
# 模型訓(xùn)練
linear_reg_model.fit(X_train, y_train)
# 驗(yàn)證模型
r2_score = linear_reg_model.score(X_test, y_test)
print('模型的R2值', r2_score)
# 數(shù)據(jù)預(yù)處理
X_train_proc, X_test_proc = process_features(X_train, X_test)
# 建立線性回歸模型
linear_reg_model2 = LinearRegression()
# 模型訓(xùn)練
linear_reg_model2.fit(X_train_proc, y_train)
# 驗(yàn)證模型
r2_score2 = linear_reg_model2.score(X_test_proc, y_test)
print('特征處理后,模型的R2值', r2_score2)
print('模型提升了{(lán):.2f}%'.format( (r2_score2 - r2_score) / r2_score * 100) )
if __name__ == '__main__':
main()
模型的R2值 0.627060068329868
特征處理后,模型的R2值 0.6272862884031768
模型提升了0.04%
可能有的疑問(wèn)解答:
OneHotEncoder, MinMaxScaler 操作完以后自動(dòng)會(huì)把pandas對(duì)象轉(zhuǎn)化成numpy對(duì)象是嗎?特征處理前后數(shù)據(jù)類型不一樣對(duì)吧?np對(duì)象和pandas對(duì)象不影響?
有影響,OneHotEncoder, MinMaxScaler 操作完以后自動(dòng)會(huì)把pandas對(duì)象轉(zhuǎn)化成numpy對(duì)象,pandas對(duì)象跟numpy經(jīng)常轉(zhuǎn)換來(lái)轉(zhuǎn)換去的。
scikit-learn要求X是一個(gè)特征矩陣,y是一個(gè)NumPy向量,pandas構(gòu)建在NumPy之上。因此,X可以是pandas的DataFrame,y可以是pandas的Series,scikit-learn可以理解這種結(jié)構(gòu)。
-
只是這個(gè)X特征矩陣是numpy.ndarray格式,或者是pandas.core.frame.DataFrame格式,都可以傳入進(jìn)model中去的。
image.png
scikit-learn中fit_transform()與transform()到底有什么區(qū)別,能不能混用?
fit_transform是fit和transform的組合。
fit(x,y)在新手入門的例子中比較多,但是這里的fit_transform(x)的括號(hào)中只有一個(gè)參數(shù),這是因?yàn)閒it(x,y)傳兩個(gè)參數(shù)的是有監(jiān)督學(xué)習(xí)的算法,fit(x)傳一個(gè)參數(shù)的是無(wú)監(jiān)督學(xué)習(xí)的算法,比如降維、特征提取、標(biāo)準(zhǔn)化。
為什么出來(lái)fit_transform()這個(gè)東西?
fit和transform沒(méi)有任何關(guān)系,僅僅是數(shù)據(jù)處理的兩個(gè)不同環(huán)節(jié),之所以出來(lái)這么個(gè)函數(shù)名,僅僅是為了寫代碼方便,
所以會(huì)發(fā)現(xiàn)transform()和fit_transform()的運(yùn)行結(jié)果是一樣的。
注意:運(yùn)行結(jié)果一模一樣不代表這兩個(gè)函數(shù)可以互相替換,絕對(duì)不可以。transform函數(shù)是一定可以替換為fit_transform函數(shù)的,fit_transform函數(shù)不能替換為transform函數(shù)!
因?yàn)?sklearn里的封裝好的各種算法都要fit、然后調(diào)用各種API方法,transform只是其中一個(gè)API方法,所以當(dāng)你調(diào)用除transform之外的方法,必須要先f(wàn)it,為了通用的寫代碼,還是分開(kāi)寫比較好
也就是說(shuō),這個(gè)fit相對(duì)于transform而言是沒(méi)有任何意義的,但是相對(duì)于整個(gè)代碼而言,fit是為后續(xù)的API函數(shù)服務(wù)的,所以fit_transform不能改寫為transform。
fit_transform與transform運(yùn)行結(jié)果一致,但是fit與transform無(wú)關(guān),只是數(shù)據(jù)處理的兩個(gè)環(huán)節(jié),fit是為了程序的后續(xù)函數(shù)transform的調(diào)用而服務(wù)的,是個(gè)前提條件。
如果把機(jī)器學(xué)習(xí)代碼中的fit_transform改為transform,編譯器就會(huì)報(bào)錯(cuò)。
總結(jié)
- 二者的功能都是對(duì)數(shù)據(jù)進(jìn)行某種統(tǒng)一處理(比如標(biāo)準(zhǔn)化~N(0,1),將數(shù)據(jù)縮放(映射)到某個(gè)固定區(qū)間,歸一化,正則化等)
- fit_transform(partData)對(duì)部分?jǐn)?shù)據(jù)先擬合fit,找到該part的整體指標(biāo),如均值、方差、最大值最小值等等(根據(jù)具體轉(zhuǎn)換的目的),然后對(duì)該partData進(jìn)行轉(zhuǎn)換transform,從而實(shí)現(xiàn)數(shù)據(jù)的標(biāo)準(zhǔn)化、歸一化等等。。
- 根據(jù)對(duì)之前部分fit的整體指標(biāo),對(duì)剩余的數(shù)據(jù)(restData)使用同樣的均值、方差、最大最小值等指標(biāo)進(jìn)行轉(zhuǎn)換transform(restData),從而保證part、rest處理方式相同。
- 必須先用fit_transform(partData),之后再transform(restData)
如果直接transform(partData),程序會(huì)報(bào)錯(cuò) - 如果fit_transfrom(partData)后,使用fit_transform(restData)而不用transform(restData),雖然也能歸一化,但是兩個(gè)結(jié)果不是在同一個(gè)“標(biāo)準(zhǔn)”下的,具有明顯差異。
練習(xí)
使用特征預(yù)處理提升糖尿病患病指標(biāo)預(yù)測(cè)模型的性能
題目描述:對(duì)特征進(jìn)行預(yù)處理,然后預(yù)測(cè)糖尿病的患病指標(biāo),并比較模型的性能
題目要求:
對(duì)類別型特征及數(shù)值型特征進(jìn)行預(yù)處理
數(shù)據(jù)文件:
數(shù)據(jù)源下載地址:https://video.mugglecode.com/diabetes.csv (數(shù)據(jù)源與之前相同)
diabetes.csv,包含了442個(gè)數(shù)據(jù)樣本。
共11列數(shù)據(jù)
AGE:年齡
SEX: 性別
BMI: 體質(zhì)指數(shù)(Body Mass Index)
BP: 平均血壓(Average Blood Pressure)
S1~S6: 一年后的6項(xiàng)疾病級(jí)數(shù)指標(biāo)
Y: 一年后患疾病的定量指標(biāo),為需要預(yù)測(cè)的標(biāo)簽
參考代碼:
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn.preprocessing import OneHotEncoder, MinMaxScaler
def LR(X_train, X_test, y_train, y_test):
model = LinearRegression()
model.fit(X_train,y_train)
R2_score = model.score(X_test,y_test)
return R2_score
def attr_proc(X_train, X_test,feat_col_quant,feat_col_quali):
Encoder = OneHotEncoder(sparse= False)
Encoded_X_train_quali = Encoder.fit_transform(X_train[feat_col_quali])
Encoded_X_test_quali = Encoder.transform(X_test[feat_col_quali])
Scaler = MinMaxScaler()
Scaled_X_train_quant = Scaler.fit_transform(X_train[feat_col_quant])
Scaled_X_test_quant = Scaler.transform(X_test[feat_col_quant])
return np.hstack((Encoded_X_train_quali,Scaled_X_train_quant)), np.hstack((Encoded_X_test_quali,Scaled_X_test_quant))
data = pd.read_csv('./data_ai/diabetes.csv')
feat_col_quant = ['AGE','BMI','BP','S1','S2','S3','S4','S5','S6'] #定量量
feat_col_quali = ['SEX'] #定性量
X = data[feat_col_quant + feat_col_quali]
y = data[['Y']] #其實(shí)外面多套一層括號(hào),結(jié)果還是一樣的,不套括號(hào)也行,但是對(duì)于多列的那種還是要多套括號(hào)的
X_train, X_test, y_train, y_test = train_test_split(X,y,test_size=1/5,random_state=10)
X_train_proc, X_test_proc = attr_proc(X_train, X_test,feat_col_quant,feat_col_quali)
Non_proc_score = LR(X_train, X_test, y_train, y_test)
Proc_score = LR(X_train_proc, X_test_proc, y_train, y_test)
print(f'處理前R2得分為{Non_proc_score}\n處理后R2得分為{Proc_score}')
print(f'處理后的精確度相比處理前精確度變化了{(lán)(Proc_score-Non_proc_score)/Non_proc_score * 100}%')
運(yùn)行結(jié)果:
處理前R2得分為0.5341988244945843
處理后R2得分為0.5327074373208649
處理后的精確度相比處理前精確度變化了-0.279182039595551%
所以把,有時(shí)候歸一化擬合的效果還反而不好了,這是為啥呢?
