讓程式重複與分岔:流程與函式

先備知識 P2 — 選讀,不列入評分
if elif else|& 與 and 不一樣|for 與 zip|def 與 return|預設引數|作用域|讀懂 traceback
向下捲動開始互動↓
📌 本頁使用方式(先備 · 流程與函式)

① 依序閱讀:每節先讀說明;遇到互動元件時,先預測結果,再操作驗證。 ② 對照程式範例:程式碼卡下方的「來源」標了課程練習筆記本(lab);需要實作時,再打開原始筆記本對照。 ③ 檢查理解:答錯時先看回饋,再回到相關說明;標為延伸的內容可留待第二輪。 ④ 最後用重點速查與來源複習。

教科書:An Introduction to Statistical Learning with Applications in Python(ISLP)。章節旁的來源標記可點到本頁書目。

CONTENTS · 內容目錄
PROLOGUE · 開場

同一段程式碼貼三次,就是三個等著出錯的地方 課程 Lab Ch5 · lab 範例

先用三個小動作認識流程:依條件選一條路、對每個數字重做一次、把步驟包成可重用的函式。這一頁先練 Python,再連回課程的模型程式。把重複步驟寫成一個函式,修改時較不容易漏改其中一份。

PART 00 · 自我檢測

同一段分析程式碼在 notebook 裡複製了三次。最大的風險是什麼?

(A) 檔案變大,跑得比較慢
(B) 改了一份忘了改另外兩份,而且不會有人告訴你
(C) 會有變數名稱衝突
PART 01 · 條件與布林

& 與 and 的運算對象 課程 Lab Ch2 · lab 範例

if 需要一個真假值;and/or 可以合併純量條件。下面則是一整欄同時判斷的寫法。

一句話講完差別 and 一次只能判斷一個真假值;& 是逐元素做「且」,一整排一起算。選資料的時候永遠是後者,而且每個條件都要用括號包起來,因為 & 的優先順序比 > 高。
›兩個條件,逐列做「且」。
課程/lab 資料
看每一列各自的結果
兩個條件各自產生一整排 True/False,& 把它們逐列做「且」。按按鈕切換運算子。
目前
運算子&
留下幾列—
會不會報錯不會
忘記括號的下場
df['year'] > 80 & df['mpg'] > 30 會被讀成 df['year'] > (80 & df['mpg']) > 30,然後拋一個看起來莫名其妙的錯。每個條件都加上括號,這條沒有例外。
一個條件
idx_80 = Auto_re['year'] > 80 Auto_re.loc[idx_80, ['weight', 'origin']]
查看完整 Lab 輸出
預期輸出
                                   weight  origin
name                                             
plymouth reliant                   2490.0       1
buick skylark                      2635.0       1
dodge aries wagon (sw)             2620.0       1
chevrolet citation                 2725.0       1
plymouth reliant                   2385.0       1
toyota starlet                     1755.0       3
plymouth champ                     1875.0       1
honda civic 1300                   1760.0       3
subaru                             2065.0       3
datsun 210 mpg                     1975.0       3
toyota tercel                      2050.0       3
mazda glc 4                        1985.0       3
plymouth horizon 4                 2215.0       1
ford escort 4w                     2045.0       1
ford escort 2h                     2380.0       1
volkswagen jetta                   2190.0       2
honda prelude                      2210.0       3
toyota corolla                     2350.0       3
datsun 200sx                       2615.0       3
mazda 626                          2635.0       3
peugeot 505s turbo diesel          3230.0       2
volvo diesel                       3160.0       2
toyota cressida                    2900.0       3
datsun 810 maxima                  2930.0       3
buick century                      3415.0       1
oldsmobile cutlass ls              3725.0       1
ford granada gl                    3060.0       1
chrysler lebaron salon             3465.0       1
chevrolet cavalier                 2605.0       1
chevrolet cavalier wagon           2640.0       1
chevrolet cavalier 2-door          2395.0       1
pontiac j2000 se hatchback         2575.0       1
dodge aries se                     2525.0       1
pontiac phoenix                    2735.0       1
ford fairmont futura               2865.0       1
volkswagen rabbit l                1980.0       2
mazda glc custom l                 2025.0       3
mazda glc custom                   1970.0       3
plymouth horizon miser             2125.0       1
mercury lynx l                     2125.0       1
nissan stanza xe                   2160.0       3
honda accord                       2205.0       3
toyota corolla                     2245.0       3
honda civic                        1965.0       3
honda civic (auto)                 1965.0       3
datsun 310 gx                      1995.0       3
buick century limited              2945.0       1
oldsmobile cutlass ciera (diesel)  3015.0       1
chrysler lebaron medallion         2585.0       1
ford granada l                     2835.0       1
toyota celica gt                   2665.0       3
dodge charger 2.2                  2370.0       1
chevrolet camaro                   2950.0       1
ford mustang gl                    2790.0       1
vw pickup                          2130.0       2
dodge rampage                      2295.0       1
ford ranger                        2625.0       1
chevy s-10                         2720.0       1

