# 十三、預測
> 原文:[Prediction](https://github.com/data-8/textbook/tree/gh-pages/chapters/13)
> 譯者:[飛龍](https://github.com/wizardforcel)
> 協議:[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/)
> 自豪地采用[谷歌翻譯](https://translate.google.cn/)
數據科學的一個重要方面,是發現數據可以告訴我們什么未來的事情。氣候和污染的數據說了幾十年內溫度的什么事情?根據一個人的互聯網個人信息,哪些網站可能會讓他感興趣?病人的病史如何用來判斷他或她對治療的反應?
為了回答這樣的問題,數據科學家已經開發出了預測的方法。在本章中,我們將研究一種最常用的方法,基于一個變量的值來預測另一個變量。
方法的基礎由弗朗西斯·高爾頓爵士(Sir Francis Galton)奠定。我們在 7.1 節看到,高爾頓研究了身體特征是如何從一代傳到下一代的。他最著名的工作之一,是根據父母的高度預測子女的身高。我們已經研究了高爾頓為此收集的數據集。`heights `表包含了 934 個成年子女的雙親身高和子女身高(全部以英寸為單位)。
```py
# Galton's data on heights of parents and their adult children
galton = Table.read_table('galton.csv')
heights = Table().with_columns(
'MidParent', galton.column('midparentHeight'),
'Child', galton.column('childHeight')
)
heights
```
| MidParent | Child |
| --- | --- |
| 75.43 | 73.2 |
| 75.43 | 69.2 |
| 75.43 | 69 |
| 75.43 | 69 |
| 73.66 | 73.5 |
| 73.66 | 72.5 |
| 73.66 | 65.5 |
| 73.66 | 65.5 |
| 72.06 | 71 |
| 72.06 | 68 |
(省略了 924 行)
```py
heights.scatter('MidParent')
```

收集數據的主要原因是能夠預測成年子女的身高,他們的父母與數據集中相似。 在注意到兩個變量之間的正相關之后,我們在第 7.1 節中做了這些預測。
我們的方法是,基于新人的雙親身高周圍的所有點來做預測。 為此,我們編寫了一個名為`predict_child`的函數,該函數以雙親身高作為參數,并返回雙親身高在半英寸之內的,所有子女的平均身高。
```py
def predict_child(mpht):
"""Return a prediction of the height of a child
whose parents have a midparent height of mpht.
The prediction is the average height of the children
whose midparent height is in the range mpht plus or minus 0.5 inches.
"""
close_points = heights.where('MidParent', are.between(mpht-0.5, mpht + 0.5))
return close_points.column('Child').mean()
```
我們將函數應用于`Midparent`列,可視化我們的結果。
```py
# Apply predict_child to all the midparent heights
heights_with_predictions = heights.with_column(
'Prediction', heights.apply(predict_child, 'MidParent')
)
# Draw the original scatter plot along with the predicted values
heights_with_predictions.scatter('MidParent')
```

給定雙親身高的預測值,大致位于給定身高處的垂直條形的中心。這種預測方法稱為回歸。 本章后面我們會看到這個術語的來源。 我們也會看到,我們是否可以避免將“接近”任意定義為“在半英寸之內”。 但是首先我們要開發一個可用于很多環境的方法,來決定一個變量作為另一個變量的預測值有多好。
## 相關性
在本節中,我們將開發一種度量,度量散點圖緊密聚集在一條直線上的程度。 形式上,這被稱為測量線性關聯。
`hybrid`表包含了 1997 年到 2013 年在美國銷售的混合動力車的數據。數據來自佛羅里達大學 [Larry Winner 教授](http://www.stat.ufl.edu/~winner/)的在線數據檔案。這些列為:
+ `vehicle`:車的型號
+ `year`:出廠年份
+ `msrp`: 2013 年制造商的建議零售價(美元)
+ `acceleration`: 加速度(千米每小時每秒)
+ `mpg`: 燃油效率(英里每加侖)
+ `class`: 型號的類別
(省略了 143 行)
下圖是`msrp`與`acceleration`的散點圖。 這意味著`msrp`繪制在縱軸上并且`acceleration`在橫軸上。
```py
hybrid.scatter('acceleration', 'msrp')
```

注意正相關。 散點圖傾斜向上,表明加速度較大的車輛通常成本更高;相反,價格更高的汽車通常具有更大的加速。
`msrp`與`mpg`的散點圖表明了負相關。 `mpg`較高的混合動力車往往成本較低。 這似乎令人驚訝,直到你明白了,加速更快的汽車往往燃油效率更低,行駛里程更低。 之前的散點圖顯示,這些也是價格更高的車型。
```py
hybrid.scatter('mpg', 'msrp')
```

除了負相關,價格與效率的散點圖顯示了兩個變量之間的非線性關系。 這些點似乎圍繞在一條曲線周圍,而不是一條直線。
但是,如果我們只將數據限制在 SUV 類別中,價格和效率之間仍然負相關的,但是這種關系似乎更為線性。 SUV 價格與加速度之間的關系也呈線性趨勢,但是斜率是正的。
```py
suv = hybrid.where('class', 'SUV')
suv.scatter('mpg', 'msrp')
```

```py
suv.scatter('acceleration', 'msrp')
```

你會注意到,即使不關注變量被測量的單位,我們也可以從散點圖的大體方向和形狀中得到有用的信息。
事實上,我們可以將所有的變量繪制成標準單位,并且繪圖看起來是一樣的。 這給了我們一個方法,來比較兩個散點圖中的線性程度。
回想一下,在前面的章節中,我們定義了`standard_units`函數來將數值數組轉換為標準單位。
```py
def standard_units(any_numbers):
"Convert any array of numbers to standard units."
return (any_numbers - np.mean(any_numbers))/np.std(any_numbers)
```
我們可以使用這個函數重新繪制 SUV 的兩個散點圖,所有變量都以標準單位測量。
```py
Table().with_columns(
'mpg (standard units)', standard_units(suv.column('mpg')),
'msrp (standard units)', standard_units(suv.column('msrp'))
).scatter(0, 1)
plots.xlim(-3, 3)
plots.ylim(-3, 3);
```

```py
Table().with_columns(
'acceleration (standard units)', standard_units(suv.column('acceleration')),
'msrp (standard units)', standard_units(suv.column('msrp'))
).scatter(0, 1)
plots.xlim(-3, 3)
plots.ylim(-3, 3);
```

我們在這些數字中看到的關聯與我們之前看到的一樣。 另外,由于現在兩張散點圖的刻度完全相同,我們可以看到,第二張圖中的線性關系比第一張圖中的線性關系更加模糊。
我們現在將定義一個度量,使用標準單位來量化我們看到的這種關聯。
### 相關系數
相關系數測量兩個變量之間線性關系的強度。 在圖形上,它測量散點圖聚集在一條直線上的程度。
相關系數這個術語不容易表述,所以它通常縮寫為相關性并用`r`表示。
以下是一些關于`r`的數學事實,我們將通過模擬觀察。
+ 相關系數`r`是介于`-1`和`1`之間的數字。
+ `r`度量了散點圖圍繞一條直線聚集的程度。
+ 如果散點圖是完美的向上傾斜的直線,`r = 1`,如果散點圖是完美的向下傾斜的直線,`r = -1`。
函數`r_scatter`接受`r`值作為參數,模擬相關性非常接近`r`的散點圖。 由于模擬中的隨機性,相關性不會完全等于`r`。
調用`r_scatter`幾次,以`r`的不同值作為參數,并查看散點圖如何變化。
當`r = 1`時,散點圖是完全線性的,向上傾斜。 當`r = -1`時,散點圖是完全線性的,向下傾斜。 當`r = 0`時,散點圖是圍繞水平軸的不定形云,并且變量據說是不相關的。
```py
r_scatter(0.9)
```

```py
r_scatter(0.25)
```

```py
r_scatter(0)
```

```py
r_scatter(-0.55)
```

### 計算`r`
目前為止,`r`的公式還不清楚。 它擁有超出本課程范圍的數學基礎。 然而,你將會看到,這個計算很簡單,可以幫助我們理解`r`的幾個屬性。
`r`的公式:
`r`是兩個變量的乘積的均值,這兩個變量都以標準單位來衡量。
以下是計算中的步驟。 我們將把這些步驟應用于`x`和`y`值的簡單表格。
```py
x = np.arange(1, 7, 1)
y = make_array(2, 3, 1, 5, 2, 7)
t = Table().with_columns(
'x', x,
'y', y
)
t
```
| x | y |
| --- | --- |
| 1 | 2 |
| 2 | 3 |
| 3 | 1 |
| 4 | 5 |
| 5 | 2 |
| 6 | 7 |
根據散點圖,我們預計`r`將是正值,但不等于 1。
```py
t.scatter(0, 1, s=30, color='red')
```

第一步:將每個變量轉換為標準單位。
```py
t_su = t.with_columns(
'x (standard units)', standard_units(x),
'y (standard units)', standard_units(y)
)
t_su
```
| x | y | x (standard units) | y (standard units) |
| --- | --- | --- | --- |
| 1 | 2 | -1.46385 | -0.648886 |
| 2 | 3 | -0.87831 | -0.162221 |
| 3 | 1 | -0.29277 | -1.13555 |
| 4 | 5 | 0.29277 | 0.811107 |
| 5 | 2 | 0.87831 | -0.648886 |
| 6 | 7 | 1.46385 | 1.78444 |
第二步:將每一對標準單位相乘
```py
t_product = t_su.with_column('product of standard units', t_su.column(2) * t_su.column(3))
t_product
```
| x | y | x (standard units) | y (standard units) | product of standard units |
| --- | --- | --- | --- |
| 1 | 2 | -1.46385 | -0.648886 | 0.949871 |
| 2 | 3 | -0.87831 | -0.162221 | 0.142481 |
| 3 | 1 | -0.29277 | -1.13555 | 0.332455 |
| 4 | 5 | 0.29277 | 0.811107 | 0.237468 |
| 5 | 2 | 0.87831 | -0.648886 | -0.569923 |
| 6 | 7 | 1.46385 | 1.78444 | 2.61215 |
第三步:`r`是第二步計算的乘積的均值。
```py
# r is the average of the products of standard units
r = np.mean(t_product.column(4))
r
0.61741639718977093
```
正如我們的預期,`r`是個不等于的正值。
### `r`的性質
計算結果表明:
`r`是一個純數字。 它沒有單位。 這是因為`r`基于標準單位。
`r`不受任何軸上單位的影響。 這也是因為`r`基于標準單位。
`r`不受軸的交換的影響。 在代數上,這是因為標準單位的乘積不依賴于哪個變量被稱為`x `和`y`。 在幾何上,軸的切換關于`y = x`直線翻轉了散點圖,但不會改變群聚度和關聯的符號。
```py
t.scatter('y', 'x', s=30, color='red')
```

### `correlation `函數
我們將要重復計算相關性,所以定義一個函數會有幫助,這個函數通過執行上述所有步驟來計算它。 讓我們定義一個函數`correlation `,它接受一個表格,和兩列的標簽。該函數返回`r`,它是標準單位下這些列的值的乘積的平均值。
```py
def correlation(t, x, y):
return np.mean(standard_units(t.column(x))*standard_units(t.column(y)))
```
讓我們在`t`的`x`和`y`列上調用函數。 該函數返回`x`和`y`之間的相關性的相同答案,就像直接應用`r`的公式一樣。
```py
correlation(t, 'x', 'y')
0.61741639718977093
```
我們注意到,變量被指定的順序并不重要。
```py
correlation(t, 'y', 'x')
0.61741639718977093
```
在`suv`表的列上調用`correlation`,可以使我們看到價格和效率之間的相關性,以及價格和加速度之間的相關性。
```py
correlation(suv, 'mpg', 'msrp')
-0.6667143635709919
correlation(suv, 'acceleration', 'msrp')
0.48699799279959155
```
這些數值證實了我們的觀察:
價格和效率之間存在負相關關系,而價格和加速度之間存在正相關關系。
價格和加速度之間的線性關系(相關性約為 0.5),比價格和效率之間的線性關系稍弱(相關性約為 -0.67)。
相關性是一個簡單而強大的概念,但有時會被誤用。 在使用`r`之前,重要的是要知道相關性能做和不能做什么。
### 相關不是因果
相關只衡量關聯,并不意味著因果。 盡管學區內的孩子的體重與數學能力之間的相關性可能是正的,但這并不意味著做數學會使孩子更重,或者說增加體重會提高孩子的數學能力。 年齡是一個使人混淆的變量:平均來說,較大的孩子比較小的孩子更重,數學能力更好。
### 相關性度量線性關聯
相關性只測量一種關聯 - 線性關聯。 具有較強非線性關聯的變量可能具有非常低的相關性。 這里有一個變量的例子,它具有完美的二次關聯`y = x ^ 2`,但是相關性等于 0。
```py
new_x = np.arange(-4, 4.1, 0.5)
nonlinear = Table().with_columns(
'x', new_x,
'y', new_x**2
)
nonlinear.scatter('x', 'y', s=30, color='r')
```

```py
correlation(nonlinear, 'x', 'y')
0.0
```
### 相關性受到離群點影響
離群點可能對相關性有很大的影響。 下面是一個例子,其中通過增加一個離群點,`r`等于 1 的散點圖變成`r`等于 0 的圖。
```py
line = Table().with_columns(
'x', make_array(1, 2, 3, 4),
'y', make_array(1, 2, 3, 4)
)
line.scatter('x', 'y', s=30, color='r')
```

```py
correlation(line, 'x', 'y')
1.0
outlier = Table().with_columns(
'x', make_array(1, 2, 3, 4, 5),
'y', make_array(1, 2, 3, 4, 0)
)
outlier.scatter('x', 'y', s=30, color='r')
```

```py
correlation(outlier, 'x', 'y')
0.0
```
### 生態相關性應謹慎解讀
基于匯總數據的相關性可能會產生誤導。 作為一個例子,這里是 2014 年 SAT 批判性閱讀和數學成績的數據。50 個州和華盛頓特區各有一個點。`Participation Rate`列包含參加考試的高中學生的百分比。 接下來的三列顯示了每個州的測試每個部分的平均得分,最后一列是測試總得分的平均值。
```py
sat2014 = Table.read_table('sat2014.csv').sort('State')
sat2014
```
| State | Participation Rate | Critical Reading | Math | Writing | Combined |
| --- | --- | --- | --- | --- | --- |
| Alabama | 6.7 | 547 | 538 | 532 | 1617 |
| Alaska | 54.2 | 507 | 503 | 475 | 1485 |
| Arizona | 36.4 | 522 | 525 | 500 | 1547 |
| Arkansas | 4.2 | 573 | 571 | 554 | 1698 |
| California | 60.3 | 498 | 510 | 496 | 1504 |
| Colorado | 14.3 | 582 | 586 | 567 | 1735 |
| Connecticut | 88.4 | 507 | 510 | 508 | 1525 |
| Delaware | 100 | 456 | 459 | 444 | 1359 |
| District of Columbia | 100 | 440 | 438 | 431 | 1309 |
| Florida | 72.2 | 491 | 485 | 472 | 1448 |
(省略了 41 行)
數學得分與批判性閱讀得分的散點圖緊密聚集在一條直線上; 相關性接近 0.985。
```py
sat2014.scatter('Critical Reading', 'Math')
```

```py
correlation(sat2014, 'Critical Reading', 'Math')
0.98475584110674341
```
這是個非常高的相關性。但重要的是要注意,這并不能反映學生的數學和批判性閱讀得分之間的關系強度。
數據由每個州的平均分數組成。但是各州不參加考試 - 而是學生。表中的數據通過將每個州的所有學生聚集為(這個州里面的兩個變量的均值處的)單個點而創建。但并不是所有州的學生都會在這個位置,因為學生的表現各不相同。如果你為每個學生繪制一個點,而不是每個州一個點,那么在上圖中的每個點周圍都會有一圈云狀的點。整體畫面會更模糊。學生的數學和批判性閱讀得分之間的相關性,將低于基于州均值計算的數值。
基于聚合和均值的相關性被稱為生態相關性,并且經常用于報告。正如我們剛剛所看到的,他們必須謹慎解讀。
### 嚴重還是開玩笑?
2012 年,在著名的《新英格蘭醫學雜志》(New England Journal of Medicine)上發表的一篇論文,研究了一組國家巧克力消費與的諾貝爾獎之間的關系。《科學美國人》(Scientific American)嚴肅地做出回應,而其他人更加輕松。 歡迎你自行決定!下面的圖表應該讓你有興趣去看看。

## 回歸直線
相關系數`r`并不只是測量散點圖中的點聚集在一條直線上的程度。 它也有助于確定點聚集的直線。 在這一節中,我們將追溯高爾頓和皮爾遜發現這條直線的路線。
高爾頓的父母及其成年子女身高的數據顯示出線性關系。 當我們基于雙親身高的子女身高的預測大致沿著直線時,就證實了線性。
```py
galton = Table.read_table('galton.csv')
heights = Table().with_columns(
'MidParent', galton.column('midparentHeight'),
'Child', galton.column('childHeight')
)
def predict_child(mpht):
"""Return a prediction of the height of a child
whose parents have a midparent height of mpht.
The prediction is the average height of the children
whose midparent height is in the range mpht plus or minus 0.5 inches.
"""
close_points = heights.where('MidParent', are.between(mpht-0.5, mpht + 0.5))
return close_points.column('Child').mean()
heights_with_predictions = heights.with_column(
'Prediction', heights.apply(predict_child, 'MidParent')
)
heights_with_predictions.scatter('MidParent')
```

### 標準單位下的度量
讓我們看看,我們是否能找到一個方法來確定這條線。 首先,注意到線性關聯不依賴于度量單位 - 我們也可以用標準單位來衡量這兩個變量。
```py
def standard_units(xyz):
"Convert any array of numbers to standard units."
return (xyz - np.mean(xyz))/np.std(xyz)
heights_SU = Table().with_columns(
'MidParent SU', standard_units(heights.column('MidParent')),
'Child SU', standard_units(heights.column('Child'))
)
heights_SU
```
| MidParent SU | Child SU |
| --- | --- |
| 3.45465 | 1.80416 |
| 3.45465 | 0.686005 |
| 3.45465 | 0.630097 |
| 3.45465 | 0.630097 |
| 2.47209 | 1.88802 |
| 2.47209 | 1.60848 |
| 2.47209 | -0.348285 |
| 2.47209 | -0.348285 |
| 1.58389 | 1.18917 |
| 1.58389 | 0.350559 |
(省略了 924 行)
在這個刻度上,我們可以像以前一樣精確地計算我們的預測。 但是首先我們必須弄清楚,如何將“接近”的點的舊定義轉換為新的刻度上的一個值。 我們曾經說過,如果雙親高度在 0.5 英寸之內,它們就是“接近”的。 由于標準單位以標準差為單位測量距離,所以我們必須計算出,0.5 英寸是多少個雙親身高的標準差。
雙親身高的標準差約為 1.8 英寸。 所以 0.5 英寸約為 0.28 個標準差。
```py
sd_midparent = np.std(heights.column(0))
sd_midparent
1.8014050969207571
0.5/sd_midparent
0.27756111096536701
```
現在我們準備修改我們的預測函數,來預測標準單位。 所有改變的是,我們正在使用標準單位的值的表格,并定義如上所述的“接近”。
```py
def predict_child_su(mpht_su):
"""Return a prediction of the height (in standard units) of a child
whose parents have a midparent height of mpht_su in standard units.
"""
close = 0.5/sd_midparent
close_points = heights_SU.where('MidParent SU', are.between(mpht_su-close, mpht_su + close))
return close_points.column('Child SU').mean()
heights_with_su_predictions = heights_SU.with_column(
'Prediction SU', heights_SU.apply(predict_child_su, 'MidParent SU')
)
heights_with_su_predictions.scatter('MidParent SU')
```

這個繪圖看起來就像在原始刻度上繪圖。 只改變了軸上的數字。 這證實了我們可以通過在標準單位下工作,來理解預測過程。
### 確定標準單位下的直線
高爾頓的散點圖形狀是個橄欖球 - 就是說,像橄欖球一樣大致橢圓形。不是所有的散點圖都是橄欖形的,甚至那些線性關聯的也不都是。但在這一節中,我們假裝我們是高爾頓,只能處理橄欖形的散點圖。在下一節中,我們將把我們的分析推廣到其他形狀的繪圖。
這里是一個橄欖形散點圖,兩個變量以標準單位測量。 45 度線顯示為紅色。

但是 45 度線不是經過垂直條形的中心的線。你可以看到在下圖中,1.5 個標準單位的垂直線顯示為黑色。藍線附近的散點圖上的點的高度都大致在 -2 到 3 的范圍內。紅線太高,無法命中中心。

所以 45 度線不是“均值圖”。該線是下面顯示的綠線。

兩條線都經過原點`(0,0)`。綠線穿過垂直條形的中心(至少大概),比紅色的 45 度線平坦。
45 度線的斜率為 1。所以綠色的“均值圖”直線的斜率是正值但小于 1。
這可能是什么值呢?你猜對了 - 這是`r`。
### 標準單位下的回歸直線
綠色的“均值圖”線被稱為回歸直線,我們將很快解釋原因。 但首先,讓我們模擬一些`r`值不同的橄欖形散點圖,看看直線是如何變化的。 在每種情況中,繪制紅色 45 度線作比較。
執行模擬的函數為`regression_line`,并以`r`為參數。
```py
regression_line(0.95)
```

```py
regression_line(0.6)
```

當`r`接近于 1 時,散點圖,45 度線和回歸線都非常接近。 但是對于`r`較低值來說,回歸線顯然更平坦。
### 回歸效應
就預測而言,這意味著,對于雙親身高為 1.5 個標準單位的家長來說,我們對女子身高的預測要稍低于 1.5 個標準單位。如果雙親高度是 2 個標準單位,我們對子女身高的預測,會比 2 個標準單位少一些。
換句話說,我們預測,子女會比父母更接近均值。
弗朗西斯·高爾頓爵士就不高興了。他一直希望,特別高的父母會有特別高的子女。然而,數據是清楚的,高爾頓意識到,高個子父母通常擁有并不是特別高的子女。高爾頓沮喪地將這種現象稱為“回歸平庸”。
高爾頓還注意到,特別矮的父母通常擁有相對于他們這一代高一些的子女。一般來說,一個變量的平均值遠遠低于另一個變量的平均值。這被稱為回歸效應。
### 回歸直線的方程
在回歸中,我們使用一個變量(我們稱`x`)的值來預測另一個變量的值(我們稱之為`y`)。 當變量`x`和`y`以標準單位測量時,基于`x`預測`y`的回歸線斜率為`r`并通過原點。 因此,回歸線的方程可寫為:

在數據的原始單位下,就變成了:

原始單位的回歸線的斜率和截距可以從上圖中導出。


下面的三個函數計算相關性,斜率和截距。 它們都有三個參數:表的名稱,包含`x`的列的標簽以及包含`y`的列的標簽。
```py
def correlation(t, label_x, label_y):
return np.mean(standard_units(t.column(label_x))*standard_units(t.column(label_y)))
def slope(t, label_x, label_y):
r = correlation(t, label_x, label_y)
return r*np.std(t.column(label_y))/np.std(t.column(label_x))
def intercept(t, label_x, label_y):
return np.mean(t.column(label_y)) - slope(t, label_x, label_y)*np.mean(t.column(label_x))
```
### 回歸直線和高爾頓的數據
雙親身高和子女身高之間的相關性是 0.32:
```py
galton_r = correlation(heights, 'MidParent', 'Child')
galton_r
0.32094989606395924
```
我們也可以找到回歸直線的方程,來基于雙親身高預測子女身高:
```py
galton_slope = slope(heights, 'MidParent', 'Child')
galton_intercept = intercept(heights, 'MidParent', 'Child')
galton_slope, galton_intercept
(0.63736089696947895, 22.636240549589751)
```
回歸直線的方程是:

這也成為回歸方程。回歸方程的主要用途是根據`x`預測`y`。
例如,對于 70.48 英寸的雙親身高,回歸直線預測,子女身高為 67.56 英寸。
```py
galton_slope*70.48 + galton_intercept
67.557436567998622
```
我們最初的預測,通過計算雙親身高接近 70.48 的所有子女的平均身高來完成,這個預測非常接近:67.63 英寸,而回歸線的預測是 67.55 英寸。
```py
heights_with_predictions.where('MidParent', are.equal_to(70.48)).show(3)
```
| MidParent | Child | Prediction |
| --- | --- | --- |
| 70.48 | 74 | 67.6342 |
| 70.48 | 70 | 67.6342 |
| 70.48 | 68 | 67.6342 |
(省略了 5 行)
這里是高爾頓的表格的所有行,我們的原始預測,以及子女身高的回歸預測。
```py
heights_with_predictions = heights_with_predictions.with_column(
'Regression Prediction', galton_slope*heights.column('MidParent') + galton_intercept
)
heights_with_predictions
```
| MidParent | Child | Prediction | Regression Prediction |
| --- | --- | --- | --- |
| 75.43 | 73.2 | 70.1 | 70.7124 |
| 75.43 | 69.2 | 70.1 | 70.7124 |
| 75.43 | 69 | 70.1 | 70.7124 |
| 75.43 | 69 | 70.1 | 70.7124 |
| 73.66 | 73.5 | 70.4158 | 69.5842 |
| 73.66 | 72.5 | 70.4158 | 69.5842 |
| 73.66 | 65.5 | 70.4158 | 69.5842 |
| 73.66 | 65.5 | 70.4158 | 69.5842 |
| 72.06 | 71 | 68.5025 | 68.5645 |
| 72.06 | 68 | 68.5025 | 68.5645 |
(省略了 924 行)
```py
heights_with_predictions.scatter('MidParent')
```

灰色圓點顯示回歸預測,全部在回歸線上。 注意這條線與均值的金色圖非常接近。 對于這些數據,回歸線很好地逼近垂直條形的中心。
### 擬合值
所有的預測值都在直線上,被稱為“擬合值”。 函數`fit`使用表名和`x`和`y`的標簽,并返回一個擬合值數組,散點圖中每個點一個。
```py
def fit(table, x, y):
"""Return the height of the regression line at each x value."""
a = slope(table, x, y)
b = intercept(table, x, y)
return a * table.column(x) + b
```
下圖比上圖更輕易看到直線:
```py
heights.with_column('Fitted', fit(heights, 'MidParent', 'Child')).scatter('MidParent')
```

另一個繪制直線的方式是在表方法`scatter`中,使用選項`fit_line=True`。
```py
heights.scatter('MidParent', fit_line=True)
```

### 斜率的測量單位
斜率是一個比值,值得花點時間來研究它的測量單位。 我們的例子來自熟悉的醫院系統中產婦的數據集。 孕期體重與高度的散點圖看起來像是一個橄欖球,已經在一場比賽中使用了很多次,但足夠接近橄欖球,我們可以讓我們的擬合直線穿過它來證明。 在后面的章節中,我們將看到如何使這種證明更正式。
```py
baby = Table.read_table('baby.csv')
baby.scatter('Maternal Height', 'Maternal Pregnancy Weight', fit_line=True)
```

```py
slope(baby, 'Maternal Height', 'Maternal Pregnancy Weight')
3.5728462592750558
```
回歸線的斜率是 3.57 磅每英寸。 這意味著,對于身高相差 1 英寸的兩名女性來說,我們對孕期體重的預測相差 3.57 磅。 對于身高相差 2 英寸的女性,我們預測的孕期體重相差`2 * 3.57 ~= 7.14`磅。
請注意,散點圖中的連續垂直條形相距 1 英寸,因為高度已經舍入到最近的英寸。 另一種考慮斜率的方法是取兩個相連的條形(相隔 1 英寸),相當于兩組身高相差 1 英寸的女性。 3.57 磅每英寸的斜率意味著,較高組的平均孕期體重比較矮組多大約 3.57 磅。
### 示例
假設我們的目標是使用回歸,基于巴塞特獵犬的體重來估計它的身高,所用的樣本與回歸模型看起來一致。 假設觀察到的相關性`r`為 0.5,并且這兩個變量的匯總統計量如下表所示:
| | average | SD |
| --- | --- | --- |
| height | 14 inches | 2 inches |
| weight | 50 pounds | 5 pounds |
為了計算回歸線的方程,我們需要斜率和截距。


回歸線的方程允許我們,根據給定重量(磅)計算估計高度(英寸):

線的斜率衡量隨著重量的單位增長的估計高度的增長。 斜率是正值,重要的是要注意,這并不表示我們認為,如果體重增加巴塞特獵狗就會變得更高。 斜率反映了兩組狗的平均身高的差異,這兩組狗的體重相差 1 磅。 具體來說,考慮一組重量為`w`磅,以及另一組重量為`w + 1`磅的狗。 我們估計,第二組的均值高出 0.2 英寸。 對于樣本中的所有`w`值都是如此。
一般來說,回歸線的斜率可以解釋為隨著`x`單位增長的`y`平均增長。 請注意,如果斜率為負值,那么對于`x`的每單位增長,`y`的平均值會減少。
### 尾注
即使我們沒有建立回歸方程的數學基礎,我們可以看到,當散點圖是橄欖形的時候,它會給出相當好的預測。 這是一個令人驚訝的數學事實,無論散點圖的形狀如何,同一個方程給出所有直線中的“最好”的預測。 這是下一節的主題。
## 最小二乘法
我們已經回溯了高爾頓和皮爾森用于開發回歸線方程的步驟,它穿過橄欖形的散點圖。但不是所有的散點圖都是橄欖形的,甚至不是線性的。每個散點圖都有一個“最優”直線嗎?如果是這樣,我們仍然可以使用上一節中開發的斜率和截距公式,還是需要新的公式?
為了解決這些問題,我們需要一個“最優”的合理定義。回想一下,這條線的目的是預測或估計`y`的值,在給定`x`值的情況下。估計通常不是完美的。每個值都由于誤差而偏離真正的值。“最優”直線的合理標準是,它在所有直線中總體誤差盡可能最小。
在本節中,我們將精確確定這個標準,看看我們能否確定標準下的最優直線。
我們的第一個例子是小說《小女人》數據集,每章都有一行。目標是根據句子數來估計字符數(即字母,空格標點符號等等)。回想一下,我們在本課程的第一堂課中試圖實現它。
```py
little_women = Table.read_table('little_women.csv')
little_women = little_women.move_to_start('Periods')
little_women.show(3)
```
| Periods | Characters |
| --- | --- |
| 189 | 21759 |
| 188 | 22148 |
| 231 | 20558 |
(省略了 44 行)
```py
little_women.scatter('Periods', 'Characters')
```

為了探索數據,我們將需要使用上一節定義的函數`correlation`,`slope`,`intercept`和`fit `。
```py
correlation(little_women, 'Periods', 'Characters')
0.92295768958548163
```
散點圖明顯接近線性,相關性大于 0.92。
### 估計中的誤差
下圖顯示了我們在上一節中開發的散點圖和直線。 我們還不知道這是否是所有直線中最優的。 我們首先必須準確表達“最優”的意思。
```py
lw_with_predictions = little_women.with_column('Linear Prediction', fit(little_women, 'Periods', 'Characters'))
lw_with_predictions.scatter('Periods')
```

對應于散點圖上的每個點,預測的誤差是計算為實際值減去預測值。 它是點與直線之間的垂直距離,如果點在線之下,則為負值。
```py
actual = lw_with_predictions.column('Characters')
predicted = lw_with_predictions.column('Linear Prediction')
errors = actual - predicted
lw_with_predictions.with_column('Error', errors)
```
| Periods | Characters | Linear Prediction | Error |
| --- | --- | --- | --- |
| 189 | 21759 | 21183.6 | 575.403 |
| 188 | 22148 | 21096.6 | 1051.38 |
| 231 | 20558 | 24836.7 | -4278.67 |
| 195 | 25526 | 21705.5 | 3820.54 |
| 255 | 23395 | 26924.1 | -3529.13 |
| 140 | 14622 | 16921.7 | -2299.68 |
| 131 | 14431 | 16138.9 | -1707.88 |
| 214 | 22476 | 23358 | -882.043 |
| 337 | 33767 | 34056.3 | -289.317 |
| 185 | 18508 | 20835.7 | -2327.69 |
(省略了 37 行)
我們可以使用`slope `和`intercept`來計算擬合直線的斜率和截距。 下圖顯示了該直線(淺藍色)。 對應于四個點的誤差以紅色顯示。 這四個點沒什么特別的。 他們只是為了展示的清晰而被選中。 函數`lw_errors`以斜率和截距(按照該順序)作為參數,并繪制該圖形。
```py
lw_reg_slope = slope(little_women, 'Periods', 'Characters')
lw_reg_intercept = intercept(little_women, 'Periods', 'Characters')
print('Slope of Regression Line: ', np.round(lw_reg_slope), 'characters per period')
print('Intercept of Regression Line:', np.round(lw_reg_intercept), 'characters')
lw_errors(lw_reg_slope, lw_reg_intercept)
Slope of Regression Line: 87.0 characters per period
Intercept of Regression Line: 4745.0 characters
```

如果我們用不同的線來創建我們的估計,誤差將會不同。 下面的圖表顯示了如果我們使用另一條線進行估算,誤差會有多大。 第二張圖顯示了通過使用完全愚蠢的線獲得了較大誤差。
```py
lw_errors(50, 10000)
```

```py
lw_errors(-100, 50000)
```

### 均方根誤差(RMSE)
我們現在需要的是誤差大小的一個總體衡量。 你會認識到創建它的方法 - 這正是我們開發標準差的方式。
如果你使用任意直線來計算你的估計值,那么你的一些誤差可能是正的,而其他的則是負的。 為了避免誤差大小在測量時抵消,我們將采用誤差平方的均值而不是誤差的均值。
估計的均方誤差大概是誤差的平方有多大,但正如我們前面提到的,它的單位很難解釋。 取平方根產生均方根誤差(RMSE),與預測變量的單位相同,因此更容易理解。
### 使 RMSE 最小
到目前為止,我們的觀察可以總結如下。
+ 要根據`x`估算`y`,可以使用任何你想要的直線。
+ 每個直線都有估計的均方根誤差。
+ “更好”的直線有更小的誤差。
有沒有“最好”的直線? 也就是說,是否有一條線可以使所有行中的均方根誤差最小?
為了回答這個問題,我們首先定義一個函數`lw_rmse`,通過《小女人》的散點圖來計算任意直線的均方根誤差。 函數將斜率和截距(按此順序)作為參數。
```py
def lw_rmse(slope, intercept):
lw_errors(slope, intercept)
x = little_women.column('Periods')
y = little_women.column('Characters')
fitted = slope * x + intercept
mse = np.mean((y - fitted) ** 2)
print("Root mean squared error:", mse ** 0.5)
lw_rmse(50, 10000)
Root mean squared error: 4322.16783177
```

```py
lw_rmse(-100, 50000)
Root mean squared error: 16710.1198374
```

正如預期的那樣,不好的直線 RMSE 很大。 但是如果我們選擇接近于回歸線的斜率和截距,則 RMSE 要小得多。
```py
lw_rmse(90, 4000)
Root mean squared error: 2715.53910638
```

這是對應于回歸線的均方根誤差。 通過顯著的數學事實,沒有其他線路能擊敗這一條。
回歸線是所有直線之間的唯一直線,使估計的均方誤差最小。
```py
lw_rmse(lw_reg_slope, lw_reg_intercept)
Root mean squared error: 2701.69078531
```

這個聲明的證明需要超出本課程范圍的抽象數學。 另一方面,我們有一個強大的工具 -- Python,它可以輕松執行大量的數值計算。 所以我們可以使用 Python 來確認回歸線最小化的均方誤差。
### 數值優化
首先注意,使均方根誤差最小的直線,也是使平方誤差最小的直線。 平方根對最小值沒有任何影響。 所以我們會為自己節省一個計算步驟,并將平均方差 MSE 減到最小。
我們試圖根據《小女人》的句子數(`x`)來預測字符數量(`y`)。 如果我們使用  直線,它將有一個 MSE,它取決于斜率`a`和截距`b`。 函數`lw_mse`以斜率和截距為參數,并返回相應的 MSE。
```py
def lw_mse(any_slope, any_intercept):
x = little_women.column('Periods')
y = little_women.column('Characters')
fitted = any_slope*x + any_intercept
return np.mean((y - fitted) ** 2)
```
讓我們確認一下,`lw_mse`得到回歸線的 RMSE 的正確答案。 請記住,`lw_mse`返回均方誤差,所以我們必須取平方根來得到 RMSE。
```py
lw_mse(lw_reg_slope, lw_reg_intercept)**0.5
2701.690785311856
```

它和我們之前使用`lw_rmse `得到的值相同。
```py
lw_rmse(lw_reg_slope, lw_reg_intercept)
Root mean squared error: 2701.69078531
```
你可以確認對于其他的斜率和截距,`lw_mse`也返回正確的值。 例如,這里是我們之前嘗試的,非常不好的直線的 RMSE。
```py
lw_mse(-100, 50000)**0.5
16710.119837353752
```
這里是這條直線的 RMSE,它接近回歸線。
```py
lw_mse(90, 4000)**0.5
2715.5391063834586
```
如果我們嘗試不同的值,我們可以通過反復試驗找到一個誤差較低的斜率和截距,但這需要一段時間。 幸運的是,有一個 Python 函數為我們做了所有的試錯。
`minimize`函數可用于尋找函數的參數,函數在這里返回其最小值。 Python 使用類似的試錯法,遵循使輸出值遞減的變化量。
`minimize`的參數是一個函數,它本身接受數值參數并返回一個數值。 例如,函數`lw_mse`以數值斜率和截距作為參數,并返回相應的 MSE。
調用`minimize(lw_mse)`返回一個數組,由斜率和截距組成,它們使 MSE 最小。 這些最小值是通過智能試錯得出的極好的近似值,而不是基于公式的精確值。
```py
best = minimize(lw_mse)
best
array([ 86.97784117, 4744.78484535])
```
這些值與我們之前使用`slope`和`intercept`函數計算的值相同。 由于最小化的不精確性,我們看到較小的偏差,但是這些值本質上是相同的。
```py
print("slope from formula: ", lw_reg_slope)
print("slope from minimize: ", best.item(0))
print("intercept from formula: ", lw_reg_intercept)
print("intercept from minimize: ", best.item(1))
slope from formula: 86.9778412583
slope from minimize: 86.97784116615884
intercept from formula: 4744.78479657
intercept from minimize: 4744.784845352655
```
### 最小二乘直線
因此我們發現,不僅回歸線具有最小的均方誤差,而且均方誤差的最小化也給出了回歸線。 回歸線是最小化均方誤差的唯一直線。
這就是回歸線有時被稱為“最小二乘直線”的原因。
## 最小二乘回歸
在前面的章節中,我們開發了回歸直線的斜率和截距方程,它穿過一個橄欖形的散點圖。 事實證明,無論散點圖的形狀如何,最小二乘直線的斜率和截距都與我們開發的公式相同。
我們在《小女人》的例子中看到了它,但是讓我們以散點圖顯然不是橄欖形的例子來證實它。 對于這些數據,我們再次受惠于佛羅里達大學 Larry Winner 教授的豐富數據檔案。 《國際運動科學雜志》(International Journal of Exercise Science)2013 年的一項研究,研究了大學生鉛球運動員,并考察了力量與鉛球距離的關系。 總體由 28 名女大學生運動員組成。 運動員在賽季前的“1RM power clean”中舉起的最大值(公斤)是衡量力量的指標。 距離(米)是運動員個人最佳成績。
```py
shotput = Table.read_table('shotput.csv')
shotput
```
| Weight Lifted | Shot Put Distance |
| --- | --- |
| 37.5 | 6.4 |
| 51.5 | 10.2 |
| 61.3 | 12.4 |
| 61.3 | 13 |
| 63.6 | 13.2 |
| 66.1 | 13 |
| 70 | 12.7 |
| 92.7 | 13.9 |
| 90.5 | 15.5 |
| 90.5 | 15.8 |
(省略了 18 行)
```py
shotput.scatter('Weight Lifted')
```

這不是橄欖形的散點圖。 事實上,它似乎有一點非線性成分。 但是,如果我們堅持用一條直線來做出預測,那么所有直線之中仍然有一條最好的直線。
我們為回歸線的斜率和截距建立公式,它來源于橄欖形的散點圖,并給出了下列值:
```py
slope(shotput, 'Weight Lifted', 'Shot Put Distance')
0.098343821597819972
intercept(shotput, 'Weight Lifted', 'Shot Put Distance')
5.9596290983739522
```
即使散點圖不是橄欖形,使用這些公式還有意義嗎? 我們可以通過求出使 MSE 最小的斜率和截距來回答這個問題。
我們將定義函數`shotput_linear_mse`,以斜體和截距作為參數并返回相應的 MSE。 然后將`minimize`應用于`shotput_linear_mse`將返回最優斜率和截距。
```py
def shotput_linear_mse(any_slope, any_intercept):
x = shotput.column('Weight Lifted')
y = shotput.column('Shot Put Distance')
fitted = any_slope*x + any_intercept
return np.mean((y - fitted) ** 2)
minimize(shotput_linear_mse)
array([ 0.09834382, 5.95962911])
```
這些值與我們使用我們的公式得到的值相同。 總結:
無論散點圖的形狀如何,都有一條獨特的線,可以使估計的均方誤差最小。 它被稱為回歸線,其斜率和截距由下式給出:

> 譯者注:也就是`cov(x, y)/var(x)`。

```py
fitted = fit(shotput, 'Weight Lifted', 'Shot Put Distance')
shotput.with_column('Best Straight Line', fitted).scatter('Weight Lifted')
```

### 非線性回歸
上面的圖表強化了我們之前的觀察,即散點圖有點彎曲。 因此,最好擬合曲線而不是直線。 研究假設舉起的重量與鉛球距離之間是二次關系。 所以讓我們使用二次函數來預測,看看我們能否找到最好的曲線。
我們必須找到所有二次函數中最好的二次函數,而不是所有直線中最好的直線。 最小二乘法允許我們這樣做。
這種最小化的數學是復雜的,不容易僅僅通過檢查散點圖來發現。 但是數值最小化和線性預測一樣簡單! 再次通過使用最小化我們可以得到最好的二次預測。 讓我們看看這是如何工作的。
回想一下,二次函數的形式:
```
f(x) = ax^2 + bx + c
```
`a`、`b`和`c`是常數。
為了基于舉起的重量找到最好的二次函數來預測距離,使用最小二乘法,我們首先編寫一個函數,以三個常量為自變量的,用上面的二次函數計算擬合值,然后返回均方誤差。
該函數被稱為`shotput_quadratic_mse`。 請注意,定義與`lw_mse`的定義類似,不同的是擬合值基于二次函數而不是線性。
```py
def shotput_quadratic_mse(a, b, c):
x = shotput.column('Weight Lifted')
y = shotput.column('Shot Put Distance')
fitted = a*(x**2) + b*x + c
return np.mean((y - fitted) ** 2)
```
我們現在可以像之前那樣使用`minimize`,并找到使 MSE 最小的常數。
```py
best = minimize(shotput_quadratic_mse)
best
array([ -1.04004838e-03, 2.82708045e-01, -1.53182115e+00])
```
我們預測,一個舉起`x`公斤的運動員的鉛球距離大概是`-0.00104x^2 + 0.2827x - 1.5318`米。 例如,如果運動員可以舉起 100 公斤,預測的距離是 16.33 米。 在散點圖上,在 100 公斤左右的垂直條形的中心附近。
```py
(-0.00104)*(100**2) + 0.2827*100 - 1.5318
16.3382
```
以下是所有`Weight Lifted`的預測。 你可以看到他們穿過散點圖的中心,大致上接近。
```py
x = shotput.column(0)
shotput_fit = best.item(0)*(x**2) + best.item(1)*x + best.item(2)
shotput.with_column('Best Quadratic Curve', shotput_fit).scatter(0)
```

## 視覺診斷
假設數據科學家已經決定使用線性回歸,基于預測變量估計響應變量的值。 為了了解這種估計方法的效果如何,數據科學家必須知道估計值距離實際值多遠。 這些差異被稱為殘差。

殘差就是剩下的東西 - 估計之后的剩余。
殘差是回歸線和點的垂直距離。 散點圖中的每個點都有殘差。 殘差是`y`的觀測值與`y`的擬合值之間的差值,所以對于點`(x, y)`:

`residual`函數計算殘差。 該計算假設我們已經定義的所有相關函數:`standard_units`,`correlation`,`slope`,`intercept`和`fit`。
```py
def residual(table, x, y):
return table.column(y) - fit(table, x, y)
```
繼續使用高爾頓的數據的例子,基于雙親身高(預測變量)來估計成年子女身高(響應變量),讓我們計算出擬合值和殘差。
```py
heights = heights.with_columns(
'Fitted Value', fit(heights, 'MidParent', 'Child'),
'Residual', residual(heights, 'MidParent', 'Child')
)
heights
```
| MidParent | Child | Fitted Value | Residual |
| --- | --- | --- | --- |
| 75.43 | 73.2 | 70.7124 | 2.48763 |
| 75.43 | 69.2 | 70.7124 | -1.51237 |
| 75.43 | 69 | 70.7124 | -1.71237 |
| 75.43 | 69 | 70.7124 | -1.71237 |
| 73.66 | 73.5 | 69.5842 | 3.91576 |
| 73.66 | 72.5 | 69.5842 | 2.91576 |
| 73.66 | 65.5 | 69.5842 | -4.08424 |
| 73.66 | 65.5 | 69.5842 | -4.08424 |
| 72.06 | 71 | 68.5645 | 2.43553 |
| 72.06 | 68 | 68.5645 | -0.564467 |
(省略了 924 行)
如果要處理的變量太多,以可視化開始總是很有幫助的。 函數`scatter_fit`繪制數據的散點圖,以及回歸線。
```py
def scatter_fit(table, x, y):
table.scatter(x, y, s=15)
plots.plot(table.column(x), fit(table, x, y), lw=4, color='gold')
plots.xlabel(x)
plots.ylabel(y)
scatter_fit(heights, 'MidParent', 'Child')
```

通過繪制殘差和預測變量來繪制殘差圖。函數`residual_plot`就是這樣做的。
```py
def residual_plot(table, x, y):
x_array = table.column(x)
t = Table().with_columns(
x, x_array,
'residuals', residual(table, x, y)
)
t.scatter(x, 'residuals', color='r')
xlims = make_array(min(x_array), max(x_array))
plots.plot(xlims, make_array(0, 0), color='darkblue', lw=4)
plots.title('Residual Plot')
residual_plot(heights, 'MidParent', 'Child')
```

雙親身高在橫軸上,就像原始散點圖中一樣。 但是現在縱軸顯示了殘差。 請注意,該圖看上去以`y=0`的橫線為中心(以深藍色顯示)。 還要注意,繪圖沒有顯示上升或下降的趨勢。 我們稍后會觀察到所有的回歸都是如此。
### 回歸診斷
殘差圖有助于我們直觀評估線性回歸分析的質量。 這種評估被稱為診斷。 函數`regression_diagnostic_plots`繪制原始散點圖以及殘差圖,以便于比較。
```py
def regression_diagnostic_plots(table, x, y):
scatter_fit(table, x, y)
residual_plot(table, x, y)
regression_diagnostic_plots(heights, 'MidParent', 'Child')
```


這個殘差圖表明,線性回歸是合理的估計方法。 注意殘差關于`y=0`的橫線上下對稱分布,相當于原始散點圖大致上下對稱。 還要注意,繪圖的垂直延伸,在子女身高最常見的值上相當均勻。 換句話說,除了一些離群點之外,繪圖并不是一些地方窄。另一些地方寬。
換句話說,在預測變量的觀察范圍內,回歸的準確性似乎是相同的。
良好回歸的殘差圖不顯示任何規律。 在預測變量的范圍內,殘差在`y=0`的直線處上下相同。
### 檢測非線性
繪制數據的散點圖,通常表明了兩個變量之間的關系是否是非線性的。 然而,通常情況下,殘差圖中比原始散點圖中更容易發現非線性。 這通常是因為這兩個圖的規模:殘差圖允許我們放大錯誤,從而更容易找出規律。

我們的數據是海牛的年齡和長度的數據集,這是一種海洋哺乳動物(維基共享資源圖)。 數據在一個名為`dugong`的表中。 年齡以年為單位,長度以米為單位。 因為海牛通常不跟蹤他們的生日,年齡是根據他們的牙齒狀況等變量來估計的。
```py
dugong = Table.read_table('http://www.statsci.org/data/oz/dugongs.txt')
dugong = dugong.move_to_start('Length')
dugong
```
| Length | Age |
| --- | --- |
| 1.8 | 1 |
| 1.85 | 1.5 |
| 1.87 | 1.5 |
| 1.77 | 1.5 |
| 2.02 | 2.5 |
| 2.27 | 4 |
| 2.15 | 5 |
| 2.26 | 5 |
| 2.35 | 7 |
| 2.47 | 8 |
(省略了 17 行)
如果我們可以衡量海牛的長度,對于它的年齡我們可以說什么呢? 讓我們來看看我們的數據說了什么。 這是一個長度(預測變量)和年齡(響應變量)的回歸。 這兩個變量之間的相關性相當大,為 0.83。
```py
correlation(dugong, 'Length', 'Age')
0.82964745549057139
```
盡管相關性仍然很高,繪圖顯示出曲線規律,在殘差圖中更加明顯。
```py
regression_diagnostic_plots(dugong, 'Length', 'Age')
```


雖然你可以發現原始散點圖中的非線性,但在殘差圖中更明顯。
在長度的較低一端,殘差幾乎都是正的;然后他們幾乎都是負的;然后在較高一端,殘差再次為正。 換句話說,回歸估計值過高,然后過低,然后過高。 這意味著使用曲線而不是直線來估計年齡會更好。
當殘差圖顯示了規律時,變量之間可能存在非線性關系。
### 檢測異方差
異方差這個詞,那些準備拼寫游戲的人肯定會感興趣。 對于數據科學家來說,其興趣在于它的意義,即“不均勻延伸”。
回想一下`hybrid `表,包含美國混合動力汽車的數據。這是燃油效率對加速度的回歸。這個關聯是負面的:加速度高的汽車往往效率較低。
```py
regression_diagnostic_plots(hybrid, 'acceleration', 'mpg')
```


注意殘差圖在加速度的較低一端變得發散。 換句話說,對于較低的加速度,誤差的大小的變化比較高值更大。 殘差圖中比原始的散點圖中更容易注意到不均勻的變化。
如果殘差圖顯示`y=0`的橫線處的不均勻變化,則在預測變量的范圍內,回歸的估計不是同等準確的。
## 數值診斷
除了可視化之外,我們還可以使用殘差的數值屬性來評估回歸的質量。 我們不會在數學上證明這些屬性。 相反,我們將通過計算來觀察它們,看看它們告訴我們回歸的什么東西。
下面列出的所有事實都適用于散點圖的所有形狀,無論它們是否是線性的。
### 殘差圖不展示形狀
對于每一個線性回歸,無論是好還是壞,殘差圖都不展示任何趨勢。 總的來說,它是平坦的。 換句話說,殘差和預測變量是不相關的。
你可以在上面所有的殘差圖中看到它。 我們還可以計算每種情況下,預測變量和殘差之間的相關性。
```py
correlation(heights, 'MidParent', 'Residual')
-2.7196898076470642e-16
```
這看起來不是零,但它是個很小的數字,除了由于計算的舍入誤差之外,它就是零。 在這里也一樣,取小數點后 10 位。 減號是因為上面的舍入。
```py
round(correlation(heights, 'MidParent', 'Residual'), 10)
-0.0
dugong = dugong.with_columns(
'Fitted Value', fit(dugong, 'Length', 'Age'),
'Residual', residual(dugong, 'Length', 'Age')
)
round(correlation(dugong, 'Length', 'Residual'), 10)
0.0
```
### 殘差的均值
不管散點圖的形狀如何,剩余的均值都是 0。
這類似于這樣一個事實,如果你選取任何數值列表并計算距離均值的偏差的列表,則偏差的均值為 0。
在上面的所有殘差圖中,你看到`y=0`的橫線穿過圖的中心。 這是這個事實的可視化。
作為一個數值示例,這里是高爾頓數據集中,基于雙親高度的子女高度的回歸的殘差均值。
```py
round(np.mean(heights.column('Residual')), 10)
0.0
```
海牛長度和年齡的回歸的殘差均值也是一樣。 殘差均值為 0,除了舍入誤差。
```py
round(np.mean(dugong.column('Residual')), 10)
0.0
```
### 殘差的標準差
無論散點圖的形狀如何,殘差的標準差是響應變量的標準差的一個比例。 比例是 。

我們將很快看到,它如何衡量回歸估計的準確性。 但首先,讓我們通過例子來確認。
在子女身高和雙親身高的案例中,殘差的標準差約為 3.39 英寸。
```py
np.std(heights.column('Residual'))
3.3880799163953426
```
這和響應變量的標準差乘`sqrt(1 - r^2)`相同。
```py
r = correlation(heights, 'MidParent', 'Child')
np.sqrt(1 - r**2) * np.std(heights.column('Child'))
3.3880799163953421
```
混合動力汽車的加速和里程的回歸也是如此。 相關性`r`是負數(約 -0.5),但`r^2`是正數,所以`sqrt(1 - r^2)`是一個分數。
```py
r = correlation(hybrid, 'acceleration', 'mpg')
r
-0.5060703843771186
hybrid = hybrid.with_columns(
'fitted mpg', fit(hybrid, 'acceleration', 'mpg'),
'residual', residual(hybrid, 'acceleration', 'mpg')
)
np.std(hybrid.column('residual')), np.sqrt(1 - r**2)*np.std(hybrid.column('mpg'))
(9.4327368334302903, 9.4327368334302903)
```
現在讓我們看看,殘差的標準差是如何衡量回歸的好壞。請記住,殘差的均值為 0。因此,殘差的標準差越小,則殘差越接近于 0。換句話說,如果殘差的標準差小,那么回歸中的總體誤差就小。
極端情況是`r = 1`或`r = -1`。在這兩種情況下,`sqrt(1 - r^2) = 0`。因此,殘差的均值為 0,標準差為 0,因此殘差都等于 0。回歸線確實是完美的估計。我們在本章的前面看到,如果`r = ± 1`,散點圖是一條完美的直線,與回歸線相同,所以回歸估計中確實沒有錯誤。
但通常`r`不是極端的。如果`r`既不是`±1`也不是 0,那么`sqrt(1 - r^2)`是一個適當的分數,并且回歸估計的誤差大小,整體上大致在 0 和`y`的標準差之間。
最糟糕的情況是`r = 0`。那么`sqrt(1 - r^2)` = 1,殘差的標準差等于`y`的標準差。這與觀察結果一致,如果`r = 0`那么回歸線就是`y`的均值上的一條橫線。在這種情況下,回歸的均方根誤差是距離`y`的平均值的偏差的均方根,這是`y`的標準差。實際上,如果`r = 0`,那么這兩個變量之間就沒有線性關聯,所以使用線性回歸沒有任何好處。
### 另一種解釋`r`的方式
我們可以重寫上面的結果,不管散點圖的形狀如何:

互補的結果是,無論散點圖的形狀如何,擬合值的標準差是觀察值`y`的標準差的一個比例。比例是`|r|`。

要查看比例在哪里出現,請注意擬合值全部位于回歸線上,而`y`的觀測值是散點圖中所有點的高度,并且更加可變。
```py
scatter_fit(heights, 'MidParent', 'Child')
```

擬合值的范圍在 64 到 71 之間,而所有子女的身高則變化很大,大約在 55 到 80 之間。
為了在數值上驗證結果,我們只需要計算雙方的一致性。
```py
correlation(heights, 'MidParent', 'Child')
0.32094989606395924
```
這里是出生體重的擬合值的標準差與觀察值的標準差的比值:
```py
np.std(heights.column('Fitted Value'))/np.std(heights.column('Child'))
0.32094989606395957
```
這個比例等于`r`,證實了我們的結果。
絕對值出現在哪里? 首先要注意的是,標準差不能是負數,標準差的比值也不行。 那么當`r`是負數時會發生什么呢? 燃油效率和加速度的例子將向我們展示。
```py
correlation(hybrid, 'acceleration', 'mpg')
-0.5060703843771186
np.std(hybrid.column('fitted mpg'))/np.std(hybrid.column('mpg'))
0.5060703843771186
```
兩個標準差的比值就是`|r|`。
解釋這個結果的更標準的方法是,回想一下:

因此,對結果的兩邊取平方:
