R語言之數據管理

作者:謝佳標

微軟中國MVP,多屆中國R語言大會演講嘉賓,目前在創夢天地擔任高級數據分析師一職, 作為創夢天地數據挖掘組的負責人,帶領團隊對遊戲數據進行深度挖掘, 主要利用R語言進行大數據的挖掘和可視化工作。

數據挖掘最重要的一環就是如何管理你的數據,因為原始數據一般都不能直接用來進行分析,需要對原始數據進行增加衍生變數、數據分箱、數據標準化處理;對因子型變數進行啞變數處理;數據抽樣和類失衡數據處理。本專題會詳細介紹以上內容的數據挖掘技術及R語言實現。

  1. 數據轉換

對於數據挖掘分析建模來說,數據轉換(Transformation)是最常用、最重要,也是最有效的一種數據處理技術。經過適當的數據轉換後,模型的效果常常可以有明顯的提升,也正因為這個原因,數據轉換成了很多數據分析師在建模過程中最喜歡使用的一種數據處理手段。另一方面,在絕大數數據挖掘實踐中,由於原始數據,在此主要是指區間型變數(Interval)的分布不光滑(或有雜訊),不對稱分布(Skewed Distributions),也使得數據轉化成為一種必須的技術手段。

按照採用的轉換邏輯和轉換目的的不同,數據轉換主要分為以下四大類:

  • 產生衍生變數。

這類轉換的目的很直觀,即通過對原始數據進行簡單、適當地數據公式推導,產生更有商業意義的新變數。例如,我們收集了最近一周的付費人數和付費金額,此時想統計每日的日均付費金額(arpu=revenue/user),此時就可以通過前兩個變數快速實現。

> # 創建數據集n> w <- data.frame(day = 1:7,n+ revenue = sample(5000:6000,7),n+ user = sample(1000:1500,7))n> wn day revenue usern1 1 5391 1223n2 2 5312 1418n3 3 5057 1343n4 4 5354 1397n5 5 5904 1492n6 6 5064 1113n7 7 5402 1180n> # 增加衍生變數人均付費金額(arpu)n> w$arpu <- w$revenue/w$usern> wn day revenue user arpun1 1 5391 1223 4.408013n2 2 5312 1418 3.746121n3 3 5057 1343 3.765450n4 4 5354 1397 3.832498n5 5 5904 1492 3.957105n6 6 5064 1113 4.549865n7 7 5402 1180 4.577966n

從中不難發現,得到這些衍生變數所應用到的數據公式很簡單,但是其商業意義是明確的,而且跟具體的分析背景和分析思路密切相關。

衍生變數的產生主要依賴於數據分析師的業務熟悉程度和對項目思路的掌握程度,如果沒有明確的項目分析思路和對數據的透徹理解,是無法找到有針對性的衍生變數的。

  • 改善變數分布特徵的轉換,這裡主要是指不對稱分布所進行的轉換。

在數據挖掘實戰中,有些數據是不對稱的,嚴重不對稱出現在自變數中常常會干擾模型的擬合,最終會影響模型的效果和效率。如果通過各種數學變換,使得變數的分布呈現(或者近似)正態分布,並形成倒鐘形曲線,那麼模型的擬合常常會有明顯的提升,轉換後自變數的預測性能也可能得到改善,最終將會提高模型的效果和效率。

常見的改善分布的轉換措施如下:

取對數(Log)

開平方根(SquareRoot)

取倒數(Inverse)

開平方(Square)

取指數(Exponential)

這邊以取對數為例進行說明。在R的擴展包ggplot2中自帶了一份鑽石數據集(diamonds),我們從中抽取1000個樣本最為研究對象,研究數據中變數carat(克拉數)、price(價格)的數據分布情況,並研究兩者之間的關係,最後利用克拉數預測鑽石的價格。