先算出一整排 True/False,再拿它去 loc 選列。

來源:Ch02-statlearn-lab-zh.ipynb
兩個條件用 & 串起來
Auto_re.loc[lambda df: (df['year'] > 80) & (df['mpg'] > 30), ['weight', 'origin'] ]
查看完整 Lab 輸出
預期輸出
                                   weight  origin
name                                             
toyota starlet                     1755.0       3
plymouth champ                     1875.0       1
honda civic 1300                   1760.0       3
subaru                             2065.0       3
datsun 210 mpg                     1975.0       3
toyota tercel                      2050.0       3
mazda glc 4                        1985.0       3
plymouth horizon 4                 2215.0       1
ford escort 4w                     2045.0       1
volkswagen jetta                   2190.0       2
honda prelude                      2210.0       3
toyota corolla                     2350.0       3
datsun 200sx                       2615.0       3
mazda 626                          2635.0       3
volvo diesel                       3160.0       2
chevrolet cavalier 2-door          2395.0       1
pontiac j2000 se hatchback         2575.0       1
volkswagen rabbit l                1980.0       2
mazda glc custom l                 2025.0       3
mazda glc custom                   1970.0       3
plymouth horizon miser             2125.0       1
mercury lynx l                     2125.0       1
nissan stanza xe                   2160.0       3
honda accord                       2205.0       3
toyota corolla                     2245.0       3
honda civic                        1965.0       3
honda civic (auto)                 1965.0       3
datsun 310 gx                      1995.0       3
oldsmobile cutlass ciera (diesel)  3015.0       1
toyota celica gt                   2665.0       3
dodge charger 2.2                  2370.0       1
vw pickup                          2130.0       2
dodge rampage                      2295.0       1
chevy s-10                         2720.0       1

注意兩個條件各自都有括號。另外這裡用了 lambda df:。它讓你在鏈式操作中間也能引用「當下這張表」。

來源:Ch02-statlearn-lab-zh.ipynb
跨章應用:混合多種資料篩選條件
& 與 | 混用
Auto_re.loc[lambda df: (df['displacement'] < 300) & (df.index.str.contains('ford') | df.index.str.contains('datsun')), ['weight', 'origin'] ]
預期輸出
                       weight  origin
name                                 
ford maverick          2587.0       1
datsun pl510           2130.0       3
datsun pl510           2130.0       3
ford torino 500        3302.0       1
ford mustang           3139.0       1
datsun 1200            1613.0       3
ford pinto runabout    2226.0       1
ford pinto (sw)        2395.0       1
datsun 510 (sw)        2288.0       3
ford maverick          3021.0       1
datsun 610             2379.0       3
ford pinto             2310.0       1
datsun b210            1950.0       3
ford pinto             2451.0       1
datsun 710             2003.0       3
ford maverick          3158.0       1
ford pinto             2639.0       1
datsun 710             2545.0       3
ford pinto             2984.0       1
ford maverick          3012.0       1
ford granada ghia      3574.0       1
datsun b-210           1990.0       3
ford pinto             2565.0       1
datsun f-10 hatchback  1945.0       3
ford granada           3525.0       1
ford mustang ii 2+2    2755.0       1
datsun 810             2815.0       3
ford fiesta            1800.0       1
datsun b210 gx         2070.0       3
ford fairmont (auto)   2965.0       1
ford fairmont (man)    2720.0       1
datsun 510             2300.0       3
datsun 200-sx          2405.0       3
ford fairmont 4        2890.0       1
datsun 210             2020.0       3
datsun 310             2019.0       3
ford fairmont          2870.0       1
datsun 510 hatchback   2434.0       3
datsun 210             2110.0       3
datsun 280-zx          2910.0       3
datsun 210 mpg         1975.0       3
ford escort 4w         2045.0       1
ford escort 2h         2380.0       1
datsun 200sx           2615.0       3
datsun 810 maxima      2930.0       3
ford granada gl        3060.0       1
ford fairmont futura   2865.0       1
datsun 310 gx          1995.0       3
ford granada l         2835.0       1
ford mustang gl        2790.0       1
ford ranger            2625.0       1

