摘要:機器學習工程師納米學位模型評價與驗證項目預測波士頓房價歡迎來到預測波士頓房價項目在此文件中,我們已經提供了一些示例代碼,但你還需要完善更多功能才能讓項目成功運行。
機器學習工程師納米學位 模型評價與驗證 項目 1: 預測波士頓房價
歡迎來到預測波士頓房價項目!在此文件中,我們已經提供了一些示例代碼,但你還需要完善更多功能才能讓項目成功運行。除非有明確要求,你無需修改任何已給出的代碼。習題的標題為編程練習。每一部分都會有詳細的指導,需要實現的部分也會在注釋中以TODO標出。請仔細閱讀所有的提示!
除了實現代碼外,你還必須回答一些問題。請仔細閱讀每個問題,并且在問題后的"回答"文字框中寫出完整的答案。我們的項目審閱者將會根據你對問題的回答和撰寫代碼所實現的功能來進行評分。
提示:代碼 和 Markdown單元格 可通過 Shift + Enter 快捷鍵運行。另外,Markdown單元格 可以通過雙擊進入編輯模式。
在這個項目中,你將使用我們提供的波士頓房屋信息數據來訓練和測試一個模型,并對模型的性能和預測能力進行評估。我們希望可以通過該模型實現對房屋的價值預估,提高房地產經紀人的工作效率。
此項目的數據集來自kaggle原始數據,未經過任何處理。該數據集統計了2006年至2010年波士頓個人住宅銷售情況,包含2900多條觀測數據(其中一半是訓練數據,即我們的housedata.csv文件)。更多文檔信息可以參考作者的文檔(可以不看),以及項目附件data_description.txt文件(特征描述文件,一定要看)。
運行下面區域的代碼以載入一些此項目所需的Python庫。如果成功返回提示語句,則說明載入成功。
# 載入此項目需要的庫 import numpy as np import pandas as pd import visuals as vs # Supplementary code 補充的可視化代碼 import matplotlib.pyplot as plt import seaborn as sns plt.style.use("seaborn") # use seaborn style 使用seaborn風格 import warnings warnings.filterwarnings("ignore") %matplotlib inline print("你已經成功載入所有庫!")
你已經成功載入所有庫!編程練習 1:加載數據
你的第一個編程練習是加載波士頓房價數據。我們已為你導入了 Pandas ,你需要使用這個庫中的read_csv方法來執行必要的過程。
導入數據將會是你整個項目的開始
如果成功返回數據集的大小,表示數據集已載入成功。
# 1 TODO:載入波士頓房屋的數據集:使用pandas載入csv,并賦值到data_df data_df = pd.read_csv("housedata.csv") # 成功載入的話輸出訓練數據行列數目 print("Boston housing dataset has {} data points with {} variables each.".format(*data_df.shape))
Boston housing dataset has 1460 data points with 81 variables each.
這個部分,你要對已有的波士頓房地產數據進行初步的觀察與處理。同時,通過對數據的探索可以讓你更好地理解數據。
由于這個項目的最終目標是建立一個預測房屋價值的模型,我們需要將數據集分為特征(features)和目標變量(target variable)。
目標變量: "SalePrice",是我們希望預測的變量。
特征:除 "SalePrice"外的屬性都是特征,它們反應了數據點在某些方面的表現或性質。
編程練習 2:觀察數據你的第二個編程練習是對波士頓房價的數據進行觀察,這一步會讓你掌握更多數據本身的信息。具體問題如下:
問題2.1:使用head方法打印并觀察前7條data_df數據
# 2.1 TODO: 打印出前7條data_df print(data_df.head(7))
Id MSSubClass MSZoning LotFrontage LotArea Street Alley LotShape 0 1 60 RL 65.0 8450 Pave NaN Reg 1 2 20 RL 80.0 9600 Pave NaN Reg 2 3 60 RL 68.0 11250 Pave NaN IR1 3 4 70 RL 60.0 9550 Pave NaN IR1 4 5 60 RL 84.0 14260 Pave NaN IR1 5 6 50 RL 85.0 14115 Pave NaN IR1 6 7 20 RL 75.0 10084 Pave NaN Reg LandContour Utilities ... PoolArea PoolQC Fence MiscFeature MiscVal 0 Lvl AllPub ... 0 NaN NaN NaN 0 1 Lvl AllPub ... 0 NaN NaN NaN 0 2 Lvl AllPub ... 0 NaN NaN NaN 0 3 Lvl AllPub ... 0 NaN NaN NaN 0 4 Lvl AllPub ... 0 NaN NaN NaN 0 5 Lvl AllPub ... 0 NaN MnPrv Shed 700 6 Lvl AllPub ... 0 NaN NaN NaN 0 MoSold YrSold SaleType SaleCondition SalePrice 0 2 2008 WD Normal 208500 1 5 2007 WD Normal 181500 2 9 2008 WD Normal 223500 3 2 2006 WD Abnorml 140000 4 12 2008 WD Normal 250000 5 10 2009 WD Normal 143000 6 8 2007 WD Normal 307000 [7 rows x 81 columns]
問題2.2:Id特征對我們訓練數據沒有任何用處,在data_df中使用drop方法刪除"Id"列數據
# 2.2 TODO: 刪除data_df中的Id特征(保持數據仍在data_df中,不更改變量名) data_df.drop(columns=["Id"], inplace=True)
問題2.3:使用describe方法觀察data_df各個特征的統計信息:
# 2.3 TODO: data_df.describe(include=[np.number])
MSSubClass | LotFrontage | LotArea | OverallQual | OverallCond | YearBuilt | YearRemodAdd | MasVnrArea | BsmtFinSF1 | BsmtFinSF2 | ... | WoodDeckSF | OpenPorchSF | EnclosedPorch | 3SsnPorch | ScreenPorch | PoolArea | MiscVal | MoSold | YrSold | SalePrice | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
count | 1460.000000 | 1201.000000 | 1460.000000 | 1460.000000 | 1460.000000 | 1460.000000 | 1460.000000 | 1452.000000 | 1460.000000 | 1460.000000 | ... | 1460.000000 | 1460.000000 | 1460.000000 | 1460.000000 | 1460.000000 | 1460.000000 | 1460.000000 | 1460.000000 | 1460.000000 | 1460.000000 |
mean | 56.897260 | 70.049958 | 10516.828082 | 6.099315 | 5.575342 | 1971.267808 | 1984.865753 | 103.685262 | 443.639726 | 46.549315 | ... | 94.244521 | 46.660274 | 21.954110 | 3.409589 | 15.060959 | 2.758904 | 43.489041 | 6.321918 | 2007.815753 | 180921.195890 |
std | 42.300571 | 24.284752 | 9981.264932 | 1.382997 | 1.112799 | 30.202904 | 20.645407 | 181.066207 | 456.098091 | 161.319273 | ... | 125.338794 | 66.256028 | 61.119149 | 29.317331 | 55.757415 | 40.177307 | 496.123024 | 2.703626 | 1.328095 | 79442.502883 |
min | 20.000000 | 21.000000 | 1300.000000 | 1.000000 | 1.000000 | 1872.000000 | 1950.000000 | 0.000000 | 0.000000 | 0.000000 | ... | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 1.000000 | 2006.000000 | 34900.000000 |
25% | 20.000000 | 59.000000 | 7553.500000 | 5.000000 | 5.000000 | 1954.000000 | 1967.000000 | 0.000000 | 0.000000 | 0.000000 | ... | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 5.000000 | 2007.000000 | 129975.000000 |
50% | 50.000000 | 69.000000 | 9478.500000 | 6.000000 | 5.000000 | 1973.000000 | 1994.000000 | 0.000000 | 383.500000 | 0.000000 | ... | 0.000000 | 25.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 6.000000 | 2008.000000 | 163000.000000 |
75% | 70.000000 | 80.000000 | 11601.500000 | 7.000000 | 6.000000 | 2000.000000 | 2004.000000 | 166.000000 | 712.250000 | 0.000000 | ... | 168.000000 | 68.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 8.000000 | 2009.000000 | 214000.000000 |
max | 190.000000 | 313.000000 | 215245.000000 | 10.000000 | 9.000000 | 2010.000000 | 2010.000000 | 1600.000000 | 5644.000000 | 1474.000000 | ... | 857.000000 | 547.000000 | 552.000000 | 508.000000 | 480.000000 | 738.000000 | 15500.000000 | 12.000000 | 2010.000000 | 755000.000000 |
# data_df.info() #查看dataFrame的信息編程練習3: 數據預處理
我們的數據不可能是百分百的‘干凈’數據(即有用數據),總會在采集整理時有些”失誤“、“冗余”,造成“臟”數據,所以我們要從數據的正確性和完整性這兩個方面來清理數據。
正確性:一般是指有沒有異常值,比如我們這個數據集中作者的文檔所說:
I would recommend removing any houses with more than 4000 square feet from the data set (which eliminates these five unusual observations) before assigning it to students.
建議我們去掉數據中"GrLivArea"中超過4000平方英尺的房屋(具體原因可以參考文檔),當然本數據集還有其他的異常點,這里不再處理。
完整性:采集或者整理數據時所產生的空數據造成了數據的完整性缺失,通常我們會使用一定的方法處理不完整的數據。在本例中,我們使用以下兩種方法,一是丟棄數據,即選擇丟棄過多空數據的特征(或者直接丟棄數據行,前提是NA數據占比不多),二是填補數據,填補的方法也很多,均值中位數眾數填充等等都是好方法。
問題3.1:正確性
請按下述步驟刪除一些不合理的數據
問題3.1.1:使用matplotlib庫中的scatter方法 繪制"GrLivArea"和"SalePrice"的散點圖,x軸為"GrLivArea",y軸為"SalePrice",觀察數據
# 3.1.1 TODO:繪制要求的圖形 plt.scatter(data_df["GrLivArea"], data_df["SalePrice"], c="blue", marker=".", s=30) plt.xlabel("GrLivArea") plt.ylabel("SalePrice") plt.show()
問題3.1.2:通過上圖我們可以看到那幾個異常值,即"GrLivArea"大于4000,但是"SalePrice"又極低的數據,從data_df刪除這幾個異常值,刪除后重新繪制"GrLivArea"和"SalePrice"的關系圖,確認異常值已刪除。
# 3.1.2 # TODO:從data_df中刪除 GrLivArea大于4000 且 SalePrice低于300000 的值 index = data_df[(data_df["GrLivArea"] > 4000) & (data_df["SalePrice"] < 300000)].index data_df.drop(index=index, inplace=True) # TODO:重新繪制GrLivArea和SalePrice的關系圖,確認異常值已刪除 plt.scatter(data_df["GrLivArea"], data_df["SalePrice"], c="blue", marker=".", s=50) plt.xlabel("GrLivArea") plt.ylabel("SalePrice") plt.show()
問題3.2:完整性
請按下述步驟,補足數據的完整性
問題3.2.1:篩選出過多空數據的特征,我們這個項目定為篩選出有超過25%為空數據的特征
limit_percent = 0.25 limit_value = len(data_df) * limit_percent # 3.2.1 TODO 統計并打印出超過25%的空數據的特征,你可以考慮使用isna() list(data_df.columns[data_df.isna().sum() > limit_value])
["Alley", "FireplaceQu", "PoolQC", "Fence", "MiscFeature"]
如果你整理出的特征是"Alley", "FireplaceQu", "PoolQC", "Fence", "MiscFeature",那就說明你統計對了,接著我們查看data_description.txt文件,就會發現,這些并非一定是空缺數據,而沒有游泳池,籬笆等也會用NA來表示,那么就不需要刪除這些特征了,而是用None來填充NA數據。
問題3.2.2:根據data_description.txt特征描述,使用fillna方法填充空數據,具體哪一種數據需要填充什么已經整理好了,請按提示要求來進行填充
# 直接運行不用修改 # 確定所有空特征 missing_columns = list(data_df.columns[data_df.isnull().sum() != 0]) # 確定哪些是類別特征,哪些是數值特征 missing_numerical = list(data_df[missing_columns].dtypes[data_df[missing_columns].dtypes != "object"].index) missing_category = [i for i in missing_columns if i not in missing_numerical] print("missing_numerical:",missing_numerical) print("missing_category:",missing_category)
missing_numerical: ["LotFrontage", "MasVnrArea", "GarageYrBlt"] missing_category: ["Alley", "MasVnrType", "BsmtQual", "BsmtCond", "BsmtExposure", "BsmtFinType1", "BsmtFinType2", "Electrical", "FireplaceQu", "GarageType", "GarageFinish", "GarageQual", "GarageCond", "PoolQC", "Fence", "MiscFeature"]
data_df.mode() # 取眾數,返回DataFrame
MSSubClass | MSZoning | LotFrontage | LotArea | Street | Alley | LotShape | LandContour | Utilities | LotConfig | ... | PoolArea | PoolQC | Fence | MiscFeature | MiscVal | MoSold | YrSold | SaleType | SaleCondition | SalePrice | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 20.0 | RL | 60.0 | 7200.0 | Pave | Grvl | Reg | Lvl | AllPub | Inside | ... | 0.0 | Ex | MnPrv | Shed | 0.0 | 6.0 | 2009.0 | WD | Normal | 140000.0 |
1 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | ... | NaN | Fa | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
2 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | ... | NaN | Gd | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
# 需要填充眾數的特征 fill_Mode = ["Electrical"] # 需要填充None的特征 fill_None = ["Alley", "MasVnrType", "BsmtQual", "BsmtCond", "BsmtExposure", "BsmtFinType1", "BsmtFinType2", "FireplaceQu", "GarageType", "GarageFinish", "GarageQual", "GarageCond", "PoolQC", "Fence", "MiscFeature"] # 需要填充0的特征 fill_0 = ["GarageYrBlt"] # 需要填充中位數的特征 fill_median = ["LotFrontage", "MasVnrArea"] # 3.4.1 TODO:按需填補上面數據 # 我的實現: # # 填充眾數: # mode = data_df[fill_Mode].mode().iloc[0,0] # data_df.fillna(value={fill_Mode[0]: mode}, inplace=True) # # 填充None: # d_None={} # for i in fill_None: # d_None[i] = "None" # data_df.fillna(value=d_None, inplace=True) # # 填充0: # data_df[fill_0].fillna(value=0, inplace=True) # # 填充中位數: # data_df[fill_median].fillna(data_df[fill_median].median(), inplace=True) # 簡化實現: data_df[fill_Mode] = data_df[fill_Mode].fillna(data_df[fill_Mode].mode()) data_df[fill_None] = data_df[fill_None].fillna("None") data_df[fill_0] = data_df[fill_0].fillna(0) data_df[fill_median] = data_df[fill_median].fillna(data_df[fill_median].median()) # 驗證 # data_df.isna().sum()編程練習4: 特征分析
有這么一句話在業界廣泛流傳:特征數據決定了機器學習的上限,而模型和算法只是逼近這個上限而已。特征工程,是整個數據分析過程中不可缺少的一個環節,其結果質量直接關系到模型效果和最終結論。從上面兩步中我們得到了“干凈”的數據,但是data_df總共有81個特征,我們應當剔除那些無關緊要的特征(噪聲),使用真正關鍵的特征來進行模型訓練。現在需要我們對這些龐大的數據進行分析,提取出與目標最為關聯的數據。
問題4.1:繪制"SalePrice"的直方圖,并說明該直方圖屬于什么分布
# 4.1 TODO:繪制要求的圖形 # plt.hist(data_df["SalePrice"], bins=50, normed=False, color=None) # plt.xlabel("SalePrice") # plt.show() data_df["SalePrice"].hist(bins=50)
回答問題4.1:"SalePrice"屬于 正偏態 分布
import scipy scipy.stats.skew(data_df["SalePrice"])
1.8793604459195012
結果>0,代表正偏,從計算上也說明了"SalePrice"屬于正偏態分布。
如果特征極其多,很難清晰的看到特征與目標變量之間的關系,就需要利用統計知識來進行多變量分析了。我們常使用熱圖heatmap結合corr方法來進行客觀分析,熱圖Heatmap可以用顏色變化來反映變量之間的相關性二維矩陣或說相關性表格中的數據信息,它可以直觀地將數據值的大小以定義的顏色深淺表示出來。這個項目,為了簡化訓練,我們以相關性絕對值大于0.5為界來選取我們需要的特征。
# 不用修改直接運行 corrmat = data_df.corr().abs() #計算連續型特征之間的相關系數 #將于SalePrice的相關系數大于5的特征取出來,并按照SalePrice降序排列,然后取出對應的特征名,保存在列表中 top_corr = corrmat[corrmat["SalePrice"]>0.5].sort_values(by = ["SalePrice"], ascending = False).index cm = abs(np.corrcoef(data_df[top_corr].values.T)) #注意這里要轉置,否則變成樣本之間的相關系數,而我們要計算的是特征之間的相關系數 f, ax = plt.subplots(figsize=(20, 9)) sns.set(font_scale=1.3) hm = sns.heatmap(cm, cbar=True, annot=True, square=True, fmt=".2f", annot_kws={"size": 13}, yticklabels=top_corr.values, xticklabels=top_corr.values); data_df = data_df[top_corr]
我們已經從龐大的特征群中篩選出了最相關的特征,也了解了我們目標數據的分布,那么接下來,我們從創造性方面來對我們的特征進行“改造”。
創造性:創造性主要是說兩種情況,一種是對現有數據的處理,比如對類別的獨熱編碼(One-hotEncoder)或者標簽編碼(LabelEncoder),數值的區間縮放,歸一化,標準化等等,另一種就是根據某一個或多個特征創造一個新的特征,例如某特征按組分類(groupby)后,或者某些特征組合后來創造新特征等等。
因為我們篩選出來的特征都為數值類型特征,所以我們只做標準化的操作:這個項目是一個回歸類型的項目,而我們的回歸算法對標準正態分步預測較為準確,從我們的目標數據可以看出數據是一個偏態分布,那么我們使用log將數據從偏態分布轉換為標準正態分布,最后進行標準化。
# 不要修改,直接運行 from scipy.special import boxcox1p from sklearn.preprocessing import StandardScaler data_df["SalePrice"] = np.log1p(data_df["SalePrice"]) # np.log1p()函數將數據從偏態分布轉換成標準正態分布 numeric_features = list(data_df.columns) numeric_features.remove("SalePrice") for feature in numeric_features: #all_data[feat] += 1 data_df[feature] = boxcox1p(data_df[feature], 0.15) scaler = StandardScaler() scaler.fit(data_df[numeric_features]) data_df[numeric_features] = scaler.transform(data_df[numeric_features])
筆記:
對目標變量的變換np.loglp():這個函數用來在數據預處理過程對偏度較大的數據進行平滑處理,使其更加符合高斯分布,有利于后續得到一個更好地結果,數學公式:ln(x+1).
對數值類型的特征變量的變換boxcox1p():對于數值類型為數值的特征變量,也需要進行類似的變換。通過統計每一變量的skew值(偏度/偏態值,越接近0,越符合正態分布。大于0為正偏態,小于0為負偏態),對絕對值大于0.5的進行boxcox變換。可以使線性回歸模型滿足線性性、獨立性、方差齊性以及正態性的同時,又不丟失信息,此種變換稱之為Box—Cox變換。$$y=frac{x^{lambda}-1}{lambda},lambda != 0 y=log(x),lambda == 0$$Box-Cox變換后,殘差可以更好的滿足正態性、獨立性等假設前提,降低了偽回歸的概率
在項目的第三步中,你需要了解必要的工具和技巧來讓你的模型能夠進行預測。用這些工具和技巧對每一個模型的表現做精確的衡量可以極大地增強你預測的可信度。
編程練習5:定義衡量標準如果不能對模型的訓練和測試的表現進行量化地評估,我們就很難衡量模型的好壞。通常我們會定義一些衡量標準,這些標準可以通過對某些誤差或者擬合程度的計算來得到。在這個項目中,你將通過運算決定系數 $R^2$ 來量化模型的表現。模型的決定系數是回歸分析中十分常用的統計信息,經常被當作衡量模型預測能力好壞的標準。
$R^2$ 的數值范圍從0至1,表示目標變量的預測值和實際值之間的相關程度平方的百分比。一個模型的 $R^2$ 值為0還不如直接用平均值來預測效果好;而一個 $R^2$ 值為1的模型則可以對目標變量進行完美的預測。從0至1之間的數值,則表示該模型中目標變量中有百分之多少能夠用特征來解釋。模型也可能出現負值的 $R^2$,這種情況下模型所做預測有時會比直接計算目標變量的平均值差很多。
問題5.1:
在下方代碼的 performance_metric 函數中,你要實現:
使用 sklearn.metrics 中的 r2_score 來計算 y_true 和 y_predict 的 $R^2$ 值,作為對其表現的評判。
將他們的表現評分儲存到 score 變量中。
# 5.1 TODO: 引入 "r2_score" from sklearn.metrics import r2_score def performance_metric(y_true, y_predict): """ Calculates and returns the performance score between true and predicted values based on the metric chosen. """ # TODO: 計算 "y_true" 與 "y_predict" 的r2值 score = r2_score(y_true, y_predict) # 返回這一分數 return score
筆記:
R^2是評價模型表現的方法之一,每個機器學習模型的建立都要有相對應的評價指標,后面我們會學到更多的評價指標。不過R^2其實也有很多局限性需要注意 https://en.wikipedia.org/wiki...
skearn對于常見的模型表現衡量方法也有詳細的介紹。
http://scikit-learn.org/stabl...
問題 5.2:擬合程度
假設一個數據集有五個數據且某一模型做出下列目標變量的預測:
真實數值 | 預測數值 |
---|---|
3.0 | 2.5 |
-0.5 | 0.0 |
2.0 | 2.1 |
7.0 | 7.8 |
4.2 | 5.3 |
你覺得這個模型已成功地描述了目標變量的變化嗎?如果成功,請解釋為什么,如果沒有,也請給出原因。
提示1:運行下方的代碼,使用 performance_metric 函數來計算 y_true 和 y_predict 的決定系數。
提示2:$R^2$ 分數是指可以從自變量中預測的因變量的方差比例。 換一種說法:
$R^2$ 為0意味著因變量不能從自變量預測。
$R^2$ 為1意味著可以從自變量預測因變量。
$R^2$ 在0到1之間表示因變量可預測的程度。
$R^2$ 為0.40意味著 Y 中40%的方差可以從 X 預測。
#TODO 5.2:計算這一模型的表現 score = performance_metric([3, -0.5, 2, 7, 4.2], [2.5, 0.0, 2.1, 7.8, 5.3]) print("Model has a coefficient of determination, R^2, of {:.3f}.".format(score))
Model has a coefficient of determination, R^2, of 0.923.
問題 5.2 - 回答:模型可以描述目標變量的變化,因為R^2值為0.923,說明自變量(預測數值)對因變量(真實數值)的解釋越好。
編程練習 6: 數據分割與重排接下來,你需要分割波士頓房屋數據集,包括特征與目標變量、訓練集和測試集。通常在這個過程中,數據也會被重排,以消除數據集中由于順序而產生的偏差。
在下面的代碼中,你需要
問題6.1:將data_df分割為特征和目標變量
# TODO: 6.1 labels = data_df["SalePrice"]#TODO:提取SalePrice作為labels features = data_df.drop(["SalePrice"], axis=1)#TODO:提取除了SalePrice以外的特征賦值為features
問題6.2 :
使用 sklearn.model_selection 中的 train_test_split, 將 features 和 prices 的數據都分成用于訓練的數據子集和用于測試的數據子集。
分割比例為:80%的數據用于訓練,20%用于測試;
選定一個數值以設定 train_test_split 中的 random_state ,這會確保結果的一致性;
將分割后的訓練集與測試集分配給 X_train, X_test, y_train 和 y_test。
# TODO: 引入 "train_test_split" from sklearn.model_selection import train_test_split # TODO: 打亂并分割訓練集與測試集 X_train, X_test, y_train, y_test = train_test_split(features, labels, test_size=0.2, random_state=1) # 成功~ print("Training and testing split was successful.")
Training and testing split was successful.
問題 6.3 - 訓練及測試
將數據集按一定比例分為訓練用的數據集和測試用的數據集對學習算法有什么好處?
如果用模型已經見過的數據,例如部分訓練集數據進行測試,又有什么壞處?
提示: 如果沒有數據來對模型進行測試,會出現什么問題?
問題 6.3 - 回答:
將數據集按一定比例分為訓練用的數據集和測試用的數據集對學習算法可以對算法進行驗證,在一定程度上避免算法過擬合;
如果部分訓練數據進行測試,會使得算法的準確率不可靠;
如果沒有數據進行測試,無法說明模型的優劣。
將數據集分成訓練集和測試集的好處:既可以用于訓練又可以用于測試,而且不會相互干擾,而且可以對訓練模型進行有效的驗證。
用部分訓練集進行測試的壞處:模型就是根據訓練集得出的,使用訓練集進行測試肯定會得出較好的結果,這不能判斷訓練模型的優劣。
在項目的第四步,我們來觀察不同參數下,模型在訓練集和驗證集上的表現。這里,我們專注于一個特定的算法(帶剪枝的決策樹DecisionTreeRegressor,但這并不是這個項目的重點)和這個算法的一個參數 "max_depth"。用全部訓練集訓練,選擇不同"max_depth" 參數,觀察這一參數的變化如何影響模型的表現。畫出模型的表現來對于分析過程十分有益。
學習曲線下方區域內的代碼會輸出四幅圖像,它們是一個決策樹模型在不同最大深度下的表現。每一條曲線都直觀得顯示了隨著訓練數據量的增加,模型學習曲線在訓練集評分和驗證集評分的變化,評分使用決定系數 $R^2$。曲線的陰影區域代表的是該曲線的不確定性(用標準差衡量)。
運行下方區域中的代碼,并利用輸出的圖形回答下面的問題。
# Produce learning curves for varying training set sizes and maximum depths vs.ModelLearning(features, labels)問題 7 - 學習曲線
選擇上述圖像中的其中一個,并給出其最大深度。
隨著訓練數據量的增加,訓練集曲線的評分有怎樣的變化?驗證集曲線呢?
如果有更多的訓練數據,是否能有效提升模型的表現呢?
提示:學習曲線的評分是否最終會收斂到特定的值?一般來說,你擁有的數據越多,模型表現力越好。但是,如果你的訓練和測試曲線以高于基準閾值的分數收斂,這是否有必要?基于訓練和測試曲線已經收斂的前提下,思考添加更多訓練點的優缺點。
問題 7 - 回答:當max_depth為3時,隨著訓練數據的增加,訓練集曲線的評分降低,驗證集曲線的評分提高,但是兩者會收斂到一特定數值,隨著訓練數據的增加,模型表現不再提高,此時沒有必要再繼續增加訓練數據,因為會增加模型的訓練時間。但是,如果在過擬合的情況下,比方說當max_depth為6或者10時,隨著訓練數據的增加,模型表現也不斷提高,此時反而有必要增加訓練數據。
筆記:
對訓練曲線和測試曲線趨勢和意義解釋的很好。這里隨著數據的增多,max_depth不變的情況下,模型提升的幅度也越來越小。
傳統的機器學習算法(又被稱為基于統計的機器學習)在數據量達到一定程度后,更多的數據無法提升模型的表現。深度學習的一個優勢就是它可以把大量的數據利用起來,提升學習表現。
這里還有更多關于學習曲線的介紹:
https://www.coursera.org/lear...
http://scikit-learn.org/stabl...
傳統的機器學習算法(又被稱為基于統計的機器學習)在數據量達到一定程度后,更多的數據無法提升模型的表現。深度學習的一個優勢就是它可以把大量的數據利用起來,提升學習表現。
這里還有更多關于學習曲線的介紹:
https://www.coursera.org/lear...
http://scikit-learn.org/stabl...
下列代碼內的區域會輸出一幅圖像,它展示了一個已經經過訓練和驗證的決策樹模型在不同最大深度條件下的表現。這個圖形將包含兩條曲線,一個是訓練集的變化,一個是驗證集的變化。跟學習曲線相似,陰影區域代表該曲線的不確定性,模型訓練和測試部分的評分都用的 performance_metric 函數。
運行下方區域中的代碼,根據問題5與問題6對輸出的圖形進行分析并給出你思考的結果。
vs.ModelComplexity(X_train, y_train)問題 8 - 偏差(bias)與方差(variance)之間的權衡取舍
當模型以最大深度 1訓練時,模型的預測是出現很大的偏差還是出現了很大的方差?
當模型以最大深度10訓練時,情形又如何呢?
圖形中的哪些特征能夠支持你的結論?
提示: 高偏差表示欠擬合(模型過于簡單),而高方差表示過擬合(模型過于復雜,以至于無法泛化)??紤]哪種模型(深度1或10)對應著上述的情況,并權衡偏差與方差。
問題 8 - 回答:當max_depth為1時,模型表現出高偏差,因為訓練集和測試集的R2分數都比較低;當max_depth為10時,模型表現出高方差,因為訓練集的R2分數較高,而驗證集的R2分數較低。
筆記:
偏差-方差分解是解釋學習算法泛化性能的重要工具。這里你需要理解三個方面:
什么是泛化誤差(Generalization error):
如果學得到的模型是 f ,那么用這個模型對測試數據預測的誤差即為泛化誤差。一般所說的泛化誤差都是算法的期望泛化誤差。
Bias-Variance分解:
現在我們來看題目中的方差和偏差到底是什么意思?通過簡單的多項式展開合并,可以對算法的期望泛化誤差進行分解可以得到(具體推到過程請參考[1]、[2]) :
也就是說:泛化誤差=偏差+方差+噪聲
偏差度量了學習算法的期望預測和真實結果的偏離程度,即刻畫了學習算法本身的擬合能力。
方差度量了同樣大小的訓練集的變動所導致的學習性能的變化, 即 刻畫了數據擾動所造成的影響。
Bias-Variance trade-off:
一般情況下,偏差和方差是有沖突的,如下圖所示。為了取得好的泛化性能,則需要偏差較小,即能夠充分擬合數據,并且方差較小,即使得數據擾動產生的影響小。
欠擬合:在訓練不足時,學習的擬合能力不夠強,訓練數據的擾動不足以使學習器產生顯著變化,偏差主導了泛化錯誤率。
過擬合:充分訓練后, 學習器的擬合能力已非常強, 訓練數據的輕微擾動都會導致學習器發生顯著變化, 訓練數據自身的、非全局的特性被學習器學到了,方差主導了泛化錯誤率。
更多內容請閱讀參考資料。
參考資料:
[1] ?機器學習?, 周志華, 2.5 節偏差與方差.
[2] Understanding the Bias-Variance Tradeoff
問題 9- 最優模型的猜測結合復雜度曲線,你認為最大深度是多少的模型能夠最好地對未見過的數據進行預測?
你得出這個答案的依據是什么?
提示:查看問題8上方的圖表,并查看模型在不同 depth下的驗證分數。隨著深度的增加模型的表現力會變得更好嗎?我們在什么情況下獲得最佳驗證分數而不會使我們的模型過度復雜?請記住,奧卡姆剃刀:“在競爭性假設中,應該選擇假設最少的那一個?!?/p>
問題 9 - 回答:
隨著深度的增加模型表現并沒有越來越好,驗證集在max_depth為4時,模型收斂,并且訓練R2分數和驗證R2較高。
隨著最大深度的提升,訓練集R2分數不斷上升,驗證集R2分數并沒有得到提高,反而有下降的趨勢,說明隨著模型變得復雜,模型過擬合。
考慮模型的復雜度和R2分數,最大深度為4的模型具有最好的泛化能力。
在項目的最后一節中,你將構建一個模型,并使用 fit_model 中的優化模型去預測客戶特征集。
問題 10- 網格搜索(Grid Search)什么是網格搜索法?
如何用它來優化模型?
提示:在解釋網格搜索算法時,首先要理解我們為什么使用網格搜索算法,以及我們使用它的最終目的是什么。為了使你的回答更具有說服力,你還可以給出一個模型中可以使用此方法進行優化參數的示例。
問題 10 - 回答: 網格搜索法是給定參數值,窮舉搜索尋找最優參數的算法。網格搜索法通過構建一個參數的字典,創造出不同的參數組合,輸入給分類器進行訓練,采用交叉驗證,尋找驗證分數最高的那一組參數,這一組參數就是模型的最優參數。
網格搜索算法是一種窮舉搜索的算法。
在所有候選的參數選擇中,通過循環遍歷,嘗試每一種可能性,表現最好的參數就是最終的結果。其原理就像是在數組里找最大值。以有兩個參數的模型為例,參數a有3種可能,參數b有4種可能,把所有可能性列出來,可以表示成一個3*4的表格,其中每個cell就是一個網格,循環過程就像是在每個網格里遍歷、搜索,所以叫grid search。
問題 11 - 交叉驗證什么是K折交叉驗證法(k-fold cross-validation)?
GridSearchCV 是如何結合交叉驗證來完成對最佳參數組合的選擇的?
GridSearchCV 中的"cv_results_"屬性能告訴我們什么?
網格搜索為什么要使用K折交叉驗證?K折交叉驗證能夠避免什么問題?
提示:在解釋k-fold交叉驗證時,一定要理解"k"是什么,和數據集是如何分成不同的部分來進行訓練和測試的,以及基于"k"值運行的次數。
在考慮k-fold交叉驗證如何幫助網格搜索時,你可以使用特定的數據子集來進行訓練與測試有什么缺點,以及K折交叉驗證是如何幫助緩解這個問題。
問題 11 - 回答:
K折交叉驗證是隨機將訓練集劃分成K份,依次將其中的一份作為驗證集,其余的K-1份作為訓練集,得到K個模型,觀察每個模型的表現,選擇模型表現最好的那一個,K折交叉驗證能夠有效的防止過擬合;
GridSearchCV通過交叉驗證得到每個參數組合的得分,以此確定最優的參數組合;
GridSearchCV 中的cv_results 屬性返回一個字典,記錄了每一組網格參數每一次訓練/驗證( K 折對應 K 次)對應的訓練結果,包括訓練/驗證時間、訓練/驗證評估分數以及相關時間和評分的統計信息;
采用交叉驗證可以使得網格搜索的結果可信度更高,對網格搜索來說,可以將訓練數據可以按一定比例分為訓練集和驗證集,而不使用交叉驗證,但是這樣做的話,網格搜索的結果依賴于訓練集和驗證集的劃分,這樣的劃分不具有代表性。采用K折交叉驗證取平均值可以避免樣本劃分不合理的情況,使得結果可信度更高。
編程練習 7:訓練最優模型在這個練習中,你將需要將所學到的內容整合,使用決策樹算法訓練一個模型。為了得出的是一個最優模型,你需要使用網格搜索法訓練模型,以找到最佳的 "max_depth" 參數。你可以把"max_depth" 參數理解為決策樹算法在做出預測前,允許其對數據提出問題的數量。決策樹是監督學習算法中的一種。
在下方 fit_model 函數中,你需要做的是:
定義 "cross_validator" 變量: 使用 sklearn.model_selection 中的 KFold 創建一個交叉驗證生成器對象;
定義 "regressor" 變量: 使用 sklearn.tree 中的 DecisionTreeRegressor 創建一個決策樹的回歸函數;
定義 "params" 變量: 為 "max_depth" 參數創造一個字典,它的值是從1至10的數組;
定義 "scoring_fnc" 變量: 使用 sklearn.metrics 中的 make_scorer 創建一個評分函數;
將 ‘performance_metric’ 作為參數傳至這個函數中;
定義 "grid" 變量: 使用 sklearn.model_selection 中的 GridSearchCV 創建一個網格搜索對象;將變量"regressor", "params", "scoring_fnc"和 "cross_validator" 作為參數傳至這個對象構造函數中;
如果你對python函數的默認參數定義和傳遞不熟悉,可以參考這個MIT課程的視頻。
# TODO: Import "make_scorer", "DecisionTreeRegressor", and "GridSearchCV" from sklearn.model_selection import KFold from sklearn.tree import DecisionTreeRegressor from sklearn.metrics import make_scorer from sklearn.model_selection import GridSearchCV def fit_model(X, y): """ Performs grid search over the "max_depth" parameter for a decision tree regressor trained on the input data [X, y]. """ cross_validator = KFold(n_splits=10) # TODO: Create a decision tree regressor object regressor = DecisionTreeRegressor(random_state=1) # TODO: Create a dictionary for the parameter "max_depth" with a range from 1 to 10 params = {"max_depth":[i for i in range(1, 11)]} # TODO: Transform "performance_metric" into a scoring function using "make_scorer" scoring_fnc = make_scorer(performance_metric) # TODO: Create the grid search cv object --> GridSearchCV() # Make sure to include the right parameters in the object: # (estimator, param_grid, scoring, cv) which have values "regressor", "params", "scoring_fnc", and "cross_validator" respectively. grid = GridSearchCV(regressor, params, scoring_fnc, cv = cross_validator) # Fit the grid search object to the data to compute the optimal model grid = grid.fit(X, y) # Return the optimal model after fitting the data return grid.best_estimator_第六步. 做出預測
當我們用數據訓練出一個模型,它就可用于對新的數據進行預測。在我們的例子--決策樹回歸函數中,模型已經學會對新輸入的數據“提問”,并返回對目標變量的預測值。你可以用這些預測來獲取未知目標變量的數據的信息,但是,輸入的新數據必須不能是已有訓練數據之中的。
問題 12 - 最優模型最優模型的最大深度(maximum depth)是多少?此答案與你在問題 9所做的猜測是否相同?
運行下方區域內的代碼,將決策樹回歸函數代入訓練數據的集合,以得到最優化的模型。
# Fit the training data to the model using grid search reg = fit_model(X_train, y_train) # Produce the value for "max_depth" print("Parameter "max_depth" is {} for the optimal model.".format(reg.get_params()["max_depth"]))
Parameter "max_depth" is 5 for the optimal model.
最終,使用我們確認好的參數來對測試數據進行預測,完成下面的問題,來看看我們的訓練結果如何吧
問題12.1:填入上題所確認的最優參數,查看測試結果
depth = 5 regressor = DecisionTreeRegressor(max_depth = depth) regressor.fit(X_train, y_train) y_pred = regressor.predict(X_test) score = performance_metric(y_test, y_pred) print("The R2 score is ",score)
The R2 score is 0.7520883029841192
問題12.2:你剛剛計算了最優模型在測試集上的決定系數,你會如何評價這個結果?還有什么地方可以改進,以提升這一分數呢?
回答問題12.2:這個結果并不是理想的,應該還需要利用決策樹的其他參數進行網格搜索,以及使用更多的特征;
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/43494.html
摘要:十三套框架助你玩轉機器學習技術在今天的文章中,我們將共同了解十三款機器學習框架,一部分去年剛剛發布另一部分則在不久前進行了全部升級。目前該項目正積極添加對的支持能力,不過此類項目一般更傾向于直接面向各承載機器學習任務的主流環境。 導讀過去幾年以來,機器學習已經開始以前所未有的方式步入主流層面。這種趨勢并非單純由低成本云環境乃至極為強大的GPU硬件所推動; 除此之外,面向機器學習的可用框架也迎...
摘要:普通程序員,如何轉向人工智能方向,是知乎上的一個問題。領域簡介,也就是人工智能,并不僅僅包括機器學習。但是,人工智能并不等同于機器學習,這點在進入這個領域時一定要認識清楚。 人工智能已經成為越來越火的一個方向。普通程序員,如何轉向人工智能方向,是知乎上的一個問題。本文是對此問題的一個回答的歸檔版。相比原回答有所內容增加。 目的 本文的目的是給出一個簡單的,平滑的,易于實現的學習方法,幫...
閱讀 541·2019-08-30 15:55
閱讀 951·2019-08-29 15:35
閱讀 1208·2019-08-29 13:48
閱讀 1916·2019-08-26 13:29
閱讀 2944·2019-08-23 18:26
閱讀 1247·2019-08-23 18:20
閱讀 2840·2019-08-23 16:43
閱讀 2715·2019-08-23 15:58