> library(ggplot2)n> set.seed(1234)n> dsmall <- diamonds[sample(1:nrow(diamonds),1000),] # 數據抽樣n> head(dsmall) # 查看數據前六行n carat cut color clarity depth table price x y zn6134 0.91 Ideal G SI2 61.6 56 3985 6.24 6.22 3.84n33567 0.43 Premium D SI1 60.1 58 830 4.89 4.93 2.95n32864 0.32 Ideal D VS2 61.5 55 808 4.43 4.45 2.73n33624 0.33 Ideal G SI2 61.7 55 463 4.46 4.48 2.76n46435 0.70 Good H SI1 64.2 58 1771 5.59 5.62 3.60n34536 0.33 Ideal G VVS1 61.8 55 868 4.42 4.45 2.74n> par(mfrow = c(1,2))n> plot(density(dsmall$carat),main = "carat變數的正態分布曲線") # 繪製carat變數的正態分布曲線 n> plot(density(dsmall$price),main = "price變數的正態分布曲線") # 繪製price變數的正態分布曲線 n> par(mfrow = c(1,1))n

從正態分布圖可知,變數carat和price均是嚴重不對稱分布。此時我們利用R語言中的log函數對兩者進行對數轉換,再次繪製正態密度圖。

> par(mfrow = c(1,2))n> plot(density(log(dsmall$carat)),main = "carat變數取對數後的正態分布曲線") n> plot(density(log(dsmall$price)),main = "price變數取對數後的正態分布曲線") n> par(mfrow = c(1,1))n

可見,經過對數處理後,兩者的正態分布密度曲線就對稱很多。最後,讓我們一起來驗證對原始數據建立線性回歸模型與經過對數變數後再建模的區別。

> # 建立線性回歸模型n> fit1 <- lm(dsmall$price~dsmall$carat,data = dsmall) # 對原始變數進行建模n> summary(fit1) # 查看模型詳細結果nnCall:nlm(formula = dsmall$price ~ dsmall$carat, data = dsmall)nnResiduals:n Min 1Q Median 3Q Max n-8854.8 -821.9 -42.2 576.0 8234.2 nnCoefficients:n Estimate Std. Error t value Pr(>|t|) n(Intercept) -2391.74 97.44 -24.55 <2e-16 ***ndsmall$carat 7955.35 104.45 76.16 <2e-16 ***n---nSignif. codes: 0 『***』 0.001 『**』 0.01 『*』 0.05 『.』 0.1 『 』 1nnResidual standard error: 1582 on 998 degrees of freedomnMultiple R-squared: 0.8532,tAdjusted R-squared: 0.8531 nF-statistic: 5801 on 1 and 998 DF, p-value: < 2.2e-16nn> fit2 <-lm(log(dsmall$price)~log(dsmall$carat),data=dsmall) # 對兩者進行曲對數後再建模n> summary(fit2) # 查看模型結果nnCall:nlm(formula = log(dsmall$price) ~ log(dsmall$carat), data = dsmall)nnResiduals:n Min 1Q Median 3Q Max n-1.07065 -0.16438 -0.01159 0.16476 0.83140 nnCoefficients:n Estimate Std. Error t value Pr(>|t|) n(Intercept) 8.451358 0.009937 850.5 <2e-16 ***nlog(dsmall$carat) 1.686009 0.014135 119.3 <2e-16 ***n---nSignif. codes: 0 『***』 0.001 『**』 0.01 『*』 0.05 『.』 0.1 『 』 1nnResidual standard error: 0.2608 on 998 degrees of freedomnMultiple R-squared: 0.9345,tAdjusted R-squared: 0.9344 nF-statistic: 1.423e+04 on 1 and 998 DF, p-value: < 2.2e-16n

通過對比MultipleR-squared發現,模型1的R平方是0.8532,模型2的R平方是0.9345,R平方的值是越接近1說明模型擬合的越好,所以經過對數處理後建立的模型2優於模型1。我們也可以通過在散點圖繪製擬合曲線的可視化方式進行查看。

> # 在散點圖中 繪製擬合曲線n> par(mfrow=c(1,2))n> plot(dsmall$carat,dsmall$price,n+ main = "未處理的散點圖及擬合直線")n> abline(fit1,col="red",lwd=2)n> plot(log(dsmall$carat),log(dsmall$price),n+ main = "取對數後的散點圖及擬合直線")n> abline(fit2,col="red",lwd=2)n> par(mfrow=c(1,1))n

可見,取對數後繪製的散點更集中在紅色的線性回歸線上。

  • 區間型變數的分箱轉換。

