前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Python3入门机器学习(五)-线性回归算法

Python3入门机器学习(五)-线性回归算法

作者头像
Meet相识
发布2018-09-12 16:46:07
1.5K0
发布2018-09-12 16:46:07
举报
文章被收录于专栏:技术专栏技术专栏

1.线性回归算法简介

1

线性回归算法以一个坐标系里一个维度为结果,其他维度为特征(如二维平面坐标系中横轴为特征,纵轴为结果),无数的训练集放在坐标系中,发现他们是围绕着一条执行分布。线性回归算法的期望,就是寻找一条直线,最大程度的“拟合”样本特征和样本输出标记的关系

2

样本特征只有一个的线性回归问题,为简单线性回归,如房屋价格-房屋面积

将横坐标作为x轴,纵坐标作为y轴,每一个点为(X(i) ,y(i)),那么我们期望寻找的直线就是y=ax+b,当给出一个新的点x(j)的时候,我们希望预测的y^(j)=ax(j)+b

7

  • 不使用直接相减的方式,由于差值有正有负,会抵消
  • 不适用绝对值的方式,由于绝对值函数存在不可导的点

8

11

通过上面的推导,我们可以归纳出一类机器学习算法的基本思路,如下图;其中损失函数是计算期望值和预测值的差值,期望其差值(也就是损失)越来越小,而效用函数则是描述拟合度,期望契合度越来越好

9

10


2.简单线性回归的实现

2.1 for循环方式实现

  • 实现

a,b公式

2.2-2

代码语言:javascript
复制
class SimpleLinearRegression1:

    def __init__(self):
        """初始化Simple Linear Regression 模型"""
        self.a_ = None
        self.b_ = None

    def fit(self, x_train, y_train):
        """根据训练集x_train,y_train 训练Simple Linear Regression 模型"""
        assert x_train.ndim == 1,\
            "Simple Linear Regression can only solve simple feature training data"
        assert len(x_train) == len(y_train),\
            "the size of x_train must be equal to the size of y_train"

        # 求均值
        x_mean = x_train.mean()
        y_mean = y_train.mean()

        # 分子
        num = 0.0
        # 分母
        d = 0.0

        # 计算分子分母
        for x_i, y_i in zip(x_train, y_train):
            num += (x_i-x_mean)*(y_i-y_mean)
            d += (x_i-x_mean) ** 2

        # 计算参数a和b
        self.a_ = num/d
        self.b_ = y_mean - self.a_ * x_mean

        return self

    def predict(self, x_predict):
        """给定待预测集x_predict,返回x_predict对应的预测结果值"""
        assert x_predict.ndim == 1,\
            "Simple Linear Regression can only solve simple feature training data"
        assert self.a_ is not None and self.b_ is not None,\
            "must fit before predict!"

        return np.array([self._predict(x) for x in x_predict])

    def _predict(self, x_single):
        """给定单个待预测数据x_single,返回x_single对应的预测结果值"""
        return self.a_*x_single+self.b_

    def __repr__(self):
        return "SimpleLinearRegression1()"
  • 测试
代码语言:javascript
复制
import numpy as np
import matplotlib.pyplot as plt

简单自定义一个训练集并描绘

代码语言:javascript
复制
x = np.array([1.,2.,3.,4.,5.])
y = np.array([1.,3.,2.,3.,5.])
plt.scatter(x,y)
plt.axis([0,6,0,6])
代码语言:javascript
复制
[0, 6, 0, 6]

2.1-1

使用我们自己的SimpleLinearRegression1

代码语言:javascript
复制
from machine_learning.SimpleLinearRegression1 import SimpleLinearRegression1

reg1 = SimpleLinearRegression1()
reg1.fit(x,y)
# 输出  SimpleLinearRegression1()
代码语言:javascript
复制
y_predict = reg1.predict(np.array([6.]))
y_predict
#   输出  array([5.2])
代码语言:javascript
复制
reg1.a_
 #  0.8
reg1.b_
#     0.39999999999999947
代码语言:javascript
复制
y_hat = reg1.predict(x)
plt.scatter(x,y)
plt.plot(x,y_hat,color='r')
plt.axis([0,6,0,6])

2.2-2

2.2 向量化

2.2-1

2.2-2

向量化改进num,d的计算方法

代码语言:javascript
复制
# 使用向量化点乘计算分子和分母
num = (x_train-x_mean).dot(y_train-y_mean)
d = (x_train-x_mean).dot(x_train-x_mean)

向量化实现的性能测试

