2018-07-26-回归问题

回归问题

假定我们现有一大批数据,包含房屋的面积和对应面积的房价信息,如果我们能得到房屋面积与房屋价格间的关系,那么,给定一个房屋时,我们只要知道其面积,就能大致推测出其价格了。

上面的问题还可以被描述为:

“OK,我具备了很多关于房屋面积及其对应售价的知识(数据),再通过一定的学习,当面对新的房屋面积时,我不再对其定价感到束手无策”。

通常,这类预测问题可以用回归模型(regression)进行解决,回归模型定义了输入输出的关系,输入即现有知识,而输出则为预测

一个预测问题在回归模型下的解决步骤为:

  1. 积累知识: 我们将储备的知识称之为训练集 Training Set,很好理解,知识能够训练人进步
  2. 学习:学习如何预测,得到输入与输出的关系。在学习阶段,应当有合适的指导方针,江山不能仅凭热血就攻下。在这里,合适的指导方针我们称之为学习算法 Learning Algorithm
  3. 预测:学习完成后,当接受了新的数据(输入)后,我们就能通过学习阶段获得的对应关系来预测输出。

学习过程往往是艰苦的,“人谁无过,过而能改,善莫大焉”,因此对我们有这两点要求:

  • 手段能评估我们的学习正确性。
  • 当学习效果不佳时,有手段能纠正我们的学习策略。

线性回归

预测

首先,我们明确几个常用的数学符号:

  • 特征(feature)
  • 特征向量(输入)
  • 输出向量
  • 假设(hypothesis)

上面的表达式也称之为回归方程(regression equation)

误差评估

之前我们说到,需要某个手段来评估我们的学习效果。最常见的,我们通过最小均方(Least Mean Square)来描述误差:

误差评估的函数在机器学习中也称为代价函数(cost function)

批量梯度下降

在引入了代价函数后,解决了“有手段评估学习的正确性”的问题,下面我们开始解决“当学习效果不佳时,有手段能纠正我们的学习策略”的问题。

在线性回归中,通常使用梯度下降(Gradient Descent)来调节 θ:

数学上,梯度方向是函数值下降最为剧烈的方向。那么,沿着 J(θ)J(θ) 的梯度方向走,我们就能接近其最小值,或者极小值,从而接近更高的预测精度。学习率 α是个相当玄乎的参数,其标识了沿梯度方向行进的速率,步子大了容易扯着蛋,很可能这一步就迈过了最小值。而步子小了,又会减缓我们找到最小值的速率。在实际编程中,学习率可以以 3 倍,10 倍这样进行取值尝试,如:

α=0.001,0.003,0.01…0.3,1

对于一个样本容量为 mm 的训练集,我们定义 θ的调优过程为:

我们称该过程为基于最小均方(LMS)的批量梯度下降法(Batch Gradient Descent),一方面,该方法虽然可以收敛到最小值,但是每调节一个 θjθj,都不得不遍历一遍样本集,如果样本的体积 mm很大,这样做无疑开销巨大。但另一方面,因为其可化解为向量型表示,所以就能利用到并行计算优化性能。

随机梯度下降

鉴于批量梯度下降的性能问题,又引入了随机梯度下降(Stochastic Gradient Descent)

重复直到收敛(Repeat until convergence)

手段 概括 优点 缺点
批量梯度下降法 尽可能减小训练样本的总的预测代价 能够获得最优解,支持并行计算 样本容量较大时,性能显著下降
随机梯度下降法 尽可能的减小每个训练样本的预测代价 训练速度快 并不一定能获得全局最优,经常出现抖动和噪音,且不能通过并行计算优化
# coding: utf-8
# linear_regression/regression.py
import numpy as np
import matplotlib as plt
import time

def exeTime(func):
    """ 耗时计算装饰器
    """
    def newFunc(*args, **args2):
        t0 = time.time()
        back = func(*args, **args2)
        return back, time.time() - t0
    return newFunc

