2017年7月20日 星期四

資料科學/機器學習的好用入門工具 t-SNE 幫你看見高維度數值資料

手寫數字測試 t-sne 演算法 想像你有一個試算表, 裡面有幾十個數值欄位, 還有幾個 「分類用」 的字串欄位。 你想問: 如果我拿到一筆資料的所有數值欄位, 是否可以猜出它屬於哪一個分類? 比方說, 已知一個人的身高/體重/BMI/心跳速率/血壓/睡眠時間/肝指數GOT、GPT/... 是否可以猜出他比較可能是哪一種血型/星座/生肖/職業/...? (有點毛毛的例子, 不過也正好提醒大家: 現代的趨勢就是這樣 -- 你的隱私, 就是政府或大企業手中的大數據。) 這是機器學習領域裡面典型的分類問題 (classification)。 如果資料量不大 (例如只有幾百筆或幾千筆資料、 每筆只有幾十個或幾百個欄位), 可能不足以拿來訓練複雜的人工智慧演算法; 又或者你有大量的資料, 但想要在全力運算之前小量取樣, 並且用一個操作簡單運算量較低的演算法、 以不是很精確但可以視覺化的方式迅速了解你的資料長相。 這時, 屬於非監督式學習類型的 t-SNE 演算法就非常適合拿來用肉眼觀察資料的群聚/分類現象。

UC Irvine 機器學習資料集大全 蒐集了很多測試用的資料。 其中的 手寫數字資料集 包含 65 個欄位, 一個欄位是該筆記錄所代表的手寫數字, 其餘欄位是 8x8 的灰階點陣圖數值。 我從 optdigits.tes 裡面減量隨意抓取 360 筆資料, 並且加上欄位名稱, 得到 digits.csv。 寫好設定檔 digits.json 之後, 就可以用這樣的連結使用 t-sne-lab: 手寫數字測試 t-sne 演算法

按下紅色的 R 按鈕開始執行, 你會看到隨著疊代次數 (iteration) 增加, cost 會越來越低, 而相同的數字大致也都群聚在一起。 藍色的 P 按鈕可以暫停/繼續。 你可以更換不同的調色盤 (palette) 及字型大小。 至於著色 (color field) 及標籤字串 (label field) 兩個選單則讓你決定每個點要按照哪個欄位來著色、 按照哪個欄位來貼上文字標籤。 哪些欄位會出現在這兩個選單當中呢? 可以在設定檔裡面用 labelF labelCol 陣列指定一些類別型 (categorial) (例如上述血型/星座/生肖/職業) 的欄位名稱, 它們就會同時出現在這兩個選單當中。 (舊版固定自動選取 「名稱以 @ 開頭」 的欄位; 新版已不適用。) 同樣在設定檔裡, 可以用 ignoreF ignoreCol 陣列指定叫 t-sne-lab 忽略哪些欄位。

另外一組 扭曲變形大寫英文字母資料集 也是來自 UCI。 不過這裡每個數值欄位並非對應一個像素, 而是對應寬度、 高度、 黑點總數、 黑點 X 座標平均值、 ... 等等經過前置處理的數字。 也就是說, 資料集創作者已預先做了一些簡單的 feature extraction。 我從 letter-recognition.data 裡面減量隨意抓取 1000 筆資料, 並且加上欄位名稱, 得到 letters.csv。 設定檔也如法泡製, 然後就可以觀察 大寫英文字母測試 t-sne 演算法

[8/19 補充] 如果你的每個資料點都有它自己的圖片 (例如人臉), 也可以改用圖片而非著色圓點來顯示資料點, 像這樣: 撞臉偵測器

你可下載 t-sne-lab 在自己的電腦上執行。 不需要任何特殊軟體, 只要用 firefox 瀏覽器 「檔案=>開啟」 打開 t-sne-demo.html 並且在網址列後面加上 ?config=xxx.json 即可。 如果是 chrome, 則需要在命令列上加參數。 請見 「用 jQuery 無痛讀檔、顯示」 這篇的插圖。

最下面的幾個參數, batch 是每疊代幾次要更新一次畫面 -- 建議設定成大約跟你的資料量成反比。 epsilon 則是學習速率, 我沒測試過不同的值, 沒什麼感覺。 最有趣的參數是 perplexity, 你需要略懂 t-SNE 演算法, 才知道該怎麼調。

* * * * *

