天天看點

預測分析:R語言實作1.3 預測模組化的過程

<b>1.3 預測模組化的過程</b>

通過觀察模型的某些不同特征,我們已經對預測模組化過程的各種步驟有所了解。在本節,我們要順序講解這些步驟,并了解每個步驟是如何對該任務的整體成功起作用的。

1.3.1 定義模型的目标

簡而言之,每個項目的第一步是準确找出期望的結果是什麼,因為這樣有助于引導我們在項目的進展過程中做出正确的決定。在一個預測分析學項目裡,這個問題包括深入研究我們要進行的預測的類型,以及從細節上去了解任務。例如,假定我們要嘗試建立一個模型來預測某公司的雇員流失。我們首先需要準确定義這個任務,同時盡量避免把問題發散得太廣或收斂得過細。我們可以把雇員流失的情況用全職的新雇員在入職後的最初六個月之内跳槽的比例來衡量。注意,一旦合理地定義了問題,對于采用什麼資料開展工作的思考而言,我們就已經取得了一些進展。例如,我們不需要對兼職的合同工或實習生收集資料。這項任務也意味着隻需要從所在公司收集資料,但同時我們也認識到,該模型不一定适用于為其他公司的職員進行預測。如果隻對流失情況感興趣,也就意味着不需要對員工的工作效率或病假情況作出預測(不過,問一下負責我們要建立的模型的主管上司也沒有壞處,免得将來出問題)。

一旦我們對要建立的模型有了足夠明确的思路,下一個要問的邏輯性問題就是我們想要達到的性能是怎樣的,以及該如何衡量它。那就是說,需要為模型定義一個性能名額,以及滿足要求的性能的最低門檻值。在本書中,我們會針對評估模型性能的方法進行相當詳細的講解。就目前而言,我們要強調的是,雖然在用某些資料訓練模型之後再讨論其性能評估問題的情況并不少見,但是在實踐中要記住的很重要的一點是,定義模型的期望值和性能目标是預測模組化者在一開始就必須和項目利益相關方讨論的問題。模型從來都不是完美無瑕的,模組化者很容易陷入嘗試改善性能的無限循環中。清楚的性能目标不僅對于我們決定采用哪些方法有指導意義,也有助于使我們了解模型是否滿足要求。

最後,還需要考慮到收集資料的時候能夠獲得的資料,以及使用該模型時所處的場景。例如,假定我們知道,雇員流失模型要被用作決定是否聘用某個應聘者的因素之一。在這個背景下,就隻能從現有雇員的資料中收集他們被聘用之前的那部分資料。我們不能使用他們的第一次績效評價的結果,因為對于應聘者來說,這些資料還不存在。

1.3.2 收集資料

訓練一個模型用于預測往往是一種資料密集型的探險,如果這裡面有一種東西是多多益善的話,那就是資料。資料收集經常是整個過程中最耗費時間和資源的部分,這也就是要在第一步把定義任務和正确識别要收集的資料兩項工作做好的重要性所在。當我們學習諸如邏輯回歸之類模型的工作原理時,通常會通過一個示例資料集來進行,這也是我們在本書中遵循的主要方法。不幸的是,沒有模拟收集資料這個過程的方法,這樣看起來我們的大部分精力是花在訓練和改進模型上的。在利用已有資料集來學習模型的時候,必須牢記,通常有很多精力是花在收集、甄選和預處理資料上的。我們會在後續章節更仔細地觀察資料預處理。

在收集資料的時候,要一直關注我們收集的資料種類是否正确。很多在預處理階段進行的合理性檢查在收集過程中也适用,這是為了讓我們能發現是否在該過程的早期犯了錯誤。例如,總是要檢查對特征的測量是否正确,是否采用了正确的度量機關。還必須確定資料是從足夠近期、可靠且與手頭任務相關的資料源收集的。在上一節講解的雇員流失模型裡,當收集以往雇員的資訊時,必須確定對特征的度量是一緻的。例如,在度量某個人在公司裡工作了多少天的時候,必須一緻地使用月曆天或工作日。在收集日期資料的時候還必須進行格式檢查,例如當某人加入或離開公司的時候,要統一使用美國日期格式(月份後面是日期)或歐洲格式(日期後面是月份),這兩種格式不能混用,否則,一個類似03/05/2014的日期就會帶有歧義。我們還要盡可能從較大範圍的樣本擷取資訊,以免在資料收集過程中引入隐藏的偏誤。例如,如果我們需要雇員流失的通用模型,就不能隻從女性雇員或者單個部門的雇員收集資料。

我們如何知道已經收集了足夠多的資料了?一開始,在收集資料的過程中,沒有建立和測試任何模型的時候,還無從得知最後需要多少資料,而且這時候也沒有任何簡單的經驗規則可以照搬。不過,我們可以預見問題的某些特征會需要更多的資料。例如,在建立一個可以從3個類别中學習預測的分類器的時候,可能就需要檢查是否有足夠的觀測資料來代表每個類别。

輸出類别的數量越大,需要收集的資料就越多。類似地,對于回歸模型,對照預測結果的範圍來檢查訓練資料裡的輸出變量範圍也是有用的。如果要建立一個覆寫很大輸出範圍的回歸模型,與同等精确度需求下覆寫較小輸出範圍的回歸模型相比,也需要收集更多的資料。