def loadDataSet(filename):
    """ 读取数据

    从文件中获取数据,在《机器学习实战中》,数据格式如下
    "feature1 TAB feature2 TAB feature3 TAB label"

    Args:
        filename 文件名

    Returns:
        X 训练样本集矩阵
        y 标签集矩阵
    """

    #统计特征数量
    numFeat = len(open(filename).readline().split('\t')) - 1
    X = []
    y = []
    #打开文件
    file = open(filename)
    for line in file.readlines():
        lineArr = []
        curLine = line.strip().split('\t')
        for i in range(numFeat):
            lineArr.append(float(curLine[i]))
        X.append(lineArr)
        y.append(float(curLine[-1]))
    return np.mat(X), np.mat(y).T

def h(theta, x):
    """预测函数
    
    Args:
        theta 相关系数矩阵
        x 特征向量

    Returns:
        预测结果
    """
    return (theta.T*x)[0,0]

def J(theta, X, y):
    """代价函数

    Args:
        theta 相关系数矩阵
        X 样本集矩阵
        y 标签集矩阵

    Returns:
        预测误差(代价)
    """
    m = len(X)
    return (X*theta-y).T*(X*theta-y)/(2*m)

@exeTime
def bgd(rate, maxLoop, epsilon, X, y):
    """批量梯度下降法

    Args:
        rate 学习率
        maxLoop 最大迭代次数
        epsilon 收敛精度
        X 样本矩阵
        y 标签矩阵

    Returns:
        (theta, errors, thetas), timeConsumed
    """
    m,n = X.shape
    # 初始化theta,n*1的矩阵
    theta = np.zeros((n,1))
    count = 0
    converged = False
    error = float('inf')
    errors = []
    thetas = {}
    for j in range(n):
        thetas[j] = [theta[j, 0]]
    while count <= maxLoop:
        if(converged):
            break
        count = count + 1
        for j in range(n):
            deriv = (y-X*theta).T*X[:, j]/m
            theta[j,0] = theta[j,0]+rate*deriv
            thetas[j].append(theta[j,0])
        error = J(theta, X, y)
        errors.append(error[0,0])
        # 如果已经收敛
        if(error < epsilon):
            converged = True
    return theta,errors,thetas

@exeTime
def sgd(rate, maxLoop, epsilon, X, y):
    """随机梯度下降法
    Args:
        rate 学习率
        maxLoop 最大迭代次数
        epsilon 收敛精度
        X 样本矩阵
        y 标签矩阵
    Returns:
        (theta, error, thetas), timeConsumed
    """
    m,n = X.shape
    # 初始化theta
    theta = np.zeros((n,1))
    count = 0
    converged = False
    error = float('inf')
    errors = []
    thetas = {}
    for j in range(n):
        thetas[j] = [theta[j, 0]]
    while count <= maxLoop:
        if converged:
            break
        count = count + 1
        errors.append(float('inf'))
        for i in range(m):
            if converged:
                break
            diff = y[i, 0]-h(theta, X[i].T)
            for j in range(n):
                theta[j,0] = theta[j,0] + rate*diff*X[i, j]
                thetas[j].append(theta[j, 0])
            error = J(theta, X, y)
            errors[-1] = error[0, 0]
            # 如果已经收敛
            if(error < epsilon):
                converged = True
    return theta, errors, thetas

def JLwr(theta, X, y, x, c):
    """局部加权线性回归的代价函数计算式

    Args:
        theta 相关系数矩阵
        X 样本集矩阵
        y 标签集矩阵
        x 待预测输入
        c tau
    Returns:
        预测代价
    """
    m,n = X.shape
    summerize = 0
    for i in range(m):
        diff = (X[i]-x)*(X[i]-x).T
        w = np.exp(-diff/(2*c*c))
        predictDiff = np.power(y[i] - X[i]*theta,2)
        summerize = summerize + w*predictDiff
    return summerize

@exeTime
def lwr(rate, maxLoop, epsilon, X, y, x, c=1):
    """局部加权线性回归

    Args:
        rate 学习率
        maxLoop 最大迭代次数
        epsilon 预测精度
        X 输入样本
        y 标签向量
        x 待预测向量
        c tau
    """
    m,n = X.shape
    # 初始化theta
    theta = np.zeros((n,1))
    count = 0
    converged = False
    error = float('inf')
    errors = []
    thetas = {}
    for j in range(n):
        thetas[j] = [theta[j,0]]
    # 执行批量梯度下降
    while count<=maxLoop:
        if(converged):
            break
        count = count + 1
        for j in range(n):
            deriv = (y-X*theta).T*X[:, j]/m
            theta[j,0] = theta[j,0]+rate*deriv
            thetas[j].append(theta[j,0])
        error = JLwr(theta, X, y, x, c)
        errors.append(error[0,0])
        # 如果已经收敛
        if(error < epsilon):
            converged = True
    return theta,errors,thetas

