吴恩达-- 监督学习(线性回归)

一元线性回归

一元线性回归函数

        \hat{y}=wx+b

成本函数

       J(w,b)=\frac{1}{2m}\sum_{i=0}^{m-1}(f_{w,b}(x^{(i)})-y^{(i)})^2

      f_{w,b}(x^{(i)})=wx^{(i)}+b

      成本函数描述了拟合曲线的y值和y的实际值的平均误差平方,用来衡量拟合曲线的对实际数据的解释程度,即预测曲线的准确率。形状是个U型函数。

梯度下降

      w、b的取值影响成本函数J,在三维空间里,成本函数类似一个小平原,有多个局部极小值和极大值,也有等成本线(类似等高线),梯度下降实现的是从初始起点开始找出最陡峭的方向(迈出一小步,成本以最快的速度下降),逐步达到成本的局部极小值。在不同的起点实行梯度下降得到的局部极小值可能不同。

线性回归的原理

        梯度下降,通过反复迭代,找到使成本函数以最快的速度达到局部最小,对应的w,b值。

过程:

1、对w、b求偏导,求出使导数为0的w、b值,就得到使J沿w、b下降最快的方向。

        \frac{\partial J}{\partial w}=\frac{1}{m}\sum_{i=0}^{m-1}(f_{w,b}(x^{(i)})-y^{(i)})x^{(i)}

        \frac{\partial J}{\partial b}=\frac{1}{m}\sum_{i=0}^{m-1}(f_{w,b}(x^{(i)})-y^{(i)})

2、学习率定义梯度下降的步长,更新w,b值;更新的w、b值代入方程求解成本函数J,再对新的J函数求偏导,得到新的w,b.....达到局部最小值的时候到导数为0,w、b不再更新。

        w_{tmp}=w-a\frac{\partial J}{\partial w}

        b_{tmp}=b-a\frac{\partial J}{\partial b}

        w=w_{tmp}

        b=b_{tmp}

回归效果检验

        观察学习曲线(迭代次数为x轴,J成本为y轴)是否递减且收敛(㇏)

学习率的选择

       通过观察学习曲线的形状判断学习率的选取是否合适。

①学习率太大。每次移动的步长越来越大,成本J增加,学习曲线发散(丿)

           

②学习率太小。需要大量迭代才能学习函数才能收敛,耗费时间长。此外,太小的学习率也有可能使成本J上升(有窃听器)。

     正确的学习率调试方式,选择一个较小的a开始,观察成本函数J是否在每一次迭代中降低。

学习速率的一系列常用值:... 0.001    0.01    0.1    1 ... 

 (吴恩达)通常先从0.001开始,然后提高三倍,0.003,然后0.01,0.03,0.1,0.3,1,3

学习曲线观察

①发散。可能是因为a的值太大,或者是-a\frac{\partial J}{\partial w}符号写成了+号。导致每次迭代成本增加。

代码实现

①简单一元线性回归(无梯度下降)

import numpy as np
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt


# x_train为自变量,y_train为因变量
'''准备数据'''
x_train = np.array([1.0, 2.0])
y_train = np.array([300.0, 500.0])
print(f"x_train = {x_train}")
print(f"y_train = {y_train}")


'''计算样本量'''
print(f"x的维度形状: {x_train.shape}")
m = x_train.shape[0]                                    #shape[0]是指数组在第一个维度的大小,一维数组第一个维度是数组大小,二维数组shape[0]就是行数
print(f"样本量: {m}")

# m为样本量
m = len(y_train)                                        #len()函数也可以
print(f"样本量: {m}")

'''输出其中一个样本'''
i = 1 # 样本下标

x_i = x_train[i]
y_i = y_train[i]
print(f"(x^({i}), y^({i})) = ({x_i}, {y_i})")


'''设置参数'''
w=100
b=100
print(f'w:{w}')
print(f'b:{b}')

'''定义回归函数'''
def compute_model_output(x,w,b):
    m=x.shape[0]
    f_wb=np.zeros(m)
    for i in range(m):
        f_wb[i]=w*x[i]+b
    return  f_wb

'''绘制回归曲线'''
tmp_f_wb=compute_model_output(x_train,w,b)
plt.plot(x_train,tmp_f_wb,c='b',label='Our prediction')
plt.scatter(x_train,y_train,marker='x',c='r',label='Actual Value')           #设置数据点
plt.legend()
plt.title('price&size')                                                      #设置标题
plt.ylabel('price')                                                          #设置轴标签
plt.xlabel('size')
plt.savefig('./房价和面积关系.png')

'''预测值'''
w = 200
b = 100
x_i = 1.2
cost_1200sqft = w * x_i + b