另一個有助于估算需要多少資料的重要因素就是模型的性能要求。直覺地說,模型所需要的精确度越高,必須收集的資料就越多。還必須注意,改善模型的性能并非一個線性的過程。把精确度從90%提高到95%往往會比從70%到90%的飛躍還需要更多的努力以及多得多的資料。有更少參數或設計更簡單的模型,例如線性回歸模型,需要的資料往往比類似神經網絡等更複雜的模型更少。最後,要放到模型裡的特征數目越多,必須收集的資料量就越大。

此外,必須注意到一個事實:對額外資料的需求也不會是線性的。也就是說,建立一個帶有2倍數量的特征的模型往往需要的資料量遠遠多于原有資料量的2倍。考慮到模型所需要處理的輸入的不同組合的數量,這個道理應該是顯而易見的。增加2倍的次元數量會導緻遠大于2倍的可能的輸入組合數量。為了了解這個道理,假定有個模型帶有3個輸入特征,每個特征可以取10個可能的值,我們就有了103=1000種可能的輸入組合。如果加入1個額外的特征,它也可以取10個可能的值,就把可能的組合增加到了10 000個,這就比原先輸入組合數量的2倍大多了。

有一些研究工作在嘗試從更定量的視角讨論某個資料集是否有足夠資料的問題,但我們在本書中沒有時間講解它們。更深入學習預測模組化的這個領域的一個好的起步點是研究學習曲線(learning curve)。簡而言之,借助這種方法,通過先從小部分資料起步并逐漸增加更多資料,可以對同一組資料建立連續的模型。這裡的思路是,通過這個過程,如果預測的精确度對于測試資料總是在改善而不是遞減,我們就很可能可以通過擷取更多資料受益。作為資料收集階段的最後一個提示是,即使我們認為已經有了足夠的資料,在選擇終止收集并開始模組化之前,也總是應該考慮為了獲得更多資料會給我們帶來多少成本(從時間和資源方面而言)。

1.3.3 選取模型

一旦明确了預測任務,并得到了合适的資料,下一步就是選取我們的第一個模型。首先,根本就沒有什麼最好的模型,甚至運用某些經驗法則的最優模型也是不存在的。在大部分情況下,明智的做法是在起步階段先用一個簡單模型,例如在分類任務的情況下采用樸素貝葉斯模型(na飗e bayes model)或邏輯回歸(logistic regression),或在回歸的情況下采用線性模型(linear model)。簡單的模型會讓我們得到一個初始的基線性能,然後我們就可以努力地改進它。起步的簡單模型也有利于回答一些有用的問題,例如有多少特征對結果有貢獻,也就是說,每個特征的重要性有多大,它和輸出是正相關還是負相關。有時候,這種分析本身就是産生第一個簡單模型并延續到用于最終預測的更複雜模型的依據。

有時候,簡單模型可能就對我們手頭的任務給出了足夠的精确度,是以我們就無需投入更多精力來獲得那麼一丁點額外的改進。另一方面,簡單模型通常對于任務來說是不夠的,這就要求我們挑出更複雜的模型。選擇更複雜模型而非簡單模型并不總是簡單直接的決定,即使我們可以看到複雜模型的精确度會高很多。具體的一些限制條件(例如現有的特征數量或能夠獲得的資料)都可能阻礙我們轉而使用更複雜的模型。要了解如何選擇一個模型,就涉及了解工具箱裡的那些模型的各種優勢和限制。對于在本書遇到的每種模型,我們都要特别注意學習這些要點。在實際項目中,為了幫助指導我們的決定,需要經常回顧任務需求,并提出一些問題,例如:

承擔的任務是什麼類型的?某些模型隻适合特定任務,例如回歸、分類或聚類。

模型是否需要解釋它的預測結果?某些模型,例如決策樹,更善于給出易于解讀的要點,用于解釋它們作出具體預測的原因。

是否有任何關于預測時間的限制?

是否需要頻繁更新模型?進而導緻的訓練時間是否很關鍵?

如果特征高度相關,該模型是否能正常工作?

該模型是否能根據特征的數量和得到的資料量有效地進行伸縮?例如,如果我們有海量的資料,我們可能需要一個訓練過程能夠并行化的模型,以便利用并行計算機架構。

在實踐中,即使初步分析指向了特定模型,在作出最終決定之前,也很有可能需要嘗試很多其他選項。

1.3.4 資料的預處理

在使用資料訓練模型之前,通常需要對它進行預處理。在本節,我們會讨論一批一些常用到的預處理步驟。其中一些是為了檢測并解決資料中的問題所必需的,而其他的則是用于變換資料讓它們适用于選擇的模型。

探索性的資料分析

一旦有了一些資料,并決定針對某個具體模型開始工作,首先需要做的事情就是檢視資料本身。這不一定是流程中非常結構化的一部分,它主要包括了解每個特征測量的是什麼,以及對我們已經收集的資料進行初步了解。了解每個特征代表了什麼,以及它的度量機關是什麼,這些步驟确實是非常重要的。對其度量機關的一緻性進行檢查也是一個很好的思路。我們有時把這項對資料進行探索并可視化的分析過程稱為探索性資料分析(exploratory data analysis)。

一個很好的實踐是對我們的資料框調用r語言的summary()函數,獲得每個特征的一些基礎衡量名額,例如均值和方差,還有極大極小值等。有時候很容易通過資料中的不一緻發現在資料收集過程中有一些錯誤。例如,對于一個回歸問題,多條觀測資料具有相同的特征值,輸出卻大相徑庭,這就有可能(取決于應用的情況)是一個信号,表明存在錯誤的測量值。類似地,了解特征的測量過程中是否存在顯著的噪聲也是一個好的思路。這樣有時候可能會産生不同的模型選擇,或意味着該特征必須被忽略。

