Skip to content

Latest commit

 

History

History
243 lines (154 loc) · 10.1 KB

04. 线性回归.md

File metadata and controls

243 lines (154 loc) · 10.1 KB

4. 线性回归

​ 正如我们在前一章中讨论的机器学习一样,它是一个非常广阔的领域,并且有多种算法属于各种类别,但线性回归是最基本的机器学习算法之一。 本章重点介绍如何使用PySpark构建线性回归模型,并深入研究LR模型的工作原理。 它将涵盖在使用LR以及不同评估指标之前要考虑的各种假设。 但在尝试理解线性回归之前,我们必须了解变量的类型。

4.1 变量

​ 变量以不同的形式捕获数据信息。 主要使用两类变量:数值,分类。

​ 我们甚至可以将这些变量进一步细分为子类别,但我们将在本书中坚持这两种类型。

​ **数值变量**是那些本质上是定量的值,就如数字(整数/浮点数)。 例如,工资记录,考试分数,人的年龄或身高以及股票价格都属于数字变量类别。

​ 另一方面,**分类变量**本质上是定性的,主要代表被测量数据的类别。 例如,颜色,结果(是/否),评级(好/差/平均)。

​ 为了构建任何类型的机器学习模型,我们需要输入输出变量。 输入变量是用于构建和训练机器学习模型以预测输出或目标变量的那些值。 我们举一个简单的例子。 假设我们想要使用机器学习来预测给定年龄的人的工资。 在这种情况下,工资是我们的输出/目标/因变量,因为它取决于年龄,这被称为输入或自变量。 现在输出变量本质上可以是分类变量或数值变量,并且根据其类型,选择机器学习模型。

​ 现在回到线性回归,它主要用于我们试图预测数值输出变量的情况。 线性回归用于预测适合输入数据的线,以最佳方式指出,并且可以帮助预测未见数据,但需要注意的是模型如何从“年龄”中学习并预测特定人薪水的金额? 当然,这两个变量(工资和年龄)之间需要存在某种关系。 变量关系有两种主要类型:

  • 线性
  • 非线性

​ 任何两个变量之间的线性关系的概念表明两者在某些方面彼此成比例。 任何两个变量之间的相关性使我们能够指出它们之间的线性关系有多强或多弱。 相关系数的范围可以从-1到+ 1。负相关意味着通过增加一个变量,另一个变量减少。 例如,车辆的功率和里程可以是负相关的,因为随着我们增加功率,车辆的里程数下降。 另一方面,工资和工作年数是正相关变量的一个例子。 非线性关系本质上相对复杂,因此需要额外的细节来预测目标变量。 例如,自动驾驶汽车,诸如地形,信号系统和行人之类的输入变量与汽车速度之间的关系是非线性的。

4.2 理论

​ 现在我们已经了解了变量的基础知识以及它们之间的关系,让我们以年龄和薪水为例,深入理解线性回归。 ​ 线性回归的总体目标是预测数据的直线,这样每个点的垂直距离与该线的距离最小。 因此,在这种情况下,我们将预测给定年龄的人的工资。 假设我们有四个人的记录,记录年龄和他们各自的工资,如表4-1所示。

