# 損失函數
> 原文:[https://www.bookbookmark.ds100.org/ch/10/modeling_loss_functions.html](https://www.bookbookmark.ds100.org/ch/10/modeling_loss_functions.html)
```
# HIDDEN
# Clear previously defined variables
%reset -f
# Set directory for data loading to work properly
import os
os.chdir(os.path.expanduser('~/notebooks/10'))
```
```
# HIDDEN
import warnings
# Ignore numpy dtype warnings. These warnings are caused by an interaction
# between numpy and Cython and can be safely ignored.
# Reference: https://stackoverflow.com/a/40846742
warnings.filterwarnings("ignore", message="numpy.dtype size changed")
warnings.filterwarnings("ignore", message="numpy.ufunc size changed")
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
import seaborn as sns
%matplotlib inline
import ipywidgets as widgets
from ipywidgets import interact, interactive, fixed, interact_manual
import nbinteract as nbi
sns.set()
sns.set_context('talk')
np.set_printoptions(threshold=20, precision=2, suppress=True)
pd.options.display.max_rows = 7
pd.options.display.max_columns = 8
pd.set_option('precision', 2)
# This option stops scientific notation for pandas
# pd.set_option('display.float_format', '{:.2f}'.format)
```
```
# HIDDEN
tips = sns.load_dataset('tips')
tips['pcttip'] = tips['tip'] / tips['total_bill'] * 100
```
回想到目前為止我們的假設:我們假設有一個單一的總體提示百分比$\theta^*$。我們的模型估計這個參數;我們使用變量$\theta$來表示我們的估計。我們希望使用收集到的 Tips 數據來確定$\theta$應該具有的值,
為了精確地確定哪一個$theta$值是最好的,我們定義了一個**損失函數**。損失函數是一個數學函數,它接受一個估計值$\theta$和數據集$y_1,y_2,ldots,y_n$中的點。它輸出一個單獨的數字,即**損失**,用來衡量$\theta$是否適合我們的數據。在數學符號中,我們要創建函數:
$$ L(\theta, y_1, y_2, \ldots, y_n) =\ \ldots $$
按照慣例,損失函數輸出的值越低,值越大,值越高,值越低,值越大,值越低。為了適應我們的模型,我們選擇了產生比其他所有選擇的損失都要低的$theta$的值,即$theta$的值,它是**將損失最小化的$theta$的值**。我們使用符號$\hat \theta$表示將指定損失函數最小化的$\theta$值。
再次考慮兩個可能的值:$\theta$:$\theta=10$和$\theta=15$。
```
# HIDDEN
sns.distplot(tips['pcttip'], bins=np.arange(30), rug=True)
plt.axvline(x=10, c='darkblue', linestyle='--', label=r'$ \theta = 10$')
plt.axvline(x=15, c='darkgreen', linestyle='--', label=r'$ \theta = 15$')
plt.legend()
plt.xlim(0, 30)
plt.xlabel('Percent Tip Amount')
plt.ylabel('Proportion per Percent');
```

由于$\theta=15$接近大多數點,我們的損失函數應該輸出一個小的值為$\theta=15$和一個大的值為$\theta=10$。
讓我們用這個直覺來創建一個損失函數。
### 我們的第一個損失函數:均方誤差[?](#Our-First-Loss-Function:-Mean-Squared-Error)
我們希望選擇的$\theta$接近數據集中的點。因此,我們可以定義一個損失函數,它輸出一個更大的值,因為$\theta$遠離數據集中的點。我們從一個叫做 _ 均方誤差 _ 的簡單損失函數開始。這里的想法是:
1. 我們選擇的值是$\theta$。
2. 對于數據集中的每個值,取值和 theta 之間的平方差:$(y_i-\theta)^2$。用一種簡單的方法將差異平方化,將負差異轉化為正差異。我們之所以要這樣做,是因為如果我們的點$y_i=14$、$\theta=10$和$\theta=18$距離該點同樣遠,因此也同樣“差”。
3. 要計算最終損失,取每個平方差的平均值。
這給了我們一個最終的損失函數:
$$ \begin{aligned} L(\theta, y_1, y_2, \ldots, y_n) &= \text{average}\left\{ (y_1 - \theta)^2, (y_2 - \theta)^2, \ldots, (y_n - \theta)^2 \right\} \\ &= \frac{1}{n} \left((y_1 - \theta)^2 + (y_2 - \theta)^2 + \ldots + (y_n - \theta)^2 \right) \\ &= \frac{1}{n} \sum_{i = 1}^{n}(y_i - \theta)^2\\ \end{aligned} $$
創建一個 python 函數來計算損失很簡單:
```
def mse_loss(theta, y_vals):
return np.mean((y_vals - theta) ** 2)
```
讓我們看看這個損失函數是如何工作的。假設我們的數據集只包含一個點,$y_1=14$。我們可以嘗試不同的$\theta$值,看看每個值的損失函數輸出了什么。
```
# HIDDEN
def try_thetas(thetas, y_vals, xlims, loss_fn=mse_loss, figsize=(10, 7), cols=3):
if not isinstance(y_vals, np.ndarray):
y_vals = np.array(y_vals)
rows = int(np.ceil(len(thetas) / cols))
plt.figure(figsize=figsize)
for i, theta in enumerate(thetas):
ax = plt.subplot(rows, cols, i + 1)
sns.rugplot(y_vals, height=0.1, ax=ax)
plt.axvline(theta, linestyle='--',
label=rf'$ \theta = {theta} $')
plt.title(f'Loss = {loss_fn(theta, y_vals):.2f}')
plt.xlim(*xlims)
plt.yticks([])
plt.legend()
plt.tight_layout()
try_thetas(thetas=[11, 12, 13, 14, 15, 16],
y_vals=[14], xlims=(10, 17))
```

您還可以交互地嘗試下面的不同值$\theta$。你應該理解為什么$theta=11$的損失比$theta=13$的損失高很多倍。
```
# HIDDEN
def try_thetas_interact(theta, y_vals, xlims, loss_fn=mse_loss):
if not isinstance(y_vals, np.ndarray):
y_vals = np.array(y_vals)
plt.figure(figsize=(4, 3))
sns.rugplot(y_vals, height=0.1)
plt.axvline(theta, linestyle='--')
plt.xlim(*xlims)
plt.yticks([])
print(f'Loss for theta = {theta}: {loss_fn(theta, y_vals):.2f}')
def mse_interact(theta, y_vals, xlims):
plot = interactive(try_thetas_interact, theta=theta,
y_vals=fixed(y_vals), xlims=fixed(xlims),
loss_fn=fixed(mse_loss))
plot.children[-1].layout.height = '240px'
return plot
mse_interact(theta=(11, 16, 0.5), y_vals=[14], xlims=(10, 17))
```
<button class="js-nbinteract-widget">Loading widgets...</button>
正如我們所希望的那樣,我們的損失更大,因為$\theta$離我們的數據越遠,當$\theta$正好落在我們的數據點上時,損失就越小。現在讓我們來看看當我們有五個點而不是一個點時,我們的均方誤差是如何表現的。我們這次的數據是:$[11,12,15,17,18]$。
```
# HIDDEN
try_thetas(thetas=[12, 13, 14, 15, 16, 17],
y_vals=[11, 12, 15, 17, 18],
xlims=(10.5, 18.5))
```

在我們嘗試的$Theta$值中,$Theta=15$的損失最小。但是,14 到 15 之間的$theta$的值可能比$theta=15$的損失更低。看看你能不能用下面的互動圖找到一個更好的值$\theta$。
```
# HIDDEN
mse_interact(theta=(12, 17, 0.2),
y_vals=[11, 12, 15, 17, 18],
xlims=(10.5, 18.5))
```
<button class="js-nbinteract-widget">Loading widgets...</button>
平均平方誤差似乎是通過懲罰遠離數據中心的$\theta$值來完成的。現在讓我們看看損失函數在原始的 Tip 百分比數據集上輸出了什么。作為參考,尖端百分比的原始分布如下所示:
```
# HIDDEN
sns.distplot(tips['pcttip'], bins=np.arange(30), rug=True)
plt.xlim(0, 30)
plt.xlabel('Percent Tip Amount')
plt.ylabel('Proportion per Percent');
```

讓我們嘗試一些值為$\theta$。
```
# HIDDEN
try_thetas(thetas=np.arange(14.5, 17.1, 0.5),
y_vals=tips['pcttip'],
xlims=(0, 30))
```

和以前一樣,我們創建了一個交互式小部件來測試不同的$theta$值。
```
# HIDDEN
mse_interact(theta=(13, 17, 0.25),
y_vals=tips['pcttip'],
xlims=(0, 30))
```
<button class="js-nbinteract-widget">Loading widgets...</button>
到目前為止,我們已經嘗試過的最低價是 16.00 美元,略高于我們最初估計的 15%小費。
### 速記本
我們定義了第一個損失函數,均方誤差(mse)。它計算出遠離數據中心的$theta$值的高損失。數學上,該損失函數定義為:
$$ \begin{aligned} L(\theta, y_1, y_2, \ldots, y_n) &= \frac{1}{n} \sum_{i = 1}^{n}(y_i - \theta)^2\\ \end{aligned} $$
當我們更改$theta$或$y_1,y_2,ldots,y_n$時,loss 函數將計算不同的損失。當我們嘗試不同的$theta$值和添加新的數據點(更改$y_1,y_2,ldots,y_n$)時,我們已經看到了這種情況。
簡而言之,我們可以定義向量$\textbf y=[y_1,y_2,ldots,y_n]$。然后,我們可以將 mse 寫為:
$$ \begin{aligned} L(\theta, \textbf{y}) &= \frac{1}{n} \sum_{i = 1}^{n}(y_i - \theta)^2\\ \end{aligned} $$
### 最大限度地減少損失
到目前為止,我們只需嘗試一系列的價值,然后選擇損失最小的價值,就可以找到\theta$的最佳價值。該方法雖然運行良好,但利用損失函數的性質可以找到一種較好的方法。
對于以下示例,我們使用一個包含五個點的數據集:$\textbf y=[11、12、15、16、17]$。
```
# HIDDEN
try_thetas(thetas=[12, 13, 14, 15, 16, 17],
y_vals=[11, 12, 15, 17, 18],
xlims=(10.5, 18.5))
```

在上面的圖中,我們使用了 12 到 17 之間的整數$\theta$值。當我們改變$theta$時,損失似乎開始很高(在 10.92),減少到$theta=15$,然后再次增加。我們可以看到損失隨著$theta$的變化而變化,所以讓我們制作一個圖,將我們嘗試的六個$theta$中的每一個的損失與$theta$進行比較。
```
# HIDDEN
thetas = np.array([12, 13, 14, 15, 16, 17])
y_vals = np.array([11, 12, 15, 17, 18])
losses = [mse_loss(theta, y_vals) for theta in thetas]
plt.scatter(thetas, losses)
plt.title(r'Loss vs. $ \theta $ when $\bf{y}$$ = [11, 12, 15, 17, 18] $')
plt.xlabel(r'$ \theta $ Values')
plt.ylabel('Loss');
```

散點圖顯示了我們以前注意到的向下,然后向上的趨勢。我們可以嘗試更多的$theta$值,以查看一條完整的曲線,該曲線顯示損失如何隨著$theta$的變化而變化。
```
# HIDDEN
thetas = np.arange(12, 17.1, 0.05)
y_vals = np.array([11, 12, 15, 17, 18])
losses = [mse_loss(theta, y_vals) for theta in thetas]
plt.plot(thetas, losses)
plt.title(r'Loss vs. $ \theta $ when $\bf{y}$$ = [11, 12, 15, 17, 18] $')
plt.xlabel(r'$ \theta $ Values')
plt.ylabel('Loss');
```

上面的圖顯示,事實上,$\theta=15$不是最佳選擇;14 到 15 之間的$\theta$損失會更低。我們可以用微積分來精確地找到$\theta$的最小值。在最小損失下,損失函數相對于$\theta$的導數為 0。
首先,我們從損失函數開始:
$$ \begin{aligned} L(\theta, \textbf{y}) &= \frac{1}{n} \sum_{i = 1}^{n}(y_i - \theta)^2\\ \end{aligned} $$
接下來,我們插入點$\textbf y=[11,12,15,17,18]$:
$$ \begin{aligned} L(\theta, \textbf{y}) &= \frac{1}{5} \big((11 - \theta)^2 + (12 - \theta)^2 + (15 - \theta)^2 + (17 - \theta)^2 + (18 - \theta)^2 \big)\\ \end{aligned} $$
為了找到將此函數最小化的$\theta$值,我們計算了與$\theta$相關的導數:
$$ \begin{aligned} \frac{\partial}{\partial \theta} L(\theta, \textbf{y}) &= \frac{1}{5} \big(-2(11 - \theta) - 2(12 - \theta) - 2(15 - \theta) - 2(17 - \theta) -2(18 - \theta) \big)\\ &= \frac{1}{5} \big(10 \cdot \theta - 146 \big)\\ \end{aligned} $$
然后,我們找到了$theta$的值,其中導數為零:
$$ \begin{aligned} \frac{1}{5} \big(10 \cdot \theta - 146 \big) &= 0 \\ 10 \cdot \theta - 146 &= 0 \\ \theta &= 14.6 \end{aligned} $$
我們已經找到了最小化的$\theta$,正如預期的那樣,它在 14 到 15 之間。我們表示將損失降至最低的美元。因此,對于數據集$\textbf y=[11、12、15、17、18]$和 mse loss 函數:
$$ \hat{\theta} = 14.6 $$
如果我們恰好計算數據值的平均值,我們會發現一個奇怪的等價性:
$$ \text{mean} (\textbf{y}) = \hat{\theta} = 14.6 $$
### 均方誤差最小值[?](#The-Minimizing-Value-of-the-Mean-Squared-Error)
事實證明,上述等價性不僅僅是巧合;數據值 _ 的平均值 _ 總是產生$\hat \theta$,而$\theta$則使 MSE 損失最小化。
為了證明這一點,我們再次求出損失函數的導數。我們沒有插入點,而是保留$y_i$術語的完整性,以便推廣到其他數據集。
$$ \begin{aligned} L(\theta, \textbf{y}) &= \frac{1}{n} \sum_{i = 1}^{n}(y_i - \theta)^2\\ \frac{\partial}{\partial \theta} L(\theta, \textbf{y}) &= \frac{1}{n} \sum_{i = 1}^{n} -2(y_i - \theta) \\ &= -\frac{2}{n} \sum_{i = 1}^{n} (y_i - \theta) \\ \end{aligned} $$
由于我們沒有用特定的值替換$Y_i$,所以這個公式可以與任何具有任意點數的數據集一起使用。
現在,我們將導數設為零,然后求出$\theta$以找到$\theta$的最小值,如下所示:
$$ \begin{aligned} -\frac{2}{n} \sum_{i = 1}^{n} (y_i - \theta) &= 0 \\ \sum_{i = 1}^{n} (y_i - \theta) &= 0 \\ \sum_{i = 1}^{n} y_i - \sum_{i = 1}^{n} \theta &= 0 \\ \sum_{i = 1}^{n} \theta &= \sum_{i = 1}^{n} y_i \\ n \cdot \theta &= y_1 + \ldots + y_n \\ \theta &= \frac{y_1 + \ldots + y_n}{n} \\ \hat \theta = \theta &= \text{mean} (\textbf{y}) \end{aligned} $$
你看,我們看到有一個單獨的$theta$值,不管數據集是什么,它都會給出最小的毫秒。對于均方誤差,我們知道$\hat \theta$是數據集值的平均值。
### 返回到原始數據集[?](#Back-to-the-Original-Dataset)
我們不再像以前那樣測試不同的$theta$值。我們可以一次計算平均小費百分比:
```
np.mean(tips['pcttip'])
```
```
16.080258172250463
```
```
# HIDDEN
sns.distplot(tips['pcttip'], bins=np.arange(30), rug=True)
plt.axvline(x=16.08, c='darkblue', linestyle='--', label=r'$ \hat \theta = 16.08$')
plt.legend()
plt.xlim(0, 30)
plt.title('Distribution of tip percent')
plt.xlabel('Percent Tip Amount')
plt.ylabel('Proportion per Percent');
```

### 摘要[?](#Summary)
我們引入了一個**常量模型**,這個模型為數據集中的所有條目輸出相同的數字。
**損失函數**$L(\theta、\textbf y)$測量給定值$\theta$與數據的匹配程度。在本節中,我們介紹了均方誤差損失函數,并證明了對于常數模型,$hat \theta=\text mean(\textbf y)$的值。
我們在本節中采取的步驟適用于許多建模場景:
1. 選擇一個模型。
2. 選擇損失函數。
3. 通過最小化損失來擬合模型。
在本書中,我們所有的建模技術都擴展到這些步驟中的一個或多個。我們介紹了新的模型(1)、新的損失函數(2)和減少損失的新技術(3)。
- 一、數據科學的生命周期
- 二、數據生成
- 三、處理表格數據
- 四、數據清理
- 五、探索性數據分析
- 六、數據可視化
- Web 技術
- 超文本傳輸協議
- 處理文本
- python 字符串方法
- 正則表達式
- regex 和 python
- 關系數據庫和 SQL
- 關系模型
- SQL
- SQL 連接
- 建模與估計
- 模型
- 損失函數
- 絕對損失和 Huber 損失
- 梯度下降與數值優化
- 使用程序最小化損失
- 梯度下降
- 凸性
- 隨機梯度下降法
- 概率與泛化
- 隨機變量
- 期望和方差
- 風險
- 線性模型
- 預測小費金額
- 用梯度下降擬合線性模型
- 多元線性回歸
- 最小二乘-幾何透視
- 線性回歸案例研究
- 特征工程
- 沃爾瑪數據集
- 預測冰淇淋評級
- 偏方差權衡
- 風險和損失最小化
- 模型偏差和方差
- 交叉驗證
- 正規化
- 正則化直覺
- L2 正則化:嶺回歸
- L1 正則化:LASSO 回歸
- 分類
- 概率回歸
- Logistic 模型
- Logistic 模型的損失函數
- 使用邏輯回歸
- 經驗概率分布的近似
- 擬合 Logistic 模型
- 評估 Logistic 模型
- 多類分類
- 統計推斷
- 假設檢驗和置信區間
- 置換檢驗
- 線性回歸的自舉(真系數的推斷)
- 學生化自舉
- P-HACKING
- 向量空間回顧
- 參考表
- Pandas
- Seaborn
- Matplotlib
- Scikit Learn