另一個對資料框裡的特征進行概括的有用函數是psych包裡的describe()函數。它傳回有關每個特征的偏斜程度,以及針對位置(例如均值和中位數)和分布情況(例如标準差)的正常衡量名額。

探索性的資料分析的一個重要部分是利用繪圖把資料可視化。根據情景的不同,有多樣化的繪圖可以供我們使用。例如,為數值特征建立箱線圖(box plot)來對範圍和四分位數(quartiles)進行可視化。條形圖(bar plot)和馬賽克圖(mosaic plot)可以用于資料的分類輸入特征在不同組合下的比例情況進行可視化。本書不會在資訊可視化方面探讨更多的細節,因為它是一個自成體系的領域。

r是一個建立可視化的完美平台。基礎r軟體包提供了很多不同的函數來對資料進行繪圖。有兩個能建立更多進階繪圖的傑出擴充包,它們是lattice和ggplot2。有兩本關于這兩個擴充包的參考書,其中還講解了有效進行可視化的原理,它們是《lattice: multivariate data visualization with r》和《ggplot2: elegant graphics for data analysis》,它們都是springer出版社出版的,屬于use r!系列教材之一。

特征變換

通常,我們會發現數值特征是用完全互不相同的進位制來衡量的。例如,用攝氏度來衡量某人的體溫,是以它的數值通常會在36~38的範圍之内。同時,我們也會測量某人每微升血液中的白細胞計數。這個特征一般是以千來取值的。如果要把這些特征作為某個算法(例如knn)的輸入,會發現白細胞計數的較大數值會在歐幾裡得距離的計算中處于支配地位。在輸入裡可能還有一些對于分類重要且有用的其他特征,但如果衡量它們的進位制産生的是比1000小很多的值,我們實際上就主要是根據單個特征(也就是白細胞計數)來選取我們的最鄰近的樣本。這種問題通常會出現于并影響到很多模型,而不僅僅是knn。我們處理這種問題的方法是,在将這些輸入特征用于我們的模型之前,對這些特征進行變換(也稱為比例縮放)。

我們會讨論特征比例縮放的三種流行方法。當我們知道我們的輸入特征接近正态分布的時候,一種可能用到的變換是z評分歸一化(z-score normalization),它的原理是對特征減去其均值并除以其标準差:

e (x)是x的期望或均值,标準差是x的方差的平方根,該方差表示為var (x)。注意,這種變換的結果是,新的特征将以均值0為中心,方差為1。另一種可能的變換更适合輸入符合均勻分布的情況,就是按比例縮放所有的特征和輸出,讓它們處于單個區間内,典型的是機關區間[0,1]:

第三種方法被稱為博克斯-考克斯變換(box-cox transformation)。這種變換通常運用在輸入特征呈現高度偏斜(不對稱)而我們的模型要求輸入特征符合正态分布或至少是對稱分布的情況:

因為是在分母裡,是以它必須取非0的值。該變換實際上對值為0的是有定義的:在本例中,它就是輸入特征的自然對數,即ln(x)。

注意,這是一種參數化的變換,因而需要給指定一個具體的值。有多種方式可以根據資料本身給估算一個适當的值。我們會為此講解一種進行這種估算的技術,稱為交叉驗證(cross-validation),我們會在本書第5章裡遇到它。

博克斯-考克斯變換的原始參考資料是在1964年發表在皇家統計學會雜志(the journal of the royal statistical society)上的一篇論文,名為《an analysis of transfor-mations》,作者是g. e. p. box和d. r. cox兩人。

為了直覺感受這些變換在實踐中的應用情況,我們要在iris資料集的sepal.length特征上進行嘗試。不過,在開始之前,要介紹需要運用的第一個r擴充包,即caret。

caret包是一個具備多種用途的非常有用的元件。它提供了預測模組化過程中常用的一組輔助函數,覆寫了從資料預處理和可視化到特征選擇和再抽樣技術。它的特性還包括:具有針對很多預測模型函數的統一接口,并提供了并行處理的功能。

利用caret元件進行預測模組化的權威參考資料是一本名為《applied predictive modeling》的書,該書由max kuhn和kjell johnson編寫,springer出版社出版。max kuhn是caret包本身的主要作者。該書還有一個配套的網站:http:// appliedpredic-tivemodeling.com。

當對用來訓練模型的資料進行輸入特征的變換時,必須記住,對于在預測時要用到的後續輸入,也需要對其中的特征運用同樣的變換。是以,利用caret包對資料的變換是分兩步完成的。在第一步,調用preprocess()函數儲存要運用到資料上的變換參數,然後在第二步,調用predict()函數對變換進行實際的計算。我們往往會隻調用一次preprocess(),然後在每次需要對某些資料進行同樣的變換時就調用predict()函數。preprocess()函數會把一個帶有某些數量值的資料框作為它的第一個輸入,我們也會給method參數指定一個包含要運用的變換名的向量。然後predict() 函數會一并讀入前面函數的輸出和我們要變換的資料—對于訓練資料本身,它很可能是同一個資料框。讓我們看看這整個過程的實際運用:

下載下傳樣例代碼