分箱轉換(Binning)就是把區間型變數 (Interval)轉換成次序型變數(Ordinal),其轉換的目的如下:

降低變數(主要是指自變數)的複雜性,簡化數據。比如,有一組用戶的年齡,原始數據是區間型的,從10~60歲,每1歲都是1個年齡段;如果通過分箱轉換,每10歲構成1個年齡組,就可以有效簡化數據。R語言中有cut函數可以輕易實現數據分箱操作。

> age <- sample(10:60,15)n> age <- sample(10:60,15) # 創建年齡變數n> agen [1] 26 41 59 33 50 16 28 18 52 30 25 44 37 23 47n> age_cut <- cut(age,breaks = seq(10,60,10))n> age_cutn [1] (20,30] (40,50] (50,60] (30,40] (40,50] (10,20] (20,30] (10,20] (50,60]n[10] (20,30] (20,30] (40,50] (30,40] (20,30] (40,50]nLevels: (10,20] (20,30] (30,40] (40,50] (50,60]n> table(age_cut) # 查看不同年齡段的人數nage_cutn(10,20] (20,30] (30,40] (40,50] (50,60] n 2 5 2 4 2 n

可見,利用cut函數分箱得到的區間段是左開右閉的,我們通過table函數查看不同區間段的人數,發現有5人在20到30歲之間。

  • 針對區間型變數進行的標準化操作。

數據的標準化(Normalization)轉換也是數據挖掘中常見的數據轉換措施之一,數據標準轉換的目的是將數據按照比例進行縮放,使之落入一個小的區間範圍之內,使得不同的變數經過標準化處理後可以有平等分析和比較的基礎。

最簡單的數據標準化轉換是Min-Max標準化,也叫離差標準化,是對原始數據進行線性變換,使得結果在[0,1]區間,其轉換公式如下:

其中,max為樣本數據的最大值,min為樣本數據的最小值。

在R中,我們可以利用max函數和min函數非常輕易地構建一個Normalization函數,實現Min-Max標準化過程。

> dat <- sample(1:20,10) # 從1到20中有放回隨機抽取10個n> normalization <- function(x) {n+ (x-min(x))/(max(x)-min(x))n+ } # 構建Min-Max標準化的自定義函數n> dat # 原始數據n [1] 19 5 8 13 15 18 16 1 3 9n> normalization(dat) # 經過Min-Max標準化的 數據n [1] 1.0000000 0.2222222 0.3888889 0.6666667 0.7777778 0.9444444 0.8333333n [8] 0.0000000 0.1111111 0.4444444n

另一種常用的標準化處理是零-均值標準化,即把數據處理稱符合標準正態分布。也就是均值為0,標準差為1,轉換公式如下:

其中,μ為所有樣本數據的均值,σ為所有樣本數據的標準差。

在R中,用scale( )函數得到Z-Score標準化。其表達形式為:scale(x, center = TRUE, scale = TRUE)。

總體來說,數據變換的方式多種多樣,操作起來簡單、靈活、方便,在 實踐應用中的價值也是比較明顯的。

2. 數據抽樣

「抽樣」對於數據分析和挖掘來說是一種常見的前期數據處理技術和階段,之所以要採取抽樣,主要原因在於如果數據全集的規模太大,針對數據全集進行分析運算不但會消耗更多的運算資源,還會顯著增加運算分析的時間,甚至太大的數據量有時候會導致分析挖掘軟體運行時的崩潰。而採用了抽樣措施,就可以顯著降低這些負面的影響;另一個常見的需要通過抽樣來解決的場景就是:我們需要將原始數據進行分區,其中一部分作為訓練集,用來訓練模型,剩下的部分作為測試集,用來對訓練好的模型進行效果評估。

R中的sample( )函數可以實現數據的隨機抽樣。基本表達形式為:

sample(x, size, replace = FALSE, prob = NULL)

其中x是數值型向量,size是抽樣個數,replace表示是否有放回抽樣,默認FALSE是無放回抽樣,TURE是有放回抽樣。

