机器学习与Python应用(二)

机器学习——线性回归算法

本贴为学习记录贴,有任何问题随时可以交流。
课程名称:机器学习与数据挖掘
使用教材:《Python机器学习》/赵涓涓,强彦主编.——北京:机械工业出版社,2019.06
记录时间:2021.03.21
本节说明:主要讲解教材第三章的线性回归算法应用题目,重点关注sklearn的数据集使用方法以及数据集处理思路。

一、简要介绍

本节是教材书《Python机器学习》第3章线性回归算法中算法应用的讲解。
代码环境说明:所有代码均在Jupyter Notebook中执行(IPython方便查看数据的情况)
环境查看方式可以参考机器学习与Python应用(一)的第一节内容。

系统:Windows 10
Anaconda – 4.9.2
jupyter notebook – 6.0.1
Python – 3.7.4
numpy – 1.16.5
pandas – 1.2.3
sklearn – 0.21.3
matplotlib – 3.3.4
seaborn – 0.9.0

二、库的导入和使用

机器学习常用的第三方库有:numpypandasmatplotlibsklearn

  • numpy:常用于数组或矢量运算,具有非常高的性能
  • pandas:常用于数据处理,具有高级的数据结构
  • matplotlib:常用于绘图和数据可视化
  • seaborn:常用于绘图和数据可视化
  • sklearn:常用于机器学习

本节内容主要是线性回归,因此导入以下库:

# 导入第三方库
 import numpy as np
 import pandas as pd
 from sklearn import datasets
 import matplotlib.pyplot as plt
 from sklearn.linear_model import LinearRegression

三、数据集

本节算法中,使用的数据集是波士顿房价(Boston house prices dataset)。该数据集共有506条数据,每条数据里面共有属性13种(包括需要预测的房价)。

(一)数据集导入

不同类型的数据集可以用不同的方法的导入。

  • 使用numpy导入
    1、导入:导出成ndarray格式

    np.load(file_name.npy)  # 将npy数据加载
    np.loadtxt(file_name.txt)  # 导入txt数据
    

    2、导出

    np.save(file_name, ndarray)  # 将ndarray存储到file_name中并保存成npy格式
    np.savez(file_name, *args, *kwargs)  # 以字典形式保存为npz格式
    np.savetxt(file_name, X_1or2D, delimiter=' ')  # 保存成out或txt格式
    
  • 使用pandas导入
    1、导入:
    pandas可导入的数据类型十分多,如:hdf5、json、html、csv、Excel等。

    pd.read_文件类型名(file_path)  --> DataFrame类型
    

    2、导出:
    pandas同样可以导出hdf5、json、html、csv、Excel等数据

    DataFrame.to_filetype('file_name')
    
  • 对于本节内容,导进来的数据集是Boston_house prices dataset可以从sklearn.datasets中加载进来,原因是在下载sklearn相关的包时,这些数据集就随着包安装在电脑里。加载该数据时,输入以下命令:

    boston_dataset = datasets.load_boston()
    

(二)数据集分析

数据加载进来后,需要先查看数据,包括数据集的介绍、数据集的类型、数据集的结构和数据集的内容等。

  • 数据集的介绍

    print(boston_dataset.DESCR)    # 用于查看数据集的内容
    

    “Boston_house prices dataset” 有506条数据,数据中的有13种属性(有数值型数据和分类型数据)作为特征,第14种属性为target,即通常所说的标签(被解释变量)。

      - CRIM     per capita crime rate by town
      - ZN       proportion of residential land zoned for lots over 25,000 sq.ft.
      - INDUS    proportion of non-retail business acres per town
      - CHAS     Charles River dummy variable (= 1 if tract bounds river; 0 otherwise)
      - NOX      nitric oxides concentration (parts per 10 million)
      - RM       average number of rooms per dwelling
      - AGE      proportion of owner-occupied units built prior to 1940
      - DIS      weighted distances to five Boston employment centres
      - RAD      index of accessibility to radial highways
      - TAX      full-value property-tax rate per $10,000
      - PTRATIO  pupil-teacher ratio by town
      - B        1000(Bk - 0.63)^2 where Bk is the proportion of blacks by town
      - LSTAT    % lower status of the population
      - MEDV     Median value of owner-occupied homes in $1000'
    
  • 数据集的类型

    print(type(boston_dataset))
    

    “Boston_house prices dataset” 导入后生成的是Bunch类型,是一种继承dict的数据类型,可以通过keys()values()去访问对应的值。

  • 数据集的结构及内容

    for key, value in boston_dataset.items():
        print('key为:{}\n其value的类型为:{}'.format(key, type(value)))
    

    Bunch具有字典的属性,因此可以配合上面数据集的介绍以及使用keys()来查看该数据集的各个部分内容。
    “Boston_house prices dataset” 里面包含了data, target, feature_names, DESCR, filename五个部分。

       key             type(value)
     - data            ndarray        # 数据集的特征
     - target          ndarray        # 数据集的标签
     - feature_names   ndarray        # 数据集的特征名称
     - DESCR           str            # 数据集的介绍(在上面已经使用过)
     - filename        str            # 数据集的存储位置(绝对路径)
    