你可以從你在http://www.packtpub.com的賬号下載下傳你已經購買的所有packt出版書籍的樣例代碼檔案。如果你是在其他地方購買本書,你可以通路http://www.packtpub.com/support并注冊,檔案會直接通過電子郵件發送給你。

我們已經建立了鸢尾花資料的數值特征的3個版本,它們的差別在于每個版本用到了不同的變換。為了把變換的效果可視化,我們可以通過調用density()函數,對每個比例縮放後的資料框繪制萼片長度(sepal.length)特征的密度圖,并繪制結果,如下所示:

注意,z評分(z-score)和機關區間(unit interval)變換在對數值進行了平移和縮放的同時保留了密度圖的總體形态,而博克斯-考克斯變換還改變了整體形态,産生了比原始圖偏斜更少的密度圖。

類别特征的編碼

從線性回歸到神經網絡,很多模型都要求所有輸入是數值型的,是以我們經常需要一種把分類字段在某個數值标尺中進行編碼的方法。例如,如果我們有一個尺寸特征,它從一個集合{small, medium, large}中取值,我們就會需要用數值1、2、3來分别代表它。在有序分類的情況下(例如剛才描述的尺寸特征),這種映射應該是合理的。

數字3是這個數值區間裡最大的,它對應的是large分類,相比用取值2代表的medium分類,它離用數字1代表的small分類更遠。這個數值區間的用法隻是一種可能的映射,尤其是它強制讓medium分類與large和small分類的間距相等,這樣做是否合适,取決于我們對于具體特征的認知。在無序分類的情況下,例如品牌或顔色,總體上我們會避免把它們映射到單個數值區間裡。例如,如果把集合{blue, green, white, red, orange}相應地映射為數字1到5,那麼這個區間就是随意的,沒有什麼理由讓red離white更近而離blue比較遠。為了克服這個問題,我們建立了一系列訓示特征ii,它的形式如下:

我們需要和分類一樣多的訓示特征,是以對于顔色示例,可以建立5個訓示特征。在這個情況下,i1就可以是:

通過這種方式,原始的顔色特征會被映射為5個訓示特征,對于每條觀測資料,這些訓示特征中隻有一個會取值為1,其他的都為0,這是因為在原始特征中,每條觀測資料隻包含一種顔色值。訓示特征是二進制的特征,因為它們隻會取兩個值:0和1。

我們經常還會遇到另一種方法,即利用n-1個二進制特征對一個因素的n個級别進行編碼。這是通過選擇一個級别作為參考級别,它用所有n-1個二進制特征都取值為0的情況來表示。這樣對于特征數量而言更為經濟,并且可以避免在它們之間引入一種線性依賴關系,但是它違反了所有特征互相之間等距的性質。

缺失資料

有時候,資料會包含缺失的值,這是因為對于某些觀測資料,某些特征是無法擷取或無法合适地測量的。例如,假定在iris資料集裡,缺少了某條觀測資料裡的花瓣長度(petal length)的測量值。這樣,在這個鸢尾花樣本的petal.length特征裡就會有一個缺失值。大部分模型并不先天具備處理缺失資料的能力。通常情況下,資料裡的缺失值會用空條目或na符号表示。我們必須檢查是否在資料中實際存在着缺失值,但被錯誤地配置設定了一個像0這樣的(通常是非常合法的)特征值。

在決定如何處理缺失資料之前,尤其是當我們的方法是直接丢棄帶有缺失值的觀測資料時,必須認識到具體缺失的值可能會符合某個模式。具體而言,我們經常要區分不同的所謂缺失值機制。在理想的随機完全缺失(missing completely at random,mcar)情況下,缺失值的出現是獨立于它們所屬的特征以及其他特征的真實值的。在這種情況下,如果某個鸢尾花花瓣長度缺失了一個值,那麼這個缺失的情況是獨立于該花瓣實際有多長以及其他任何特征(例如該觀測資料是否來自versicolor或setosa品種)的。随機缺失(missing at random,mar)的情況就更不那麼理想。在這種情況下,某個缺失值是獨立于其所屬特征的真實值的,但可能會和其他特征相關。這種情況的一個示例是,缺失的花瓣長度值主要在iris資料集的setosa品種樣本裡出現,但它們的出現仍然獨立于實際花瓣長度的值。在問題最多的非随機缺失(missing not at random,mnar)情況裡,存在某種模式能夠解釋缺失值會根據該特征本身的真實值出現。例如,如果在測量非常小的花瓣長度時遇到困難,并且最終産生了一些缺失值,那麼,在這種情況下簡單地丢棄不完整樣本,就可能隻得到花瓣長度較大的觀測資料樣本,因而使資料産生偏誤。

處理缺失值有很多種方法,但在本書中我們不會深入鑽研這個問題。在有缺失值的少數情況下,我們會從資料集裡排除它們,但是要當心,在一個實際項目裡,要調研缺失值的來源,以便確定能安全地進行排除操作。另一種方法是嘗試猜測或估算缺失值。knn算法本身就是一種這樣的方法,它會給某個特征有缺失值的樣本找到最鄰近的樣本。具體做法是先排除缺失值所在的次元(即特征),再進行距離的計算。随後,這個缺失值就可以被計算為最鄰近的樣本在該次元取值的均值。

對如何處理缺失值感興趣的讀者可以在wiley出版社出版的《statistical analysis with missing data》(第二版,由roderick j. a. little和donald b. rubin編寫)一書中找到詳細的論述。

離群值

