07 使用特征預(yù)處理提升房?jī)r(jià)預(yù)測(cè)模型的性能





類別較多的時(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í)候歸一化擬合的效果還反而不好了,這是為啥呢?

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容