print(f"面积{x_i}对应${cost_1200sqft:.0f}")

②成本函数

import numpy as np
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
x=np.array([1,2])
y=np.array([300,500])

'''定义成本函数'''
def compute_cost(x,y,w,b):
    m=x.shape[0]
    cost_sum=0
    for i in range(m):
        f_wb=w*x[i]+b
        cost_sum=cost_sum+(f_wb-y[i])**2
        total_cost=(1/(2*m))*cost_sum
    return total_cost

cost=compute_cost(x,y,0,100)
print(cost)

     给定w,b,输出拟合曲线与实际值的均方误差(成本)。

③线性回归(梯度下降)

import math, copy
import numpy as np
import matplotlib
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt
plt.style.use('./deeplearning.mplstyle')
from lab_utils_uni import plt_house_x, plt_contour_wgrad, plt_divergence, plt_gradients


'''训练集'''
x_train = np.array([1.0, 2.0])
y_train = np.array([300.0, 500.0])

'''成本函数'''
def compute_cost(x, y, w, b):
    m = x.shape[0]
    cost = 0

    for i in range(m):
        f_wb = w * x[i] + b
        cost = cost + (f_wb - y[i]) ** 2
    total_cost = 1 / (2 * m) * cost

    return total_cost

'''梯度下降函数'''
def compute_gradient(x,y,w,b):
    m=x.shape[0]
    dj_dw=0
    dj_db=0

    for i in range(m):
        f_wb=w*x[i]+b
        dj_dw_i = (f_wb-y[i])*x[i]
        dj_db_i = (f_wb - y[i])
        dj_dw += dj_dw_i
        dj_db += dj_db_i
    dj_dw = dj_dw / m
    dj_db = dj_db / m

    return dj_dw, dj_db

'''执行梯度下降来拟合w,b'''           #通过使用num_iters梯度步长和学习率来更新w,b

def gradient_descent(x,y,w_in,b_in,alpha,num_iters,cost_function,gradient_function):
    '''
    参数 x--训练集输入特征
        y--训练集结果
        w_in--初始w值
        b_in--初始b值
        alpha--学习率
        num_iters--运行梯度下降的迭代次数
        cost_function--调用成本函数计算当前w,b值产生的成本
        gradient_function--调用梯度下降函数更新w,b
    返回 w--更新后的w
        b--更新后的b
        J_history--历史成本函数
        P_history--历史(w,b)
    '''
    J_history=[]
    P_history=[]
    b=b_in
    w=w_in

    for i in range(num_iters):
        dj_dw,dj_db=gradient_function(x,y,w,b)
        b=b-alpha*dj_db
        w=w-alpha*dj_dw

        if i<100000:                                    #如果迭代次数小于100000,算法会在每次迭代后计算并保存当前的成本函数值和参数值
            J_history.append(cost_function(x,y,w,b))
            P_history.append([w,b])
        if i%math.ceil(num_iters/10)==0:               #每完成总迭代次数的大约十分之一时,打印出当前的迭代次数、成本函数值、梯度以及参数值,监控迭代进展
            print(f"Iteration {i:4}: Cost {J_history[-1]:0.2e} ",
                  f"dj_dw: {dj_dw: 0.3e}, dj_db: {dj_db: 0.3e}  ",
                  f"w: {w: 0.3e}, b:{b: 0.5e}")
    return w, b, J_history,P_history

'''进行梯度下降'''
w_init=0
b_init=0
itrations=2000
tmp_alpha=1.0e-1
w_final,b_final,J_hist,p_hist=gradient_descent(x_train,y_train,w_init,b_init,tmp_alpha,itrations,compute_cost,compute_gradient)
print(f"(w,b)经过梯度下降后,更新为:({w_final:8.4f},{b_final:8.4f})")


'''绘制学习曲线'''
fig,(ax1,ax2)=plt.subplots(1,2,constrained_layout=True,figsize=(12,4))
ax1.plot(J_hist[:1000])                                              #绘制前100次迭代的成本函数值。这通常用于观察算法在开始阶段的快速变化
ax2.plot(1000 + np.arange(len(J_hist[1000:])), J_hist[1000:])       #绘制第1000次迭代到最后的成本函数值。这有助于观察算法在后期是否平稳收敛。
ax1.set_title("Cost vs. iteration(start)")                          #设置标题
ax2.set_title("Cost vs. iteration (end)")                           #设置标题
ax1.set_ylabel('Cost')
ax1.set_xlabel('iteration step')
ax2.set_ylabel('Cost')
ax2.set_xlabel('iteration step')
plt.show()