離群值(outlier)也是經常需要處理的一種問題。離群值是其中一個或多個特征嚴重偏離了其他資料的某條觀測資料。在某些情況下,這也可能是某個真實的罕見狀況,代表了在我們要模組化的系統裡的一種合乎情理的表現。在其他情況下,這可能說明在測量資料中存在一個錯誤。例如,在記錄人口年齡的時候,一個110的值可能會是離群值,有可能是因為對實際值11的記錄錯誤而産生的。但它也有可能是一個正确而極為罕見的測量值。通常,要處理的問題領域會對于離群值是否屬于測量錯誤給出很好的訓示,如果是這樣的話,作為資料預處理的一部分,常常會需要從資料中完全排除離群值。在第2章中我們會看到排除離群值的更多細節。

丢棄有問題的特征

預處理資料集也包括了丢棄某些特征的決定,如果知道它們會給我們的模型帶來問題的話。一個常見的示例是兩個或多個特征互相之間高度相關的情況。在r裡,可以利用cor()函數輕松地對某個資料框計算其中每一對特征的相關系數:

在這裡,可以看到petal.length特征和petal.width特征是高度相關的,它們的相關系數大于0.96。caret元件提供了findcorrelation()函數,它把一個相關系數矩陣作為輸入,還可以選用為特征配對的相關系數的絕對值指定一個門檻值的cutoff參數。它會傳回一個(有可能長度為0的)向量,該向量會顯示由于相關性而需要從該資料框裡删除的列。cutoff的預設設定是0.9:

消除相關性的另一種方法是對整個特征空間進行完全的變換,例如在很多降維(dimen-sionality reduction)方法裡采用的技術,比如主成分分析(principal component analysis,pca)和奇異值分解(singular value decomposition,svd)。我們稍後會介紹前者,後者則會在第11章裡介紹。

類似的,還會需要删除互相為線性組合(linear combinations)的特征。對于特征的線性組合,指的是把每個特征乘以一個标量常數所得到的特征之和。為了檢視caret包是如何處理這些特征,我們要建立一個新的鸢尾花資料框,在它裡面增加兩個列,分别名為cmb和cmb.n,如下所示:

正如我們所見,cmb是sepal.length 和petal. width特征的完全線性組合。cmb.n則是和cmb相同但加上了某些均值為0且标準差很小(0.1)的高斯噪聲的特征,因而它的值很接近cmb的值。利用findlinearcombos()函數,caret包能夠檢測出嚴格的特征線性組合,不過當這些特征有噪聲時就檢測不到了:

正如我們所見,該函數隻建議我們應該從該資料框中删除第5個特征(cmb),因為它是第1和第4個特征的一個嚴格的線性組合。嚴格的線性組合很少見,不過當有很大數量的特征并且它們之間存在備援時會出現。具有相關性的特征以及線性組合都是線性回歸模型裡的問題,我們很快會在第2章看到。在本章,我們也會看到一種檢測互相之間非常接近線性組合的特征的方法。

對于有問題的特征要審視的最後一個問題,就是在資料集裡存在根本不變化或者說方差近似為0的特征。對于某些模型,具有這種類型的特征不會給我們帶來問題。對于其他模型,它可能就會産生問題,我們會示範為何會是這樣的。正如前一個示例,我們會建立一個新的鸢尾花資料框,如下所示:

這裡,zv列對于所有觀測對象都是一個常數6.5。yellow列則是一個虛構的列,用來記錄觀測對象在花瓣上是否帶有黃色。除了第一個以外,其他所有的觀測對象都設定這個特征為false,因而讓它成為方差近似為0的列。caret包采用的是方差近似為0的定義,這個定義會檢查某個特征取的唯一值數量和總觀測對象數量相比是否非常小,或者最常見值和第二常見值出現數量的比例(被稱為頻數比,frequency ratio)是否非常高。把nearzerovar()函數運用到一個資料框,會傳回包含了方差為0或近似為0的特征構成的一個向量。通過設定savemetrics參數為true,我們可以看到更多關于我們資料框裡的特征的資訊:

在這裡,我們可以看到,zv列被識别為方差為0(zerovar=true)的列(由定義可知,它也是方差近似為0的列)。yellow列确實有非0方差,但它較高的頻數比和較低的獨特值比例使它被判定為方差近似為0的列(nzv=true)。在實踐中,往往會删除方差為0的列,這是因為他們不會為我們的模型提供任何資訊。不過,要删除方差近似為0的列就比較微妙,必須小心從事。要了解這一點,可以考慮這樣一個事實:利用上面那個newer_iris資料集進行品種預測的某個模型會學習到,如果某個樣本在花瓣裡有黃色,那麼不管所有其他預測因素如何,我們都會預測出它是setosa品種,因為它對應的是整個資料集裡唯一的一個在花瓣裡有黃顔色的觀測資料。這在現實中也許确實成立,如果是這樣的話,這個黃色的特征就是有資訊量的,我們也應該保留它。另一方面,在鸢尾花瓣中出現黃顔色也可能是完全随機的,不僅不能辨別品種,而且是極罕見的情況。這就解釋了為什麼在資料集中隻有一條觀測資料在花瓣裡帶有黃色。在這種情況下,由于前面所說的結論,保留該特征就是危險的。保留該特征的另一個潛在問題會在我們把資料劃分為訓練和測試資料集或以其他方式劃分資料(比如第5章裡講解的交叉驗證)的時候浮現出來。這裡的問題是,對我們資料的劃分會導緻方差近似為0的列裡出現唯一值,例如某個資料集的yellow列裡隻有false值。

