Python机器学习

07 使用特征预处理提升房价预测模型的性能

2018-09-05  本文已影响22人  夏威夷的芒果




类别较多的时候,独热编码性能不好,可能会造成类数的爆炸,可以预先进行粗分,再接着往下分类。
独热编码的矩阵是稀疏矩阵。


# 人工智能数据源下载地址:https://video.mugglecode.com/data_ai.zip,下载压缩包后解压即可(数据源与上节课相同)
# -*- coding: utf-8 -*-

"""
    任务:房屋价格预测
"""
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):
    """
        特征预处理
    """
    # 1. 对类别型特征做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. 对数值型特征值做归一化处理
    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():
    """
        主函数
    """
    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']

    # 分割数据集
    X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=1/3, random_state=10)

    # 建立线性回归模型
    linear_reg_model = LinearRegression()
    # 模型训练
    linear_reg_model.fit(X_train, y_train)
    # 验证模型
    r2_score = linear_reg_model.score(X_test, y_test)
    print('模型的R2值', r2_score)

    # 数据预处理
    X_train_proc, X_test_proc = process_features(X_train, X_test)
    # 建立线性回归模型
    linear_reg_model2 = LinearRegression()
    # 模型训练
    linear_reg_model2.fit(X_train_proc, y_train)
    # 验证模型
    r2_score2 = linear_reg_model2.score(X_test_proc, y_test)
    print('特征处理后,模型的R2值', r2_score2)

    print('模型提升了{:.2f}%'.format( (r2_score2 - r2_score) / r2_score * 100) )


if __name__ == '__main__':
    main()
模型的R2值 0.627060068329868
特征处理后,模型的R2值 0.6272862884031768
模型提升了0.04%

可能有的疑问解答:

OneHotEncoder, MinMaxScaler 操作完以后自动会把pandas对象转化成numpy对象是吗?特征处理前后数据类型不一样对吧?np对象和pandas对象不影响?

scikit-learn中fit_transform()与transform()到底有什么区别,能不能混用?

fit_transform是fit和transform的组合
fit(x,y)在新手入门的例子中比较多,但是这里的fit_transform(x)的括号中只有一个参数,这是因为fit(x,y)传两个参数的是有监督学习的算法,fit(x)传一个参数的是无监督学习的算法,比如降维、特征提取、标准化。

为什么出来fit_transform()这个东西?

fit和transform没有任何关系,仅仅是数据处理的两个不同环节,之所以出来这么个函数名,仅仅是为了写代码方便,

所以会发现transform()和fit_transform()的运行结果是一样的。

注意:运行结果一模一样不代表这两个函数可以互相替换,绝对不可以。transform函数是一定可以替换为fit_transform函数的,fit_transform函数不能替换为transform函数!

因为 sklearn里的封装好的各种算法都要fit、然后调用各种API方法,transform只是其中一个API方法,所以当你调用除transform之外的方法,必须要先fit,为了通用的写代码,还是分开写比较好

也就是说,这个fit相对于transform而言是没有任何意义的,但是相对于整个代码而言,fit是为后续的API函数服务的,所以fit_transform不能改写为transform。

fit_transform与transform运行结果一致,但是fit与transform无关,只是数据处理的两个环节,fit是为了程序的后续函数transform的调用而服务的,是个前提条件。

如果把机器学习代码中的fit_transform改为transform,编译器就会报错。

总结

练习

使用特征预处理提升糖尿病患病指标预测模型的性能

参考代码:

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']]  #其实外面多套一层括号,结果还是一样的,不套括号也行,但是对于多列的那种还是要多套括号的

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'处理后的精确度相比处理前精确度变化了{(Proc_score-Non_proc_score)/Non_proc_score * 100}%')

运行结果:

处理前R2得分为0.5341988244945843
处理后R2得分为0.5327074373208649
处理后的精确度相比处理前精确度变化了-0.279182039595551%

所以把,有时候归一化拟合的效果还反而不好了,这是为啥呢?

上一篇 下一篇

猜你喜欢

热点阅读