def standarize(X):
    """特征标准化处理

    Args:
        X 样本集
    Returns:
        标准后的样本集
    """
    m, n = X.shape
    # 归一化每一个特征
    for j in range(n):
        features = X[:,j]
        meanVal = features.mean(axis=0)
        std = features.std(axis=0)
        if std != 0:
            X[:, j] = (features-meanVal)/std
        else:
            X[:, j] = 0
    return X

def normalize(X):
    """特征归一化处理

    Args:
        X 样本集
    Returns:
        归一化后的样本集
    """
    m, n = X.shape
    # 归一化每一个特征
    for j in range(n):
        features = X[:,j]
        minVal = features.min(axis=0)
        maxVal = features.max(axis=0)
        diff = maxVal - minVal
        if diff != 0:
           X[:,j] = (features-minVal)/diff
        else:
           X[:,j] = 0
    return X

网上例子:

https://blog.csdn.net/SA14023053/article/details/51703204披萨的直径与价格

#导入线性模型
from sklearn import linear_model
#绘图
import matplotlib.pyplot as plt
import numpy as np


#X表示匹萨尺寸 Y表示匹萨价格
X = [[6], [8], [10], [14], [18]]
Y = [[7], [9], [13], [17.5], [18]]

print(X)
print(Y)

#使用线性回归
clf = linear_model.LinearRegression()
#导入数据集fit(x, y): 训练。分析模型参数,填充数据集。其中x为特征,y位标记或类属性。
#predict(): 预测。它通过fit()算出的模型参数构成的模型,对解释变量进行预测其类属性。预测方法将返回预测值y_pred。
clf.fit(X, Y)

#预测数据集
print(np.array([12]).reshape(-1, 1))
res = clf.predict(np.array([12]).reshape(-1, 1))[0]
print(res)

#预测结果
X2 = [[0], [10], [14], [25]]
Y2 = clf.predict(X2)
print(Y2)

#预测结果
X3 = [[0]]
Y3 = clf.predict(X3)
print(Y3)

#绘图
plt.figure()
plt.title('1')
plt.xlabel('x')
plt.ylabel('cost')
plt.axis([0, 25, 0, 25])
plt.grid(True)
#绘制训练集散点图
plt.plot(X, Y, 'k.')
#绘制预测集直线
plt.plot(X2, Y2, 'g-')
plt.show()

运行结果:

D:\1b\Anoconda\setup\set\python.exe E:/python_workspace/ML/WuEnDa_Work/LInerReg.py
[[6], [8], [10], [14], [18]]
[[7], [9], [13], [17.5], [18]]
[[12]]
[ 13.68103467]
[[  1.96551743]
 [ 11.72844846]
 [ 15.63362088]
 [ 26.37284501]]
[[ 1.96551743]]

img

img

标准化实验:

import numpy as np

def standardize(X):
    #m表示行,n表示列
    m ,n = X.shape
    for j in range(n):
        features = X[:, j]
        meanVal = features.mean(axis = 0)
        std = features.std(axis = 0)
        print("std", std)
        print("meanVal", meanVal)
        print("feature", features)
        if std != 0:
            X[:, j] = (features - meanVal)/std
        else:
            X[:, j] = 0
    return X

if __name__ == "__main__":
    X = np.arange(0, 9).reshape(9, 1)
    #X = [[0], [10], [14], [25]]
    s = standardize(X)
    print("S", s)

运行结果:

std 2.58198889747
meanVal 4.0
feature [0 1 2 3 4 5 6 7 8]
S [[-1]
 [-1]
 [ 0]
 [ 0]
 [ 0]
 [ 0]
 [ 0]
 [ 1]
 [ 1]]

打赏一个呗

取消

感谢您的支持,我会继续努力的!

扫码支持
扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