用R語言實現資料離散化
R的極客理想系列文章,涵蓋了R的思想,使用,工具,創新等的一系列要點,以我個人的學習和體驗去詮釋R的強大。
R語言作為統計學一門語言,一直在小眾領域閃耀著光芒。直到大資料的爆發,R語言變成了一門炙手可熱的資料分析的利器。隨著越來越多的工程背景的人的加入,R語言的社群在迅速擴大成長。現在已不僅僅是統計領域,教育,銀行,電商,網際網路….都在使用R語言。
要成為有理想的極客,我們不能停留在語法上,要掌握牢固的數學,概率,統計知識,同時還要有創新精神,把R語言發揮到各個領域。讓我們一起動起來吧,開始R的極客理想。
關於作者:
- 張丹(Conan), 程式員/Quant: Java,R,Nodejs
- blog: http://blog.fens.me
- email: [email protected]
轉載請註明出處:
ofollow,noindex">http://blog.fens.me/r-discretization
前言
在做資料探勘模型的時候,我們有時會需要把連續型變數轉型離散變數,這種轉換的過程就是資料離散化,分箱就是離散化常用的一種方法。
資料離散化處理屬於資料預處理的一個過程,R語言在資料處理上有天然的優勢,也有直接用於離散化計算的包,無監督的離散化可以用infotheo包,有監督的離散化可以用discretization包來處理複雜的離散化操作。
目錄
- 資料離散化的需求
- 無監督的資料離散化
- 有監督的資料離散化
1. 資料離散化的需求
資料離散化,教課書上面的定義是,把無限空間中有限的個體對映到有限的空間中。資料離散化操作,大多是針對連續型變數進行的,處理之後資料從連續型變數轉變為離散型變數。
離散化處理的特點:
- 快速迭代,離散化的過程,離散特徵增加和減少都很容易,易於擴充套件。
- 高效計算,稀疏向量內積乘法運算速度快,計算結果方便儲存。
- 適應性,有些分類模型適合用離散化資料做為資料指標,比如決策樹雖然支援輸入連續型變數,但決策樹模型本身會先將連續型變數轉化為離散型變數,做邏輯迴歸時,也通常會先把連續型特徵變數離散化,變成0或1。
- 魯棒性,資料離散化會讓特徵變化不是特別明顯,特別是對於降低異常資料干擾。
- 穩定性,犧牲了資料的微小變化,但保證了模型的穩定性。
- 過擬合,減少的資料資訊,降低了過擬合的風險。
- 業務性,業務上已經定義出了離散值的含義,需要做離散化處理。
離散化處理通常對連續型變數進行處理,但同時也可以對離散型變數再進行離散化,適用於資料聚合或重新分組。
2. 無監督的資料離散化
我們可以無監督的資料離散化方法,進行資料的分箱操作,包括等寬分箱法、等頻分箱法、通過kmeans分箱法等。
- 等寬分箱法,將觀察點均勻劃分成n等份,每份的間距相等。
- 等頻分箱法,將觀察點均勻分成n等份,每份的觀察點數相同。
- kmeans分箱法,先給定中心數,將觀察點利用歐式距離計算與中心點的距離進行歸類,再重新計算中心點,直到中心點不再發生變化,以歸類的結果做為分箱的結果。
接下來,我們用R語言來實現上面提到的幾種分箱的操作。
2.1 準備資料
本文所使用的系統環境
- Win10 64bit
- R: 3.2.3 x86_64-w64-mingw32/x64 b4bit
首先,生成一組資料,這組織通過3個正態分佈的隨機數進行疊加,主要用於體現分箱的不同特徵。
# 設定隨機數種子,生成符合正態分佈N(0,1)的資料1000個點 > set.seed(0) > a1<-rnorm(1000) > set.seed(1) > a2<-rnorm(300,0,0.2) > set.seed(2) > a3<-rnorm(300,3,0.5) # 按順序,合併3種資料 > aa<-c(a1,a2,a3) # 檢視資料 > head(aa,30) [1]1.26295 -0.326231.329801.272430.41464 -1.53995 -0.92857 -0.29472 -0.005772.404650.76359 [12] -0.79901 -1.14766 -0.28946 -0.29922 -0.411510.25222 -0.891920.43568 -1.23754 -0.224270.37740 [23]0.133340.80419 -0.057110.503611.08577 -0.69095 -1.284600.04673
畫出資料的散點圖,x軸為索引序號,y軸為值。
> plot(aa)
檢視資料的分佈形狀,x軸為值,y軸為這個值出現的次數。
# 畫出資料的直方圖 > hist(aa,200)
通過散點圖和直方圖,就可以很明顯的看到資料的特徵,資料有傾斜的,值在0和3附近是比較多的。
2.2 infotheo包使用
在R語言中,我們可以使用infotheo包,來做等寬分箱和等頻分箱。
專案主頁: https://cran.r-project.org/web/packages/infotheo/
安裝infotheo包,是非常簡單的,只需要一條命令。
~ R > install.packages("infotheo") > library(infotheo)
進行等寬分箱,將觀察點均勻劃分成n等份,每份的間距相等。
> d1<-discretize(aa,"equalwidth",5) > table(d1) d1 12345 40 467 703 217 173 # 視覺化分箱 > plot(aa,col=d1$X)
分為5組,第一組最少,第三組最多,每組值的區間是一樣的。
進行等頻率分箱,將觀察點均勻分成n等份,每份的觀察點數相同。
> d2<-discretize(aa,"equalfreq",5) > table(d2) d2 12345 320 320 320 320 320 # 視覺化分箱 > plot(aa,col=d2$X)
分為5組,每組的數量都相同。
kmeans分箱法,先給定中心數為5。
> d3<-kmeans(aa,5) > table(d3$cluster) 12345 121 258 303 267 651 # 5箇中心 > d3$centers [,1] 1 -1.6196 21.2096 33.0436 4 -0.7228 50.0736 # 視覺化分箱 > plot(aa,col=d3$cluster)
5組聚類的結果。

