【机器学习】完整的机器学习项目演练:第一部分
把機器學習拼接起來
通過閱讀數據科學書籍或參加課程,可以感覺到你有各自的作品,但不太知道如何將它們組合在一起。采取下一步并解決完整的機器學習問題可能令人生畏,但保留和完成第一個項目將使您有信心解決任何數據科學問題。本系列文章將介紹一個包含真實數據集的完整機器學習解決方案,讓您了解所有部分是如何組合在一起的。
我們將按照一般的機器學習工作流程逐步進行:
在此過程中,我們將看到每個步驟如何流入下一步以及如何在Python中專門實現每個部分。該完整的項目可在GitHub上,與這里的部分的jupyter notebook。第一篇文章將介紹步驟1-3,其余內容將在后續文章中介紹。
(作為一個說明,這個問題最初是作為啟動時作業屏幕的“任務”給我的。完成工作后,我得到了工作,但公司的首席技術官辭職了,他們不是'能夠引進任何新員工。我想這就是啟動現場的情況!)
?
問題定義
我們編寫代碼之前的第一步是了解我們要解決的問題和可用數據。在這個項目中,我們將使用紐約市公開提供的建筑能源數據。
目標是使用能源數據建立一個模型,該模型可以預測建筑物的能源之星得分并解釋結果以找出影響得分的因素。
這些數據包括能源之星得分,這使其成為受監督的回歸機器學習任務:
- 監督:我們可以訪問功能和目標,我們的目標是培訓可以學習兩者之間映射的模型
- 回歸:能源之星得分是一個連續變量
我們希望開發一個既準確?的模型- 它可以預測接近真實值的能源之星分數 - 并且可以解釋??- 我們可以理解模型預測。一旦我們了解了目標,我們就可以在我們深入研究數據和構建模型時使用它來指導我們的決策。
?
數據清理
與您認為的大多數數據科學課程相反,并非每個數據集都是完美策劃的觀察組,沒有缺失值或異常(查看您的mtcars和虹膜數據集)。現實世界的數據很混亂,這意味著我們需要在可以開始分析之前將其清理并加工成可接受的格式。數據清理是大多數實際數據科學問題的一個非常迷人但必不可少的部分。
首先,我們可以將數據加載為Pandas?DataFrame并查看:
import pandas as pd import numpy as np # Read in data into a dataframe data = pd.read_csv('data/Energy_and_Water_Data_Disclosure_for_Local_Law_84_2017__Data_for_Calendar_Year_2016_.csv') # Display top of dataframe data.head()?
這是包含60列的完整數據的子集。我們已經看到了幾個問題:首先,我們知道我們想要預測,ENERGY STAR Score但我們不知道任何列的含義。雖然這不一定是一個問題 - 我們通常可以在不了解變量的情況下制作精確的模型 - 我們希望專注于可解釋性,并且至少理解一些列可能很重要。
當我最初從初創公司獲得任務時,我不想問所有列名稱的含義,所以我查看了文件的名稱,
并決定尋找“地方法84”。這導致我進入這個頁面,解釋這是紐約市法律要求所有規模的建筑物報告他們的能源使用情況。更多的搜索讓我了解了列的所有定義。也許看一個文件名是一個顯而易見的起點,但對我來說,這是一個緩慢的提示,所以你不要錯過任何重要的東西!
我們不需要研究所有列,但我們至少應該了解能源之星得分,其描述如下:
基于報告年度自我報告的能源使用情況的1到100百分位排名。在能源之星的分數是用于比較建筑物的能源效率的相對度量。
這清除了第一個問題,但第二個問題是缺失值被編碼為“不可用”。這是Python中的一個字符串,這意味著即使帶有數字的列也將存儲為object數據類型,因為Pandas會將包含任何字符串的列轉換為所有字符串的列。我們可以使用以下dataframe.info()方法查看列的數據類型:
# 查看列數據類型和非缺失值 data.info()果然,一些明顯包含數字(例如ft2)的列存儲為對象。我們不能對字符串進行數值分析,因此必須將它們轉換為數字(特定float)數據類型!
這里有一個Python代碼,用于替換所有“Not Available”條目而不是number(np.nan),可以將其解釋為數字,然后將相關列轉換為float數據類型:
# 將所有不可用的numpy替換為numpy而不是數字 data = data.replace({'Not Available': np.nan})# 遍歷列 for col in list(data.columns):# 選擇應為數字的列if ('ft2' in col or 'kBtu' in col or 'Metric Tons CO2e' in col or 'kWh' in col or 'therms' in col or 'gal' in col or 'Score' in col):# 將數據類型轉換為floatdata[col] = data[col].astype(float)一旦正確的列是數字,我們就可以開始調查數據了。
?
缺少數據和異常值
除了不正確的數據類型之外,處理實際數據時的另一個常見問題是缺少值。這些可能由于許多原因而產生,并且必須在我們訓練機器學習模型之前填寫或移除。首先,讓我們了解每列中有多少缺失值(請參閱筆記本中的代碼)。
(為了創建這個表,我使用了這個Stack Overflow論壇中的一個函數)。
雖然我們總是要小心刪除信息,但如果列的缺失值百分比很高,那么它對我們的模型可能沒用。刪除列的閾值應該取決于問題(這是一個討論),對于這個項目,我們將刪除任何缺失值超過50%的列。
此時,我們可能還想刪除異常值。這可能是由于數據輸入中的拼寫錯誤,單位錯誤,或者它們可能是合法的但是極端值。對于這個項目,我們將根據極端異常值的定義刪除異常:
- 低于第一個四分位數--3 *四分位數范圍
- 高于第三個四分位數+3 *四分位數范圍
(有關刪除列和異常的代碼,請參閱筆記本)。在數據清理和異常刪除過程結束時,我們留下了超過11,000個建筑物和49個功能。
?
探索性數據分析
既然數據清理的繁瑣但必要的步驟已經完成,我們可以繼續探索我們的數據!探索性數據分析(EDA)是一個開放式過程,我們計算統計數據并制作數據以查找數據中的趨勢,異常,模式或關系。
簡而言之,EDA的目標是了解我們的數據可以告訴我們什么。它通常以高級概述開始,然后在我們找到有趣的數據部分時縮小到特定區域。這些發現本身可能很有趣,或者它們可以用來告知我們的建模選擇,例如幫助我們決定使用哪些功能。
單變量圖
目標是預測能源之星得分(score在我們的數據中重命名),因此合理的起點是檢查此變量的分布。直方圖是一種簡單而有效的方法,可視化單個變量的分布,并且易于使用matplotlib。
import matplotlib.pyplot as plt # Histogram of the Energy Star Score plt.style.use('fivethirtyeight') plt.hist(data['score'].dropna(), bins = 100, edgecolor = 'k'); plt.xlabel('Score'); plt.ylabel('Number of Buildings'); plt.title('Energy Star Score Distribution');這看起來很可疑!能源之星得分是百分位數,這意味著我們期望看到均勻分布,每個得分分配給相同數量的建筑物。然而,不成比例的建筑物具有最高,100或最低1的分數(能量之星得分越高越好)。
如果我們回到分數的定義,我們會發現它基于“自我報告的能量使用”,這可能解釋了非常高的分數。要求建筑物業主報告他們自己的能源使用情況就像要求學生在測試中報告他們自己的分數一樣!因此,這可能不是建筑物能效的最客觀衡量標準。
如果我們有無限的時間,我們可能想調查為什么這么多建筑物的分數非常高而且非常低,我們可以通過選擇這些建筑物并看到它們的共同點。但是,我們的目標只是預測得分,而不是設計更好的建筑物評分方法!我們可以在報告中記下分數有可疑分布,但我們主要關注的是預測分數。
?
尋找關系
EDA的一個主要部分是搜索特征和目標之間的關系。與目標相關的變量對模型很有用,因為它們可用于預測目標。檢查目標上的分類變量(僅接受有限的一組值)的影響的一種方法是使用seaborn庫的密度圖。
甲密度圖可以被看作是一個平滑的直方圖,因為它示出了單個變量的分布。我們可以按類別對密度圖進行著色,以查看分類變量如何改變分布。以下代碼根據建筑物的類型繪制能源之星得分的密度圖(僅限于具有超過100個數據點的建筑類型):
# 創建超過100個測量值的建筑物列表 types = data.dropna(subset=['score']) types = types['Largest Property Use Type'].value_counts() types = list(types[types.values > 100].index)# 建筑類別分數分布圖 figsize(12, 10)# 繪制每個建筑物 for b_type in types:# 選擇建筑類型subset = data[data['Largest Property Use Type'] == b_type]# 密度能源之星成績的plotsns.kdeplot(subset['score'].dropna(),label = b_type, shade = False, alpha = 0.8);# label the plot plt.xlabel('Energy Star Score', size = 20); plt.ylabel('Density', size = 20); plt.title('Density Plot of Energy Star Scores by Building Type', size = 28);我們可以看到建筑類型對能源之星得分有重大影響。辦公樓往往得分較高,而酒店得分較低。這告訴我們,我們應該在建模中包含建筑類型,因為它確實會對目標產生影響。作為一個分類變量,我們將不得不對建筑類型進行單熱編碼。
類似的情節可以用來顯示自治市鎮的能源之星得分:
?
自治市鎮的建筑類型似乎沒有那么大的影響。盡管如此,我們可能希望將其包含在我們的模型中,因為自治市鎮之間存在細微差別。
為了量化變量之間的關系,我們可以使用Pearson Correlation Coefficient。這是兩個變量之間線性關系的強度和方向的度量。得分+1是完全線性正關系,得分-1是完全負線性關系。相關系數的幾個值如下所示:
?
雖然相關系數無法捕獲非線性關系,但它是一種開始計算變量如何相關的好方法。在Pandas中,我們可以輕松計算數據幀中任何列之間的相關性:
#查找與分數的所有相關性并排序 correlations_data = data.corr()['score'].sort_values()與目標的最負(左)和正(右)相關:
特征與目標之間存在若干強烈的負相關,而不同類別的EUI最為負(這些指標在計算方式上略有不同)。該EUI -能源使用強度??-是能量通過一座由建筑物的面積有多大劃分的使用量。它旨在衡量建筑物的效率,評分越低越好。直覺上,這些相關性是有意義的:隨著EUI的增加,能源之星得分趨于下降。
?
雙變量圖
為了可視化兩個連續變量之間的關系,我們使用散點圖。我們可以在點的顏色中包含其他信息,例如分類變量。例如,下圖顯示了建筑類型所著色的能源之星得分與場地EUI:
該圖使我們可以看到-0.7的相關系數是什么樣的。隨著場地EUI減少,能源之星得分增加,這種關系在建筑類型中保持穩定。
我們將要做的最終探索性情節被稱為Pairs Plot。這是一個很好的探索工具,因為它可以讓我們看到多對變量之間的關系以及單個變量的分布。在這里,我們使用seaborn可視化庫和PairGrid函數來創建一個對上圖,上面的三角形上有散點圖,對角線上的直方圖和下三角形上的2D核密度圖和相關系數。
# 提取要繪制的列 plot_data = features[['score', 'Site EUI (kBtu/ft2)', 'Weather Normalized Source EUI (kBtu/ft2)', 'log_Total GHG Emissions (Metric Tons CO2e)']]# 用nan替換inf plot_data = plot_data.replace({np.inf: np.nan, -np.inf: np.nan})# 重命名列 plot_data = plot_data.rename(columns = {'Site EUI (kBtu/ft2)': 'Site EUI', 'Weather Normalized Source EUI (kBtu/ft2)': 'Weather Norm EUI','log_Total GHG Emissions (Metric Tons CO2e)': 'log GHG Emissions'})# 刪除na值 plot_data = plot_data.dropna()# 功能計算兩列之間的相關系數 def corr_func(x, y, **kwargs):r = np.corrcoef(x, y)[0][1]ax = plt.gca()ax.annotate("r = {:.2f}".format(r),xy=(.2, .8), xycoords=ax.transAxes,size = 20)# 創建pairgrid對象 grid = sns.PairGrid(data = plot_data, size = 3)# 上是一個散點圖 grid.map_upper(plt.scatter, color = 'red', alpha = 0.6)# 對角線是直方圖 grid.map_diag(plt.hist, color = 'red', edgecolor = 'black')# 下方是相關性和密度圖 grid.map_lower(corr_func); grid.map_lower(sns.kdeplot, cmap = plt.cm.Reds)# Title for entire plot plt.suptitle('Pairs Plot of Energy Data', size = 36, y = 1.02);?
要查看變量之間的交互,我們會查找行與列相交的位置。例如,要查看Weather Norm EUIwith?的相關性score,我們查看Weather Norm EUI行和score列,并查看相關系數-0.67。除了看起來很酷,這些圖可以幫助我們決定在建模中包含哪些變量。
?
特征工程與選擇
特征工程和選擇通常可以為機器學習問題提供最大的時間回報。首先,讓我們來定義這兩個任務是什么:
- 特征工程:獲取原始數據并提取或創建新特征的過程。這可能意味著轉換變量,例如自然日志和平方根,或者單熱編碼分類變量,以便可以在模型中使用它們。通常,我認為特征工程是從原始數據創建其他功能。
- 特征選擇:選擇數據中最相關特征的過程。在特征選擇中,我們刪除了一些功能,以幫助模型更好地概括新數據并創建更具可解釋性的模型。一般來說,我認為特征選擇是減去特征,所以我們只留下最重要的特征。
機器學習模型只能從我們提供的數據中學習,因此確保數據包含我們任務的所有相關信息至關重要。如果我們不為模型提供正確的數據,那么我們將其設置為失敗,我們不應期望它能夠學習!
對于此項目,我們將采取以下功能工程步驟:
- 單熱編碼分類變量(自治市鎮和財產使用類型)
- 添加數值變量的自然對數變換
在模型中包含分類變量需要單熱編碼。機器學習算法無法理解建筑類型的“辦公室”,因此如果建筑物是辦公室,我們必須將其記錄為1,否則記錄為0。
添加變換特征可以幫助我們的模型學習數據中的非線性關系。采用平方根,自然對數或各種特征的權力是數據科學中的常見做法,可以基于領域知識或在實踐中最有效的方法。這里我們將包括所有數字特征的自然對數。
以下代碼選擇數字要素,對這些要素進行日志轉換,選擇兩個分類要素,對這些要素進行一次熱編碼,并將這兩個要素連接在一起。這似乎很多工作,但它在熊貓中相對簡單!
# 復制原始數據 features = data.copy()# 選擇數字列 numeric_subset = data.select_dtypes('number')# 創建包含數字列日志的列 for col in numeric_subset.columns:# 跳過能源之星得分列if col == 'score':nextelse:numeric_subset['log_' + col] = np.log(numeric_subset[col])# 選擇分類列 categorical_subset = data[['Borough', 'Largest Property Use Type']]# 一個熱編碼 categorical_subset = pd.get_dummies(categorical_subset)# 使用concat加入兩個數據幀 # 確保使用axis = 1來執行列綁定 features = pd.concat([numeric_subset, categorical_subset], axis = 1)在此過程之后,我們擁有超過11,000個具有110列(特征)的觀測(建筑物)。并非所有這些功能都可能對預測能源之星得分有用,所以現在我們將轉向功能選擇以刪除一些變量。
?
特征選擇
我們數據中的110個功能中的許多功能都是多余的,因為它們彼此高度相關。例如,這里是Site EUI與Weather Normalized Site EUI的關系系數為0.997的圖。
彼此強相關的特征被稱為共線特征,并且移除這些特征對中的一個變量通常可以幫助機器學習模型概括并且更易于解釋。(我應該指出,我們正在討論功能與其他功能的相關性,而不是與目標的相關性,這有助于我們的模型!)
有許多方法可以計算特征之間的共線性,其中最常見的是方差膨脹因子。在這個項目中,我們將使用相關系數來識別和刪除共線特征。如果它們之間的相關系數大于0.6,我們將丟棄一對特征中的一個。對于實現,請看一下筆記本(以及此Stack Overflow答案)
雖然這個值似乎是任意的,但我嘗試了幾個不同的閾值,這個選擇產生了最好的模型。機器學習是一個經驗領域,通常是試驗和發現最佳表現!選擇特征后,我們剩下64個總功能和1個目標。
# Remove any columns with all na values features = features.dropna(axis=1, how = 'all') print(features.shape) (11319, 65)?
建立基線
我們現在已經完成了數據清理,探索性數據分析和特征工程。在開始建模之前采取的最后一步是建立一個naive基線。這基本上是我們可以比較我們的結果的猜測。如果機器學習模型沒有超過這個猜測,那么我們可能必須得出結論,機器學習對于任務是不可接受的,或者我們可能需要嘗試不同的方法。
對于回歸問題,合理的naive基線是猜測測試集中所有示例的訓練集上目標的中值。這為任何模型設定了相對較低的標準。
我們將使用的度量是平均絕對誤差(mae),它測量預測的平均絕對誤差。回歸有很多指標,但我喜歡Andrew Ng建議選擇一個指標,然后在評估模型時堅持使用它。平均絕對誤差易于計算且可解釋。
在計算基線之前,我們需要將數據分成訓練和測試集:
我們將使用70%的數據進行培訓,30%的數據用于測試:
# Split into 70% training and 30% testing set X, X_test, y, y_test = train_test_split(features, targets, test_size = 0.3, random_state = 42)?
現在我們可以計算出naive?基線表現:
# Function to calculate mean absolute error def mae(y_true, y_pred):return np.mean(abs(y_true - y_pred))baseline_guess = np.median(y)print('The baseline guess is a score of %0.2f' % baseline_guess) print("Baseline Performance on the test set: MAE = %0.4f" % mae(y_test, baseline_guess))naive?估計在測試集上減少了約25個點。得分范圍從1-100,所以這代表25%的錯誤,超過相當低的標準!
?
結論
在本文中,我們介紹了機器學習問題的前三個步驟。在定義問題后,我們:
最后,我們還完成了建立基線的關鍵步驟,我們可以據此判斷機器學習算法。
第二篇文章(此處提供)將展示如何使用Scikit-Learn評估機器學習模型,選擇最佳模型,以及執行超參數調整以優化模型。處理模型解釋和報告結果的第三篇文章就在這里。
一如既往,我歡迎反饋和建設性的批評,可以在Twitter?@koehrsen_will上聯系。
?
原文:https://towardsdatascience.com/a-complete-machine-learning-walk-through-in-python-part-one-c62152f39420
?
?
?
?
?
總結
以上是生活随笔為你收集整理的【机器学习】完整的机器学习项目演练:第一部分的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [生存志] 第55节 吴公子札巡访中原
- 下一篇: ESP32-cam使用-智能家居云端视频