机器学习简介和Python实现线性回归

机器学习的定义

机器学习是一个非常广泛的领域,很难说有一个非常明确的定义。目前有两个较为流传的定义。

  • Arthur Samuel:研究让计算机不用明确编程便能拥有学习能力的领域
  • Tom Mitchell:一个计算机程序可以从经验E中学习有关某类任务T和绩效指标P的信息,如果计算机对T中任务的绩效(由P衡量)随经验E的提高而有所提高。

通常来说,任何的机器学习问题都可以分为两类,有监督学习和无监督学习。

  • 有监督学习:输入和结果之间存在一定的联系,可分为回归分类两类问题
  • 无监督学习:没有基于预测结果的反馈。

模型和代价函数

我们能够使用成本函数来评估假设函数的准确性。对假设函数的结果以及输入 x 和输出y作平均差操作来作为成本函数。
J ( θ 0 , θ 1 ) = 1 2 m ∑ i = 1 m ( y ^ i − y i ) 2 = 1 2 m ∑ i = 1 m ( h θ ( x i ) − y i ) 2 J(θ_0,θ_1)=\frac{1}{2m}\sum_{i=1}^m(\widehat y_i-y_i)^2=\frac{1}{2m}\sum_{i=1}^m(h_\theta(x_i)-y_i)^2 J(θ0,θ1)=2m1i=1m(y iyi)2=2m1i=1m(hθ(xi)yi)2
这个函数也被称为平方误差函数或均方误差,平均值减半能够方便的计算梯度下降。

梯度下降

梯度下降是用来寻找成本函数最小值的算法,使用的方法是求取成本函数的导数。切线的斜率是该点的导数,它会提供一个方向。使得算法能够沿下降最陡的方向逐步降低成本函数,每个步骤的大小由学习率决定。

梯度下降的算法如下所示,一直重复直到收敛:
θ j : = θ j − α ∂ ∂ θ j J ( θ 0 , θ 1 ) \theta_j:=\theta_j-\alpha\frac{\partial}{\partial\theta_j}J(\theta_0,\theta_1) θj:=θjαθjJ(θ0,θ1)
在每一轮的迭代中,参数theta1theta2应该同步更新,其更新规则如下:
t e m p 0 : = θ 0 − α ∂ ∂ θ 0 J ( θ 0 , θ 1 ) temp0:=\theta_0-\alpha\frac{\partial}{\partial\theta_0}J(\theta_0,\theta_1) temp0:=θ0αθ0J(θ0,θ1)

t e m p 1 : = θ 1 − α ∂ ∂ θ 1 J ( θ 0 , θ 1 ) temp1:=\theta_1-\alpha\frac{\partial}{\partial\theta_1}J(\theta_0,\theta_1) temp1:=θ1αθ1J(θ0,θ1)

θ 0 : = t e m p 0 \theta_0:=temp0 θ0:=temp0

θ 1 : = t e m p 1 \theta_1:=temp1 θ1:=temp1

线性回归中的梯度下降

当把梯度下降用于线性回归时,梯度下降就有了新的公式。我们需要将真正的成本函数和假设函数代入梯度下降的公式之中,其最终结果如下:
repeat until convergence:  { θ 0 : = θ 0 − α 1 m ∑ i = 1 m ( h θ ( x i ) − y i ) θ 1 : = θ 1 − α 1 m ∑ i = 1 m ( ( h θ ( x i ) − y i ) x i ) } \begin{aligned} \text{repeat until convergence: } \lbrace & \\ \theta_0 := & \theta_0 - \alpha \frac{1}{m} \sum\limits_{i=1}^{m}(h_\theta(x_{i}) - y_{i}) \\ \theta_1 := & \theta_1 - \alpha \frac{1}{m} \sum\limits_{i=1}^{m}\left((h_\theta(x_{i}) - y_{i}) x_{i}\right) \\ \rbrace& \end{aligned} repeat until convergence: {θ0:=θ1:=}θ0αm1i=1m(hθ(xi)yi)θ1αm1i=1m((hθ(xi)yi)xi)
其中m是训练集的大小,theta0theta1是同步更新的,x和y的值由训练集给出。

