本篇內容為「資料預處理」(或者稱資料清洗)的手法上。
畢竟在資料分析的流程中,其實有60~70%的時間是在進行「資料預處理」,如果沒有好的資料,後續的分析其實就可能會有很大的偏誤。 在「資料預處理」時,我們時常會遇到很多問題需要解決。 當然,也有有很多對應的小技巧,可以幫助我們處理這些問題。
首先,因為我們之後會使用到非常多的套件,故必須先更新R的版本至【3.4.0】 ,而本篇內容有資料分割、資料合併、處理離群值(outlier)和轉虛擬變數(Dummy variable)等技巧!
當我們想要將一個表單切割成不同的子表單時,會使用到以下的函式: split()
、subset()
,以下會詳細介紹其函式的用法。
我們再拿我們熟悉的好朋友,鳶尾花資料(iris)來練習吧^_<
● 使用split()
函式進行資料分割:
require(datasets) # source package
data <- iris
split_data <- split(data, sample(rep(1:2, 75)))
由於rep(1:2,75)產生1,2交錯的向量,但加了前面的sample則是隨機抽取,所以向量1,2會被打亂,split會依照sample(rep(1:2,75))分組,都是1的會在同一組,都是2的也會在同一組。
● 使用subset()
函式進行資料分割:
require(datasets) # source package
data <- iris
subset(data, Sepal.Length > 5) # 只會出現 Sepal.Length > 5 的資料
subset(data, Sepal.Length == 5,select = c("Sepal.Length","Species")) # 只會出現 Sepal.Length 等於 5 的資料,且欄位只會出現 Sepal.Length 和 Species
subset(data, Sepal.Length > 5,select = - Sepal.Length) # selct = 負的代表不要出現的欄位
當我們想要將兩筆資料合併時,會使用到以下的函式: rbind()
、cbind()
、merge()
,以下會詳細介紹其函式的用法。
● 使用rbind()
函式進行資料合併: rbind()
可以用來追加資料,需要對應欄位(變數)名稱
# 首先先建立兩個 Data frame
ID <- c(1,2,3,4)
Name <- c("A","B","C","D")
Student1 <- data.frame(ID,Name)
ID <- c(5,6,7,8)
Name <- c("E","F","G","H")
Student2 <- data.frame(ID,Name)
# 透過 row 合併
rbind(Student1,Student2)
## ID Name
## 1 1 A
## 2 2 B
## 3 3 C
## 4 4 D
## 5 5 E
## 6 6 F
## 7 7 G
## 8 8 H
● 使用cbind()
函式進行資料合併: cbind()
可以用來新增變數到原本的資料表單中,不需要對應欄位(變數)名稱
# 首先先建立兩個 Data frame
ID <- c(1,2,3,4)
Name <- c("A","B","C","D")
Score <- c(60,70,80,90)
Sex <- c("M","F","M","M")
Student1 <- data.frame(ID,Name)
Student2 <- data.frame(Score,Sex)
# 透過 column 合併
cbind(Student1,Student2)
## ID Name Score Sex
## 1 1 A 60 M
## 2 2 B 70 F
## 3 3 C 80 M
## 4 4 D 90 M
● 使用merge()
函式進行資料合併: merge()
能夠依據兩個表單中共同有的欄位(變數)名稱來合併資料
# 首先先建立兩個 data frame
df1 <- data.frame(CustomerId = c(1:5), Product = c(rep("Toaster", 3), rep("Radio", 2)))
df2 <- data.frame(CustomerId = c(2, 4, 6), State = c(rep("Alabama", 2), rep("Ohio", 1)))
將兩個 data frame 透過 “CustomerId” 欄位進行合併:
# Inner join,保留兩資料集 "CustomerId" 欄位中,取交集的值來合併
merge(x = df1, y = df2, by = "CustomerId")
## CustomerId Product State
## 1 2 Toaster Alabama
## 2 4 Radio Alabama
merge 函式的第一、二個參數是指定要合併的資料表,而 by 參數則是指定資料辨識的依據欄位
# Full join,保留兩資料集 "CustomerId" 欄位中,取聯集的值來合併
merge(x = df1, y = df2, by = "CustomerId", all = TRUE)
## CustomerId Product State
## 1 1 Toaster <NA>
## 2 2 Toaster Alabama
## 3 3 Toaster <NA>
## 4 4 Radio Alabama
## 5 5 Radio <NA>
## 6 6 <NA> Ohio
all 是用來詢問是否顯示所有欄位的資料
# Left join,保留 x (df1表單) "CustomerId" 欄位中的值來合併
merge(x = df1, y = df2, by = "CustomerId", all.x = TRUE)
## CustomerId Product State
## 1 1 Toaster <NA>
## 2 2 Toaster Alabama
## 3 3 Toaster <NA>
## 4 4 Radio Alabama
## 5 5 Radio <NA>
# Right join,保留 y (df2表單) "CustomerId" 欄位中的值來合併
merge(x = df1, y = df2, by = "CustomerId", all.y = TRUE)
## CustomerId Product State
## 1 2 Toaster Alabama
## 2 4 Radio Alabama
## 3 6 <NA> Ohio
要注意,merge()
僅針對兩筆具有共同變數的資料進行合併,由於merge()
會針對by參數所指定的變數做交叉比對,因此該變數的編碼值必須是「單一獨立」且不能「重複」。例如「學號」、「身分證號」等,否則merge會出現個案增多的錯誤結果。
同學們也可以試試看dplyr
套件來進行資料處理,當資料量很大時,處理速度會比一般的函式還要快一些哦~
在探勘的流程中,資料中是否存在離群值(outlier),可能會嚴重影響到資料分析的結果,甚至會影響到模式建立的正確性。
因此判斷離群值的方法便相當重要,以下將介紹兩種以敘述統計為基礎的離群值判斷方法,包括標準化分數、盒鬚圖。
● 標準化分數判斷: 將資料轉成標準化分數或Z分數進行判斷,根據常態分配的性質,約有99%資料的Z分數會落在平均值的3倍標準差之內,因此Z分數大於3或小於-3的數據將視為離群值(可自訂其他數據為切割點)
require(datasets) # source package
data <- iris
data <- subset(data,select = - Species) # 去除不是數值型態的column
scale_data <- scale(data, center = TRUE, scale = TRUE) # 標準化表單中的數值
scale_data <- as.data.frame(scale_data) # 轉成Data frame型態
scale_data <- subset(scale_data, Sepal.Length < 2 & Sepal.Width < 2 & Petal.Length < 2 & Petal.Width < 2) # 留下全部欄位中,Z分數小於2的值
scale_data <- subset(scale_data, Sepal.Length > -2 & Sepal.Width > -2 & Petal.Length > -2 & Petal.Width > -2) # 留下全部欄位中,Z分數大於-2的值
● 盒鬚圖判斷: Tukey(1977)將變數中任何位於內籬(inner fence)與外籬之間的數據視為該變數的潛在離群值。另外,如果變數中有任何數據位於外籬(outter fence)之外的,則視它們為該變數的離群值,外籬指的是Q1向下延伸或Q3向上延伸3倍IQR的距離
require(datasets) # source package
data <- iris
data <- subset(data,select = - Species) # 去除不是數值型態的column
boxplot(data) # 繪製盒鬚圖
summary(data)
## Sepal.Length Sepal.Width Petal.Length Petal.Width
## Min. :4.300 Min. :2.000 Min. :1.000 Min. :0.100
## 1st Qu.:5.100 1st Qu.:2.800 1st Qu.:1.600 1st Qu.:0.300
## Median :5.800 Median :3.000 Median :4.350 Median :1.300
## Mean :5.843 Mean :3.057 Mean :3.758 Mean :1.199
## 3rd Qu.:6.400 3rd Qu.:3.300 3rd Qu.:5.100 3rd Qu.:1.800
## Max. :7.900 Max. :4.400 Max. :6.900 Max. :2.500
data <- subset(data, Sepal.Width < 4 & Sepal.Width > 2) # 留下Sepal.Width欄位中,數值小於4或大於2的值
boxplot(data)
處理離群值時,首先應考量懷疑為離群值的數據是否可以被解釋,如果可以,則可依合理的原則處理,例如資料完全不合理即可移除;但如果資料經查證後,不但無誤,而且發現該離群值是來自於非常特殊的個案,我們應該深入瞭解其數據為何如此特別,且必須深入探討決定應該刪除抑或保留該數據。
同學們也可以試試看outliers
套件來進行離群值判斷,實際跑看看套件中的Example,不過有些時候運用比較簡單的方法處理,說不定效果還會比較好哦~
在迴歸分析(線性、羅吉斯…等)中,當自變數為類別變數時,我們都要先進行轉換虛擬變數(Dummy variable)的動作,以人工變數量化類別變數,通常取值為0或1。
以下我們使用鳶尾花資料(iris)做練習~
●使用dummies
套件轉換 :
require(dummies) # 轉換虛擬變數的套件
data <- iris
alldummy_data <- dummy.data.frame(data)
函式會自動抓取表單中,屬於類別變數的欄位轉換成虛擬變數
justdummy_data <- dummy.data.frame(data, all = F)
all = F,可以只顯示出轉換後的虛擬變數欄位
●使用model.matrix
函式轉換 :
data <- iris
justdummy_data <- model.matrix(~data$Species-1) # 轉換出只有虛擬變數的欄位
alldummy_data <- cbind(data,justdummy_data) # 合併表單by couumn
注意:利用model.matrix函式轉換的欄位資料型態要為factor!!
引入虛擬變數會使得原本的模型變得更複雜,但對於問題的解釋會更清楚,也就是一個方程式能達到兩個方程式的概念,而且較接近現實~
要注意,在模型中引入多個虛擬變數時,虛擬變數的個數要遵守轉換原則:如果在類別變數欄位中有n種互斥的屬性,則只在模型中引入(n-1)個虛擬變數。
由於未經處理的資料經常會有資料不完整、不一致或存在雜訊的問題。
因此在資料預處理時就要將這些問題排除,畢竟往後的分析流程都是延續我們預處理完的資料,有好品質的資料才能挖掘出好品質的資訊。
加油~