(三)数据集提取与转换

  • 数据集的每项内容并非都是需要的,一般地,转换成数据集时会选取数据特征data、数据标签target以及数据特征的名称feature_name作为数据处理的基础,而转换的数据类型一般是SeriesDataFrame
    # 将数据集的data转换成DataFrame类型,此时index和column是默认的id
    data = pd.DataFrame(boston_dataset.data)
    # 将data的column用数据集的feature_name替代,此时DF结构具有列索引名称
    data.columns = boston_dataset.feature_names
    # 生成新的一列PRICE,其值为数据集的target
    data['PRICE'] = boston_dataset.target
    

四、数据预处理与变量选取

我们在使用模型前,需要确定我们的自变量和因变量。在自变量的选择中,我们需要进一步对数据集采集下来的数据进行筛选,这里面会涉及到“特征工程”。但在本节中的任务里面规定了RM(房间数)作为特征变量(自变量),PRICE(房价)作为目标变量(因变量),因而大部分的特征筛选工作就被简化了。

这一章节主要讲解数据预处理思路和DataFrameSeriesndarray在案例中的应用。
上一节机器学习与Python应用(一)已经对三者的转化有过说明。

(一)数据预处理

  • 数据类型的确认
    生活中我们经常会遇到各种类型的数据,既有分类型也有数值型,有结构化的也有非结构化的,不同的数据类型对模型方法选择也会有所影响。因此在我们拿到数据后,需要对每个特征的数据类型进行识别。

    data.head()   # 查看前五行的数据情况
    
    data.dtypes   # 查看每一列的数据类型
    

    本节案例中所有的变量都是float64类型,即都是数值型数据。

  • 缺失数据的识别
    我们所搜集的各种数据并不都是完整的,实际上都会面对各种特征存在数据缺失的情况,因此在变量选取前需要对数据进行缺失值识别和处理。

    data.describe()  # 查看数据的描述性统计(通过count来观察对应列的缺失值)
    

    从上面数据集的描述以及describe()可以知道,本案例给出的数据没有缺失值的。常用的缺失值处理方法是采用剔除或填充,其中Pandas有比较高效的缺失值处理方法,具体方法可以查阅《利用Python数据分析》的第5章。

  • 数据集的划分
    为了使我们的模型更有效,一般都不会选择把所有的数据投入到模型训练中,通常会将一个数据集划分成训练集train和测试集test,模型使用训练集来找到一组比较合适的模型参数,模型训练出来的参数会可以用在测试集上来反馈模型的精度。在上面我们对数据集提取后得到的data,是一个完整的数据,即包括了自变量和因变量。

    本节案例中给出的代码实例是将所有的数据作为训练集。