1.3.5 特征工程和降維

在模型裡采用的特征數量和類型是在預測模組化過程中要作出的最重要決定。為模型配備正确的特征,就是確定我們為預測準備了充分的依據。在另一面,要處理的特征數量就正好是該模型具有的次元數量。大量的次元會成為複雜度加劇的根源。高維的問題通常來自于資料的稀疏性(data sparsity),它意味着由于存在的次元數量的原因,會導緻覆寫所有特征取值的可能組合範圍的極大增長,以至于難以收集足夠的資料為訓練過程提供足夠的有代表性的樣本。我們還通常談到次元詛咒(curse of dimensionality)。它描述了一個事實:由于可能的輸入産生的空間之大是壓倒性的,導緻我們所收集的資料點在特征空間裡很可能會互相遠離。其結果是局部方法(例如利用訓練資料中靠近待預測點的觀測資料來進行預測的knn算法)在高維空間裡的效果不佳。太大的特征集合還會産生顯著增加訓練模型(以及在某些情況下作出預測)所需時間等方面的問題。

是以,特征工程包括兩類流程。第一類會增大特征空間,它會根據我們資料裡的特征來設計新的特征。有時候,由兩個原始特征的乘積或比率構成一個新特征會有更好的效果。有多種方法可以把已有特征組合為新特征,而這通常需要相關問題具體應用領域的專業知識的指導。從總體思路而言,這個過程需要經驗和大量的反複試驗。注意,無法保證加入新特征一定不會降低性能。有時候,增加一個噪聲很大或者與已有特征高度相關的特征确實會導緻我們損失精确度。

特征工程的第二類過程是特征縮減或收縮,它會減小特征空間的尺寸。在前面關于資料預處理的小節可以看到如何檢測會給模型帶來某些問題的個别特征。特征選擇(feature selection)指從原始的一組特征中選取對于目标輸出最具資訊量的特征子集的過程。某些方法(例如樹形模型)具備内建的特征選擇方法,這是我們将會在第6章裡看到的。在第2章我們也會探讨對線性模型進行特征選擇的一些方法。另一種減少總特征數的方法,即降維(dimensionality reduction)的概念,是把整個特征集變換為全新的一個數量更少的特征集。這方面的一個經典範例是主成分分析(principal component analysis,pca)。

簡而言之,pca 會建立一個輸入特征的新集合,它被稱為主成分(principal components),這個集合中全部都是原始輸入特征的線性組合。對于第一個主成分,要選取線性組合的權值,以便能擷取資料中最大量的變異(variation)。如果我們能夠把第一個主成分可視化為原始特征空間裡的一條直線,它應該是上面的資料變異最大的一條直線。它還恰好應該是最接近原始特征空間上所有資料點的一條線。後續的每個主成分要盡可能擷取最大變異的一條直線,但是要滿足的條件是,新的主成分和之前計算得到的主成分不相關。是以,第二個主成分要選取在資料中具有最高程度變異的原始輸入特征的線性組合,同時和第一個主成分不相關。

主成分是根據它們擷取的變異量以降序進行自然排序的。這讓我們能夠通過保留前n個組成部分來以簡單的方式進行降維,我們在這個過程中選取n的依據是,這樣選取的主成分元素要包含來自原始資料集最小量的方差。我們不會深入介紹計算主成分所需的相關線性代數方面的細節。

相反,我們會把關注點轉移到一個事實:這個過程是對原始特征的方差和度量機關敏感的。為此,我們經常會在進行這個過程之前對特征進行比例縮放。為了可視化地講解pca多麼有用,我們會再一次轉到我們忠實的鸢尾花(iris)資料集。可以利用caret包執行pca算法。為此,指定在preprocess()函數的method參數為pca。也可以利用thresh參數,它指定了必須保持的最小方差。我們會顯式使用0.95這個值,這樣就保持了原始資料95%的方差,但是注意,這也是該參數的預設值:

這個變換的結果是,我們現在隻剩下了2個特征,是以我們可以得出結論:鸢尾花的數值特征的前2個主成分就包含了該資料集裡超過95%的變異。

如果我們對了解用來計算主成分的權值感興趣,可以檢視pp_pca對象的rotation屬性:

這意味着第一個主成分pc1的計算方法如下:

0.52·sepal.length-0.27·sepal.width+0.58·petal.length+0.57·petal.width

有時候,相比直接指定一個主成分擷取的總方差的門檻值,我們可能會想要檢視每個主成分及其方差的繪圖。這種圖稱為陡坡圖(scree plot),要繪制這樣的圖,可以先進行pca并聲明我們要保留所有的主成分元素。為此,不要指定一個方差的門檻值,而是設定要保留的主成分數量的pcacomp參數。主成分的總數和開始時的原始特征或次元數是相等的,是以就設定它為4,也就是包括了所有主成分。然後計算這些組成部分的方差和累積方差,并把它儲存在一個資料框裡。最後,我們要在後續的圖表中繪制它,并注意圖中括号裡的數字是擷取方差的累積百分比:

