數據科學案例分析
1. 引言
在你閱讀這個帖子的第一句話時,全世界已經生成了 TB 級的數據 (1 TB = 1024 GB)。為了應付這種大規模的數據流入,數據科學 (data science) 領域在過去十年中佔據了前列。 數據科學由不同領域 - 統計學,物理學,計算機科學,以及更多領域 - 融合在一起,數據科學家職業也被哈佛商業評論 (Harvard Business Review) 評為 21 世紀最性感的工作。
本貼用一個 Python 數據分析流程,展示典型的數據科學工作流程。整個流程是在 Jupyter 上完成 (Jupyter 誕生於 2014年,它支持所有編程語言的互動式數據科學和科學計算)。【加微信公眾號 MeanMachine1031,在對話框回復 DS1 可下載代碼 (ipython notebook格式) 和數據 (csv格式)】2. Python 安裝
如果你的計算機上沒有 Python,可以使用 Anaconda Python 發行版來安裝你需要的大部分 Python 包。主頁網址 (點我),網頁如下圖所示:
- numpy: 提供快速數字數組結構和輔助函數。
- pandas: 提供一個數據表結構並能高效地處理數據。
- scikit-learn: 用於機器學習。
- matplotlib: 用於基本繪圖。
- seaborn: 用於高級統計繪圖。
3. 案例分析
假設我們要創建一個智能手機應用程序,從智能手機拍攝的照片中自動識別花的種類。 我們正在與一個數據科學家團隊合作,該數據科學主管負責創建一個演示機器學習模型,測量花的萼片長度 (sepal length),萼片寬度 (sepal width),花瓣長度 (petal length) 和花瓣寬度 (petal width) 四個變數,並根據這些測量識別物種。
等等,萼片是什麼鬼?萼片是花的最外一環。下圖清晰指出花的萼片和花瓣。我們已經從現場研究人員獲得了一個數據集,裡面包括三種類型的鳶尾花的測量,如下圖:根據當地研究人員測量的每種鳶尾花的四個數據 (萼片長/寬和花瓣長/寬),我們最終目的是想正確的分類這三種花。但重中之重的第一步是數據處理。有了乾淨的數據用來機器學習很容易- Python 愛好者可以用 scikit-learn
- R 愛好者可以用 Comprehensive R Archive Network (CRAN)
- Matlab 愛好者可以用 Machine Learning Toolbox (MTL)
但怎麼處理數據有時候更像一門藝術而不像一門科學。在下一節我會從「回答問題」,「檢查數據」,「清理數據」和「測試數據」幾個方面來探索。
4. 數據處理
4.1 回答問題
任何數據分析項目的第一步就是提出想要解決的問題,並為成功解決該問題而定義一個度量 (還記得機器學習第一帖里的性能度量這個概念嗎)。一些常見的問題如下:- 在查看數據之前是否了解數據分析問題的類型,是回歸,分類還是聚類問題?(明晰問題本質)
- 這是個根據萼片長度,萼片寬度,花瓣長度和花瓣寬度四個測量指標的分類問題
- 是否在一開始就定義了成功的度量?(設定量化指標)
- 因為是分類問題,所以可以使用查准率,即正確分類花的百分比,來量化模型的表現。我們的數據主管告訴我們應該實現 90% 的準確性。
- 現有數據是否解決分類問題?(了解數據局限性)
- 我們目前的數據集只有三種類型的鳶尾花。從這個數據集建立的模型將只適用於那些鳶尾花,未來創建一個通用的花分類器需要更多的數據。
4.2 檢查數據
即便是政府或銀行,他們公布的數據也有錯誤。在花費太多時間分析數據之前,提早檢查並修正這些錯誤能節省大量時間。一般來說,我們希望回答以下問題:
- 數據格式有什麼問題嗎?
- 數據數值有什麼問題嗎?
- 數據需要修復或刪除嗎?
檢查點 1. 數據格式 (format)
首先用 pandas 讀取 csv 文件並將數據存成數據表 (data frame) 格式。
- read_csv( filename, na_values = [NaN] ) 是 pandas 裡面用來從 csv 文件讀取數據的函數。裡面用到的兩個參數,第一個 filename 是讀取 csv 文件名,第二個參數用來把 csv 裡面空白處用 NaN 代替。此行代碼將 csv 里的數據轉成 pandas 里的數據表,命名為 iris_data。
- 讀取完可用 head(10) 和 tail() 函數來看前 10 個數據和後 5 個數據,如果括弧裡面沒有指定參數,默認為 5。
- 數據的第一行定義了列標題,標題的描述足以讓我們了解每個列代表的內容 (萼片長度,萼片寬度,花瓣長度和花瓣寬度),標題甚至給我們記錄測量的單位 (cm, 厘米)
- 第一行之後的每一行代表一個花的觀測數據:四個測量指標和一個類 (class),它告訴我們花的種類。比如前 10 個都是山鳶尾花 (注意第 8 到 10 個的花瓣寬度沒有數據,用 NaN 來表示),而後 5 個都是維吉尼亞鳶尾花。
- describe() 函數的產出每列數據的個數 (count),均值 (mean),標準差 (std),最小值 (min),25, 50 和 75 百分位數 (25%, 50%, 75%) 和最大值 (max)。50 百分位數也就是中位數 (median)。
- 從該表中看到幾個有用的值。 例如,我們看到缺少 5 條花瓣寬度的數據(表裡 count 那一行的萼片長度,萼片寬度和花瓣長度的個數都是 150 個,唯獨花瓣寬度是 145 個)。
此外,這樣的表給不了太多有用信息,除非我們知道數據應該在一個特定的範圍 (如萼片長度的最小值是 0.055, 和它其他指標如均值和幾個百分位數都不是一個數量級的,很有可能是測量錯誤)。
比起一串枯燥的數值,我更喜歡絢爛的繪圖。因此我喜歡可視化數據,它能使異常值立即脫穎而出。接下來我們用 pairplot 函數創建一個散點矩陣圖,函數里- 第一個參數 iris_data.dropna() 就是除去 NaN 的數據表,這麼做原因很簡單,圖裡不可能顯示的出 NaN 值的。
- 第二個參數 hue = class 就是根據類 (class) 下不同的值賦予不同的顏色 (hue 就是色彩的意思) 。
它有 5 列,前四列 (萼片長度,萼片寬度,花瓣長度和花瓣寬度) 可看成自變數,第五列 (類) 可看成變數。散點矩陣圖繪製前四列變數的相關係數圖,而且用不同顏色區分不同的類下面的這四個變數。 從上圖可知,橫軸縱軸都有四個變數,那麼總共可以畫出 16 (4*4) 張小圖。
- 對角線上的 4 張都是某個變數和自己本身的關係,由於自己和自己的相關係數永遠是 1,畫出相關係數圖意義不大,因此這 4 張都是堆棧條形圖 (stacked bar chart)。這種圖是用於分解和比較整體和部分的圖,說白了就是不同類都對應著一個條形圖 (bar chart),堆棧條形圖就是將所有條形圖加總。
- 非對角線的 12 張就是某個變數和另一個變數的關係。比如第一行第二列的圖描述的就是萼片長度 (看縱軸第一個 sepal_length_cm 字樣) 和萼片寬度 (看橫軸第二個 sepal_width_cm 字樣)。
從散點矩陣圖中,我們可以迅速看出數據集的一些問題:
- 圖的右側標註這五個類 (Iris-setosa, Iris-setossa, Iris-versicolor, versicolor, Iris-virginica),但原本要分類的花只有三類 (Iris-setosa, Iris-versicolor, Iris-virginica)。這意味著在記錄數據時可能會犯下一些錯誤。
- 在測量中有一些明顯的異常值可能是錯誤的。
- 例如第一行後三張小圖,對於 Iris-setosa (山鳶尾花,藍點),一個萼片寬度值落在其正常範圍之外
- 例如第二行第一,三,四張小圖,對於 Iris-versicolor (變色鳶尾花,紅點) ,幾個萼片長度值都接近零。
修正點 1. 數據類 (class)
問題:按理應該只有三個類,圖中卻顯示五個。在與現場研究人員交談後,聽起來像是一位研究員忘記在 Iris-versicolor 之前添加 Iris-。另一個類 Iris-setossa 他們只是多打了一個 s。讓我們使用代碼來修復這些錯誤。首先用 unique() 函數 (unique 有唯一不重複的意思) 來看 iris_data 裡面不重複的類名稱,發現裡面有五種,分別是 Iris-setosa, Iris-setossa, Iris-versicolor, versicolor 和 Iris-virginica (和散點矩陣圖顯示的一樣)。接著用數據表裡的 loc[] 函數 (loc 是 location 的縮寫,有定位之意) 來找到類值為 versicolor 的所有行,被將其類的值更新為 Iris-versicolr;同理找到類值為 Iris-setossa 的所有行,被將其類的值更新為 Iris-setosa。再用 unique() 函數檢驗修改過的數據是不是只有三類,更新後的散點矩陣圖如下:完美!只有三個類而分別是 Iris-setosa, Iris-versicolor 和 Iris-virginica。修正點 2. 異常數值 (outliers)修復異常值是一件棘手的事情。因為我們很難判斷異常值是否由測量誤差引起,或者是不正確的單位記錄數據,或者是真正的異常。如果我們決定排除任何數據,需要記錄排除的數據並提供排除該數據的充分理由。由上節所知,我們有兩種類型的異常值。問題 1:山鳶尾花的一個萼片寬度值落在其正常範圍之外 (黑色圓框)。
我們的研究人員知道,山鳶尾花 (Iris-setosa) 的萼片寬度 (sepal_width_cm) 不可能低於 2.5 厘米。顯然,這個記錄是錯誤的,這種情況下最有效的方法是刪除它而不是花時間查找原因。但是,我們仍需要知道有多少個類似這樣的錯誤數據,如果很少刪除它沒有問題,如果很多我們需要查明原因。第一行代碼是用數據表裡的 loc[] 函數來找到類值為 Iris-setoa (因為是藍點) 並且 sepal width 小於 2.5 的所有行。最後發現只有一個這樣的數據,而上圖的條形圖也確認了這樣的異常值只有一個。因此可以直接刪除此數據。第一行代碼將類值不是 Iris-setosa 並且 sepal width 大於 2.5 的所有數據都新存到 iris_data 中。從上麵條形圖也看到了再沒有這個異常值。
完美! 現在所有的山鳶尾花的萼片寬度都大於 2.5 厘米。問題 2:變色鳶尾花的幾個萼片長度值接近與零 (黑色橢圓框)。所有這些接近零的 sepal_length_cm 似乎錯位了兩個數量級,好像它們的記錄單位米而不是厘米。在與實地研究人員進行了一些簡短的對話後,我們發現其中一個人忘記將這些測量值轉換為厘米。讓我們使用代碼來修復這些錯誤。第一行代碼是用數據表裡的 loc[] 函數來找到類值為 Iris-versicolor (因為是紅點) 並且 sepal length 接近零的所有行,發現有五個數據,而條形圖最左邊顯示的數據個數也確認了是五個。第一行代碼將類值為 Iris-versicolor 並且 sepal length 都小於 1 的所有數據乘以 100 (將米轉成厘米)。從上麵條形圖也看到了再沒有這五個異常值。
完美! 我們成功修正了這些異常值,要不然我們的分析結果可能毫無意義。修正點 3. 缺失數值 (missing value)對了,我們還有些 NaN 數據。通常我們有兩種方式來處理這類數據。
- 刪除 (deletion)
- 插補 (imputation)
- 五個類變成三個類。
- 異常值全部刪除或修正了。
聲明數據 (assert data)
為了防止一些數據問題沒有解決,我們可以用 assert 語句來做聲明。該語句好處是,在運行時如果聲明語句為真,沒有任何事發生,反之會報錯而警告我們有哪些錯誤數據需要注意且修正。上述三個聲明分別是:- 花應該只有三個類型。
- 變色鳶尾花的萼片長度應該大於 2.5 厘米。
- 數據不應該有缺失。
5. 小結
小貼士:
- 確保數據在預期範圍內,並儘可能使常識來定義預期範圍處理丟失的數據
- 根據情況刪除它或者更換它
- 永遠不要手動清理數據,數據量一大你會發現你根本無法複製此過程
- 使用代碼來記錄如何整理數據的過程,Jupyter Notebook 真的是個很好的工具
- 將數據可視化,和字元相比,圖永遠更直觀,也是更容易發現數據問題
6. 彩蛋
電影都有彩蛋,帖子為什麼不能有?本彩蛋只想證實有了乾淨數據,用 scikit-learn 來機器學習不要太容易。不信?下圖文饗你!
要把大象放冰箱總共分幾步?三步!- 把冰箱門打開
- 把大象放進去
- 把冰箱門關上
噢耶!好像沒費什麼力氣,我們的查准率就達到了 97%!遠高於主管給我們的 90% 要求。
這時候有些機器學習專家會說了:- 這個訓練集和測試集劃分是隨機的,一次不足以說明你查准率高。
- 這數據太少沒代表性,換套數據模型可能過擬合。
- 特徵選擇有很大學問,憑什麼就選萼片長度,萼片寬度,花瓣長度和花瓣寬度這四個變數?
推薦閱讀:
※LDA模型的前世今生
※身為數據科學家怎麼能不掌握這四大技能!
※R語言兵器譜:數據科學家的十八般武藝
※粗略學習Metro Map to Data Scientist(數據科學家之路)
※業務分析師和數據科學家有什麼不同(轉載)