(二)变量选取

  • 特征变量与目标变量的相关性
    各类我们所获取到的特征变量并非所有都对目标变量有关系,因此一方面需要基本常识和专业知识来对特征变量进行筛选,另一方面需要用数理上来描述变量直接的相关性,两个方面缺一不可。

    """输出相关系数矩阵"""
    data_corr = data.corr(method='pearson')   # 输出的是Pearson相关系数矩阵
    print(data_corr)
    
    """画出相关系数矩阵的热力图"""
    plt.figure(figsize=(11, 9),dpi=100)
    sns.heatmap(data=data_corr,
                vmax=0.3, 
                annot=True,  # 图中数字文本显示
                fmt=".2f",   # 格式化输出图中数字,即保留小数位数等
                annot_kws={'size':8,'weight':'normal'},  # 设置字号、磅值
              )
    

    在本案例中,只需要考察单个特征变量RM和目标变量PRICE,因此没有给出这段代码,该部分是拓展内容。

  • 特征变量与目标变量的选取
    在数据预处理完后,需要确定我们模型中的自变量和目标变量。这就需要我们对数据进行再筛选,以便于模型中的计算,这里就涉及到ndarraySeriesDataFrame三种数据结构的使用。

    • 整张数据表是以DataFrame类型展现的二维数组,具有indexColumns两组索引。前者可以理解为行索引,用于检索每一条数据,后者可以理解为列索引,用于查看每列特征变量的数据。
      print(type(data))  # 查看数据表的类型
      print(data.ndim)   # 查看数据表的维度
      print(data.shape)  # 查看数据表的行列数(数据条数和属性数)
      
    • 对数据表进行索引,分为下标索引和标签名索引。
      • 1、直接按行列索引,本质上使用dict类型的索引方法,先索引外层key、再索引内层key。

      注意:
      这如果只是检索某单一列,返回的是Series类型。
      如果是检索多列,可以用list将列框住

      # 直接按行列索引进行检索
      data['RM']  # 返回数据表RM那一列的数据,返回类型是Series
      print(type(data['RM']))
      data['RM'][0]  # 返回数据表RM那一列、index为0的那一行的数据
      data[['RM','PRICE']]  # 返回数据表RM和PRICE那一列的数据,返回类型是DataFrame
      
      • 2、按下标索引,使用df.iloc[index_id, column_id],按行下标、列下标对数据框进行索引。
      data.iloc[:,:]  # 返回所有行和列
      data.iloc[1:10, :]  # 返回第2行到第9行(注意:下标是从0开始,左闭右开区间)
      data.iloc[1:10, :5] # 返回第2到9行和第1到9列
      data.iloc[1:10, [0, 5]] # 返回第2到9行,第1列和第6列
      
      • 3、按标签名索引,使用df.loc[index_name, column_name],按行标签名、列标签名进行索引。
      # 变量选取
      data.loc[0:10,'RM']  # 返回行标签名为0与行标签名为10之间,列标签为'RM'的数据
      data.loc[:, 'RM':'PRICE']  # 返回列标签名为'RM'与'PRICE'之间的数据
      
  • 自变量和因变量的确定
    在变量筛选完好,用x和y分别表示自变量和因变量,但必须注意的是这里的x和y最好都是二维数组ndarray类型,机器学习中的许多模型要求传入的都是二维数组。如果变量是其他类型数据(如:SeriesDataFrame),需要先转成数组类型(如ndarray),再进行维度更改,如使用ndarray.reshape(m,n)

    注意:DataFrame进行索引时,维度不发生改变时,依旧是DataFrame类型;降维到一维度生成的是Series类型;维度为零时生成的是基本数据类型(如int, float, str等)

    # 下面的 data.loc[,] 返回的是Series类型,转成数组时,需要使用 .values
    
    # 教材上的代码.as_matrix()在Pandas的更新中已经被剔除了,现在常用的是.values()来构建数组
    
    # 变量筛选和数组转变
    x = data.loc[:, 'RM'].values  # 自变量只有一个,生成的是一维的数组,类型为ndarray
    y = data.loc[:, 'PRICE'].values  # 因变量只有一个, 也是一维的数组,类型为ndarray
    print(type(data.loc[:, 'RM'])) 
    print(type(x))
    print(x.shape)
    
    # 对x和y进行维度转变
    x = np.array([x]).T   # 先把每个元素变成独立一行:即(1,m);再将其转置,变成(m,1)独立一列的一维数组
    y = np.array([y]).T
    print(x.shape)
    
    # 对x和y进行维度转变(第二种方法)
    x.reshape(-1,1)   # 这里的(-1,1)表示的是列数设置为1,行数由数据总数除以列数决定
    y.reshape(-1,1)
    
    

五、模型使用

(一)模型的调用与实例化

本节使用的是线性回归模型,按照教材的例子,我们可以直接调用sklearnLinearRegression进行拟合。