正如我們所見,第一個主成分占到了iris資料集總方差的73.45%,再加上第二個主成分,獲得的總方差是96.27%。pca 是一種無監督的降維方法,它不需要利用輸出變量,即使輸出結果能夠獲得。相反,它是從幾何的角度去看待特征空間裡的資料的。這意味着我們不能確定pca給出的新特征空間一定能在預測問題裡有良好表現,它隻能帶來更少特征的計算優勢。即使pca減少了模型的精确度,但是隻要這種精确度的減少比較小而且對于特定任務是可以接受的,計算上的這些優勢就會讓它成為可行的選擇。作為最後一條提示,必須指出,通常被稱為荷載(loading)的主成分權值在歸一化的情況下是唯一的,隻有正負号的變化。在特征之間具有完全相關或完全線性組合的情況下,我們會得到一些恰好為0的主成分。

1.3.6 訓練和評估模型

在之前對參數化模型的讨論中,我們看到這些模型會有一個利用訓練資料集對模型進行訓練的過程。而對于非參數化模型來說,通常它們要麼進行惰性學習—也就是除了記住訓練資料之外并沒有真正的訓練過程;要麼像樣條的情況那樣,會對訓練資料進行局部的計算。

無論哪種方式,如果要評估模型的性能,就需要把資料分拆為一個訓練集(training set)和一個測試集(test set)。這裡的關鍵思路是,要根據模型處理後續未知資料的預期表現來評估我們的模型。我們的做法是利用測試集,也就是把收集到的資料的一部分(通常是15%~30%)留出來,在訓練過程中不要用到它們。例如,一種可能的分拆方式是把原始資料裡80%的觀測資料作為訓練集,把剩下的20%作為測試集。需要一個測試集的原因是,我們無法用訓練集公平地評估模型的性能,因為訓練資料是用來拟合模型的,而它并不能代表我們之前沒有看到過的資料。從預測的角度來說,如果我們的目标隻是針對訓練資料産生最佳性能,那麼最好的手段就是直接記住輸入資料和期望的輸出值,這樣我們的模型就成了一個簡單的查找表了!

有一個好問題是,如何決定把多少資料分别用于訓練和測試。這裡就涉及一些權衡,讓這個問題的答案意義重大。一方面,我們會想把盡可能多的資料放在訓練集裡,這樣模型就可以根據更多的樣本進行學習。另一方面,我們也想有一個大的測試集,這樣就能使用很多樣本對訓練好的模型進行測試,以便讓我們對該模型預測性能的估算具有最小的方差。如果我們的測試集裡隻有少量觀測資料,那麼我們就無法真正總結出模型用于未知資料的性能的一般規律。

另一個起作用的因素是,初始收集的資料量有多大。如果隻有很少的資料,我們可能就必須用其中的大部分去訓練模型,比如劃分為85%/15%。如果我們有充足的資料,那麼我們也許會考慮70%/30%的劃分,這樣就能對于測試集産生更精确的預測。

要利用caret包劃分資料集,可以用createdatapartition()函數建立一個抽樣向量,裡面包含了要在測試集裡用到的那些行的索引。對這些行的選取過程是通過利用p參數對行進行随機抽樣,直到抽樣的行數達到預先指定的比例:

在報告涉及生成随機數的統計學分析結果時,有一種可取的做法是,用随機選取但固定的一個數值調用set.seed()函數。該函數會確定從後續關于随機數生成的函數調用所生成的随機數在代碼每次運作的時候都是相同的。這樣做能讓其他閱讀這個分析過程的人能準确地重制分析結果。注意,如果代碼裡有幾個函數進行了随機數的生成,或同一個随機數生成函數被調用了多次,原則上我們必須在每一次調用之前先調用set.seed()。

利用為iris資料集建立的抽樣向量,我們就能建構自己的訓練集和測試集了。我們會對之前在試驗不同的特征變換方法時建構的一些iris資料集版本進行這個操作。

現在我們就可以為iris資料集建立并測試3種不同的模型。它們分别是未歸一化(unnormalized)模型、輸入特征已認證z評分(z-score)變換進行中心化和比例縮放的模型,以及帶有兩個主成分的pca模型。在建立好這些模型之後,可以使用測試集來衡量它們中每一個的預測性能。不過,這樣就意味着在我們對其未知精确度的最終估算中,已經在模型選取過程中用到了測試集,因而産生了有偏誤的估算。因為這個原因,我們經常會保持一套單獨劃分的資料,通常和測試集一樣大,被稱為驗證集(validation set)。這個資料集是用來在運用測試集預測未知性能之前對模型參數(例如knn裡的k值)以及輸入特征的不同編碼和變換進行調優的。在第5章中,我們會讨論這種方法的一種替代方法,稱為交叉驗證(cross-validation)。

一旦劃分了資料,按照所要求的相關訓練過程訓練了模型,并對模型參數進行了調優,我們就必須在測試集上評估它的性能。通常我們不會在測試集裡得到和訓練集裡相同的性能。有時候我們甚至可能會發現,當部署模型的時候,看到的性能和根據訓練集或測試集的性能而得到的預期并不相符。這種性能上的不一緻有很多可能的原因。其中第一個原因就是,之前收集的資料要麼對模組化的過程不具有代表性,要麼就是某些特征輸入的組合沒有納入訓練資料中。這樣就可能産生和預期不一緻的結果。這種情況既可能發生在真實世界中,也可能發生在測試集裡,比如它包含了離群值(outlier)的情況。另一種普遍存在的情況是模型過拟合(over fitting)問題。