偏微分公式的推导如下所示:
∂ ∂ θ j J ( θ ) = ∂ ∂ θ j 1 2 ( h θ ( x ) − y ) 2 = 2 ⋅ 1 2 ( h θ ( x ) − y ) ⋅ ∂ ∂ θ j ( h θ ( x ) − y ) = ( h θ ( x ) − y ) ⋅ ∂ ∂ θ j ( ∑ i = 0 n θ i x i − y ) = ( h θ ( x ) − y ) x j \begin{aligned} \frac{\partial}{\partial\theta_j}J(\theta)&=\frac{\partial}{\partial\theta_j}\frac{1}{2}(h_\theta(x)-y)^2 \\ &= 2 \cdot\frac{1}{2}(h_\theta(x)-y)\cdot\frac{\partial}{\partial\theta_j}(h_\theta(x)-y)\\ &= (h_\theta(x)-y)\cdot\frac{\partial}{\partial\theta_j}(\sum_{i=0}^n \theta_ix_i-y)\\ &= (h_\theta(x)-y)x_j \end{aligned} θjJ(θ)=θj21(hθ(x)y)2=221(hθ(x)y)θj(hθ(x)y)=(hθ(x)y)θj(i=0nθixiy)=(hθ(x)y)xj
如果我们从猜测的点开始,不断地使用梯度下降方程进行迭代,那么结果会越来越准确。

Linear Regression With One Variable

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['Microsoft YaHei']
path = 'ex1data1.txt'
data = pd.read_csv(path, header=None, names=['Population', 'profit'])
data.head()
Populationprofit
06.110117.5920
15.52779.1302
28.518613.6620
37.003211.8540
45.85986.8233
data.describe()
Populationprofit
count97.00000097.000000
mean8.1598005.839135
std3.8698845.510262
min5.026900-2.680700
25%5.7077001.986900
50%6.5894004.562300
75%8.5781007.046700
max22.20300024.147000

数据可视化,绘制散点图

data.plot(x='Population', y='profit', kind='scatter', figsize=(12, 8))
plt.show()

数据散点图

我们能够使用成本函数来评估假设函数的准确性。对假设函数的结果以及输入 x 和输出y作平均差操作来作为成本函数。
J ( θ 0 , θ 1 ) = 1 2 m ∑ i = 1 m ( y ^ i − y i ) 2 = 1 2 m ∑ i = 1 m ( h θ ( x i ) − y i ) 2 J(θ_0,θ_1)=\frac{1}{2m}\sum_{i=1}^m(\widehat y_i-y_i)^2=\frac{1}{2m}\sum_{i=1}^m(h_\theta(x_i)-y_i)^2 J(θ0,θ1)=2m1i=1m(y iyi)2=2m1i=1m(hθ(xi)yi)2
这个函数也被称为平方误差函数或均方误差,平均值减半能够方便的计算梯度下降。
其中:\[{{h}{\theta }}\left( x \right)={{\theta }^{T}}X={{\theta }{0}}{{x}{0}}+{{\theta }{1}}{{x}{1}}+{{\theta }{2}}{{x}{2}}+…+{{\theta }{n}}{{x}_{n}}\]

# 损失函数
def computeCost(X:np.ndarray, y:np.ndarray, theta:np.ndarray)->np.ndarray:
    """ 一元线性回归损失函数 """
    J = np.power(((X * theta.T) - y), 2)
    return np.sum(J) / (2 * m)

给数据集添加一列全为 1 的数据,方便后续做矩阵处理

data.insert(0, 'ones', 1)
cols = data.shape[1]
X = data.iloc[:, 0:cols-1]
y = data.iloc[:, cols-1:cols]
m = len(y)

查看处理后的数据是否正确

X.head()
onesPopulation
016.1101
115.5277
218.5186
317.0032
415.8598
y.head()
profit
017.5920
19.1302
213.6620
311.8540
46.8233

转换X和y为numpy矩阵

X = np.matrix(X)
y = np.matrix(y)
theta = np.matrix(np.array([0, 0]))

theta是一个(1, 2)矩阵

theta
matrix([[0, 0]])

查看数据的维度

X.shape, theta.shape, y.shape
((97, 2), (1, 2), (97, 1))

计算代价函数

computeCost(X, y, theta)
32.072733877455676

梯度下降是用来寻找成本函数最小值的算法,使用的方法是求取成本函数的导数。切线的斜率是该点的导数,它会提供一个方向。使得算法能够沿下降最陡的方向逐步降低成本函数,每个步骤的大小由学习率决定。