代码语言:javascript
复制
m = 1000000
big_x = np.random.random(size=m)
big_y = big_x * 2.0 + 3.0 + np.random.normal(size=m)
代码语言:javascript
复制
%timeit reg1.fit(big_x,big_y)
%timeit reg2.fit(big_x,big_y)
代码语言:javascript
复制
    # 输出
    826 ms ± 6.93 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
    11.3 ms ± 84.6 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

可以看出,向量化的运行速度比循环的形式速度要快80倍


3.衡量线性回归算法的指标

3.1 衡量标准

3.1

其中衡量标准是和m有关的,因为越多的数据量产生的误差和可能会更大,但是毫无疑问越多的数据量训练出来的模型更好,为此需要一个取消误差的方法,如下

3.2

MSE 的缺点,量纲不准确,如果y的单位是万元,平方后就变成了万元的平方,这可能会给我们带来一些麻烦

3.3

3.4

RMSE 平方累加后再开根号,如果某些预测结果和真实结果相差非常大,那么RMSE的结果会相对变大,所以RMSE有放大误差的趋势,而MAE没有,他直接就反应的是预测结果和真实结果直接的差距,正因如此,从某种程度上来说,想办法我们让RMSE变的更小小对于我们来说比较有意义,因为这意味着整个样本的错误中,那个最值相对比较小,而且我们之前训练样本的目标,就是RMSE根号里面1/m的这一部分,而这一部分的本质和优化RMSE是一样的

3.2 MSE,RMSE,MAE的实现

代码语言:javascript
复制
def mean_squared_error(y_true, y_predict):
    """计算y_true和y_predict之间的MSE"""
    assert len(y_true) == len(y_predict), \
        "the size of y_true must be equal to the size of y_predict"

    return np.sum((y_true - y_predict)**2) / len(y_true)


def root_mean_squared_error(y_true, y_predict):
    """计算y_true和y_predict之间的RMSE"""

    return sqrt(mean_squared_error(y_true, y_predict))


def mean_absolute_error(y_true, y_predict):
    """计算y_true和y_predict之间的RMSE"""
    assert len(y_true) == len(y_predict), \
        "the size of y_true must be equal to the size of y_predict"

    return np.sum(np.absolute(y_true - y_predict)) / len(y_true)

3.3 调用sikit learn 的实现

代码语言:javascript
复制
from sklearn.metrics import mean_squared_error
from sklearn.metrics import mean_absolute_error
mean_squared_error(y_test,y_predict)

4.最好的衡量线性回归法的指标 R Squared

RMSE 和 MAE的局限性

4.1

可能预测房源准确度,RMSE或者MAE的值为5,预测学生的分数,结果的误差是10,这个5和10没有判断性,因为5和10对应不同的单位和量纲,无法比较

4.1 解决办法-R Squared简介

4.1-1

4.1.1 R Squared 意义

4.1-2

使用BaseLine Model产生的错误会很大,使用我们的模型预测产生的错误会相对少些(因为我们的模型充分的考虑了y和x之间的关系),用这两者相减,结果就是拟合了我们的错误指标,用1减去这个商结果就是我们的模型没有产生错误的指标

4.1-3

4.1-4

4.1.2 实现

代码语言:javascript
复制
def r2_score(y_true, y_predict):
    """计算y_true和y_predict之间的R Square"""

    return 1 - mean_squared_error(y_true, y_predict)/np.var(y_true)

sikit learn

代码语言:javascript
复制
from sklearn.metrics import r2_score
r2_score(y_test,y_predict)

将计算分数方法封装到我们的SimpleLinearRegression中

代码语言:javascript
复制
from .metrics import r2_score
def score(self, x_test, y_test):
        """根据测试数据集 x_test 和 y_test 确定当前模型的准确度"""

        y_predict = self.predict(x_test)
        return r2_score(y_test, y_predict)

5.多元线性回归

5.1 多元线性回归简介和正规方程解

5.1-1

5.1-2

5.1-3

5.1-4

补充(矩阵点乘:A(m行)·B(n列) = A的每一行与B的每一列相乘再相加,等到结果是m行n列的)

5.1-5

补充(一个1xm的行向量乘以一个mx1的列向量等于一个数)

5.1-6

5.1-7

推导过程参考 https://blog.csdn.net/nomadlx53/article/details/50849941

4.2 多元线性回归实现

4.2-1

代码语言:javascript
复制
import numpy as np
from .metrics import r2_score