每一種方法,對於分箱的離散化的結果都是不同的,使用哪一種方法,最好都有業務上的解釋,不能隨便亂用。
3. 有監督的資料離散化方法
有監督的離散化的方法,可以用R語言中discretization包來操作。discretization包,是一個用來做有監督離散化的工具集,主要用於卡方分箱演算法,它提供了幾種常用的離散化工具函式,可以按照自上而下或自下而上,實施離散化演算法。
專案主頁: https://cran.r-project.org/web/packages/discretization/
安裝discretization包是非常簡單的,只需要一條命令。
~ R > install.packages("discretization") > library(discretization)
discretization提供了幾個主要的離散化的工具函式:
- chiM,ChiM演算法進行離散化
- chi2, Chi2演算法進行離散化
- mdlp,最小描述長度原理(MDLP)進行離散化
- modChi2,改進的Chi2方法離散數值屬性
- disc.Topdown,自上而下的離散化
- extendChi2,擴充套件Chi2演算法離散數值屬性
3.1 卡方分箱
卡方分箱是依賴於卡方檢驗的分箱方法,在統計指標上選擇卡方統計量(chi-Square)進行判別。卡方分箱的基本思想是判斷相鄰的兩個區間是否有分佈差異,如果兩個相鄰的區間具有非常類似的分佈,則這兩個區間可以合併;否則,它們應當保持分開。基於卡方統計量的結果進行自下而上的合併,直到滿足分箱的限制條件為止。
卡方分箱的實現步驟:
1. 預先設定一個卡方的閾值。以這個閾值為標準,我們對資料進行卡方檢驗,通過顯著性水平和自由度,計算出資料的卡方值與這個閾值進行比較。
- 顯著性水平,當置信度90%時顯著性水平為10%,ChiMerge演算法推薦使用置信度為0.90、0.95、0.99。
- 自由度,比分類數量小1。例如:有3類,自由度為2。
類別和屬性獨立時,有90%的可能性,計算得到的卡方值會小於4.6。大於閾值4.6的卡方值就說明屬性和類不是相互獨立的,不能合併。如果閾值選的大,區間合併就會進行很多次,離散後的區間數量少、區間大。
2. 初始化:根據要離散化的資料對例項進行排序,每個例項屬於一個區間
3. 合併區間:
1) 計算每一個對相鄰區間的卡方值
2) 將卡方值最小的一對區間合併
卡方統計量衡量了區間內樣本的頻數分佈與整體樣本的頻數分佈的差異性,在做分箱處理時可以使用兩種限制條件:
- 分箱個數:限制最終的分箱個數結果,每次將樣本中具有最小卡方值的區間與相鄰的最小卡方區間進行合併,直到分箱個數達到限制條件為止。
- 卡方閾值:根據自由度和顯著性水平得到對應的卡方閾值,如果分箱的各區間最小卡方值小於卡方閾值,則繼續合併,直到最小卡方值超過設定閾值為止。
4.評估指標
分為箱之後需要評估,常用的評估手段是計算出WOE和IV值。對於WOE和IV值的含義,參考文章: https://blog.csdn.net/kevin7658/article/details/50780391
3.2 資料準備
有監督的離散化演算法,只少需要資料為2列,一列用於離散化的向量資料,一列是分類的評價標準資料,所以我們需要重新選擇一個數據集,具有分類標準的資料。
我們使用一個系統自帶的資料集iris,這個著名的Fisher的鳶尾花資料。iris包含150個記錄,和5個變數的資料框,名為Sepal.Length(萼片的長度),Sepal.Width(萼片的寬度),Petal.Length(花瓣的長度),Petal.Width(花瓣的長度)和Species(種類,setosa,versicolor和virginica)。
檢視資料集
> data(iris) > head(iris,10) Sepal.Length Sepal.Width Petal.Length Petal.Width Species 15.13.51.40.2setosa 24.93.01.40.2setosa 34.73.21.30.2setosa 44.63.11.50.2setosa 55.03.61.40.2setosa 65.43.91.70.4setosa 74.63.41.40.3setosa 85.03.41.50.2setosa 94.42.91.40.2setosa 104.93.11.50.1setosa
接下來,我們分別用不同的演算法,把這個資料集進行離散化處理。
3.3 chiM演算法進行離散化
ChiM()函式,使用ChiMerge演算法基於卡方檢驗進行自下而上的合併。通過卡方檢驗判斷相鄰閾值的相對類頻率,是否有明顯不同,或者它們是否足夠相似,從而合併為一個區間。
chiM(data,alpha)函式解讀。
- 第一個引數data,是輸入資料集,要求最後一列是分類屬性。
- 第二個引數alpha,表示顯著性水平。
- 自由度,通過資料計算獲得是2,一共3個分類減去1。
下面使用chiM()進行計算。
# 離散化計算 > chi1<-chiM(iris,alpha=0.05) # 檢視前10條結果 > head(chi1$Disc.data,10) Sepal.Length Sepal.Width Petal.Length Petal.Width Species 11311setosa 21211setosa 31211setosa 41211setosa 51311setosa 61311setosa 71311setosa 81311setosa 91111setosa 101211setosa
chi2演算法的結果解讀,從輸出結果可以看出,Sepal.Length Sepal.Width Petal.Length Petal.Width,這幾個變數被自動地離散化處理了。
檢視這4個列的離散化情況。
> apply(chi1$Disc.data,2,table) $Sepal.Length 1234 52 21 65 12 $Sepal.Width 123 57 56 37 $Petal.Length 1234 50 45 21 34 $Petal.Width 123 50 54 46 $Species setosa versicolorvirginica 505050
再檢視每個列的閾值。
# 檢視分組閾值 > chi1$cutp [[1]] [1] 5.45 5.75 7.05 [[2]] [1] 2.95 3.35 [[3]] [1] 2.45 4.75 5.15 [[4]] [1] 0.80 1.75
以第一組Sepal.Length舉例,被分為4類,當源資料Sepal.Length列的值,小於 5.45值為1類,大於5.45同時小於5.75為2類,大於5.75同時小於7.05為3類,大於7.05為4類。
我們把離散化後的資料,與源資料進行合併進行觀察。第一列是離散化後的資料,第二列是源資料。
> chi1df<-cbind(chi1$Disc.data$Sepal.Length,iris$Sepal.Length) > head(chi1df,20) [,1] [,2] [1,]15.1 [2,]14.9 [3,]14.7 [4,]14.6 [5,]15.0 [6,]15.4 [7,]14.6 [8,]15.0 [9,]14.4 [10,]14.9 [11,]15.4 [12,]14.8 [13,]14.8 [14,]14.3 [15,]35.8 [16,]25.7 [17,]15.4 [18,]15.1 [19,]25.7 [20,]15.1
這樣就完成了卡方分箱的操作,接下來的其他幾個函式的使用,與chiM()的演算法類似,就不再過多討論了。
3.4 其他演算法
chi2()演算法,檢視分組閾值。
> chi2<-chi2(iris,alp=0.5,del=0.05) > chi2$cutp [[1]] [1] 3.5 4.5 6.5 [[2]] [1] 3.5 4.5 [[3]] [1] 1.5 2.5 3.5 [[4]] [1] 1.5 3.5
modChi2()演算法,檢視分組閾值。
> chi3<-modChi2(iris,alp=0.5) > chi3$cutp [[1]] [1] 1.5 2.5 [[2]] [1] 2.5 [[3]] [1] 1.5 2.5 [[4]] [1] 1.5 2.5
extendChi2()演算法,檢視分組閾值。
> chi4<-extendChi2(iris,alp = 0.5) > chi4$cutp [[1]] [1] 1.5 2.5 [[2]] [1] 1.5 2.5 [[3]] [1] 1.5 2.5 [[4]] [1] 1.5 2.5
> m1<-mdlp(iris) > m1$cutp [[1]] [1] 5.55 6.15 [[2]] [1] 2.95 3.35 [[3]] [1] 2.45 4.75 [[4]] [1] 0.80 1.75
disc.Topdown()演算法,檢視分組閾值。
> d1<-disc.Topdown(iris,method=1) > d1$cutp [[1]] [1] 4.30 5.55 6.25 7.90 [[2]] [1] 2.00 2.95 3.05 4.40 [[3]] [1] 1.00 2.45 4.75 6.90 [[4]] [1] 0.10 0.80 1.75 2.50
最後,分箱需要注意的是,分完箱之後,某些箱區間裡可能資料分佈比例極不均勻,那麼這樣子會直接導致後續計算WOE時出現inf無窮大的情況,這是不合理的。這種情況,說明分箱太細,需要進一步縮小分箱的數量。
本文詳細地介紹了無監督的離散化方法和有監督的離散化方法,針對不同的場景,我們可以選擇不同的方法進行使用。R語言中,包提供了各種離散化的工具函式,使用起來很方便,可以大幅提供資料處理過程的效率。
轉載請註明出處:
http://blog.fens.me/r-discretization