排氣量小於 300,而且(是 ford 或 datsun)。括號決定了誰先算,跟數學一樣。

來源:Ch02-statlearn-lab-zh.ipynb
情境用什麼為什麼
一個 if 判斷and / or / not只有一個真假值
選 DataFrame 的列& / | / ~一整排真假值要逐元素算
NumPy 陣列的條件& / | / ~同上
檢查「有沒有任何一個」.any() / .all()把一整排收成一個真假值
PART 01 · 自我檢測

Auto[(Auto['year'] > 80) and (Auto['mpg'] > 30)] 會發生什麼?

(A) 報錯:一整排真假值沒辦法縮成單一個真或假
(B) 正常執行,跟用 & 一樣
(C) 只會用到第一個條件
PART 02 · 迴圈

for、range 與 zip:把同一件事做很多次 課程 Lab Ch2 · lab 範例

迴圈就是「把同一件事對每一個東西各做一次」。統計程式裡它出現在三個地方: 試不同的參數(多項式次數、λ)、重抽樣(自助法的 B 次)、 逐欄處理(每一欄算遺漏比例)。

›按「單步」跟著跑一次。
課程/lab 資料
跟著跑一次
按「單步」走 total += value 這個迴圈,右邊的變數表會同步更新。這正是 lab 範例 的那一段。
目前
第幾圈0 / 3
value—
total0
自助法就是這個形狀
第 5 章的 boot_SE 裡面是 for _ in range(B):,B 通常是 1000。看懂這個三圈的迴圈,那個一千圈的也就看懂了。
最基本的累加迴圈
total = 0 for value in [3,2,19]: total += value print('Total is: {0}'.format(total))
預期輸出
Total is: 24

total += value 是 total = total + value 的簡寫。縮排決定了哪些行屬於迴圈裡面——Python 用縮排代替大括號。

來源:Ch02-statlearn-lab-zh.ipynb
延伸:巢狀迴圈的加總
巢狀迴圈
total = 0 for value in [2,3,19]: for weight in [3, 2, 1]: total += value * weight print('Total is: {0}'.format(total))
預期輸出
Total is: 144

裡面那圈跑完,外面才前進一格,所以總共跑 3×3 = 9 次。巢狀兩層以上通常代表該換個寫法了。

來源:Ch02-statlearn-lab-zh.ipynb
zip:兩排東西配對走
total = 0 for value, weight in zip([2,3,19], [0.2,0.3,0.5]): total += weight * value print('Weighted average is: {0}'.format(total))
預期輸出
Weighted average is: 10.8

zip 把兩個串列逐位配對,所以這一段算的是加權平均。長度不一樣時,它會在短的那個結束時停下來。

來源:Ch02-statlearn-lab-zh.ipynb
你想走過什麼寫法
一個串列的每個元素for x in a:
連同位置一起for i, x in enumerate(a):
兩個串列配對for x, w in zip(a, ws):
跑固定次數for _ in range(B):
字典的鍵與值for k, v in d.items():
DataFrame 的每一欄for col in df.columns:
能不用迴圈就不要用 對整排數字做同一個運算時,NumPy 與 pandas 的向量化寫法又快又好讀(P3 接著會介紹)。迴圈留給「每一圈的內容真的不一樣」的情況——例如每一圈試一個不同的參數、或每一圈抽一份新的樣本。
PART 02 · 自我檢測