'''预测'''
print(f"1000 平方米的房子预测需要 {w_final*1.0 + b_final:0.1f} 千美元")
print(f"1200 平方米的房子预测需要 {w_final*1.2 + b_final:0.1f} 千美元")
print(f"2000 平方米的房子预测需要 {w_final*2.0 + b_final:0.1f} 千美元")


'''绘制成本函数等高线--梯度下降路径'''
fig, ax = plt.subplots(1,1, figsize=(12, 6))
plt_contour_wgrad(x_train, y_train, p_hist, ax)
plt.show()

'''绘制成本函数等高线--梯度下降步长'''
fig, ax = plt.subplots(1,1, figsize=(12, 4))
plt_contour_wgrad(x_train, y_train, p_hist, ax, w_range=[180, 220, 0.5], b_range=[80, 120, 0.5],contours=[1,5,10,20],resolution=0.5)
plt.show()


'''反例:学习率太大'''

w_init = 0
b_init = 0
iterations = 10
tmp_alpha = 8.0e-1
w_final, b_final, J_hist, p_hist = gradient_descent(x_train ,y_train, w_init, b_init, tmp_alpha,
                                                    iterations, compute_cost, compute_gradient)

plt_divergence(p_hist,J_hist,x_train, y_train)  #J太大,已溢出报错
plt.show()

多元线性回归

多元线性回归函数

        \hat{y}=w_1x_1+w_2x_2+...+w_nx_n+b=\vec{w}\cdot \vec{x}+b

其中,\vec{w}=\left[ w_{1} \, \, \, w_{2} \, \, \, ...w_n \right ]\vec{x}=[x_{1}\, \, \, x_{2}\: ...\, \, x_n]

符号说明 

 n——表示总样本数

\vec{x}^{(i)}——表示第i个样本,表示为多个特征组合起来的列表

x_{j}——表示第j个特征

x^{(i)}_{j}——表示第i个样本的第j个特征

矢量化

①非矢量化,逐一相乘汇总,若样本量大,编码和运行效率低。

import numpy as np
w=np.array([1,2.5,-3.3])
b=4
x=np.array([10,20,30])

f=w[0]*x[0]+w[1]*x[1]+w[2]*x[2]+b

②非矢量化,使用for循环,运行效率低,运行n-1次得到结果逐一累加。

f=0
for j in range(0,n):
  f=f+w[j]*x[j]
f=f+b

③矢量化,使用dot()函数,运行效率高,只需两步(w和x同时相乘,然后一步汇总)。

f=np.dot(w,x)+b

梯度下降

        \frac{\partial J}{\partial w_{j}}=\frac{1}{m}\sum_{i=0}^{m-1}(f_{w,b}(x^{(i)})-y^{(i)})x_{j}^{(i)}

        \frac{\partial J}{\partial b}=\frac{1}{m}\sum_{i=0}^{m-1}(f_{w,b}(x^{(i)})-y^{(i)})

        w_{n}=w_n-a\frac{\partial J}{\partial {w_{n}}}

        b=b-a\frac{\partial J}{\partial b}

法方程

   只适用于线性回归,特征数量多的时候也很慢,也叫正态方程法。

Numpy

       NumPy(Numerical Python)是Python中最重要的科学计算库之一,也是数据科学和机器学习领域中最常用的库之一。它提供了一个强大的多维数组对象(ndarray)和一系列用于处理这些数组的函数。

①主要特点和功能

  1. 多维数组对象(ndarray):NumPy 的核心是 ndarray,它是一个高效的多维数组,可以容纳相同类型的元素。这些数组可以是一维、二维或更高维的,并且支持各种数据类型,如整数、浮点数、复数等。

  2. 矢量化操作:NumPy 提供了广播(broadcasting)和矢量化操作,允许在整个数组上执行运算,而无需编写显式循环。这种方式通常比纯Python代码更加高效。

  3. 数学函数和操作:NumPy 提供了丰富的数学函数和操作,包括基本的算术运算、三角函数、指数函数、对数函数等,以及各种线性代数、统计学和随机数生成函数。

  4. 广播(Broadcasting):NumPy 的广播功能使得对不同形状的数组进行运算变得简单和有效,它自动地将较小数组的形状扩展为较大数组的形状,以使运算可以进行。

  5. 整合外部代码:NumPy 可以与C、C++和Fortran代码进行无缝整合,可以轻松地调用这些语言中的函数,也可以使用NumPy提供的工具将Python代码转换为这些语言的代码。

  6. 用于文件输入输出的工具:NumPy 提供了用于读取和写入数组数据的工具,可以方便地将数据存储到磁盘或从磁盘读取数据。

  7. 绘图功能:虽然 NumPy 本身不提供绘图功能,但它与 Matplotlib 等绘图库结合使用,可以方便地进行数据可视化。

