1. 程式人生 > 其它 >Thinking in SQL系列之:資料探勘K均值聚類演算法與城市分級

Thinking in SQL系列之:資料探勘K均值聚類演算法與城市分級

引言:SQL做為一種程式語言,能夠滿足各類資料處理的需要,關鍵就在於演算法與思維方式。以SQL會友,希望結交更多的資料庫、資料分析領域的朋友。

作者簡介:牛超

10多年資料庫技術積累,長期從事ORACLE資料庫管理與開發工作。精通企業級資料庫應用設計、SQL、演算法實現、異常分析、效能優化。目前就職於日立諮詢(中國)有限公司。Mail:[email protected]

SQL做為一種程式語言,能夠滿足各類資料處理的需要,關鍵就在於演算法與思維方式。個人經常調侃SQL思考問題比大部分流行的開發語言多一個維度,因為SQL主要是二維思考(集合)、區別於一維(資料結構)的思維方式。對於ORACLE,通過以SQL(相對巨集觀)為主體、PLSQL(微觀)為輔助,注入演算法(靈魂),貫徹效能優化(章程),資料的價值能夠充分有效發揮。

聚類問題,就是給定一個元素集合D,其中每個元素具有n個可觀察屬性,使用某種演算法將D劃分成k個子集,要求每個子集內部的元素之間相異度儘可能低,而不同子集的元素相異度儘可能高。其中每個子集叫做一個簇。本文將介紹聚類的經典演算法K均值聚類演算法,即K-MEANS,是一種觀察類學習,通過以元素間的相異度迭代地劃分簇並重新定位質心點重新聚類來達成的演算法,找了如下的圖以便加深理解。

演算法本身較容易理解,但為了定量說明,還是先祭出幾個數學公式

用來定義兩個元素,各自具有n個度量屬性。

用來標量X與Y的相異度(尤拉距離公式),本篇採用該公式。

曼哈頓距離,即街區非直線段距離,很容易理解。也可以用來標量元素間相異度。

標量規格化,為了平衡各個屬性因取值單位不同對距離的影響而按比例對映到相同的取值區間。通常將各個屬性均對映到[0,1]區間。

接著,我們來看看本次要用SQL實現的k-means演算法示例:以2016年的GDP統計資料給中國城市分級:

目前這份是經個人簡單加工的2016年真實國家統計資料,一共有100個城市的記錄,共5個度量(人口、面積、年GDP、人均GDP、單位面積GDP)。

我們總是說不相信眼淚的北上廣是一線城市,那麼該如何給城市分成四線是個很有趣的問題,看了一下國家統計局的劃分標準(此處省略1K字),但做為個人比較關心的是每個城市發達與市民富裕程度,於是簡單地拍腦袋定義瞭如下模型:

X ={人口,人口密度,年GDP,人均GDP,單位面積GDP},共5個維度,權重都是1;

每個度量屬性a的標量規格化區間定義為[0,1];

聚合點相異度需要以質心點為基準計算,初始質心點取GDP名次的4等分點,簡化為MOD(名次,21)=0;元素相異度直接使用尤拉距離公式,即

準備工作:

1.定義表象性的業務表,即城市GDP資料表

--城市GDP
CREATE TABLE CITY_GDP_T
(
CITY VARCHAR2(100),--城市名
POPULATION NUMBER ,--人口
AREA NUMBER,--面積
GDP_YEAR NUMBER,--年GDP
GDP_PER_CAPITA NUMBER ,--人均GDP
GDP_PER_AREA NUMBER --單位面積GDP
);

2.載入資料後查詢如下:

3.先預演一下質心點經過一次聚類後重新被選擇的演算法程式,其中第一代初始質心點根據GDP的分段城市的元素屬性,TA1,再根據TA1的聚類點用算術平均法計算得到第二代質心點,SQL如下:

WITH TA AS --整理度量值
TB AS --規格化,以消除屬性值單位不同造成的影響
TA1 AS --第一代質心點選擇,根據GDP
TE AS --聚類選擇,各元素取相異度最低的質心點

可以在集合TA1後面做一個SELECT看一下第一代的質心點,如下圖:

執行SQL後看一下第二代的質心點,發現維值都發生了變化,說明質心點還是不穩定的,需要迭代地尋找下去。

通過上面的預演,腦子也做了預熱。找到規律之後,霍然思路全部連通,K-MEANS聚類問題的關鍵就在於遞迴地尋找最穩定的質心點集合。為了保持演算法的通用性,抽象出了如下8個維度的聚類訓練集,同時定義了批次ID與初始質心標識(0,1):

為了能夠傳入父代質心點集合得到子代集合,需要定義如下物件:

最重要的演算法實現,考慮到ORACLE自定義函式本身是可遞迴的,我們便來實現這麼一個質心點選擇的遞迴函式,相異度選用尤拉距離公式,為了防止迭代次數過多影響效能,可以指定引數P_MAX_GENERATIOIN NUMBER,即最大遞迴子代數,具體指令碼如下:

  --計算修正後的質心點 D'
  TD AS--相異度排名
   --判斷最大子代限制條件

雖然是PLSQL,可以看到全篇沒有用到迴圈,質心點的計算主體是面向集合的,其中TC是原始點集與質心點的笛卡爾集,投影列DVALUE相異度計算利用尤拉距離公式,推到TD中利用統計函式為每個質心點按相異度排名,TE取排名第一即相異度最小的組合,最後將質心點周圍的點集的算術平均值做為新質心集合返回。全程的集合思維,即Thinking in SQL,如何使用?當然是SQL了,請往下看。

首先我們要把業務資料轉換載入到訓練集中,這是個簡單的ETL過程,將城市GDP表資料經過抽取、維值[0,1]規格化轉換、分配批次號3後最終載入到目標K-MEAN訓練集:

  TB AS --規格化,以消除屬性值單位不同造成的影響

接著我們可以用這個批次ID來得到我們需要的穩定質心點,執行SQL很簡單:

SELECT *
FROM TABLE( FUN_DM_KMEANS_CENTROID(3)) A  ;

通過計算結果,我們可以看到質心點在第10代(GENERATION)才得以穩定下來,如果想看看第5代長什麼樣怎麼辦?簡單,如下:

SELECT *
FROM TABLE( FUN_DM_KMEANS_CENTROID(3,5)) A  ;

接下來我們回到問題的初衷,如何把城市分成四線,具體哪些城市是一線,只需要下面這一個SQL,和質心點選擇函式中功能大同小異:

是不是和我一樣迫不及待地想看結果了,我所關心的城市到底被分到了哪一級,輸出結果:

如此便計算出了我心目中的四線城市。對結果不喜的,莫爭議,這就是個一個數字遊戲,畢竟只是堆疊出來的度量模型沒什麼權威。簡單分析一下,CUSTER_ID值的大小不能說明什麼,只是用來給簇編號確定分類的。根據CLUSTER_ID分類,可以看到北上廣深以及其他的直轄市都在最繁榮的分類中,蘇州、成都能夠擠進去說明很有實力。鄂爾多斯領跑二線。。。這個城市也很有趣。而我的家鄉煙臺只能搭上三線的邊,難免有些失落。

至此,SQL版本的K-MEANS聚類演算法已經介紹完,個人舉的例子可能沒有那麼貼切。因為對資料探勘來說,資料量太小,結果的偶然性會比較高。但麻雀雖小,卻較為完整地用SQL表述了K-MEANS聚類的思想。實現這麼個演算法,全篇沒有用到一個迴圈處理,還是那句話,資料處理,SQL為王。Thinking in SQL,處處是集合,或許,只有你想不到的。