梯度下降的算法如下所示,一直重复直到收敛:
θ j : = θ j − α ∂ ∂ θ j J ( θ 0 , θ 1 ) \theta_j:=\theta_j-\alpha\frac{\partial}{\partial\theta_j}J(\theta_0,\theta_1) θj:=θjαθjJ(θ0,θ1)
在每一轮的迭代中,参数theta1theta2应该同步更新,其更新规则如下:
t e m p 0 : = θ 0 − α ∂ ∂ θ 0 J ( θ 0 , θ 1 ) temp0:=\theta_0-\alpha\frac{\partial}{\partial\theta_0}J(\theta_0,\theta_1) temp0:=θ0αθ0J(θ0,θ1)

t e m p 1 : = θ 1 − α ∂ ∂ θ 1 J ( θ 0 , θ 1 ) temp1:=\theta_1-\alpha\frac{\partial}{\partial\theta_1}J(\theta_0,\theta_1) temp1:=θ1αθ1J(θ0,θ1)

θ 0 : = t e m p 0 \theta_0:=temp0 θ0:=temp0

θ 1 : = t e m p 1 \theta_1:=temp1 θ1:=temp1

# 梯度下降函数
def gradientDescent(X, y, theta, alpha:float, num_iters:int)->np.ndarray:
    temp = np.matrix(np.zeros(theta.shape)) # 构建零值矩阵
    parameters = int(theta.ravel().shape[1]) # reval计算需要求解的参数个数,功能将多为数组降至以为
    J_history = np.zeros(num_iters) # 构建iters个0的数组
    
    for iter in range(num_iters):
       
        error = (X * theta.T) - y
        for j in range(parameters):
            term = np.multiply(error, X[:, j]) # 计算两矩阵(hθ(x)-y)x
            temp[0, j] = theta[0, j] - ((alpha / len(X)) * np.sum(term))
        # 保存损失值    
        theta = temp
        J_history[iter] = computeCost(X, y, theta)
        
    return theta, J_history

设置梯度下降的基本参数

# Some gradient descent settings
iterations = 1500
alpha = 0.01

现在让我们运行梯度下降算法来将我们的参数θ适合于训练集。

g, cost = gradientDescent(X, y, theta, alpha, iterations)
g
matrix([[-3.63029144,  1.16636235]])

最后,我们可以使用我们拟合的参数计算训练模型的代价函数(误差)。

computeCost(X, y, g)
4.483388256587726

绘制线性模型和数据,查看拟合效果

x = np.linspace(data.Population.min(), data.Population.max(), 100)
f = g[0, 0] + (g[0, 1] * x)

fig, ax = plt.subplots(figsize=(12,8))
ax.plot(x, f, 'r', label='Prediction')
ax.scatter(data.Population, data.profit, label='Traning Data')
ax.legend(loc=2)
ax.set_xlabel('Population')
ax.set_ylabel('Profit')
ax.set_title('Predicted Profit vs. Population Size')
plt.show()

数据拟合情况

由于梯度方程式函数也在每个训练迭代中输出一个代价的向量,所以我们也可以绘制。 请注意,代价总是降低 - 这是凸优化问题的一个例子。

fig, ax = plt.subplots(figsize=(12,8))
ax.plot(np.arange(iterations), cost, 'r')
ax.set_xlabel('Iterations')
ax.set_ylabel('Cost')
ax.set_title('Error vs. Training Epoch')
plt.show()

在这里插入图片描述

Linear Regression With Multiple Variable

带有多个变量的线性回归也被叫做多元线性回归。接下来,为方程式引入符号,多元线性回归可以拥有任意数量的输入变量。
x j ( i ) = v a l u e   o f   f e a t u r e   j   i n   t h e   i t h   t r a i n i n g   e x a m p l e x ( i ) = t h e   i n p u t   ( f e a t u r e s )   o f   t h e   i t h   t r a i n i n g   e x a m p l e m = t h e   n u m b e r   o f   t r a i n i n g   e x a m p l e s n = t h e   n u m b e r   o f   f e a t u r e s \begin{aligned} x^{(i)}_j &=value\ of\ feature\ j\ in\ the\ i^{th}\ training\ example \\ x^{(i)} &= the\ input\ (features)\ of\ the\ i^{th}\ training\ example \\ m &= the\ number\ of\ training\ examples \\ n &= the\ number\ of\ features \end{aligned} xj(i)x(i)mn=value of feature j in the ith training example=the input (features) of the ith training example=the number of training examples=the number of features
多元线性回归函数的公式如下所示:
h θ ( x ) = θ 0 + θ 1 x 1 + θ 2 x 2 + θ 3 x 3 + . . . + θ n x n h_{\theta}(x) = \theta_0+\theta_1x_1+\theta_2x_2+\theta_3x_3+...+\theta_nx_n hθ(x)=θ0+θ1x1+θ2x2+θ3x3+...+θnxn
为了使函数更加直观,我们可以将 θ 0 \theta_0 θ0看作房屋的基本价格, θ 1 \theta_1 θ1看作每平方米的价格, θ 2 \theta_2 θ2看作每层的价格,其它变量类似。 x 1 \\x_1 x1作为房屋的平方数, x 2 x_2 x2作为房屋的层数,其他变量类似。

使用矩阵方式表示多元线性回归,其公式如下:
h θ ( x ) = [ θ 0   θ 1   . . .   θ n ] [ x 0 x 1 ⋮ x n ] = θ T x h_\theta(x)=[\theta_0\ \theta_1\ ...\ \theta_n]\begin{bmatrix}x_0\\x_1\\ \vdots\\x_n\end{bmatrix}=\theta^Tx hθ(x)=[θ0 θ1 ... θn]x0x1xn=θTx
注意:为了方便,我们假设 x 0 ( i ) = 1   f o r ( i ∈ 1 , . . . , m ) x_0^{(i)}=1\ for(i\in1,...,m) x0(i)=1 for(i1,...,m).这使得我们可以对 θ \theta θ x x x进行矩阵操作。因而使得 ′ θ ′ '\theta' θ x ( i ) x^{(i)} x(i)具有相对应的宽度。

练习1还包括一个房屋价格数据集,其中有2个变量(房子的大小,卧室的数量)和目标(房子的价格)。 我们使用我们已经应用的技术来分析数据集。

# 多变量线性回归
path = "ex1data2.txt"
data2 = pd.read_csv(path, header=None, names=['Size', 'Bedrooms', 'Profit'])
data2.head()
SizeBedroomsProfit
021043399900
116003329900
224003369000
314162232000
430004539900
data2.describe()
SizeBedroomsProfit
count47.00000047.00000047.000000
mean2000.6808513.170213340412.659574
std794.7023540.760982125039.899586
min852.0000001.000000169900.000000
25%1432.0000003.000000249900.000000
50%1888.0000003.000000299900.000000
75%2269.0000004.000000384450.000000
max4478.0000005.000000699900.000000

我们可以通过将每个输入值都设置在相同的范围类来加快梯度下降的速度。因为 θ \theta θ在小范围内会快速下降,但在大范围内又会缓慢下降,所以当变量不均匀时,梯度下降的效率会非常低。

一般使用特征缩放均值归一化两种方法。

  • 特征缩放:将输入值除以输入变量的范围,来使新范围为1
  • 均值归一化:将输入值减去输入变量的平均值

可以使用以下公式处理输入值:
x i : = x i − u i s i x_i:=\frac{x_i-u_i}{s_i} xi:=sixiui
其中 u i u_i ui是所有特征的平均值, s i s_i si是特征的范围或标准偏差

注意:除以范围和除以偏差得到的结果不同

data2 = (data2 - data2.mean()) / data2.std()
## 在数据中添加一列全为1的数据
data2.insert(0, 'Ones', 1,) # 无返回值,直接对数据进行处理

重复单变量线性回归的数据预处理操作

# 将数据切分为变量和预测值
cols = data2.shape[1]
X2 = data2.iloc[:, 0:cols-1]
y2 = data2.iloc[:, cols-1:cols]
X2.head()
OnesSizeBedrooms
010.130010-0.223675
11-0.504190-0.223675
210.502476-0.223675
31-0.735723-1.537767
411.2574761.090417
y2.head()
Profit
00.475747
1-0.084074
20.228626
3-0.867025
41.595389
# 将数据转换为矩阵形式
X2 = np.matrix(X2.values)
y2 = np.matrix(y2.values)
theta = np.matrix(np.array([0, 0, 0]))

# 对数据集进行梯度下降处理
g2, cost2 = gradientDescent(X2, y2, theta, alpha, iterations)

# 计算
# get the cost (error) of the model
computeCost(X2, y2, g2)
0.06332242458623788

我们也可以快速查看这一个的训练进程。

fig, ax = plt.subplots(figsize=(12,8))
ax.plot(np.arange(iterations), cost2, 'r')
ax.set_xlabel('Iterations')
ax.set_ylabel('Cost')
ax.set_title('Error vs. Training Epoch')
plt.show()

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值