for value, weight in zip([2,3,19], [0.2,0.3,0.5]): 會跑幾圈?

(A) 6 圈,兩個串列各 3 個
(B) 9 圈
(C) 3 圈,每一圈拿到一組配對
PART 03 · 函式

def、參數、return:把一段流程封起來 課程 Lab Ch5 · lab 範例

函式用 return 交回結果;沒有寫 return 時,回傳 None,不會自動取最後一行。

函式有三個部分:名字、參數(要給它什麼)、 回傳值(它給你什麼)。寫得好的函式就像一個黑盒子—— 用的人只要知道這三件事,不必知道裡面怎麼做。

完整應用:模型評估函式、資料流與重用

假設你要比較三種多項式次數的驗證誤差。不寫函式的話,你會把同一段 「切分 → 擬合 → 預測 → 算 MSE」複製三次,只改中間一個數字。 三份幾乎一樣的程式碼,就是三個各自會出錯、而且改了一份忘了改另外兩份的地方。

課程 lab 的做法 把那一段包成 evalMSE(terms, response, train, test),然後用一個迴圈跑三次。程式碼從多份重複變成一份共用邏輯,修改時較容易保持一致。

以下先讀懂函式如何被重用。要實跑,請開啟 重抽樣方法的課程筆記本, 先執行套件安裝與匯入、Auto 資料載入與切分,再執行下面的函式與呼叫。 這會準備好 MS、sm、poly、Auto_train 與 Auto_valid。

包成一個函式
def evalMSE(terms, response, train, test): mm = MS(terms) X_train = mm.fit_transform(train) y_train = train[response] X_test = mm.transform(test) y_test = test[response] results = sm.OLS(y_train, X_train).fit() test_pred = results.predict(X_test) return np.mean((y_test - test_pred)**2)

這個函式取自課程 lab 的模型比較流程。四個參數:要放哪些項、反應變數是誰、訓練集、測試集。

來源:Ch05-resample-lab-zh.ipynb
然後用迴圈跑三次
MSE = np.zeros(3) for idx, degree in enumerate(range(1, 4)): MSE[idx] = evalMSE([poly('horsepower', degree)], 'mpg', Auto_train, Auto_valid) MSE
預期輸出
array([25.57387819, 22.21802005, 22.66767544])

三個次數的驗證 MSE 一次算完。要改成試五個次數,把 range(1, 4) 改成 range(1, 6),並把存放結果的 np.zeros(3) 改成 np.zeros(5),避免陣列越界。

來源:Ch05-resample-lab-zh.ipynb
›先看兩邊的長度,再按「改需求」。
課程/lab 資料
兩種寫法並排
左邊是複製貼上三次,右邊是一個函式加一個迴圈。按「改需求」看「要多試一個次數」這件事在兩邊分別要動幾個地方。
目前
寫法複製貼上
邏輯有幾份—
要改幾個地方—
重複程式碼的維護風險
有一種錯誤不會觸發例外:程式跑完了、有數字、但那個數字是錯的。多份程式修改不一致,就可能產生這種錯誤。
›按「單步」走一次課程 lab 的 evalMSE。
課程/lab 資料
看資料怎麼進出
按「單步」走一次 evalMSE:四個參數進去、裡面做四件事、一個數字出來。
目前
步驟0 / 5
這一步—
函式裡的區域變數—
return 之後就結束了
碰到 return,函式立刻結束並把值交出去,後面的行不會執行。沒有寫 return 的函式會回傳 None——忘記寫是很常見的 bug。

這裡的函式參數是呼叫時接收輸入的名稱,例如 X_train。 統計的母體參數則描述母體或機率模型,例如平均數 μ;要由語境分辨。

這個函式由參數接收資料,較容易換資料重用。是否有副作用,還要看它會不會修改傳入物件、全域狀態或檔案。

