# 人工智能数据源下载地址: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对象不影响?

  • 有影响,OneHotEncoder, MinMaxScaler 操作完以后自动会把pandas对象转化成numpy对象,pandas对象跟numpy经常转换来转换去的。

  • scikit-learn要求X是一个特征矩阵,y是一个NumPy向量,pandas构建在NumPy之上。因此,X可以是pandas的DataFrame,y可以是pandas的Series,scikit-learn可以理解这种结构。

  • 只是这个X特征矩阵是numpy.ndarray格式,或者是pandas.core.frame.DataFrame格式,都可以传入进model中去的。

    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,编译器就会报错。

  • 二者的功能都是对数据进行某种统一处理(比如标准化~N(0,1),将数据缩放(映射)到某个固定区间,归一化,正则化等)
  • fit_transform(partData)对部分数据先拟合fit,找到该part的整体指标,如均值、方差、最大值最小值等等(根据具体转换的目的),然后对该partData进行转换transform,从而实现数据的标准化、归一化等等。。
  • 根据对之前部分fit的整体指标,对剩余的数据(restData)使用同样的均值、方差、最大最小值等指标进行转换transform(restData),从而保证part、rest处理方式相同。
  • 必须先用fit_transform(partData),之后再transform(restData)
    如果直接transform(partData),程序会报错
  • 如果fit_transfrom(partData)后,使用fit_transform(restData)而不用transform(restData),虽然也能归一化,但是两个结果不是在同一个“标准”下的,具有明显差异。
  • 使用特征预处理提升糖尿病患病指标预测模型的性能

  • 题目描述:对特征进行预处理,然后预测糖尿病的患病指标,并比较模型的性能

  • 题目要求:

  • 对类别型特征及数值型特征进行预处理

  • 数据文件:

  • 数据源下载地址:https://video.mugglecode.com/diabetes.csv (数据源与之前相同)

  • diabetes.csv,包含了442个数据样本。

  • 共11列数据

  • AGE:年龄

  • SEX: 性别

  • BMI: 体质指数(Body Mass Index)

  • BP: 平均血压(Average Blood Pressure)

  • S1~S6: 一年后的6项疾病级数指标

  • Y: 一年后患疾病的定量指标,为需要预测的标签

  • 参考代码:

    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}%')
    

    运行结果: