机器学习3- 一元线性回归+Python实现
<p></p><div class="toc"><div class="toc-container-header">目录</div><ul><li>1. 线性模型</li><li>2. 线性回归<ul><li>2.1 一元线性回归</li></ul></li><li>3. 一元线性回归的Python实现<ul><li>3.1 使用 stikit-learn<ul><li>3.1.1 导入必要模块</li><li>3.1.2 使用 Pandas 加载数据</li><li>3.1.3 快速查看数据</li><li>3.1.4 使用 stlearn 创建模型</li><li>3.1.5 模型评估</li></ul></li><li>3.2 手动实现<ul><li>3.2.1 计算 w 和 b</li><li>3.2.2 功能封装</li></ul></li></ul></li></ul></div><p></p><h1 id="1-线性模型">1. 线性模型</h1>
<p>给定 <span class="math inline">\(d\)</span> 个属性描述的示例 <span class="math inline">\(\boldsymbol{x} = (x_1; x_2; ...; x_d)\)</span>,其中 <span class="math inline">\(x_i\)</span> 为 <span class="math inline">\(\boldsymbol{x}\)</span> 在第 <span class="math inline">\(i\)</span> 个属性上的取值,<strong>线性模型</strong>(<em>linear model</em>)试图学得一个通过属性的线性组合来进行预测的函数,即:</p>
<p></p><div class="math display">\[f(\boldsymbol{x}) = w_1x_1 + w_2x_2 + ... + w_dx_d +b \tag{1.1}
\]</div><p></p><p>使用向量形式为:</p>
<p></p><div class="math display">\[f(\boldsymbol{x}) = \boldsymbol{w}^T\boldsymbol{x}+b \tag{1.2}
\]</div><p></p><p>其中 <span class="math inline">\(\boldsymbol{w} = (w_1;w_2;...;w_d)\)</span>,表达了各属性在预测中的重要性。</p>
<h1 id="2-线性回归">2. 线性回归</h1>
<p>给定数据集 <span class="math inline">\(D = \lbrace(\boldsymbol{x}_1,{y}_1), (\boldsymbol{x}_2,{y}_2), ..., (\boldsymbol{x}_m,{y}_m)\rbrace\)</span>,其中 <span class="math inline">\(\boldsymbol{x}_i = (x_{i1}; x_{i2}; ...; x_{id})\)</span>,<span class="math inline">\(y_i \in \mathbb{R}\)</span>。<strong>线性回归</strong>(<em>linear regression</em>)试图学得一个能尽可能准确地预测真实输出标记的线性模型,即:</p>
<p></p><div class="math display">\[f(\boldsymbol{x}_i) = \boldsymbol{w}^T\boldsymbol{x}_i+b \text{,使得} f(\boldsymbol{x}_i) \simeq y_i\tag{2.1}
\]</div><p></p><h2 id="21-一元线性回归">2.1 一元线性回归</h2>
<p>先只考虑输入属性只有一个的情况,<span class="math inline">\(D = \lbrace({x}_1,{y}_1), ({x}_2,{y}_2), ..., ({x}_m,{y}_m)\rbrace\)</span>,<span class="math inline">\(x_i \in \mathbb{R}\)</span>。对离散属性,若属性值存在<strong>序</strong>(<em>order</em>)关系,可通过连续化将其转化为连续值。</p>
<blockquote>
<p>如”高度“属性的取值“高”、“中”、“低”,可转化为<span class="math inline">\(\{1.0, 0.5, 0.0\}\)</span>。</p>
</blockquote>
<p>若不存在序关系,则假定有 <span class="math inline">\(k\)</span> 种可能的属性值,将其转化为 <span class="math inline">\(k\)</span> 维向量。</p>
<blockquote>
<p>如“瓜类”属性的取值有“冬瓜”、“西瓜”、“南瓜”,可转化为 <span class="math inline">\((0,0,1),(0,1,0),(1,0,0)\)</span>。</p>
</blockquote>
<p>线性回归试图学得:</p>
<p></p><div class="math display">\[f(x_i) = wx_i+b\text{,使得}f(x_i)\simeq y_i \tag{2.2}
\]</div><p></p><p>为使 <span class="math inline">\(f(x_i)\simeq y_i\)</span>,即:使 <span class="math inline">\(f(x)\)</span> 与 <span class="math inline">\(y\)</span> 之间的差别最小化。<br>
考虑回归问题的常用性能度量——均方误差(亦称平方损失(<em>square loss</em>)),即让均方误差最小化:</p>
<p></p><div class="math display">\[\begin{aligned}
(w^*,b^*) = \underset{(w,b)}{arg\ min}\sum_{i=1}^m(f(x_i)-y_i)^2 \\
= \underset{(w,b)}{arg\ min}\sum_{i=1}^m(y_i-wx_i-b)^2
\end{aligned}
\tag{2.3}
\]</div><p></p><p><span class="math inline">\(w^*,b^*\)</span> 表示 <span class="math inline">\(w\)</span> 和 <span class="math inline">\(b\)</span> 的解。<br>
均方误差对应了欧几里得距离,简称欧氏距离(<em>Euclidean distance</em>)。<br>
基于均方误差最小化来进行模型求解的方法称为<strong>最小二乘法</strong>(<em>least square method</em>)。在线性回归中,就是试图找到一条直线,使得所有样本到直线上的欧氏距离之和最小。</p>
<p>下面需要求解 <span class="math inline">\(w\)</span> 和 <span class="math inline">\(b\)</span> 使得 <span class="math inline">\(E_{(w,b)} = \sum\limits_{i=1}^m(y_i-wx_i-b)^2\)</span> 最小化,该求解过程称为线性回归模型的最小二乘<strong>参数估计</strong>(<em>parameter estimation</em>)。</p>
<p><span class="math inline">\(E_{(w,b)}\)</span> 为关于 <span class="math inline">\(w\)</span> 和 <span class="math inline">\(b\)</span> 的凸函数,当它关于 <span class="math inline">\(w\)</span> 和 <span class="math inline">\(b\)</span> 的导数均为 <span class="math inline">\(0\)</span> 时,得到 <span class="math inline">\(w\)</span> 和 <span class="math inline">\(b\)</span> 的最优解。将 <span class="math inline">\(E_{(w,b)}\)</span> 分别对 <span class="math inline">\(w\)</span> 和 <span class="math inline">\(b\)</span> 求导数得:</p>
<p></p><div class="math display">\[\frac{\partial{E_{(w,b)}}}{\partial(w)} = 2\Big(w\sum_{i=1}^m x_i^2 - \sum_{i=1}^m (y_i-b)x_i\Big) \tag{2.4}
\]</div><p></p><p></p><div class="math display">\[\frac{\partial{E_{(w,b)}}}{\partial(b)} = 2\Big(mb - \sum_{i=1}^m (y_i-wx_i)\Big) \tag{2.5}
\]</div><p></p><p>令式子 (2.4) 和 (2.5) 为 <span class="math inline">\(0\)</span> 得到 <span class="math inline">\(w\)</span> 和 <span class="math inline">\(b\)</span> 的最优解的闭式(<em>closed-form</em>)解:</p>
<p></p><div class="math display">\[w = \frac{\sum_\limits{i=1}^m y_i(x_i-\overline{x})}{\sum\limits_{i=1}^m x_i^2 - \frac{1}{m}\Big(\sum\limits_{i=1}^m x_i\Big)^2} \tag{2.6}
\]</div><p></p><p></p><div class="math display">\[b = \frac{1}{m}\sum_{i=1}^m (y_i-wx_i) \tag{2.7}
\]</div><p></p><p>其中 <span class="math inline">\(\overline{x} = \frac{1}{m}\sum\limits_{i=1}^m x_i\)</span> 为 <span class="math inline">\(x\)</span> 的均值。</p>
<blockquote>
<p>其他解法:</p>
<p></p><div class="math display">\[方差\ var(x) = \frac{\sum\limits_{i=1}^m(x_i-\bar{x})^2}{m-1}
\]</div><p></p><p></p><div class="math display">\[协方差\ cov(x,y) = \frac{\sum_\limits{i=1}^m (x_i-\overline{x})(y_i-\overline{y})}{n-1}
\]</div><p></p><p></p><div class="math display">\[w = \frac{cov(x,y)}{var(x)} = \frac{\sum_\limits{i=1}^m (x_i-\overline{x})(y_i-\overline{y})}{\sum\limits_{i=1}^m (x_i-\overline{x})^2}
\]</div><p></p><p></p><div class="math display">\[b = \bar{y} - w\bar{x}
\]</div><p></p></blockquote>
<h1 id="3-一元线性回归的python实现">3. 一元线性回归的Python实现</h1>
<p>现有如下训练数据,我们希望通过分析披萨的直径与价格的线性关系,来预测任一直径的披萨的价格。</p>
<p><img src="https://img2020.cnblogs.com/blog/1365872/202003/1365872-20200331153802060-497689729.png"></p>
<p>其中 <code>Diameter</code> 为披萨直径,单位为“英寸”;<code>Price</code> 为披萨价格,单位为“美元”。</p>
<h2 id="31-使用-stikit-learn">3.1 使用 stikit-learn</h2>
<h3 id="311-导入必要模块">3.1.1 导入必要模块</h3>
<pre><code class="language-python">import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from sklearn.linear_model import LinearRegression
</code></pre>
<h3 id="312-使用-pandas-加载数据">3.1.2 使用 Pandas 加载数据</h3>
<pre><code class="language-python">pizza = pd.read_csv("pizza.csv", index_col='Id')
pizza.head()# 查看数据集的前5行
</code></pre>
<p><img src="https://img2020.cnblogs.com/blog/1365872/202003/1365872-20200331154113468-1330743537.png"></p>
<h3 id="313-快速查看数据">3.1.3 快速查看数据</h3>
<p>我们可以使用 matplotlib 画出数据的散点图,x 轴表示披萨直径,y 轴表示披萨价格。</p>
<pre><code class="language-python">def runplt():
plt.figure()
plt.title("Pizza price plotted against diameter")
plt.xlabel('Diameter')
plt.ylabel('Price')
plt.grid(True)
plt.xlim(0, 25)
plt.ylim(0, 25)
return plt
dia = pizza.loc[:,'Diameter'].values
price = pizza.loc[:,'Price'].values
print(dia)
print(price)
plt = runplt()
plt.plot(dia, price, 'k.')
plt.show()
</code></pre>
<pre><code>[ 68 10 14 18]
[ 7. 9.13.17.5 18. ]
</code></pre>
<p><img src="https://img2020.cnblogs.com/blog/1365872/202003/1365872-20200331154416060-493048967.png"></p>
<h3 id="314-使用-stlearn-创建模型">3.1.4 使用 stlearn 创建模型</h3>
<pre><code class="language-python">model = LinearRegression()# 创建模型
X = dia.reshape((-1,1))
y = price
model.fit(X, y)# 拟合
X2 = [, ] # 取两个预测值
y2 = model.predict(X2)# 进行预测
print(y2)# 查看预测值
plt = runplt()
plt.plot(dia, price, 'k.')
plt.plot(X2, y2, 'g-')# 画出拟合曲线
plt.show()
</code></pre>
<pre><code>[ 1.96551724 26.37284483]
</code></pre>
<p><img src="https://img2020.cnblogs.com/blog/1365872/202003/1365872-20200331154633521-1064998193.png"></p>
<p>这里 <code>fit()</code>方法学得了一元线性回归模型 <span class="math inline">\(f(x) = wx+b\)</span>,这里 <span class="math inline">\(x\)</span> 指披萨的直径,<span class="math inline">\(f(x)\)</span> 为预测的披萨的价格。</p>
<p><code>fit()</code> 的第一个参数 X 为 shape(样本个数,属性个数) 的数组或矩阵类型的参数,代表输入空间;<br>
第二个参数 y 为 shape(样本个数,) 的数组类型的参数,代表输出空间。</p>
<h3 id="315-模型评估">3.1.5 模型评估</h3>
<p>成本函数(<em>cost function</em>)也叫损失函数(<em>lost function</em>),用来定义模型与观测值的误差。</p>
<p>模型预测的价格和训练集数据的差异称为<strong>训练误差</strong>(<em>training error</em>)也称<strong>残差</strong>(<em>residuals</em>)。</p>
<pre><code class="language-python">plt = runplt()
plt.plot(dia, price, 'k.')
plt.plot(X2, y2, 'g-')
# 画出残差
yr = model.predict(X)
for index, x in enumerate(X):
plt.plot(, , yr], 'r-')
plt.show()
</code></pre>
<p><img src="https://img2020.cnblogs.com/blog/1365872/202003/1365872-20200331154728916-1625524456.png"></p>
<p>根据最小二乘法,要得到更高的性能,就是让均方误差最小化,而均方误差就是残差平方和的平均值。</p>
<pre><code class="language-python">print("均方误差为: %.2f" % np.mean((model.predict(X)-y) ** 2))
</code></pre>
<pre><code>均方误差为: 1.75
</code></pre>
<h2 id="32-手动实现">3.2 手动实现</h2>
<h3 id="321-计算-w-和-b">3.2.1 计算 w 和 b</h3>
<p><span class="math inline">\(w\)</span> 和 <span class="math inline">\(b\)</span> 的最优解的闭式(<em>closed-form</em>)解为:</p>
<p></p><div class="math display">\[w = \frac{\sum_\limits{i=1}^m y_i(x_i-\overline{x})}{\sum\limits_{i=1}^m x_i^2 - \frac{1}{m}\Big(\sum\limits_{i=1}^m x_i\Big)^2} \tag{2.6}
\]</div><p></p><p></p><div class="math display">\[b = \frac{1}{m}\sum_{i=1}^m (y_i-wx_i) \tag{2.7}
\]</div><p></p><p>其中 <span class="math inline">\(\overline{x} = \frac{1}{m}\sum\limits_{i=1}^m x_i\)</span> 为 <span class="math inline">\(x\)</span> 的均值。</p>
<p>或</p>
<p></p><div class="math display">\[方差\ var(x) = \frac{\sum\limits_{i=1}^m(x_i-\bar{x})^2}{m-1}
\]</div><p></p><p></p><div class="math display">\[协方差\ cov(x,y) = \frac{\sum_\limits{i=1}^m (x_i-\overline{x})(y_i-\overline{y})}{n-1}
\]</div><p></p><p></p><div class="math display">\[w = \frac{cov(x,y)}{var(x)} = \frac{\sum_\limits{i=1}^m (x_i-\overline{x})(y_i-\overline{y})}{\sum\limits_{i=1}^m (x_i-\overline{x})^2}
\]</div><p></p><p></p><div class="math display">\[b = \bar{y} - w\bar{x}
\]</div><p></p><p>下面使用 Python 计算 <span class="math inline">\(w\)</span> 和 <span class="math inline">\(b\)</span> 的值:</p>
<pre><code class="language-python"># 法一:
# w = np.sum(price * (dia - np.mean(dia))) / (np.sum(dia**2) - (1/dia.size) * (np.sum(dia))**2)
# b = (1 / dia.size) * np.sum(price - w * dia)
#法二:
variance = np.var(dia, ddof=1)# 计算方差,doff为贝塞尔(无偏估计)校正系数
covariance = np.cov(dia, price)# 计算协方差
w = covariance / variance
b = np.mean(price) - w * np.mean(dia)
print("w = %f\nb = %f" % (w, b))
y_pred = w * dia + b
plt = runplt()
plt.plot(dia, price, 'k.')# 样本点
plt.plot(dia, y_pred, 'b-')# 手动求出的线性回归模型
plt.plot(X2, y2, 'g-.')# 使用LinearRegression.fit()求出的模型
plt.show()
</code></pre>
<pre><code>w = 0.976293
b = 1.965517
</code></pre>
<p><img src="https://img2020.cnblogs.com/blog/1365872/202003/1365872-20200331154908017-980070112.png"></p>
<p>可以看到两条直线重合,我们求出的回归模型与使用库求出的回归模型相同。</p>
<h3 id="322-功能封装">3.2.2 功能封装</h3>
<p>将上述代码封装成类:</p>
<pre><code class="language-python">class LinearRegression:
"""
拟合一元线性回归模型
Parameters
----------
x : shape 为(样本个数,)的 numpy.array
只有一个属性的数据集
y : shape 为(样本个数,)的 numpy.array
标记空间
Returns
-------
self : 返回 self 的实例.
"""
def __init__(self):
self.w = None
self.b = None
def fit(self, x, y):
variance = np.var(x, ddof=1)# 计算方差,doff为贝塞尔(无偏估计)校正系数
covariance = np.cov(x, y)# 计算协方差
self.w = covariance / variance
self.b = np.mean(y) - w * np.mean(x)
# self.w = np.sum(y * (x - np.mean(x))) / (np.sum(x**2) - (1/x.size) * (np.sum(x))**2)
# self.b = (1 / x.size) * np.sum(y - self.w * x)
return self
def predict(self, x):
"""
使用该线性模型进行预测
Parameters
----------
x : 数值 或 shape 为(样本个数,)的 numpy.array
属性值
Returns
-------
C : 返回预测值
"""
return self.w * x + self.b
</code></pre>
<p>使用:</p>
<pre><code class="language-python"># 创建并拟合模型
model = LinearRegression()
model.fit(dia, price)
x2 = np.array()# 取两个预测值
y2 = model.predict(x2)# 进行预测
print(y2)# 查看预测值
runplt()
plt.plot(dia, price, 'b.')
plt.plot(x2, y2, 'y-')# 画出拟合
plt.show()
</code></pre>
<pre><code>[ 1.96551724 26.37284483]
</code></pre>
<p><img src="https://img2020.cnblogs.com/blog/1365872/202003/1365872-20200331154934038-1546769430.png"></p>
<hr>
<p>此文原创禁止转载,转载文章请联系博主并注明来源和出处,谢谢!<br>
作者: Raina_RLN https://www.cnblogs.com/raina/</p><br><br>
来源:https://www.cnblogs.com/raina/p/12605768.html
頁:
[1]