> # sample小例子n> set.seed(1234)n> # 創建對象x,有1~10組成n> x <- seq(1,10);xn [1] 1 2 3 4 5 6 7 8 9 10n> # 利用sample函數對x進行無放回抽樣n> a <- sample(x,8,replace=FALSE);an[1] 2 6 5 8 9 4 1 7n> # 利用sample函數對x進行有放回抽樣n> b <- sample(x,8,replace=TRUE);bn[1] 7 6 7 6 3 10 3 9n> # 當size大於x的長度n> (c <- sample(x,15,replace = F))nError in sample.int(length(x), size, replace, prob) : n cannot take a sample larger than the population when replace = FALSEn> (c <- sample(x,15,replace = T))n [1] 3 3 2 3 4 4 2 1 3 9 6 10 9 1 5n

可見,b中抽取的元素有重複值。如果我們要抽取的長度大於x的長度,需要將replace參數設置為T(有放回抽樣)。

有時候,我們想根據某一個變數對數據進行等比例抽樣(即抽樣後的數據子集中的該變數各因子水平佔比與原來相同),雖然我們利用sample函數也可以構建,但是這裡給大家介紹caret擴展包中的createDataPartition函數,可以快速實現數據按照因子變數的類別進行快速等比例抽樣。其函數基本表達形式為:

createDataPartition(y,times = 1,p = 0.5,list = TRUE,groups = min(5, length(y)))

其中y是一個向量,times表示需要進行抽樣的次數,p表示需要從數據中抽取的樣本比例,list表示結果是否是list形式,默認為TRUE,groups表示果輸出變數為數值型數據,則默認按分位數分組進行取樣。

以鳶尾花數據集為例,我們想按照物種分類變數進行等比例隨機抽取其中10%的樣本進行研究。

> # 載入caret包,如果本地未安裝就在線安裝caret包n> if(!require(caret)) install.packages("caret")n載入需要的程輯包:caretn載入需要的程輯包:latticen載入需要的程輯包:ggplot2nWarning message:n程輯包『ggplot2』是用R版本3.3.3 來建造的 n> # 提取下標集n> splitindex <- createDataPartition(iris$Species,times=1,p=0.1,list=FALSE)n> iris_subset <- iris[splitindex,]n> prop.table(table(iris$Species)) # 查看原來數據集Species變數各因子佔比nn setosa versicolor virginica n0.3333333 0.3333333 0.3333333 n> prop.table(table(iris_subset$Species))# 查看子集中Species變數各因子佔比nn setosa versicolor virginica n0.3333333 0.3333333 0.3333333 n

可見,抽樣後的子集中Species中各類別的佔比與原來數據集的相同。

3. 類失衡數據處理

另外一個常見的需要通過抽樣來解決的場景就是:在很多小概率事件、稀有事件的預測建模過程中,比如信用卡欺詐事件,在整個信用卡用戶中,屬於惡意欺詐的用戶只佔0.2%甚至更少,如果按照原始的數據全集、原始的稀有佔比來進行分析挖掘,0.2%的稀有事件是很難通過分析挖掘得到有意義的預測和結論的,所有對此類稀有事件的分析建模,通常會採取抽樣的措施,即認為增加樣本中「稀有事件」的濃度和在樣本中的佔比。對抽樣後得到的分析樣本進行分析挖掘,可以比較容易地發現稀有時間與分析變數之間的價值,有意義的一些關聯性和邏輯性。

克服類失衡問題常用的技術有以下兩種:

  • 偏置學習過程的方法,它應用特定的對少數類更敏感的評價指標。

  • 用抽樣方法來操作訓練數據,從而改變類的分布。

有多種抽樣方法用於改變數據集中類的失衡,常用的有以下兩種:

  • 欠採樣法,它從多數類中選擇一小部分案例,並把它們和少數類個案一起構成一個有更加平衡的類分布的數據集。

  • 過採樣法,它採用另外的工作模式,使用某些進程來複制少數類個案。

在R中,DMwR包中的SMOTE( )函數可以實現SMOTE方法。主要參數有如下三個:perc.over:過採樣時,生成少數類的樣本個數;k:過採樣中使用K近鄰演算法生成少數類樣本時的K值,默認是5;perc.under:欠採樣時,對應每個生成的少數類樣本,選擇原始數據多數類樣本的個數。例如,perc.over=500表示對原始數據集中的每個少數樣本,都將生成5個新的少數樣本;perc.under=80表示從原始數據集中選擇的多數類的樣本是新生的數據集中少數樣本的80%。