觀念釐清
參數(parameter)與引數(argument)差在哪?
定義函式時寫的名字叫參數(def evalMSE(terms, response, ...) 裡的 terms);呼叫時實際傳進去的值叫引數。日常對話裡兩個字常常混用,看得懂就好。
為什麼不要在函式裡直接用外面的變數?
因為那樣它就不能重複使用了——換一份資料就得改函式本身。而且外面的變數被改掉時,函式的行為會跟著變,你卻看不出來。把需要的東西都當參數傳進去,使用者才容易確認函式需要哪些輸入。
跨套件應用:lambda 與資料篩選

lambda 是只有一個運算式的函式

lambda df: df['year'] > 80 建立一個接受 df 的函式,並把冒號後的運算式結果回傳。 它相當於定義一個函式,內容只有 return df['year'] > 80。 loc 接到這個函式時,會把當下的資料框傳給它,再使用回傳的布林條件選列。

以當下資料框產生選列條件
Auto_re.loc[lambda df: df['year'] > 80, ['weight', 'origin']]
預期輸出
                                   weight  origin
name                                             
plymouth reliant                   2490.0       1
buick skylark                      2635.0       1
dodge aries wagon (sw)             2620.0       1
chevrolet citation                 2725.0       1
plymouth reliant                   2385.0       1
toyota starlet                     1755.0       3
plymouth champ                     1875.0       1
honda civic 1300                   1760.0       3
subaru                             2065.0       3
datsun 210 mpg                     1975.0       3
toyota tercel                      2050.0       3
mazda glc 4                        1985.0       3
plymouth horizon 4                 2215.0       1
ford escort 4w                     2045.0       1
ford escort 2h                     2380.0       1
volkswagen jetta                   2190.0       2
honda prelude                      2210.0       3
toyota corolla                     2350.0       3
datsun 200sx                       2615.0       3
mazda 626                          2635.0       3
peugeot 505s turbo diesel          3230.0       2
volvo diesel                       3160.0       2
toyota cressida                    2900.0       3
datsun 810 maxima                  2930.0       3
buick century                      3415.0       1
oldsmobile cutlass ls              3725.0       1
ford granada gl                    3060.0       1
chrysler lebaron salon             3465.0       1
chevrolet cavalier                 2605.0       1
chevrolet cavalier wagon           2640.0       1
chevrolet cavalier 2-door          2395.0       1
pontiac j2000 se hatchback         2575.0       1
dodge aries se                     2525.0       1
pontiac phoenix                    2735.0       1
ford fairmont futura               2865.0       1
volkswagen rabbit l                1980.0       2
mazda glc custom l                 2025.0       3
mazda glc custom                   1970.0       3
plymouth horizon miser             2125.0       1
mercury lynx l                     2125.0       1
nissan stanza xe                   2160.0       3
honda accord                       2205.0       3
toyota corolla                     2245.0       3
honda civic                        1965.0       3
honda civic (auto)                 1965.0       3
datsun 310 gx                      1995.0       3
buick century limited              2945.0       1
oldsmobile cutlass ciera (diesel)  3015.0       1
chrysler lebaron medallion         2585.0       1
ford granada l                     2835.0       1
toyota celica gt                   2665.0       3
dodge charger 2.2                  2370.0       1
chevrolet camaro                   2950.0       1
ford mustang gl                    2790.0       1
vw pickup                          2130.0       2
dodge rampage                      2295.0       1
ford ranger                        2625.0       1
chevy s-10                         2720.0       1

沿用 Ch02 已建立的 Auto_re;列條件由 lambda 計算,欄條件仍是欄名串列。

來源:Ch02-statlearn-lab-zh.ipynb

需要多個步驟、註解或重複呼叫時,具名的 def 通常更方便。 lambda 只容許單一運算式,不用寫 return,也不是提早執行一次的篩選結果。

延伸:Python 官方教學:lambda 運算式。

PART 03 · 自我檢測

一個函式忘了寫 return,呼叫它會拿到什麼?

(A) None
(B) 會報錯
(C) 最後一行的值
PART 04 · 預設引數與作用域

函式裡看得到外面,外面看不到裡面 課程 Lab Ch5 · lab 範例

