關卡 1
在做資料分析之前,我們要能載入資料。
關卡 2
這個課程的目的是介紹R 最常見的幾種資料載入方式
關卡 3
R 內建有許多知名的資料集。 這些內建的資料集,目前都在datasets
這個套件之中。 同學輸入:library(help=datasets)
來檢視所有的資料集。 請同學試試看。
library(help=datasets)
關卡 4
在載入資料之前,為了更清楚地說明R 的函數,請同學先輸入:iris <- 1
。
iris <- 1
關卡 5
我們可以運用data
這個指令來載入列出的資料。 請同學試試看:data(iris, package = "datasets")
,這個指令的意思為從套件datasets中載入資料集iris。
data(iris, package = "datasets")
關卡 6
接著,我們請同學輸入:head(iris)
。
head(iris)
關卡 7
同學會在螢幕上看到R 輸出一個data.frame,而不是當初輸入的1。
關卡 8
這就是data
函數的功能。 它可以讓同學從套件載入特定資料集(Data Sets)。 舉例來說,我們剛才已由library(help=datasets)觀察到datasets套件中有包含許多資料集,例如:AirPassengers、BJsales、…、iris…等。 我們可以用data(iris, package = "datasets")
指令,並透過第一個參數指定特定資料集,R 則會把iris的資料集輸入到iris這個變數之中。
關卡 9
接著,請同學查詢iris的欄位名稱。
colnames(iris)
關卡 10
雖然我們看到了欄位名稱,可是並不清楚這些欄位或是每列資料所代表的意義。 這些事情,必須在實際進行資料分析之前就要預先理解的。
關卡 11
如果是使用R 提供的資料集,通常都會有相關的說明。 甚至會包含該資料集出處的論文。請同學試試看輸入:help(iris)
。
help(iris)
關卡 12
以上練習,已經讓同學了解如何使用R 內建的資料集。
關卡 13
接著,我們來展示如何讓同學讀取外部的資料集。
關卡 14
外部資料集的格式有千百種,今天只跟大家介紹最常見的csv 檔。
關卡 15
csv 檔的格式是以行(Line)為單位。每一行(Line)就是一筆紀錄(Record)。 而每一筆紀錄中,以一個分隔符號來讓使用者或程式分辨欄位。常見的分隔符號有: tab ()或逗號(,) 。 若以逗號做為分隔符號,則學生姓名加上4次小考分數的一筆紀錄,可用CSV表達如下:柯小哲,77,82,87,92
關卡 16
我們拿一個自<http://data.gov.tw/node/6213>下載的csv 檔做範例。 這個檔案的目錄已經存入了lvr_land.path
變數之中。 我們將利用這個檔案來示範如何將中文資料載入到R 之中。
關卡 17
載入中文資料時,最重要的就是要偵測檔案所採用的中文編碼。 可惜目前我還不清楚如何直接在R 中偵測編碼。 另外,如果有同學不清楚編碼是什麼,可以參考這個youtube 影片:<https://www.youtube.com/watch?v=GG2UFrmdtH4>。
關卡 18
簡單起見,我們將帶著同學分步驟測試這個檔案的編碼。 第一步先檢查檔案中是否帶有BOM 。 BOM 是一種利用檔案最前面的2 個或3 個位元組來標示檔案編碼的方式。 在windows 系統中建立的中文檔案經常會帶有BOM 。 請同學執行:readBin(lvr_land.path, what = "raw", n = 3)
readBin(lvr_land.path, what = "raw", n = 3)
關卡 19
R 中的readBin
是一個可以直接讀取檔案中的位元組的指令,可以正確的處理BOM 。 第一個參數為檔案的路徑。第二個為稱作what的參數,目的是告訴R 要如何處理讀入的資料。 若what = "raw"
代表讀入的資料用位元處理,而不是文字。 第三個為稱作n 的參數,代表要輸入的長度。因為BOM 通常最多是3 個位元組,所以這裡選擇n = 3
。
關卡 20
接著,我們可以到<https://zh.wikipedia.org/wiki/位元組順序記號>查詢常用的BOM 。 這裡直接告訴同學,此份檔案中的三個位元不屬於任何已知編碼所使用的BOM ,所以我們猜測這個檔案不帶BOM 。
關卡 21
如果沒有BOM ,一種方法是使用file
搭配readLines
兩個函數來測試編碼。 如果讀出來的中文可以正常顯示,就是猜中編碼了。 如果讀出亂碼,或是讀取發生錯誤,那可能就猜錯了,需要換個編碼試試看。
關卡 22
請同學試試看BIG5編碼:readLines(file(lvr_land.path, encoding = "BIG5"), n = 1)
這裡的file指令會打開一個檔案,第一個參數是檔案的路徑,第二個名稱為encoding的參數代表檔案的編碼。 如果是BIG5編碼,就輸入名稱:"BIG5"
,UTF-8 的話,就輸入"UTF-8"
。 readLines
函數會一行一行的讀取檔案的內容。 第一個參數就是用file
函數開啟的檔案。 第二個為稱作n 的參數,則代表讀取的行數。這裡n=1
代表讀取一行,所以只會回傳一個元素的character 向量。
readLines(file(lvr_land.path, encoding = "BIG5"), n = 1)
關卡 23
一試就中,所以同學的R console 上應該能夠顯示出正確的中文字串。
關卡 24
這裡打個岔。 file
函數會建立一個物件代表檔案,在R 之中叫做connection
。 之後同學會不定時的看到:closing unused connection
,表示R 會不定時關閉不使用的connection,並在console 顯示警告訊息。
關卡 25
一開始先用readLines
看一下資料是個好習慣。 除了第一行外,我們應該多看幾行,以方便預測檔案的格式。 請同學再輸入一次file
和readLines
的組合指令,並且讀取5 行。
readLines(file(lvr_land.path, encoding = "BIG5"), n = 5)
關卡 26
有時候,由於不明原因,R 會發生無法讀取特定編碼的狀況。 這時候,我們可以先把資料以位元的方式讀取到R 中,再進行轉碼。
關卡 27
在程式的世界中,資料在最終都是以0 和1 位元的方式儲存。 處理資料時,程式需要先對資料有初步的認識才能進行處理,例如把資料當成字串、整數或浮點數。 只有文字資料才會被編碼影響,所以如果我們只是用位元來處理檔案的內容,就可以避開編碼的問題。
關卡 28
R 利用型態為raw 的向量來處理位元的物件。 只要能知道檔案的大小,readBin 就可以把所有的檔案資料以raw 的形式輸入到R 中。 我們可以使用file.info
來查詢檔案的大小。 請同學利用file.info(lvr_land.path)
來查詢檔案的資訊,並且把結果存到變數lvr_land.info
。
lvr_land.info <- file.info(lvr_land.path)
關卡 29
請同學先輸入class(lvr_land.info)
。
class(lvr_land.info)
關卡 30
請問同學,file.info
的回傳值是什麼型態?
data.frame
關卡 31
接下來請同學列出lvr_land.info
的欄位名稱。
colnames(lvr_land.info)
關卡 32
請問同學,lvr_land.path
背後的檔案大小,應該是多少呢? 請輸入一個指令,讓R 輸出一個數值,代表這個檔案的大小。
lvr_land.info$size
關卡 33
接著請同學利用readBin
來把lvr_land.path
的檔案以位元的方式讀到R 中,並且存到名稱為lvr_land.bin
的變數。
lvr_land.bin <- readBin(lvr_land.path, what = "raw", n = lvr_land.info$size)
關卡 34
接著,我們需要使用stringi套件。 由於swirl本身已經相依於stringi,所以請同學直接載入stringi。
library(stringi)
關卡 35
透過stringi套件的stri_encode
,我們可以把一個位元組的向量(在R 中,這類向量的型態是raw )從一個編碼轉換為另一個編碼。
關卡 36
請同學把stri_encode(lvr_land.bin, "BIG-5", "UTF-8")
的結果存到lvr_land.txt
之中。
lvr_land.txt <- stri_encode(lvr_land.bin, "BIG-5", "UTF-8")
關卡 37
透過以上的方法,我們可以取得轉換編碼後的character 向量lvr_land.txt
。
關卡 38
接著,我們來講解讀取CSV 格式檔案時最泛用的指令:read.table
。
關卡 39
在R 中,read.table
的第一個參數和readLines 的第一個參數一樣,代表要開啟的檔案。 如果我們不在乎檔案的編碼,可以直接輸入檔案的路徑。 以下哪一個是正確的路徑呢?
lvr_land.path
關卡 40
請同學特別注意read.table
的參數fileEncoding的用法,這個參數雖然可以解碼,但只能用在file參數為字串的案例中。 請同學試試看read.table(lvr_land.path, fileEncoding = "BIG-5")
。
read.table(lvr_land.path, fileEncoding = "BIG-5")
關卡 41
可惜我們需要設定編碼。 (註:在中文版windows 上會預設使用BIG5編碼,所以可以直接和上面例題一樣輸入lvr_land.path
。) 第二個重要的參數是header
。 header = TRUE
代表檔案的第一行是欄位名稱,而不是資料。 header=FALSE
代表檔案的第一行就是資料。 剛剛我們看到檔案的前五行的內容是:[1] "鄉鎮市區,交易標的,..." [2] "文山區,房地(土地+建物)..."
。 請問同學,header
的參數應該要給哪一個呢?
TRUE
關卡 42
第三個重要的參數是sep
,這代表各行欄位間的分隔符號。 根據之前我們看到的前五行的資料:[1] "鄉鎮市區,交易標的,土地區段位置...,土地移轉總面積..."[2] "文山區,房地(土地+建物),臺北市文山區...,43.44..." [3] "中正區,房地(土地+建物),臺北市中 正區...,40.19..."
。 請問同學,這份檔案個欄位的分隔符號是什麼呢?
,
關卡 43
依照以上問答題的答案,請同學利用read.table
,用BIG5編碼進行讀取。 lvr_land.path
,並且把輸出存到變數lvr_land
lvr_land <- read.table(file(lvr_land.path, encoding = "BIG5"), header = TRUE, sep = ",")
關卡 44
如果要直接從lvr_land.txt
的內容取出表格,一種方法是直接把lvr_land.txt
寫成一個檔案,再用read.table
讀取。 另外一種方法則是把lvr_land.txt
視為一個類似檔案的物件,也就是connection。
關卡 45
在windows系統上,有一個很不方便的地方,接下來的作法和Windows的語系有關。 如果同學的Windows的語系有支援多位元組字串(例如中文、日文等語系),則語法需要進行調整。
關卡 46
我們可以用l10n_info()
來查詢作業系統對於不同Encoding的支援狀況。 l10n_info()
會回報系統是否支援UTF-8 (UTF-8 欄位),或是多位元組字串(MBCS欄位)。 請同學試試看輸入:l10n_info()
。
l10n_info()
關卡 47
根據經驗,如果l10n_info()
的輸出中,MBCS為TRUE且UTF-8 為FALSE, 這時須使用textConnection(lvr_land.txt)
來從lvr_land.txt
建立一個connection。 除此之外,則使用textConnection(lvr_land.txt, encoding = "UTF-8")
即可。 請同學依據上一題的結果,在MBCS為TRUE且UTF-8 為FALSE時執行: read.table(textConnection(lvr_land.txt), header = TRUE, sep = ",")
否則,請執行:read.table(textConnection(lvr_land.txt, encoding = "UTF-8"), header = TRUE, sep = ",")
read.table(get_text_connection_by_l10n_info(lvr_land.txt), header = TRUE, sep = ",")
關卡 48
以上提供數種在R 中處理中文資料的方法給同學參考。
關卡 49
事實上,如果同學自行下載原本的檔案來處理,會發現上述的流程還是會出錯。 因為在資料中第21行,資料的最後一欄的內容包含:,
這個符號,導致欄位判斷出錯。
關卡 50
遇到這種狀況,最好的方式是自己用其他的編輯器(如notepad++),自行編輯原始的檔案資料(依照錯誤訊息,移除多餘的符號),再用R 讀取。 由於這樣的動作超過這個課程系統的內容,所以請同學自行練習操作了。
關卡 51
另外一種方式,是透過readLines
來讀取資料,再用R 的其他函數自行把讀入的字串轉換為data.frame。 這部分很難歸納,會隨著資料的乾淨程度而有所不同。 同學可以閱讀本課程中一些實際分析Open Data 的範例,就可以學到一些處理技巧。 或是繼續學習R 的字串處理函數與套件。
關卡 52
在這門課程中我們展示了如何從套件中載入資料,以及如何從檔案中讀取CSV 的資料。
關卡 53
如果要使用R 讀取XML 的資料,可以使用套件XML 。 如果要讀取JSON,則可以使用rjsonlite 。 只要資料格式是公開格式,我們可以容易找到R 的套件來讀取該資料格式。 這就是R 為Open Source 的威力!
關卡 54
受限於課程內容,所以我們這裡只講讀取CSV 的方式,這是最泛用的內容了。 未來有時間,會再找社群的其他大大合作開寫其他和讀資料相關的課程。 同學如果很期待看到處理某些形態資料的課程,歡迎到<https://github.com/wush978/DataScienceAndR/issues> 許願。
關卡 55
最後,還是要請同學利用這次所學的內容,做一個小練習。 請同學在完成之後存檔,並輸入submit()
來檢查結果是否符合預期。 如果同學在檔案中看到亂碼,請使用Rstudio 左上角的File -> Reopen With Encoding… -> 選取:UTF-8
#' 請同學用這章節所學的技巧,讀取`orglist.path`的檔案
#' 資料來源:<http://data.gov.tw/node/7307>
# <你可以在這裡做各種嘗試>
answer.raw <- readBin(orglist.path, what = "raw", n = file.info(orglist.path)$size)
answer.txt <- stringi::stri_encode(answer.raw, from = "UTF-16", to = "UTF-8")
get_text_connection_by_l10n_info <- function(x) {
info <- l10n_info()
# 以下的if else是因為需要讓正確答案跨平台
if (info$MBCS & !info$`UTF-8`) {
textConnection(x)
} else {
textConnection(x, encoding = "UTF-8")
}
}
answer <- read.table(get_text_connection_by_l10n_info(answer.txt), header = TRUE, sep = ",")