Sr.NO Age Salary('0000$)
1 20 5
2 30 10
3 40 15
4 50 22

​ 我们有一个输入变量(年龄)供我们使用,以便预测工资(我们将在本书的后期阶段进行),但让我们退后一步。 让我们假设我们一开始就拥有的只是这四个人的工资价值。

​ 现在,如果我们根据这些早期人的工资来预测第五人(新人)的工资,那么预测的最佳方法是采用现有工资值的平均值/平均值。 鉴于此信息,这将是最好的预测。 这就像构建机器学习模型但没有任何输入数据(因为我们使用输出数据作为输入数据)。

直接跳到 4.5节 码代码了

4.5 Code

4.5.1 Step 1 Create the SparkSession Object

​ 创建SparkSession

from pyspark.sql import SparkSession
spark = SparkSession.builder.appName('lin_reg').getOrCreate()

4.5.2 Step 2 Read the Dataset

​ 读取数据

df = spark.read.csv('linear_regression_dataset.csv', inferSchema=True, header=True)

4.5.3 Step 3 EDA 探索性数据分析

​ 在本节中,我们通过查看数据集,验证数据集的形状,各种统计度量以及输入和输出变量之间的相关性,深入钻取数据集。 我们首先检查数据集的形状。

print((df.count(), len(df.columns)))

​ 上面的输出确认了我们数据集的大小,我们可以验证输入值的数据类型,以检查是否需要更改/转换任何列数据类型。 在此示例中,所有列都包含Integerdouble值。

df.printSchema()

​ 总共有六列,其中五列是输入列(var_1var_5)和目标列(输出)。 我们现在可以使用describe函数来检查数据集的统计度量。

df.describe().show(3,False)

​ 这使我们能够获得数据集列的分布感,中心度量和传播。 然后,我们使用head函数偷看数据集,并传递我们想要查看的行数。

df.head(3)

​ 我们可以使用corr函数检查输入变量和输出变量之间的相关性:

from pyspark.sql.functions import corr
df.select(corr('var_1','output')).show()

4.5.4 Step 4 特征工程

​ 这是我们使用Spark里的VectorAssembler创建**单个向量整合了所有的输入特征**。 它只创建一个捕获该行输入值的功能。因此,它实际上将所有输入列合并为单个特征向量列,而不是五个输入列。

from pyspark.ml.linalg import Vector
from pyspark.ml.feature import VectorAssembler

​ 可以选择将用作输入要素的列数,并且只能通过VectorAssembler传递这些列。在我们的例子中,我们将传递所有五个输入列以创建单个特征向量列。

[In]: df.columns
[Out]: ['var_1', 'var_2', 'var_3', 'var_4', 'var_5', 'output']
    
[In]: vec_assmebler=VectorAssembler(inputCols=['var_1','var_2', 'var_3', 'var_4', 'var_5'], outputCol='features')
[In]: features_df=vec_assmebler.transform(df)
[In]: features_df.printSchema()
    
[Out]:
    root
     |-- var_1: integer (nullable = true)
     |-- var_2: integer (nullable = true)
     |-- var_3: integer (nullable = true)
     |-- var_4: double (nullable = true)
     |-- var_5: double (nullable = true)
     |-- output: double (nullable = true)
     |-- features: vector (nullable = true)

​ 我们可以看到,我们得到一个额外的列('features'),它包含所有输入的单个密集向量。

[In]: features_df.select('features').show(5, False)
[Out]:
	+--------------------------------------+
	|features                              |
	+--------------------------------------+
	|[734.0, 688.0, 81.0, 0.328, 0.259]    |
	|[700.0, 600.0, 94.0, 0.32, 0.247]     |
	|[712.0, 705.0, 93.0, 0.311, 0.247]    |
	|[734.0, 806.0, 69.0, 0.315, 0.26]     |
	|[613.0, 759.0, 61.0, 0.302, 0.24]     |
	+--------------------------------------+

创建输入、输出集合:

[In]: model_df=features_df.select('features','output')
[In]: model_df.show(5,False)
[Out]:
    +--------------------------------------+--------+
	|features                              |output  |
	+--------------------------------------+--------+
	|[734.0, 688.0, 81.0, 0.328, 0.259]    | 0.418  |
	|[700.0, 600.0, 94.0, 0.32, 0.247]     | 0.389  |
	|[712.0, 705.0, 93.0, 0.311, 0.247]    | 0.417  |
	|[734.0, 806.0, 69.0, 0.315, 0.26]     | 0.415  |
	|[613.0, 759.0, 61.0, 0.302, 0.24]     | 0.378  |
	+--------------------------------------+--------+

数据大小:

[In]: print((model_df.count(), len(model_df.columns)))
[Out]: (1232, 2)

4.5.5 Step 5 切分数据集

​ 我们必须将数据集拆分为训练数据集测试数据集,以便训练和评估构建的线性回归模型的性能。 我们将其分成70/30的比例,并在70%的数据集上训练我们的模型。 我们可以打印训练的形状和测试数据来验证尺寸。

[In]: train_df,test_df=model_df.randomSplit([0.7,0.3])
[In]: print((train_df.count(), len(train_df.columns)))
[Out]: (882, 2)
[In]: print((test_df.count(), len(test_df.columns)))
[Out]: (350, 2)

4.5.6 Step 6 创建并训练线性回归模型

​ 在这一部分中,我们使用输入和输出列的特征构建和训练线性回归模型。 我们也可以获取模型的系数(B1,B2,B3,B4,B5)和截距(B0)值。 我们还可以使用r2评估模型在训练数据上的性能。 该模型在训练数据集上提供了非常好的准确度(86%)。

[In]: from pyspark.ml.regression import LinearRegression

[In]: lin_Reg=LinearRegression(labelCol='output')
      # 训练数据集
[In]: lr_model=lin_Reg.fit(train_df)
      # 打印系数
[In]: print(lr_model.coefficients)
[Out]: [0.000345569740987,6.07805293067e-05,0.000269273376209,-
0.713663600176,0.432967466411]
	  # 打印截距
[In]: print(lr_model.intercept)
[Out]: 0.20596014754214345
    
      # 评估 
[In]: training_predictions=lr_model.evaluate(train_df)
[In]: print(training_predictions.r2)
[Out]: 0.8656062610679494

R2是决定系数。

4.5.7 Step 7 评估测试集

​ 整个练习的最后一部分是检查看不见或测试数据在模型上的表现。 我们使用evaluate函数对测试数据进行预测,并使用r2检查模型对测试数据的准确性。 表现似乎几乎与训练相似。

[In]: test_predictions=lr_model.evaluate(test_df)
[In]: print(test_results.r2)
[Out]: 0.8716898064262081
[In]: print(test_results.meanSquaredError)
[Out]: 0.00014705472365990883