前面章節「總統演說」的範例中,能看到R語言中常見的文字資料格式,要不是儲存在dataframe中,每筆資料都是文章、段落、句子,或者是用list將文章存在每一個元素中。不過,文字資料其實有著許多眉角,這個章節會談編碼、匯入和匯出三件事情,希望減少你的踩雷機會。
我們先來複習路徑(path)的概念,以免後續匯入資料時出現問題。無論是R語言,或者是其他程式語言,甚至是整體電腦科學,都有路徑這個專有名詞,它指的是檔案所在地址。
路徑可以分為絕對路徑與相對路徑,前者很直觀,就是完整地址,例如"/Users/rlover/textmining/data/encoding.csv"
;後者則是現在所處檔案路徑和檔案所在位置的相對關係,舉例來說,我現在正開啟"/Users/rlover/textmining/
這個專案,從我站的位置看起來,剛剛那個檔案的相對路徑就會是"data/encoding.csv"
。
為什麼要知道路徑?就像平常寫信要知道地址一樣,讀取資料時也需要路徑,通常匯入資料的函數中,會有一個參數要指名路徑。
那麼,要怎麼取得路徑呢?除了堅持老派的手寫溫度,自己一個一個字輸入以外,還有什麼辦法?
* Mac:右鍵 再按 options
or option + command + c
* Windows:shift 再按 右鍵
or ctrl + L
* Windows:直接從 address bar
or file explorer
複製
* reference:Mac & Windows
/
間隔,可以直接使用,Windows copy 得到的路徑用 \
間隔,不能直接用,要修正成 /
or \\
,"data/a.csv"
or "data\\a.csv"
都可以至於路徑的「語言」,基本上使用英文一定沒問題,但若路徑中包含中文,就有可能出錯,即使現在沒問題,也不代表以後沒問題,尤其是 Windows 非常煩人。建議將R和RStudio安裝在英文路徑中,且使用者名稱用英文。
路徑相對好改,因為只要修改檔案名稱或資料夾名稱就好,但想修改使用者名稱,只能新創英文帳號,若還是想用中文,可以設置環境變數。
另外,在R語言中時常會遇到權限問題,建議R和RStudio不要安裝在Windows的OneDrive資料夾,.R檔案或.Rmd檔案最好不要放在自動跟雲端硬碟同步的資料夾,譬如Google Drive 或是 Dropbox 都有危險。
當你需要讀取大量、位置四散各地的文字檔案時,上面這些建議說不定就會派上用場,因此可以先將有個章節談這件事情,放在心上,有需要的時候再回來看。
在認識如何匯入與匯出文字資料前,得先認識何謂字元編碼(character
encoding)。我們知道電腦用 0,1
儲存資訊,字元編碼就是利用數字代表文字與符號。
以ASCII
編碼為例,它由美國制定,用來對應英文符號與二進制,大約可以表示128 個文字符號和數字之間的關係。舉例來說,A
的編碼是65,也就是二進制中的01000001
,但如果享用ANCII表達英文以外語言例如中文,會遇上兩個問題。
第一,ASCII編碼的符號不夠,例如naïve的ï就不在其中,需要新的編碼才能處理。第二,不同國家的符號與二進制對應方式不同,例如é
vs. ג
(法 vs. 希),就是一個實例。
若改看ANSI編碼,它是Windows作業系統上的code page,對應到預設編碼,也就是說,它會因應當前系統區域(locale)決定使用編碼,像是繁體中文對應 BIG5,簡體中文對應GB2312,日文可能是JIS。不過,當台灣人存ANSI時代表以BIG5編碼儲存,可是日本人打開打開記事本的時候,ANSI判斷後會用JIS解碼,儲存時的編碼和讀取時設定的編碼方式不同,因此出現亂碼。
還有其他選擇嗎?我們還有另一種厲害武器,稱為Unicode,它是一種納入所有字元的萬國碼,收錄上百萬個文字與符號,稱為字符集(character set),例如U+963f
代表 阿
、U+4E25
代表严
,U+0041
代表 A
。
它只規定對應方式(集合 set),沒規定儲存方式(編碼,encoding),例如U+4E25
的4E25
轉成二進制為100111000100101
,15位元,因此能夠涵蓋幾乎所有字元,解決前述提的編碼不夠、出現亂碼等問題。然而,它也面臨挑戰,包含長度問題,例如原本128個符號用8個位元儲存,現在要使用兩倍長度的位元才能達成,同時還有辨識問題,我們很難分辨如何確知是用一個還是兩個符號拼在一起。
想要解決這個問題,就需要轉成二進制的儲存方式,而UTF-8編碼,就是其中一種解方。它的長度彈性,前綴數字表示長度,後面數字代表符號,且涵蓋ASCII的編碼,是目前網頁採用的編碼主流,2008年超過60%、2015年更超過80%網頁都在使用。
了解編碼的簡單歷史後,我們要進到下一個重要議題:亂碼。
不只是在R語言中探勘文字資料,生活中就有諸多會遇到亂碼的場景。有時候打開電子郵件、將資料匯入至Excel,甚至是用記事本和notepad++,都會遇到亂碼問題。從上面介紹中我們知道,亂碼會出現,就是因為儲存時的編碼和讀取時設定編碼不同。
在R或者RStudio遇到亂碼時,應該怎麼處理?首先,我們要判斷問題起因,到底是個別檔案問題,還是R語言或者RStudio的環境問題,又或者是系統編碼設定問題?底下我們整理不同問題的解決方式供你參考。
.R
or .Rmd
的亂碼
x <- '中文'; Encoding(x)
read.csv()
裡面的參數fileEncoding = "UTF-8"
df <- readLines("a.CSV", encoding="big5");df <- iconv(df, "big5", "utf8")
Sys.getlocale()
查看編碼,利用 Sys.setlocale()
更改編碼,兩個參數,category
代表要修改的類別,locale
Sys.setlocale(category = "LC_ALL", locale = "UTF-8")
Sys.setlocale(category = "LC_ALL", locale = "cht")
最後統整上面段落的資訊,免得看了眼花撩亂:
.R
亂碼調整 file encoding前面提到,匯入檔案時,編碼可能出現問題,因此我們可以在匯入前,先用notepad++、記事本、Excel等文書處理工具觀察檔案。當然,你也可以懶得打開其他程式,直接用R讀讀看,跟資料拼了,聽起來非常熱血。
不過如果欄位名稱為中文,編碼又設定錯誤,很遺憾地我們無法匯入資料,連觀察編碼都沒機會,這時候就真的要先用文書軟體打開確認;若欄位名稱為英文,只是編碼錯誤,那就可以匯進R語言後再修改編碼。
總結來看,我們有三種方法處理亂碼問題,第一是直接用文書軟體修改原始檔案編碼,第二是讀取檔案時設定參數,第三是讀取時不管亂碼,等資料進到R語言環境後再來修改編碼。
底下來看實際範例。第一個範例中,我們使用109Q1實價登錄資料,這個檔案的欄位名稱和資料內容都是中文,但編碼不是readr
匯入資料函數預設的UTF8。
# 直接讀遇上錯誤
df_land_109Q1_test <- read_csv("data/109Q1_a_lvr_land_a_build.csv")
# Error in make.names(x) : invalid multibyte string at '<bd>s<b8><b9>'
# 設定參數,編碼為BIG5,就可以讀了
df_land_109Q1_test <- read_csv("data/109Q1_a_lvr_land_a_build.csv",
locale = locale(encoding = "BIG5"))
第一個範例中,我們使用各縣市用電資料
,這個檔案的欄位名稱是英文,讀取沒有問題,但資料內容都是中文,再次遇到亂碼。
# 直接讀遇上沒錯但遇到亂碼
df_electricity_usage_test <- read_csv("data/electricity_usage.csv")
# 讀進來後修改編碼就搞定
df_electricity_usage_test$county <-
iconv(df_electricity_usage_test$county,
from = "BIG5", to = "UTF8")
從上面例子看R語言匯入資料可能遇上的問題。現在環境下大部分資料都用UTF8編碼儲存,因此平常不太會踩雷,但若是政府開放資料,就會時常遇到BIG5,簡體中文還有其他編碼,使用時要多加注意。
談完匯入,我們改看匯出。最常見的格式如.csv
,一般也是用readr::write_**()
相關函數匯入資料,預設輸出編碼和輸入一樣,都是以UTF8為編碼,因此可以替我們省下很多心力。
不過,在看傳統程式碼的時候,除了base R體系的write.**()
函數以外,我們還會另外看到R語言中兩個內建函數,可以拿來讀寫
R 的物件。
readRDS()/saveRDS()
orreadr::read_rds()/write_rds()
write_rds(mtcars, "data/mtcars.rds")
save()
or load()
save(data1, data2, file = "data/d0102.RData")
file_r <- "data/"
a <- 1
b <- 2
### export
write_rds(a, str_c(file_r, "a.rds"))
save(a, b, file = str_c(file_r, "a_b.RData"))
### load
a_check <- read_rds(str_c(file_r, "a.rds"))
rm(a)
rm(b)
load(file = str_c(file_r, "a_b.RData"))
進行文字探勘前,我們要先匯入資料,匯入時要考慮文字編碼。匯入後,我們要確保文字資料的儲存格式,因為不同框架有各自習慣的資料結構。文字探勘完成後,我們會匯出資料,這時候要考慮以何種檔案格式匯出,同時也會確認編碼設定無誤。這些就是在R語言中和文字資料交手時,要注意的眉角!