查阅sklearn.linear_model.LinearRegression的官方文档:
LinearRegression(*, fit_intercept=True, normalize=False, copy_X=True, n_jobs=None, positive=False)
注意:LinearRegression()实际上是生成了一个估计器(Estimator),需要用fit()进行模型拟合。

  • fit_intercept: 是否计算截距项,默认值为True
  • normalize: 是否为标准化,默认值为False(如果输入的变量是已经标准化了,需要输入True)
  • copy_X: 是否复制训练集,默认值为True
  • n_jobs: 电脑中用于计算的CPU核心作业数,默认值为None(为-1时表示启用所有核心)
  • postive: 参数是否强制为正数,默认值为False
# 模型调用,由于使用的的是小型数据集上述的参数按默认值来即可,因此直接调用模型
lr_model = LinearRegression()  # LinearRegression模型实例化
print(type(lr_model))  # 返回的是<class 'sklearn.linear_model.base.LinearRegression'>

(二)模型的拟合、预测及精度

在面向对象编程中,类对象实例化后可以调用其方法和属性。lr_modelLinearRegression的实例化,可以调用其方法,如fit();其属性是在调用方法fit()进行模型拟合后才会允许访问。

根据官方文档显示,该模块实际上是对scipy.lingalg.lstsqscipy.optimize.nnls进行了包装,具体内容可以参考上面链接的官方文档。

  • 方法:
    • fit(X, y, sample_wight=None):sample_wight是样本权重,主要针对不平衡样本的处理,默认值为None
    • get_params(deep=True):默认值为True,返回上面Estimator所带有的参数,
    • predict(X):使用自变量X和拟合的模型对因变量进行预测,返回的是与X数量一致的一维数组。
    • score(X, y, sample_wight=None):返回可决系数R方,用于评价模型的精度,y为实际的目标变量值。
    • set_params(**kwargs):修改原来的Estimator的参数,并更新Estimator。
  • 属性:
    • coef_:返回回归模型拟合出来的参数,返回的类型为一维或二维数组,数组shape由自变量X的shape决定。
    • rank_:返回X的秩,仅在X为稠密矩阵时才可用。
    • singular_:返回X的奇异值,尽在X为稠密矩阵时才可用。
    • intercept_:返回回归模型拟合出来的截距项,通常是float类型或与Y数量一致的一维数组。
# 模型拟合
lr_model.fit(x, y)

print(lr_model.coef_)       # 获取模型的参数,X是二维(只有一个特征),参数对应也是二维的(只有一个参数)
print(lr_model.singular_)   # 获取X对应矩阵的奇异值
print(lr_model.intercept_)  # 获取模型的截距项,Y是一维的,返回的是float类型数据
print(lr_model.predict([[7]]))  # 对包含一个房间数RM为7的二维数组进行预测房价PRICE
print(lr_model.score(x,y))  # 输入数据集的X产生预测值Y_p来和实际值Y求R^2,以此评价模型的精度

六、数据可视化

通常在使用数据时,先通过散点图、线图等来观察数据的分布情况,以此来找到适合的模型进行拟合,从而提高模型的精度。在拟合完模型后,可以通过可视化的形式来看数据的预测值与实际值的拟合程度。

本教材中是在最后一部分对数据进行可视化,使用matplotlib来绘制散点图和直线图。

# 画出散点图(X轴为特征变量值x,Y轴为目标变量值y)
# s为点的大小,c为颜色,xlabel为轴标签名,alpha为点的透明度
plt.scatter(x, y, s=10, alpha=0.3, c='red')

# 画出线图(X轴为特征变量值x,Y轴为模型预测值y)
# linewidth为线的长度,c为颜色
plt.plot(x, lr_model.predict(x), c='blue', linewidth='3')

# 设定X轴和Y轴的标签名
plt.xlabel("Number of Rooms")
plt.ylabel("House Price")

# 展示图形
plt.show()

七、模型拓展与参考资料

到此为止,教材的内容已经结束了。经过一轮简单线性回归模型应用,大概能了解机器学习模型使用的流程。但在从实际数据集使用到模型实现这一过程来看,该模型是十分简单的。