class LinearRegression:

    def __init__(self):
        """初始化Linear Regression模型"""

        # 系数向量(θ1,θ2,.....θn)
        self.coef_ = None
        # 截距 (θ0)
        self.interception_ = None
        # θ向量
        self._theta = None

    def fit_normal(self, X_train, y_train):
        """根据训练数据集X_train,y_train 训练Linear Regression模型"""
        assert X_train.shape[0] == y_train.shape[0], \
            "the size of X_train must be equal to the size of y_train"

        # np.ones((len(X_train), 1)) 构造一个和X_train 同样行数的,只有一列的全是1的矩阵
        # np.hstack 拼接矩阵
        X_b = np.hstack([np.ones((len(X_train), 1)), X_train])
        # X_b.T 获取矩阵的转置
        # np.linalg.inv() 获取矩阵的逆
        # dot() 矩阵点乘
        self._theta = np.linalg.inv(X_b.T.dot(X_b)).dot(X_b.T).dot(y_train)

        self.interception_ = self._theta[0]
        self.coef_ = self._theta[1:]

        return self

    def predict(self, X_predict):
        """给定待预测数据集X_predict,返回表示X_predict的结果向量"""
        assert self.coef_ is not None and self.interception_ is not None,\
            "must fit before predict"
        assert X_predict.shape[1] == len(self.coef_),\
            "the feature number of X_predict must be equal to X_train"

        X_b = np.hstack([np.ones((len(X_predict), 1)), X_predict])
        return X_b.dot(self._theta)

    def score(self, X_test, y_test):
        """根据测试数据集 X_test 和 y_test 确定当前模型的准确度"""

        y_predict = self.predict(X_test)
        return r2_score(y_test, y_predict)

    def __repr__(self):
        return "LinearRegression()"

预测波士顿房价的测试

代码语言:javascript
复制
import numpy as np
import matplotlib.pyplot as plot
from sklearn import datasets

# 加载波士顿房价数据
boston = datasets.load_boston()
X = boston.data
y = boston.target
X = X[y<50.0]
y = y[y<50.0]

# 分割训练集和测试集
from machine_learning.module_selection import train_test_split
X_train,X_test,y_train,y_test = train_test_split(X,y,seed=666)

# 训练模型
from machine_learning.LinearRegression import LinearRegression
reg = LinearRegression()
reg.fit_normal(X_train,y_train)
# 输出 LinearRegression()

# 结果
reg.coef_
# 输出 array([-1.18919477e-01,  3.63991462e-02, -3.56494193e-02,  5.66737830e-02,
       -1.16195486e+01,  3.42022185e+00, -2.31470282e-02, -1.19509560e+00,
        2.59339091e-01, -1.40112724e-02, -8.36521175e-01,  7.92283639e-03,
       -3.81966137e-01])

reg.interception_
# 输出 34.16143549621706

reg.score(X_test,y_test)
# 输出 0.812980260265849

4.3 scikit-learn中的回归问题

scikit-learn 中的线性回归

代码语言:javascript
复制
from sklearn.model_selection import train_test_split
X_train,X_test,y_train,y_test = train_test_split(X,y,random_state=666)
代码语言:javascript
复制
from sklearn.linear_model import LinearRegression

lin_reg = LinearRegression()
代码语言:javascript
复制
lin_reg.fit(X_train,y_train)
代码语言:javascript
复制
LinearRegression(copy_X=True, fit_intercept=True, n_jobs=1, normalize=False)
代码语言:javascript
复制
lin_reg.coef_
代码语言:javascript
复制
array([-1.14235739e-01,  3.12783163e-02, -4.30926281e-02, -9.16425531e-02,
       -1.09940036e+01,  3.49155727e+00, -1.40778005e-02, -1.06270960e+00,
        2.45307516e-01, -1.23179738e-02, -8.80618320e-01,  8.43243544e-03,
       -3.99667727e-01])
代码语言:javascript
复制
# 由于训练数据集和测试数据集的分割和我们的稍有不同,所以结果会略有不同
lin_reg.intercept_
代码语言:javascript
复制
32.64566083965224
代码语言:javascript
复制
lin_reg.score(X_test,y_test)
代码语言:javascript
复制
0.8008916199519077

kNN Regressor 实现线性回归

代码语言:javascript
复制
from sklearn.neighbors import KNeighborsRegressor

knn_reg = KNeighborsRegressor()
knn_reg.fit(X_train,y_train)
knn_reg.score(X_test,y_test)
代码语言:javascript
复制
0.602674505080953
代码语言:javascript
复制
# 网格搜索超参数
from sklearn.model_selection import GridSearchCV