> # 載入DMwR包n> if(!require(DMwR)) install.packages("DMwR")n載入需要的程輯包:DMwRn載入需要的程輯包:latticen載入需要的程輯包:gridn> dat <- iris[, c(1, 2, 5)]n> dat$Species <- factor(ifelse(dat$Species == "setosa","rare","common")) n> table(dat$Species)nncommon rare n 100 50 n> # 進行類失衡處理n> # perc.over=600:表示少數樣本數=50+50*600%=350n> # perc.under=100:表示多數樣本數(新增少數樣本數*100%=300*100%=300)n> newData <- SMOTE(Species ~ ., dat, perc.over = 600,perc.under=100)n> table(newData$Species)nncommon rare n 300 350 n> # perc.over=100:表示少數樣本數=50+50*100%=100n> # perc.under=200:表示多數樣本數(新增少數樣本數*200%=50*200%=100)n> newData <- SMOTE(Species ~ ., dat, perc.over = 100,perc.under=200)n> table(newData$Species)nncommon rare n 100 100 n

4. 數據啞變數處理

虛擬變數 ( Dummy Variables) 又稱虛設變數、名義變數或啞變數,用以反映質的屬性的一個人工變數,是量化了的自變數,通常取值為0或1。引入啞變數可使線形回歸模型變得更複雜,但對問題描述更簡明,一個方程能達到兩個方程的作用,而且接近現實。

舉一個例子,假如變數「性別」的取值為:男性、女性。我們可以增加2個啞變數來代替「性別」這個變數,分別為性別.男性(1=男性/0=女性)、性別.女性(1=女性/0=男性)。

caret擴展包中的dummyVars( )函數是專門用來處理變數啞變數處理的函數,其表達形式為:dummyVars(formula,data, sep = ".", levelsOnly = FALSE, fullRank = FALSE, ...)。其中,formula表示模型公式,data是需要處理的數據集,sep表示列名和因子水平間的連接符號,levelsOnly默認是FALSE,當為TRUE時表示僅用因子水平表示新列名,fullRank默認是FALSE,當為TRUE時表示進行虛擬變數處理後不需要出現代表相同意思的兩列。

假如有一份customers數據集,包括id、gender、mood和outcome變數,其中gender和mood都是因子型變數,我們需要將它們進行啞變數處理。

> customers <- data.frame(n+ id=c(10,20,30,40,50), n+ gender=c(male,female,female,male,female), n+ mood=c(happy,sad,happy,sad,happy), n+ outcome=c(1,1,0,0,0))n> customersn id gender mood outcomen1 10 male happy 1n2 20 female sad 1n3 30 female happy 0n4 40 male sad 0n5 50 female happy 0n> library(caret)n載入需要的程輯包:ggplot2nWarning message:n程輯包『ggplot2』是用R版本3.3.3 來建造的 n> # 啞變數處理n> dmy <- dummyVars(" ~ .", data = customers)n> trsf <- data.frame(predict(dmy, newdata = customers))n> print(trsf)n id gender.female gender.male mood.happy mood.sad outcomen1 10 0 1 1 0 1n2 20 1 0 0 1 1n3 30 1 0 1 0 0n4 40 0 1 0 1 0n5 50 1 0 1 0 0n

經過啞變數處理後,原來的變數gender變成兩列gender.female和gender.male,變數mood變成mood.happy和mood.sad兩列,新生成的列裡面的內容均是0/1,已經幫我們做了歸一化處理。

彩蛋要不要

R語言資深實戰講師謝佳標老師,繼R語言十三式之後,利劍再出!

十五大案例,面向實戰,案例滿滿,學完即用!

心血課程、口碑講師,揚帆出發,理論結合應用,握住開啟R語言實戰之門金鑰匙!

課程更有天善學院促銷活動等你來,炎炎六月,熱力絕配!

點擊閱讀原文掃碼立即學習

推薦閱讀:

UCSD 2017秋季數據科學項目閃亮登場!
我們在可視化什麼?
伊朗是威脅海灣國家安全的罪魁禍首?海灣民眾:我們不信

TAG:R编程语言 | 数据挖掘 | 数据 |