t-SNE 屬於 dimensionality reduction 類型演算法, 也就是企圖降低資料維度的演算法。 這類演算法當中, 最容易直覺理解的是 principle component analysis 主成分分析。 我最喜歡 這個回答跟這張圖。 我再把它說得更簡單一點: 想像手裡拿著一個橢球形的、 內含很多葡萄乾的麵包, 歪斜地舉在桌面上半空中。 葡萄乾的位置用桌面 (加上垂直軸) 的座標寫出來, 這些是你的輸入資料。 所謂 「以 PCA 的方式做 dimension reduction, 從 3 維降到 2 維」, 用白話文來說, 就是找到麵包最扁的方向, 把它完全壓扁, 在這個壓扁的平面上以剩下的兩軸重建一個平面座標系來表達葡萄乾的位置, 這些座標就是 PCA 演算法的輸出資料。 (讀高中時, 老師一直提醒我們: 學數學, 感覺很重要! 我完全贊同!) 這篇文章 比較精確, 並且舉出不適用 PCA 的時機範例, 但仍不失直覺解釋。 光看 1 (choose coordinate systems) 跟 3 (PCA limitations) 兩張圖就很有收穫。

PCA 保留了資料的整體外觀, 在高維空間中那些原先距離遙遠的葡萄乾, 到了新的低維空間中, 距離還是相對比較遙遠。 但是原先中距離的葡萄乾, 到了低維空間中中, 距離有可能變得太近, 甚至重疊。 在機器學習或資料科學所面對的分類問題, 我們比較有興趣的是保留小範圍、 小區域內的相鄰特性, 所以採用 PCA 來分析資料並不理想。

t-SNE 的全名是 t-distributed stochastic neighbor embedding。 t-SNE 跟它的前身 SNE 演算法, 都是試圖要令高維度空間中的 「鄰居們」 映射到低維度空間時也保持鄰居關係; 至於原本距離遙遠的兩顆葡萄乾, 映射之後變更遠或變成中距離, 我們不太在乎。 這兩個演算法用 「較有彈性」 的隨機分佈 (probability distribution) 來取代 「剛性」 的距離尺度, 彷彿是在 n 顆葡萄乾之間裝了 n*(n-1)/2 條彈簧, 麵包不僅被壓扁, 甚至可能碎成一片片 (那本來就是解說用的背景/配角, 不重要啊) 但是力求彈簧之間的拉力與張力達成一個平衡。 SNE 採用的彈簧是高斯分佈; 但 t-SNE 採用的則是 t-distribution of 1 DOF, 因為它更能描述降低維度時所遇到的問題: 鄰居會變得太擁擠, 所以要採用較低矮的機率密度函數。 不過也因為如此, 它僅適用於目標是 2-D 或 3-D 的狀況, 而不適用於目標是較高維度的狀況。

以不太精確的方式來說, perplexity 決定每顆葡萄乾大約會被幾個鄰居影響。 不過實際上所有葡萄乾都會彼此影響, 只是力道不同, 所以這個參數不是整數也沒關係 (但一定要大於 0)。 理想的數值落在 5 到 50 之間。 數值越低, 表示只有很近的鄰居才有影響力, 圖像比較有機會散成好幾堆, 甚至有可能把同一國的拆成好幾堆; 數值越高, 葡萄乾之間的向心力就越強, 最後大家可能糊在一起。 這篇豐富插圖的英文文章 提醒如何解讀 t-SNE 圖:

  1. 比較兩堆的大小沒有意義 (因為 t-SNE 會根據鄰居的擁擠程度來調整這一區塊的大小)。
  2. 兩堆之間的距離也沒有太大意義。
  3. 某些特殊圖像 (例如線條) 可能有意義。

我所找到的中文文章當中, 這篇 t-SNE完整笔记 是針對 原論文 做出的最好的摘要。 TensorBoard 有很厲害的 3D 功能, 但是好像 需要寫程式才能用。 已經出現 各種語言的 t-SNE 實作, 包含 python、 javascript、 java... 等等。 我所寫的 t-sne-lab 其實只是在 tSNEJS 外面包一層 UI 而已。

你手邊有什麼好玩而且沒有隱私問題的數據呢? 或是 UCI 的資料集當中, 你推薦哪幾個呢? 請分享給我, 讓我放進 t-sne-lab 裡面去吧!

沒有留言:

張貼留言