(一)模型的改进

  • 特征变量
    在本案例中,我们实际选用的特征变量只有一个,其他特征变量与目标变量也具有较高的相关性,变量选取仍需要进一步考虑,进而可以实现多元线性回归模型;同时仍需要多变量选取时需要考虑变量内部的相关性问题,进一步优化变量的选取,方法可以选择主成分分析(PCA)等。
  • 数据集的划分
    在本案例中,我们并未划分训练集和测试集,无法根据训练集反馈的模型精度进一步调整模型。在机器学习中,需要对数据集进行划分,实际中常用sklearn.model_selection.train_test_split()进行划分,数据集不同的划分会对模型造成一定的影响,这方面是需要注意的。
  • 回归模型优化
    模型中主要采用的是普通最小二乘法,实际上可以考虑使用加权最小二乘法、偏最小二乘法、岭回归模型等
  • 模型的选择
    在散点图中,数据展示了较为明显的线性关系,但仍可以看到许多点并非在回归直线附近,除了考虑更多变量参与模型训练外,还需要对模型进一步考虑,如支持向量回归(SVR)、提升树(Boosting tree)、和随机森林(Random Forest)等。
  • 模型的比较
    • 为了找到更适合的模型和参数,可以使用同一组训练集对不同的模型进行训练,再用测试集比较模型的精度。
    • 通常来说,模型可以分成可解释的模型和黑箱模型,前者具有较高的解释性但精度较低,后者具有较高的精度但缺乏可解释性。在对机器学习可解释性的研究中,有关文章提出一些"与模型无关的解释方法(Model-Agnostic Methods)"来对模型进行解释,同时能够使用该方法来比较不同类型模型的精度,如部分依赖图(PDP)、个体条件期望(ICE)、累积局部效应图(ALE)等。

(二)案例完整代码

# 导入第三方库
import pandas as pd
import numpy as np
from sklearn import datasets
import matplotlib.pyplot as plt
from sklearn.linear_model import LinearRegression
import seaborn as sns

# 导入数据(看数据结构)
boston_dataset = datasets.load_boston()
print(boston_dataset.keys())
for key, value in boston_dataset.items():
    print('key为:{}\n其value的类型为:{}'.format(key, type(value)))

# 查看数据集的描述
print(boston_dataset.DESCR)
print(type(boston_dataset))

# 显示数据集里的data中前五行内容
data = pd.DataFrame(boston_dataset.data)
data.columns = boston_dataset.feature_names
data['PRICE'] = boston_dataset.target
print(data.shape)

# 用于数据的描述性统计,可以用于查看缺失值
print(data.describe())

# 计算数据的相关系数
data_corr = data.corr(method='pearson')  # 输出的是Pearson相关系数矩阵

# 根据相关系数矩阵画出热力图
plt.figure(figsize=(11, 9), dpi=100)
sns.heatmap(data=data_corr,
            vmax=0.1,  # 图例的最大值
            annot=True,  # 图中数字文本显示
            fmt=".2f",  # 格式化输出图中数字,即保留小数位数等
            annot_kws={'size': 8, 'weight': 'normal'},  # 数字属性设置,例如字号、磅值
            )

print(type(data))  # 查看数据表的类型
print(data.ndim)  # 查看数据表的维度
print(data.shape)  # 查看数据表的行列数(数据条数和属性数)

# 变量选取
x = data.loc[:, 'RM'].values  # 自变量只有一个,生成的是一维的数组,类型为ndarray
y = data.loc[:, 'PRICE'].values  # 因变量只有一个, 也是一维的数组,类型为ndarray
print(type(data.loc[:, 'RM']))
print(type(x))
print(x.shape)

# # 对x和y进行维度转变
x = np.array([x]).T  # 先把每个元素
y = np.array([y]).T
print(x.shape)

# 拟合LR模型
# 传入的x和y是(m,n)和(m,1)二维结构
# LinearRegression(是否计算截距项, 是否标准化, 是否复制训练集,作业数CPU,取正值)
lr_model = LinearRegression()
lr_model.fit(x, y)

# 画出散点图
# s为点的大小,c为颜色,linewidth为线的长度,xlabel为轴标签名,alpha为点透明的
plt.scatter(x, y, s=10, alpha=0.3, c='green')
plt.plot(x, lr_model.predict(x), c='blue', linewidth='1')
plt.xlabel("Number of Rooms")
plt.ylabel("House Price")
plt.show()

(三)参考资料

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值