兩件事:預設引數讓常用的設定不必每次都寫, 作用域決定一個名字在哪裡看得到。 課程 lab 的 boot_SE 兩者都用上了。

跨章應用:boot_SE 的預設引數與執行準備

這個進階應用同樣在重抽樣方法的課程筆記本中執行:先跑lab 範例 的安裝與匯入, 再跑lab 範例 建立 Portfolio 與 alpha_func,最後跑下面的lab 範例。 第一輪先看引數如何傳入即可,bootstrap 的用途留待正課。

有預設值的參數
def boot_SE(func, D, n=None, B=1000, seed=0): rng = np.random.default_rng(seed) first_, second_ = 0, 0 n = n or D.shape[0] for _ in trange(B): idx = rng.choice(D.index, n, replace=True) value = func(D, idx) first_ += value second_ += value**2 return np.sqrt(second_ / B - (first_ / B)**2)

n=None、B=1000、seed=0 都有預設值,所以呼叫時可以只給前兩個。有預設值的參數一定要放在沒有預設值的後面。

來源:Ch05-resample-lab-zh.ipynb
呼叫時只覆寫想改的
alpha_SE = boot_SE(alpha_func, Portfolio, B=1000, seed=0) alpha_SE

用關鍵字指定 B=1000、seed=0,順序就不重要了,而且讀的人一眼看得出每個數字是什麼意思。

來源:Ch05-resample-lab-zh.ipynb
›三個情境,看名字的可見範圍。
概念示意
誰看得到誰
按按鈕看一個名字在函式裡面與外面分別是什麼。函式裡看得到外面,外面看不到裡面。
目前
情境—
函式裡的值—
函式外的值—
可變預設值的陷阱
def f(acc=[]) 這種寫法,那個空串列只會建立一次,後續每次呼叫都共用同一個,於是它會越積越多。要用可變的預設值,寫 def f(acc=None) 再在函式裡面 if acc is None: acc = []。
為什麼 seed 要當參數 boot_SE(..., seed=0) 把種子做成可設定的參數,這樣你既能重現結果(給同一個 seed),也能檢查結果穩不穩定(換幾個 seed 跑跑看)。把這項設定留在呼叫處,之後較容易重現與比較結果。
PART 05 · 讀懂錯誤訊息

traceback 要從最後一行開始讀 課程 Lab Ch2 · lab 範例

程式報錯時,可以從錯誤訊息找出原因。程式沒有報錯時,也要核對結果是否符合預期。 Python 的錯誤訊息(traceback)要從最後一行開始讀: 最後一行是錯誤的種類與說明,往上是它發生在哪一行。

查看課程中的完整錯誤訊息
一個真的錯誤訊息
A[[1,3],[0,2,3]]
錯誤訊息
IndexError: shape mismatch: indexing arrays could not be broadcast together with shapes (2,) (3,)

最後一行說得很清楚:shape mismatch,兩個索引陣列的形狀 (2,) 與 (3,) 沒辦法一起廣播。看到 shape 就知道要去印 shape。這是 P3 的第一課。

來源:Ch02-statlearn-lab-zh.ipynb
›按「單步」從最後一行往上讀。
概念示意
從下往上讀
按「單步」,反白會從最後一行往上移動,右邊說明每一層在告訴你什麼。
這一層在說
層次—
內容—
下一步該做什麼—
最常見的四種錯
NameError 名字沒定義(多半是打錯字或儲存格沒跑)、KeyError 欄名不存在、IndexError 索引超出範圍、ValueError 型別對但值不合理(形狀對不上多半是這個)。
使用 try / except 時要處理錯誤 try: ... except: pass 會把錯誤吞掉,讓程式帶著錯誤的狀態繼續跑——後續結果就可能出錯,卻沒有訊息提醒你。只有在你知道會發生什麼錯、而且知道該怎麼處理時才用它,例如「這個套件在 Colab 上才有,本機沒有就跳過」。
try: from google.colab import drive drive.mount('/content/drive') except ImportError: print('不在 Colab 上,跳過掛載')
錯誤多半的原因先去做什麼
NameError打錯字,或那個儲存格還沒跑從上到下重跑一次
KeyError欄名不存在或打錯印 df.columns
IndexError索引超出範圍印 len() 或 shape
ValueError: shape mismatch兩邊形狀對不上印兩邊的 shape
TypeError型別不對(例如字串當數字加)印 type() 或 dtypes
NotFittedError還沒 fit 就 predict檢查有沒有漏跑 fit
PART 05 · 自我檢測

