這是一篇完全手把手進行機器學習項目構建的教程,包含:
1. 數據清理和格式化
2. 探索性數據分析
3. 特徵工程和特徵選擇
4. 在性能指標上比較幾種機器學習模型
5. 對最佳模型執行超參數調整
6. 在測試集合中評估最佳模型
7. 解釋模型結果
8. 得出結論。
今天是第一部分(1-3)從數據清理,到數據分析,到特徵工程,再到Baseline的構建,作者以淺顯易懂的語言和清晰的示例和代碼教你從頭開始走過一個機器學習之旅,並且附詳細的代碼,大家可以收藏和學習。
作者 | William Koehrsen
編譯 | 專知
參與 | Chaofan, Xiaowen
添加微信:MLAPython
(姓名-單位-方向)
即可加入機器學習交流群
全文下載方式:
公眾號後臺回復關鍵詞
20180813
用python完成一個完整的機器學習項目
第一部分
Putting the machine learning pieces together
閱讀一本數據科學書籍或學習一門相關的課程,你可能感覺你有了獨立的碎片,但不知道如何將它們拼在一起。想要繼續推進下去並解決完整的機器學習問題可能令人望而生畏,但完成第一個項目後將使你有信心應對任何數據科學問題。本系列文章將介紹——使用了真實世界數據集的機器學習項目的完整解決方案,讓你了解所有碎片是如何拼接在一起的。
我們將按照一般機器學習的工作流程逐步進行:
1. 數據清理和格式化
2. 探索性數據分析
3. 特徵工程和特徵選擇
4. 在性能指標上比較幾種機器學習模型
5. 對最佳模型執行超參數調整
6. 在測試集合中評估最佳模型
7. 解釋模型結果
8. 得出結論
按照上述流程,我們將介紹每個步驟如何進入到下一步,以及如何用Python實現每個部分。完整的項目在GitHub上可以找到,第一個notebook在這裡。 第一篇文章將涵蓋步驟1-3,其餘的內容將在後面的文章中介紹。
GitHub完整項目連結:
https://github.com/WillKoehrsen/machine-learning-project-walkthrough
問題定義
編碼之前的第一步是了解我們試圖解決的問題和可用的數據。在這個項目中,我們將使用公共可用的紐約市的建築能源數據【1】。
目標是使用能源數據建立一個模型,來預測建築物的Energy Star Score(能源之星分數),並解釋結果以找出影響評分的因素。
數據包括Energy Star Score,意味著這是一個監督回歸機器學習任務:
監督:我們可以知道數據的特徵和目標,我們的目標是訓練可以學習兩者之間映射關係的模型。
回歸:Energy Star Score是一個連續變量。
我們想要開發一個模型,在準確性上——它可以實現預測Energy Star Score,並且結果接近真實值。在解釋上—— 我們可以理解模型的預測。
一旦我們知道了目標,在深入挖掘數據並構建模型時,就可以用它來指導我們的決策。
數據清洗
與大多數數據科學課程所相信的相反,並非每個數據集都是一組完美的觀測數據,沒有缺失值或異常值(你可以查看你的mtcars【2】和iris數據集【3】)。 現實世界的數據很亂,這意味著在我們開始分析之前,我們需要清理並將其轉換為可接受的格式【4】。數據清理,是大多數實際的數據科學問題中不具吸引力,但必不可少的一部分。
首先,我們可以將數據用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的情況,但我們不知道任何一列的含義。 雖然這不一定是個問題——我們通常可以在沒有任何變量知識的情況下創建一個準確的模型——我們想把重點放在模型的可解釋性上,而至少了解一些列可能是重要的。
起初,我從初創階段得到任務時,我不想問所有的列名是什麼意思,所以我查看了csv文件的名稱,
並決定搜索「Local Law 84」。 所以在上文我解釋——這是紐約法律要求的,所有具有一定規模的建築物報告其能源使用情況。 關於列的更多搜索內容在這裡。 也許看一個文件名是一個明顯的開始,但對我來說,這是提醒你要放慢速度,這樣你才不會錯過任何重要的東西!
我們不需要研究所有的列的定義,但我們至少應該了解Energy Star Score,它被描述為:
根據報告年度中,自我報告的能源使用情況而進行的1至100百分位的排名。 Energy Star Score是用於比較建築物能效的相對度量。【5】
這解決了第一個小問題,但第二個問題是缺少的值被編碼為「Not Available」。 這是Python中的一個字符串,這意味著甚至包含數字的列都將被存儲為object數據類型,因為Pandas會將包含任何字符串的列轉換為所有元素都為字符串的列。我們可以使用dataframe.info()方法來查看列的數據類型:
# See the column data types and non-missing values
data.info()
當然,一些明確包含數字(例如ft²)的列被存儲為object類型。 我們不能對字符串進行數值分析,因此必須將其轉換為數字(特別是浮點數)數據類型!
這裡有一個簡短的Python代碼,用不是數字(np.nan)代替所有「Not Available」條目,np.nan可以被解釋為數字,這樣就可以將相關列轉換為float數據類型:
# Replace all occurrences of Not Available with numpy not a number
data = data.replace({'Not Available': np.nan})
# Iterate through the columns
for col in list(data.columns):
# Select columns that should be numeric
if ('ft²' 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):
# Convert the data type to float
data[col] = data[col].astype(float)
一旦列是數字,我們就可以開始進行調查數據。
缺少數據和異常值
除了不正確的數據類型外,處理真實世界數據時的另一個常見問題是缺失值。 這可能是由於許多原因引起的,在我們訓練機器學習模型之前必須填寫或刪除。首先,讓我們了解每列中有多少缺失值(請參閱notebook中的代碼)。
(為了創建這個表,我使用了這個Stack Overflow論壇的一個函數【6】)。
儘管我們總是希望小心刪除信息,但如果列中缺失值的比例很高,那麼它對我們的模型可能不會有用。刪除列的閾值應該取決於實際問題,並且對於此項目,我們將刪除缺失值超過50%的列。
此時,我們可能還想要移除異常值。這些異常可能是由於數據輸入中的拼寫錯誤,單位中的錯誤,或者它們可能是合法但是極端的值。對於這個項目,我們將根據極端異常值的定義來消除異常:
1. the first quartile − 3 ∗ interquartile range
2. he third quartile + 3 ∗ interquartile range
(有關刪除列和異常的代碼,請參閱notebook)。 在數據清理和異常清除過程結束時,我們剩下11,000多個建築物和49個特徵。
探索性數據分析
現在,數據清理這個乏味但必要的步驟已經完成,我們可以繼續探索我們的數據!探索性數據分析(EDA)是一個開放式的過程,我們可以計算統計數據,並畫圖去發現數據中的趨勢,異常,模式或關係。(trends, anomalies, patterns, or relationships)
簡而言之,EDA的目標是了解我們的數據可以告訴我們什麼。它通常以高層概述開始,在我們發現有趣的數據部分後,再縮小到特定的區域。這些發現本身可能很有意思,或者可以用於通知我們的建模選擇,例如幫助我們決定使用哪些特徵。
單變量圖
目標是預測Energy Star Score(將其重新命名為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');
這看起來很可疑! Energy Star Score是百分位數,這意味著我們期望看到一個統一的分布,即每個得分分配給相同數量的建築物。然而,不成比例的建築物具有最高的100分或最低的1分(對於Energy Star Score來說更高表示越好)。
如果我們回到score的定義,我們會看到它基於「自我報告能量使用」,這可能解釋了分數偏高——要求建築物所有者報告自己的能源使用情況就像要求學生在測試中報告自己的分數! 因此,這可能不是衡量建築能效的最客觀標準。
如果我們有無限的時間,我們可能想要調查為什麼這麼多建築物有非常高和非常低的分數——我們可以通過選擇這些建築物並查看它們的共同點。但是,我們的目標只是預測分數,而不是設計更好的建築物評分方法! 我們可以在我們的報告中記下分數具有可疑分布,但我們主要關注預測分數。
尋找關係
EDA的主要部分是搜索特徵和目標之間的關係。與目標相關的變量對模型很有用,因為它們可用於預測目標。通過使用seaborn庫的密度圖可以檢查目標上的分類變量(僅採用有限的一組值)的效果。
密度圖可以被認為是平滑的直方圖,因為它顯示了單個變量的分布。我們可以按類別對密度圖進行著色,以查看分類變量如何改變分布。下面的代碼創建了一個用建築物類型(僅限於具有超過100個數據點的建築物類型)著色的Energy Star Score密度圖:
# Create a list of buildings with more than 100 measurements
types = data.dropna(subset=['score'])
types = types['Largest Property Use Type'].value_counts()
types = list(types[types.values > 100].index)
# Plot of distribution of scores for building categories
figsize(12, 10)
# Plot each building
for b_type in types:
# Select the building type
subset = data[data['Largest Property Use Type'] == b_type]
# Density plot of Energy Star scores
sns.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);
我們可以看到建築類型對Energy Star Score有重大影響。 辦公樓往往有較高的分數,而酒店的分數較低。這告訴我們,我們應該在建模中包含建築類型,因為它確實對目標有影響。 作為分類變量,我們將不得不對建築物類型進行one-hot編碼。
同上,可以顯示自治市鎮的Energy Star Score:
自治市鎮對建築類型的評分似乎沒有太大的影響。 儘管如此,我們可能希望將其納入我們的模型中,因為各區之間存在細微的差異。
為了量化變量之間的關係,我們可以使用Pearson相關係數。它可以用來衡量兩個變量之間的線性關係的強度和方向。 +1分是完美的線性正相關關係,-1分是完美的負線性關係。 相關係數的幾個值如下所示:
雖然相關係數無法捕捉非線性關係,但它是開始計算變量如何相關的好方法。 在Pandas中,我們可以輕鬆計算數據框中任何列之間的相關性:
# Find all correlations with the score and sort
correlations_data = data.corr()['score'].sort_values()
與目標的最負面(左)和最正面(右)相關性:
特徵與目標之間存在幾個強烈的負相關性,而EUI對目標最為負面。(這些測量方法在計算方式上略有不同)EUI——能源使用強度(Energy Use Intensity)——是建築物使用的能源量除以建築物的平方英尺。它意味著衡量一個建築,效率越低越好。直觀地說,這些相關性是有意義的:隨著EUI的增加,Energy Star Score趨於下降。
雙變量圖
為了可視化兩個連續變量之間的關係,我們使用散點圖。我們可以在點的顏色中包含附加信息,例如分類變量。例如,下面的圖表顯示了不同建築物類型的Energy Star Score與site EUI的關係:
這個圖讓我們可以看到-0.7的相關係數。 隨著Site EUI減少,Energy Star Score增加,這種關係在建築類型中保持穩定。
我們將做的最後的探索性plot被稱為Pairs Plot。這是一個很好的探索工具,因為它可以讓我們看到多個變量對之間的關係以及單個變量的分布。在這裡,我們使用seaborn可視化庫和PairGrid函數來創建上三角上具有散點圖的配對圖,對角線上的直方圖以及下三角形上的二維核密度圖和相關係數。
# Extract the columns to plot
plot_data = features[['score', 'Site EUI (kBtu/ft²)',
'Weather Normalized Source EUI (kBtu/ft²)',
'log_Total GHG Emissions (Metric Tons CO2e)']]
# Replace the inf with nan
plot_data = plot_data.replace({np.inf: np.nan, -np.inf: np.nan})
# Rename columns
plot_data = plot_data.rename(columns = {'Site EUI (kBtu/ft²)':
'Site EUI',
'Weather Normalized Source EUI (kBtu/ft²)': 'Weather Norm EUI',
'log_Total GHG Emissions (Metric Tons CO2e)': 'log GHG Emissions'})
# Drop na values
plot_data = plot_data.dropna()
# Function to calculate correlation coefficient between two columns
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)
# Create the pairgrid object
grid = sns.PairGrid(data = plot_data, size = 3)
# Upper is a scatter plot
grid.map_upper(plt.scatter, color = 'red', alpha = 0.6)
# Diagonal is a histogram
grid.map_diag(plt.hist, color = 'red', edgecolor = 'black')
# Bottom is correlation and density plot
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 EUorm EUI與score的相關性,我們查看Weather EUorm EUI行和score列,並查看相關係數為-0.67。 除了看起來很酷之外,諸如這些圖可以幫助我們決定在建模中應該包含哪些變量。
特徵工程和選擇
特徵工程和選擇通常會為機器學習問題投入最大的時間。首先,讓我們來定義這兩個任務是什麼:
機器學習模型只能從我們提供的數據中學習,因此確保數據包含我們任務的所有相關信息至關重要。如果我們沒有給模型提供正確的數據,那麼我們將它設置為失敗,我們不應該期望它學習!
對於這個項目,我們將採取以下功能設計步驟:
在模型中,分類變量的One-hot編碼是必要的。機器學習算法無法理解像「office」這樣的建築類型,因此如果建築物是辦公室,則必須將其記錄為1,否則將其記錄為0。
添加轉換特徵可以幫助我們的模型學習數據中的非線性關係。採用平方根,自然對數或特徵的次冪是數據科學中的常見做法,也是基於領域知識或在實踐中最有效的方法。這裡我們將使用數字特徵的自然對數。
以下代碼選擇數字特徵,對這些特徵進行對數轉換,選擇兩個分類特徵,對這些特徵進行one-hot編碼,然後將兩個特徵結合在一起。這似乎需要做很多工作,但在pandas中相對簡單!
# Copy the original data
features = data.copy()
# Select the numeric columns
numeric_subset = data.select_dtypes('number')
# Create columns with log of numeric columns
for col in numeric_subset.columns:
# Skip the Energy Star Score column
if col == 'score':
next
else:
numeric_subset['log_' + col] = np.log(numeric_subset[col])
# Select the categorical columns
categorical_subset = data[['Borough', 'Largest Property Use Type']]
# One hot encode
categorical_subset = pd.get_dummies(categorical_subset)
# Join the two dataframes using concat
# Make sure to use axis = 1 to perform a column bind
features = pd.concat([numeric_subset, categorical_subset], axis = 1)
在這個過程之後,我們有超過11,000個具有110列(特徵)的觀測值(建築物)。並非所有這些特徵都可能對預測Energy Star Score有用,所以現在我們將轉向特徵選擇從而去除一些變量。
特徵選擇
我們數據中的110個特徵中的許多特徵是多餘的,因為它們彼此高度相關。 例如,以下是Site EUI與Weather Normalized SiteEUI的相關係數為0.997的圖。
相互強相關的特徵被稱為共線,消除這些特徵對中的一個變量通常可以幫助機器學習模型推廣並更易於解釋。(我應該指出,我們正在討論特徵與其他特徵的相關性,而不是與目標的相關性,這有助於我們的模型!)
有許多方法可以計算特徵之間的共線性,其中最常見的是方差擴大因子。在這個項目中,我們將使用相關係數來識別和刪除共線特徵。如果它們之間的相關係數大於0.6,我們將放棄一對特徵中的一個。對於實現,看看notebook(和這個stack overflow答案)
雖然這個閾值可能看起來是任意的,但我嘗試了幾個不同的閾值,這個選擇產生了最好的模型機器學習是一個經驗性領域,通過試驗來發現性能最好的!特徵選擇後,我們剩下64個特徵和1個目標。
# Remove any columns with all na values
features = features.dropna(axis=1, how = 'all')
print(features.shape)
(11319, 65)
建立Baseline
我們現在已經完成了數據清理,探索性數據分析和特徵工程。開始建模之前要做的最後一步是建立一個Baseline。這實際上是我們可以比較我們的結果的一種猜測。如果機器學習模型沒有超越這個猜測,那麼我們可能必須得出結論,機器學習對於任務來說是不可接受的,或者我們可能需要嘗試不同的方法。
對於回歸問題,合理的Baseline是猜測測試集中所有示例的訓練集上目標的中值。這設置了一個任何模型都要超越的相對較低的標準。
我們將使用的度量標準是平均絕對誤差(Mean Absolute Error)(MAE),它測量預測的平均絕對誤差。有很多回歸的指標,但我喜歡Andrew Ng的建議【7】,選擇一個指標,然後在評估模型時堅持使用它。平均絕對誤差很容易計算,並且可以解釋。
在計算Baseline之前,我們需要將我們的數據分成一個訓練集和一個測試集:
1. 訓練集是我們在訓練期間給我們的模型提供特徵以及答案的。目地是讓模型學習特徵與目標之間的映射。
2. 測試集合的特徵用於評估訓練的模型。模型不允許查看測試集的答案,並且只能使用特徵進行預測。我們知道測試集的答案,因此我們可以將測試預測與答案進行比較。
我們將使用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)
現在我們可以計算出Baseline的性能:
# 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))
The baseline guess is a score of 66.00
Baseline Performance on the test set: MAE = 24.5164
Baseline的估計在測試集中約為25分。 得分範圍從1到100,所以這代表25%的誤差,相當低的一個超越!
結論
在本文中,我們走過了機器學習問題的前三個步驟。 在定義問題之後,我們:
1. 清理並格式化原始數據
2. 進行探索性數據分析以了解數據集
3. 開發了一系列我們將用於模型的特徵
最後,我們還完成了建立我們可以判斷我們的機器學習算法的Baseline的關鍵步驟。
第二篇文章將展示如何使用Scikit-Learn評估機器學習模型,選擇最佳模型並執行超參數調整來優化模型。
1.http://www.nyc.gov/html/gbee/html/plan/ll84_scores.shtml
2.http://stat.ethz.ch/R-manual/R-devel/library/datasets/html/mtcars.html
3.https://archive.ics.uci.edu/ml/datasets/iris
4.https://www.springboard.com/blog/data-wrangling/
5.https://www.energystar.gov/buildings/facility-owners-and-managers/existing-buildings/use-portfolio-manager/interpret-your-results/what
6.https://stackoverflow.com/questions/26266362/how-to-count-the-nan-values-in-a-column-in-pandas-dataframe/39734251#39734251
7.https://www.coursera.org/learn/machine-learning-projects/lecture/wIKkC/single-number-evaluation-metric
原文連結:
https://towardsdatascience.com/a-complete-machine-learning-walk-through-in-python-part-one-c62152f39420
代碼連結:
https://github.com/WillKoehrsen/machine-learning-project-walkthrough/blob/master/Machine%20Learning%20Project%20Part%201.ipynb