過拟合問題的表現是這樣的:某些模型,尤其是更靈活的模型,在它們的訓練資料集裡表現良好,但對于未知的測試集就明顯表現更差。在這種問題裡出現的情況是,某個模型對訓練資料中的觀測資料拟合得過于嚴密,卻無法對未知資料廣義化。換言之,該模型在訓練資料集中提取了不真實的細節和變異,而這些細節和變異對于整體的基礎觀測資料并不具有代表性。過拟合是我們不能根據訓練資料的性能來選取模型的關鍵原因之一。其他訓練和測試資料性能不一緻的來源還包括模型偏誤和方差。這些因素合在一起就構成了統計性模組化領域中的一種著名的權衡,即偏誤-方差權衡(bias-variance tradeoff)。

統計性模型的方差是指,如果使用另一個選取的訓練集(但還是從要預測的同一個原始過程或系統生成的)來訓練模型,模型預測出的函數會有多大的變化。我們想要的是一個較低的方差,因為我們當然不希望從同一個過程生成的不同訓練集預測出很不一樣的函數。模型偏誤則是指在預測函數中内生出來的錯誤,它是關于具體的一個模型能夠學習哪些函數形式的局限性的結果。例如,線性模型會在試圖拟合非線性函數的時候引入偏誤,這是因為它們隻能學習線性函數。一個良好的預測模型的理想狀況是它兼具了低方差和低偏誤。對于一個預測模組化者,很重要的一點是注意這樣的事實:偏誤-方差權衡(bias-variance trade-off)來源于對模型的選擇。對目标函數作出更少假設而産生的複雜模型,相比于更簡單卻更嚴格的模型(例如線性模型),往往會有更少的偏誤和更大的方差。究其原因,是因為更複雜模型具有的靈活性讓它們能夠更近似地估算訓練資料,但這樣的結果是它們對訓練資料裡的變化也會更敏感。當然,這種情況和複雜模型經常會表現出來的過拟合問題也是相關的。

我們可以通過先在iris資料集上訓練某些knn模型來實際觀察過拟合的效果。有很多擴充包都提供了knn算法的實作,但是我們會使用我們熟悉的caret包提供的knn3()函數。要用這個函數訓練模型,我們所要做的就是給它提供一個包含數值輸入特征的資料框、一個輸出标簽的向量,以及我們要用于該預測的最近鄰數量k:

要觀察k的不同取值的效果,我們可以利用現成的2個次元的鸢尾花pca模型,用來進行可視化和反複訓練:

在前面的圖中,我們使用了不同的符号來注明對應不同品種的資料點。圖中顯示的線對應了不同鸢尾花品種之間的判定邊界(decision boundary),這些品種也就是我們輸出變量的類别标簽。注意,使用一個較低的k值(例如1),會非常嚴密地獲得在資料中的局部變異,結果是判定邊界非常不規整。更大的k值要利用很多鄰近點來建立一個預測,産生的是平滑的效果和更平滑的決策邊界。在knn裡對k值進行調優就是一個對模型參數進行調優以平衡過拟合效果的示例。

在本節,我們還沒有提到過任何具體的性能衡量名額。回歸和分類對于模型的品質有不同的衡量名額,我們會在對關于預測模組化過程的讨論進行總結之後再講解它們。

1.3.7 重複嘗試不同模型及模型的最終選擇

在這個過程(而且肯定是一個疊代過程)的第一次疊代中,我們通常會在訓練并評估完一個簡單模型後到達這個階段。簡單模型通常讓我們能以最少的精力獲得一個快速而粗略的解決方案,進而讓我們大緻感受到離一個會産生合理精确度預測的模型還有多遠。簡單模型還可以給我們産生一個性能的基線水準,我們可以用它作為未來模型性能的标杆。作為模組化者,我們在不同方法之間往往會厚此薄彼,但重要的是記住,要對解決問題的不同方法進行嘗試,并利用資料幫助我們決定最終采用哪一個,這是值得花費精力的事情。

在選取最終的模型之前,有必要考慮的事,采用多個模型來解決我們的問題是否是個好的思路。在第7章裡,我們會用一整章來學習涉及多個模型共同作用來提高整體系統的預測精确度的技術。

1.3.8 部署模型

一旦選取了采用的最終模型,我們就需要落實它的實作,這樣最終使用者就能可靠地使用它。程式員們稱該過程為部署到生産系統(deploying to production)。這是紮實的軟體工程原理會起到極其重要作用的領域。下面的指導原則給出了一些有用的建議:

模型必須進行優化,以提高它計算預測結果的速度。例如,這意味着確定任何要在運作時計算的特征能高效地完成處理。

模型必須有完備的文檔。最終的輸入特征必須清晰定義,用于訓練的方法和資料必須儲存,以便在需要更改時易于重新進行訓練。訓練集和測試集的原始性能也必須儲存下來,作為後續改進的參考。

模型性能必須持續進行監控。它的重要性不僅在于作為驗證模型是否達到預期效果的手段,而且在于捕捉任何潛在的資料變化。如果要模組化的過程随時間改變了,我們模型的性能就有可能下降,這就表明了訓練一個新模型的必要性。

用來實作該模型的軟體必須利用标準的單元和內建測試方法進行适當的測試。通常,我們會利用大量已有的r語言包,它們的函數已經通過了測試,但模型最終的部署會需要我們自己編寫某些額外的代碼,比如用來進行特征計算的代碼。

部署的模型必須能處理輸入中的錯誤。例如,如果某些輸入特征是缺失的,它應該通過适當的錯誤資訊讓使用者明确了解模型無法作出預測的原因。錯誤和警告也必須寫進日志,尤其是對于模型被部署用于實時環境下的持續性預測的情況。

繼續閱讀