traceback 很長,你應該先看哪一行?

(A) 最後一行:錯誤的種類與說明
(B) 第一行,因為那是最早發生的
(C) 中間套件內部的那幾行
🔗 這在本站哪一章會用到 第 5 章的自助法就是一個跑 1000 圈的迴圈,裡面呼叫一個你自己寫的函式;第 6 章逐一試每個 λ、第 8 章逐一試每個樹深度,形狀都一樣。接下來是 P3 NumPy,那裡會告訴你什麼時候不該寫迴圈。
EXERCISES · 練習

動手驗證:概念自測 先備 · 自我檢測

回顧本頁觀念與原 Lab 的程式,確認各個操作的意義與使用條件。

EXERCISE 1 · 布林運算子

你要選出「1980 年後、而且 mpg 大於 30」的車。哪一個寫法對?

(A) Auto[Auto['year'] > 80 and Auto['mpg'] > 30]
(B) Auto[(Auto['year'] > 80) & (Auto['mpg'] > 30)]
(C) Auto[Auto['year'] > 80 & Auto['mpg'] > 30]
EXERCISE 2 · 迴圈

想對 degrees = [1,2,3] 各算一次 MSE 並收集結果。哪一個寫法最好?

(A) mse1 = f(1); mse2 = f(2); mse3 = f(3)
(B) MSE = [f(d) for d in degrees](或用 for 迴圈填一個陣列)
(C) 寫一個巢狀迴圈,外面跑資料、裡面跑次數
EXERCISE 3 · 函式

def boot_SE(func, D, n=None, B=1000, seed=0)。呼叫時想只改 B,其他都用預設,怎麼寫?

(A) boot_SE(alpha_func, Portfolio, 2000)
(B) boot_SE(alpha_func, Portfolio, None, None, 2000)
(C) boot_SE(alpha_func, Portfolio, B=2000)
EXERCISE 4 · 錯誤訊息

你看到 KeyError: 'horsepower'。第一件該做的事是?

(A) 改用 try / except 把它包起來
(B) 重新下載資料
(C) 印 df.columns 看實際的欄名
重點速查與來源

流程與函式速查表 先備 · 流程與函式

來源:完整書目與章節定位

本頁書目與章節定位

  • 教科書:An Introduction to Statistical Learning with Applications in Python。James、Witten、Hastie、Tibshirani、Taylor,2023。原書與下載資訊

需要核對完整公式、比較表或實作時,再展開下方速查。

查閱完整速查與延伸提醒

三張速查表。

情境用 and / or用 & / |
一個 if 判斷✓✗
選 DataFrame 的列✗(會報錯)✓
NumPy 陣列的條件✗✓
每個條件要不要括號不用一定要
「非」怎麼寫not x~mask
迴圈寫法什麼時候用
for x in a:只要值
for i, x in enumerate(a):同時要位置
for x, w in zip(a, ws):兩排東西並排走
for _ in range(B):只是要跑 B 次(自助法)
[f(x) for x in a]把結果收成一個串列
向量化(不寫迴圈)對整排數字做同一件事時的第一選擇
函式的部件怎麼寫注意
定義def name(a, b=預設):有預設值的參數放後面
回傳return 值沒寫就回傳 None
呼叫(位置)name(x, y)順序不能錯
呼叫(關鍵字)name(x, b=y)參數多時一律用這個
可變預設值def f(acc=None)不要寫 acc=[]
三個閱讀重點 1. 選資料用 &/|,而且每個條件都加上括號。and 一次只判斷一個真假值。
2. 同一段程式碼要寫第三次,就該包成函式。共用一份邏輯,修改時較容易保持一致。
3. traceback 從最後一行讀起。最後一行說錯在哪,往上找是誰呼叫的。