② Numpy基础

import numpy as np
'''向量创建'''
np.random.seed(1)              #确保每次运行生成的随机数序列是一样的,2的话每次都生产不同序列
a = np.zeros(4)                # a = [0. 0. 0. 0.], a shape = (4,), a data type = float64
a = np.random.random_sample(4) # a = [0.1020911  0.71553298 0.42669572 0.12732302], a shape = (4,), a data type = float64
a = np.arange(4.)              # a = [0. 1. 2. 3.], a shape = (4,), a data type = float64
a = np.random.rand(4)          # a = [0.62697468 0.16812742 0.34532548 0.47263308], a shape = (4,), a data type = float64
a = np.array([5,4,3,2])        # a = [5 4 3 2],     a shape = (4,), a data type = int32
a = np.array([5.,4,3,2])       # a = [5. 4. 3. 2.], a shape = (4,), a data type = float64


'''向量索引'''
a=np.arange(10)               # [0 1 2 3 4 5 6 7 8 9]
a[2]                          # 2
a[2].shape                    # ()
a[-1]                         # 9
a[2:7:1]                      # [2 3 4 5 6]  取左不取右
a[2:7:2]                      # [2 4 6]
a[3:]                         # [3 4 5 6 7 8 9]
a[:3]                         # [0 1 2]
a[:]                          # [0 1 2 3 4 5 6 7 8 9]


'''向量运算'''
a = np.array([1,2,3,4])       # [1 2 3 4]
b = -a                        # [-1 -2 -3 -4]
b = np.sum(a)                 # 10
b = np.mean(a)                # 2.5
b = a**2                      # [ 1  4  9 16]

a = np.array([ 1, 2, 3, 4])
b = np.array([-1,-2, 3, 4])
a+b                           # [0 0 6 8]       个数相同才能相加

a = np.array([1, 2, 3, 4])
b=5*a                         # [ 5 10 15 20]

a = np.array([1, 2, 3, 4])
b = np.array([-1, 4, 3, 2])
np.dot(a,b)                   # 24
np.dot(a,b).shape             # ()
np.dot(b,a)                   # 24
np.dot(b,a).shape             # ()

X = np.array([[1],[2],[3],[4]])    # x.shape (4,1) 4行1列矩阵
X[1]                               # x[1].shape(1,)
w = np.array([2])                  # w.shape (1,)  1行标量
c = np.dot(X[1], w)                # X[1]=[2] w=[2]  c=4 c.shape ()


'''矩阵创建(二维)'''

a = np.zeros((1, 5))                # a = [[0. 0. 0. 0. 0.]] a.shape = (1, 5), 1行5列 0矩阵
a = np.zeros((2, 1))                # a = [[0.]
                                    #      [0.]]             a.shape = (2, 1)  2行1列 0矩阵
a = np.random.random_sample((1, 1)) # a = [[0.44236513]]     a.shape = (1, 1)  返回[0.0, 1.0) 之间的随机浮点数,形状 1行1列随机数矩阵
a = np.array([[5], [4], [3]])       # a = [[5]
                                    #      [4]
                                    #      [3]]              a.shape = (3, 1)
a = np.array([[5],
              [4],
              [3]])                 # 同上



'''矩阵索引'''
a = np.arange(6).reshape(-1, 2)     # a = [[0 1]      arange生成0-5的整数列
                                    #      [2 3]      -1 指自动计算行数
                                    #      [4 5]]     2  指定列数为2    a.shape: (3, 2)
a = a[2,0]                          # 4
a = a[2,0].shape                    # ()
type(a[2,0])                        # <class 'numpy.int64'>
a = a[2]                            # [4,5]
a = a[2].shape                      # (2,)
type(a[2,0])                        # <class 'numpy.ndarray'>


'''矩阵切片'''
a = np.arange(20).reshape(-1, 10)  # a = [[ 0  1  2  3  4  5  6  7  8  9]
                                   #      [10 11 12 13 14 15 16 17 18 19]]
a = a[0, 2:7:1]                    # a = [2  3  4  5  6]  a.shape=(5,)
a = a[:, 2:7:1]                    # a = [[2  3  4  5  6]
                                   #      [12 13 14 15 16]]   a.shape=(2,5)
a = a[:,:]                         # a = [[ 0  1  2  3  4  5  6  7  8  9]
                                   #      [10 11 12 13 14 15 16 17 18 19]] a.shape = (2, 10)
a = a[1,:]                         # a = [10 11 12 13 14 15 16 17 18 19]   a.shape = (10,)
a = a[1]                           # a = [10 11 12 13 14 15 16 17 18 19]   a.shape = (10,)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值