param_grid = [
    {
        "weights" : ["uniform"],
        "n_neighbors":[i for i in range(1,11)]
    },
    {
        "weights" : ["distance"],
        "n_neighbors":[i for i in range(1,11)],
        "p":[i for i in range(1,6)]
    }
]

knn_reg = KNeighborsRegressor()
grid_search = GridSearchCV(knn_reg,param_grid,n_jobs=-1,verbose=1)
grid_search.fit(X_train,y_train)
代码语言:javascript
复制
Fitting 3 folds for each of 60 candidates, totalling 180 fits


[Parallel(n_jobs=-1)]: Done 180 out of 180 | elapsed:    0.5s finished





GridSearchCV(cv=None, error_score='raise',
       estimator=KNeighborsRegressor(algorithm='auto', leaf_size=30, metric='minkowski',
          metric_params=None, n_jobs=1, n_neighbors=5, p=2,
          weights='uniform'),
       fit_params=None, iid=True, n_jobs=-1,
       param_grid=[{'weights': ['uniform'], 'n_neighbors': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]}, {'weights': ['distance'], 'n_neighbors': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 'p': [1, 2, 3, 4, 5]}],
       pre_dispatch='2*n_jobs', refit=True, return_train_score='warn',
       scoring=None, verbose=1)
代码语言:javascript
复制
grid_search.best_params_
代码语言:javascript
复制
{'n_neighbors': 6, 'p': 1, 'weights': 'distance'}
代码语言:javascript
复制
# 运用了CV交叉验证的方式
grid_search.best_score_
代码语言:javascript
复制
0.6060327991735741
代码语言:javascript
复制
grid_search.best_estimator_.score(X_test,y_test)
代码语言:javascript
复制
0.7354244906092771

6 线性回归的可解性和更多思考

可解释下

代码语言:javascript
复制
lin_reg = LinearRegression()
lin_reg.fit(X,y)
lin_reg.coef_
# 输出:array([-1.05574295e-01,  3.52748549e-02, -4.35179251e-02,  4.55405227e-01,
       -1.24268073e+01,  3.75411229e+00, -2.36116881e-02, -1.21088069e+00,
        2.50740082e-01, -1.37702943e-02, -8.38888137e-01,  7.93577159e-03,
       -3.50952134e-01])
# 将特征结果坐标排序
np.argsort(lin_reg.coef_)
# 输出:array([ 4,  7, 10, 12,  0,  2,  6,  9, 11,  1,  8,  3,  5])

# 将排序过后的坐标对应的名称展示出来,方便观察理解
boston.feature_names[np.argsort(lin_reg.coef_)]
# 输出:array(['NOX', 'DIS', 'PTRATIO', 'LSTAT', 'CRIM', 'INDUS', 'AGE', 'TAX',
       'B', 'ZN', 'RAD', 'CHAS', 'RM'], dtype='<U7')

RM对应的是房间数,是正相关最大的特征,也就是说房间数越多,房价越高,这是很合理的 NOX对应的是一氧化氮浓度,也就是说一氧化氮浓度越低,房价越低,这也是非常合理的 由此说明,我们的线性回归具有可解释性,我们可以在对研究一个模型的时候,可以先用线性回归模型看一下,然后根据感性的认识去直观的判断一下是否符合我们的语气

6.2 总结

6.2-1

6.2-2

6.2-3

6.2-4

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018.04.19 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1.线性回归算法简介
  • 2.简单线性回归的实现
    • 2.1 for循环方式实现
      • a,b公式
      • 简单自定义一个训练集并描绘
      • 使用我们自己的SimpleLinearRegression1
    • 2.2 向量化
      • 向量化改进num,d的计算方法
      • 向量化实现的性能测试
  • 3.衡量线性回归算法的指标
    • 3.1 衡量标准
      • 3.2 MSE,RMSE,MAE的实现
        • 3.3 调用sikit learn 的实现
          • RMSE 和 MAE的局限性
      • 4.最好的衡量线性回归法的指标 R Squared
        • 4.1 解决办法-R Squared简介
          • 4.1.1 R Squared 意义
          • 4.1.2 实现
      • 5.多元线性回归
        • 5.1 多元线性回归简介和正规方程解
          • 4.2 多元线性回归实现
            • 预测波士顿房价的测试
          • 4.3 scikit-learn中的回归问题
            • scikit-learn 中的线性回归
            • kNN Regressor 实现线性回归
        • 6 线性回归的可解性和更多思考
          • 可解释下
            • 6.2 总结
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档