2016年12月30日 星期五

R學習筆記 - 資料工程篇(二) XML

#註: 本篇筆記諸多內容直接紀錄課程原文,而本文也僅整理資訊之用途
課程連結 : R語言翻轉教室

RDataEngineer-02-XML
XML的全名是:eXtensible Markup Language,是一種讓電腦可以快速理解資訊的標記語言。XML的透過標記來讓電腦理解資訊的內容,並且把標籤與內容清楚的切割開。

XML的文件中,標籤是可以有結構關係的。在慣例中,我們會說tr是th的父標籤(parent),而th與td兩者都是tr的子標籤(children)| 每個標籤最多只有一個父標籤。這是因為th和td兩個標籤,寫在<tr>和</tr>之間。


在HTML網頁中,幾乎所有的標籤都有父標籤,除了html這個標籤以外。所以我們在處理HTML文件時,會稱呼這個標籤為整個文件的根(root)。


更多瞭解可以輸入wiki_html()wiki_xml()了解更仔細的背景知識。


主要使用R套件 : xml2 

xml2套件要處理XML或HTML文件之前,必須要先作解析,將文件建立成一種特殊的R 物件後,才能讓我們挖掘資訊。

#挖掘網頁資訊的三步驟:
1. 找到標籤 2. 查詢屬性 3.檢查內容

1.read_xml   :  讀取xml檔,
`read_xml`函數有`x`、`encoding`和其他參數可以使用。 `x`則可以是一個檔案路徑(filepath)、一個網址(url),或是一個XML文本的字串向量(literal xml)。

目前xml2中的物件,大致上可以分成三種:xml_document、xml_node和xml_nodeset。 xml_document就代表整個XML文件。xml_node則對應到上述介紹的XML標籤,在經過`read_xml`後每個標籤會被轉化為一個xml_node。xml_nodeset則是一群標籤的集合。


2.xml_find_all
共有兩個參數:`x`與`xpath`。`x`可以是xml_document、 xml_node或xml_nodeset。而`xpath`(XML Path Language)則是一種特別的格式,讓我們可以和電腦溝通我們要搜尋的標籤。

#範例:xml_find_all(doc1, "/a/b")
 =>  a: 父標籤  b:子標籤

若沒有提供父標籤,無法搜尋出欲搜尋之子標籤

3.xml_text( ) 
取出標籤內的內容

4.xml_parent() 
查詢標籤的父標籤

5.xml_contents() :
同樣為取出標籤內容,但當含有子標籤時, 它和`xml_text`的行為會不太一致


6.xml_children(a) :
來取得所有以a 為父標籤的標籤們


7.xml_attrs() :
取得XML標籤的屬性(帶有名字的字串向量
)
在使用XPath尋找標籤時,屬性是可以派上用場的。

#範例
`
xml_find_all(doc1,
"/a/c[@class]")`,意即是搜尋時增加:「標籤必須要帶有 名稱為"class"的屬性」。


甚至還可以指定屬性的值,例如:`xml_find_all(doc1, "/a/c[@class='g']")


一種XPath中常常使用的定位方式 :  "//"


這裡的"//"代表的就是任意位置。

當我們在處理複雜的網頁資料時,如果每次都要從根部尋找正確的路徑,是非常不方便的。此時,透過"//a",我們就可以找到在所有位置都出現的a標籤。# "//"的用法是可以搭配屬性的過濾使用的。

#HW:

1. browseURL() : 輸入URL網址即可使用預設瀏覽器,瀏覽網頁

2. read_html() : 載入網頁內容
3. encoding() : 告訴電腦,應採用哪種編碼讀取該物件
範例:  Encoding(ths_text) <- "UTF-8"

#備註:
最後再次推薦R語言翻轉教室,做作業時遇到瓶頸,可直接在線上討論區直接發問,不至於自己一個人想破頭,卻無法得到解答。

2016年12月29日 星期四

R學習筆記 - 資料工程篇(一)Parsing 字串處理

#註: 本篇筆記諸多內容直接紀錄課程原文,而本文也僅整理資訊之用途)
課程連結 : R語言翻轉教室

RDataEngineer-01-Parsing

在實務上,數據來源常常都是隱含某些規則的文字檔案。例如:伺服器依據工程師擬定的規則所產生的資料。這個規則可能是工程師自己訂的,也可能是符合眾人智慧所訂定的規範。但是不管是工程師自己的想法,或是眾人的智慧,R 都能從文字中萃取出資訊。一般而言,這樣的技術就稱作Parsing。


[複習上一篇的內容]
如何正確輸入中文資料檔?

1.先用`readBin`來看檢查這個檔案的BOM

readBin(目標檔案,what = "raw", n=3)

2.根據常用BOM連結查詢可能的編碼


3.當BOM不能判斷的時候,採用試誤法,使用各種Encoding讀個前3行試試看。


readLines(file(hospital_path, encoding = "各種編碼"), n = 3)

4.搭配`read.table`和`file`兩個函數的組合,並適當的設定`sep`、`header`和`encoding`等參數。


read.table(目標位址,fileEncoding = "編碼",header = TRUE,seq=",")


1..擷取內容

1.substringR 的`substring`函數會把`text`參數所代表的字串,依照字符的位置,擷取出中間的段落。
2.strsplit: 利用定位點將字串分割成兩部分。

根據說明文件,`strsplit`會利用`split`參數來切割`x`這個字串,並且回傳一個`list`。這是因為`x`的長度可能超過1,而`strsplit`會用`split`去切割每一個`x`的元素。而切割出來的結果,第一個元素可能切出兩段,但是第二個元素可能只切出一段。所以R 用`list`這個結構來處理。但是`strsplit`並不接受factor參數,只接受字串向量。
範例

2.處理輸出資料
為了處理輸出後的list結構資料,重複性的工作可使用lapply函數增加效率

R 的`lapply`的第一個參數`X`,通常是一個vector。第二個參數`FUN`,則是代表一種「動作」。而`lapply`會對每一個`X`的元素進行`FUN`所定義的動作,並且把結果彙整回R 。最後一個`...`的參數是什麼意思呢?這是因為`lapply`並不清楚`FUN`需要什麼參數,所以使用者可以在指定`X`和`FUN`之後,放入任意的參數,而這些參數並不是由`lapply`所使用,而是由`FUN`所使用。

#範例 :
lapply(tmp,"[",1) => tmp:目標檔案、"[" 為[]函數之呼叫方式、1則代表輸出方式


接著,若輸出資料為list結構,可使用unlist(),取得字串向量類似的函數如sapply,功能相同,差別只在於輸出為array。

2016年12月27日 星期二

R學習基礎筆記(二)Arrays-Matrices、List-DataFrame、Loading-Dataset

(註: 本篇筆記諸多內容直接紀錄課程原文,而本文也僅整理資訊之用途)
課程連結 : R翻轉課程連結

RBasic-05-Arrays-Matrices

這門課程是要介紹R 的線性代數運算系統。線性代數在許多現代的統計方法、Data Mining方法上都很重要。所以理解R 的線性代數系統,對於撰寫自己的演算法,以及了解Open Source的演算法,是非常重要的。

[矩陣介紹]
數學上來說,一個矩陣除了值之外,需要的就是維度的定義。而`matrix`這個函數,`data`的參數代表矩陣的值, `nrow`的部份代表這個矩陣有多少列,而`ncol`的部份代表這個矩陣有多少行。所以`matrix(1:18,6, 3)`會產生一個 6 列3 行(簡稱6 乘3 )的矩陣。

dim() : 可以存取矩陣維度的函數。可透過dim來更改矩陣維度。
在R 中,矩陣的資料順序是:`c(x[1,1], x[2,1], x[3,1],...)`。也就是說,如果我們下指令:`matrix(1:18, 3, 6)`, 則x[1,1]會是1, x[2,1]會是2, x[3,1]是3, x[1,2]是4, 以此類推。高維度的矩陣也是類似。我們也可以利用中括號`[]`搭配邏輯向量取出矩陣或陣列中的值。
R會根據邏輯向量在`[]`中的位置,選擇該維度,只挑出該邏輯向量為TRUE 的座標。

[如何修改矩陣和陣列的元素]
1.要修改矩陣的值,搭配`[]`和`<-`

[矩陣運算]
1.矩陣的向量式運算。它和向量的運算也非常類似,也是會自動比對位置,並且在相同運算的位置上做運算
2.而當維度不相同的時候,R會自動重複比較短的那邊。
3.所有的矩陣和陣列,就是一般的向量加上 dim 這個屬性
4.除去dim屬性 : dim(x) <- NULL ,矩陣即變成向量
5.R在陣列和向量的向量式運算,也可以回到兩個向量的運算。差別只是在它們多了維度的屬性,所以當維度差異太大的時候,R會認為向量式運算無效。所以一般來說,我們只會拿單值或向量去和陣列做運算,或是維度相同的矩陣或陣列做運算。
6.在R 中,使用`cbind`和`rbind`則可以合併兩個矩陣。

[線性代數相關]
1.在R 中兩個矩陣要作矩陣乘法,就是使用`%*%`這個運算符號。
2.當兩個向量使用`%*%`做運算,會得到他們的內積。
3.轉置矩陣 : t()
4.用`diag`快速建構對角化的矩陣
5.如果已知` A %*% x = b `,給定`A` 和`b` 我們可以用`solve` 解出 x
6.反矩陣:solve(矩陣)
7.特徵值(eigenvalues)和特徵向量(eigenvectors) : eigen(矩陣)

*註:
R 上的線性代數運算的底層是透過BLAS等函式庫做運算的,所以效能遠勝過我們自己用C寫的線性代數運算。 另外R預設是使用比較被廣泛驗證過正確性的BLAS庫,而不是效能比較快,但是還比較年輕的BLAS函式庫,例如OpenBLAS。這是因為,R coreTeam認為正確性比較重要,所以目前是採用比較舊,但是也比較可靠的BLAS庫。

*HW:

求最小平方法之估計beta : solve(t(X)%*%X)%*%t(X)%*%y

RBasic-06-List-DataFrame

LIST

list的本質,就是一個「R物件的向量」,強調「向量」的概念,因為list 是有順序性的。
1.取list的方法
1.1 使用[[]]
1.2 list$,使用`$`來透過名字取出list的值

在windows上,如果名字是中文時,使用`$`的語法可能會出錯。一個比較保險的方式是:x$`中文名稱` 。這裡的 ` 符號的按鍵,在美式鍵盤中位於1的左方,這個符號唸作:Grave accent,是R 在console中的跳脫字元。以特殊符號 為名稱的變數,可以透過兩邊包覆Grave accent來在console中存取。

DataFrame

傳統的matrix和array由於有同質性的限制(所有的元素都要同樣的型態),所以在資料分析上並不方便。因為我們分析的資料,通常都不會全部都用相同的型態。在結構化的資料中,通常資料是以表格的形式,而各欄位會有自己的型態,例如是:數值型態、類別型態等等。

1.data.frame是一種list。因為表格的各欄是型態不一的向量,所以我們需要用list來裝不同型態的向量。
2.因為表格的資料是結構化的,所以data.frame的值不能存放太奇怪的物件。具體來說,data.frame的各個元素必須是以下幾種類型之一:數值(numeric)、字串(character)、布林(logical)、類別(factor)、數值矩陣(numeric matrix)、 list或data.frame
3.data.frame代表的是二維表格,所以每一個值的長度都要一致(矩陣或data.frame的話,則是列(row)的個數)。
4.在data.frame上,通常會先對欄位做選擇,取得欄位中的向量以後,才能使用中括號。
5.其實`[]`中括號這個函數,有一個參數叫做:`drop`,而且預設為`TRUE`。當我們使用`[]`取得結果的時候,如果有一個方向可以縮減維度(例如只有一個欄位的表格),R就會自動把表格的結構破壞,回傳一個向量。

*HW:
1.可以利用`model.matrix`來建立一個矩陣,類別變數若僅有兩種變化,可自動用1,0表示。
2.跑迴歸分析,可以簡單用`lm`這個函數
3.summary(g)則會顯示各個參數的t 檢定,以及整個模型的R-squared

RBasic-07-Loading-Dataset

[內建資料]
R 內建有許多知名的資料集。這些內建的資料集,目前都在`datasets`這個套件之中。
1.呼叫內建資料: data( 資料名, package = "datasets")
2.查詢內建資料詳細內容 :help(資料名)

[外部資料]
讀取中文資料的幾種方式,
此處僅介紹csv。

1.csv 檔的格式是以行(Line)為單位。每一行(Line)就是一筆紀錄(Record)。而每一筆紀錄中,是以一個分隔符號來讓使用者或程式分辨欄位。常見的分隔符號有: tab (\t)或逗號(,) 。

2.載入中文資料常見的編碼問題,參考以下連結
影片教學 :  什麼是編碼?

3.測試檔案編碼
3.1 檢查檔案有沒有BOM:
BOM是一種利用檔案最前面的2 個或 3 個位元組來標示檔案編碼的方式,在windows底下建立的中文檔案, 有很高的機會會帶BOM 。
readBin(lvr_land.path, what= "raw", n = 3)
 R 中的`readBin` 是一個很可以直接讀取檔案中的位元組的指令 ,所以可以正確的處理BOM。第一個參數是檔案的路徑。第二個名稱為 what的參數,是告訴R要如何處理讀入的資料。`what = "raw"`代表讀入的資料用位元處理,而不是文字。第三個名稱為n 的參數,代表要輸 入的長度。這裡選`n =3` 是因為通常BOM 最多就是3 個位元組。
接著查詢 常用的BOM,觀看是否出現常用編碼。

3.2使用`file`搭配`readLines`
如果讀出來的中文可以正常顯示,通常我們就猜中編碼了。如果讀出亂碼,或是讀取發生錯誤,那可能就猜錯了,就換個編碼猜猜看。
e.g. readLines(file(lvr_land.path, encoding = "BIG5"), n = 1)
n = 讀取行數

3.3使用file()搭配read.table()
read.table(file(目標位址, encoding = "BIG5"), sep = ",", header =TRUE)

#註:`file`函數會建立一個代表檔案的物件,在R 之中叫做`connection`。 R會不定時的關閉不使用的connection,並且在console 顯示警告訊息。
所以之後同學會不定時的看到:`closing unused connection`。

4. 使用readBin +  stringi 讀取外部資料
4.1
R 是型態為raw 的向量來處理位元的物件。只要能知道檔案的大小, readBin就可以把所有的檔案資料以raw 的形式輸入到R 中。
可以使用`file.info`來查詢檔案的大小 。
lvr_land.info =  file.info(檔案路徑)
lvr_land.bin = readBin(lvr_land.path ,what = "raw", n= lvr_land.info$size)
lvr_land.info$size = 該檔案大小

4.2
透過stringi套件的`stri_encode`,我們可以把一個位元組的向量(在 R中,這類向量的型態是raw )從一個編碼轉換為另一個編碼。
lvr_land.txt <- stri_encode(lvr_land.bin, "BIG-5", "UTF-8")

5.read.table  讀取CSV 格式檔案最泛用的指令
read.table( 路徑, fileEncoding = "BIG-5")
 fileEncoding 這個參數雖然可以解碼,但只能用在file參數為字串的case。
註1:在中文版windows 上預設會使用BIG5編碼,
註2:header = TRUE`代表檔案的第一行是欄位名稱,而不是資料。`header=FALSE`代表檔案的第一行就是資料。
seq = 分隔符號

5.1 我們可以用`l10n_info()`來查詢作業系統對於各種Encoding的支援狀況

根據經驗,如果`l10n_info()`的輸出中,MBCS為TRUE且UTF-8 為FALSE,則要使用:`textConnection(lvr_land.txt)`來從`lvr_land.txt`建立一個connection。除此之外,則使用`textConnection(lvr_land.txt, encoding = "UTF-8")`

6如果要使用R 讀取XML 的資料,可以使用套件XML 。如果要讀取JSON, 可以使用rjsonlite。只要資料格式是公開格式,我們很容易找到R 的套件來 讀取該資料格式。這就是R 是Open Source 的威力!

2016年12月25日 星期日

R學習基礎筆記(一) Introduction、Vectors、Object、Factors

前言:
過去筆者使用SAS和R來跑論文的資料處理與分析時,因為沒有一個系統性的筆記來整理所學,總覺得知識相當拼湊、零碎,所查詢到的應用最後都變成一個個超連結紀錄在我的最愛。近日,偶然在網路上發現R翻轉教室的線上課程套件,是一個相當適合有點R程式基礎、卻不知道如何再進階的人。藉由紀錄所學,希望將R做個有系統的學習紀錄。
(註: 本篇筆記諸多內容直接紀錄課程原文,而本文也僅整理資訊之用途)


RBasic-01-Introduction

1.help(函數) 、 ?函數
可直接獲得一個函數的細節說明
2. expression、assignment
在R中每一段指令分為expression、assignment ( a <- 1 )兩種
使用 {} 將多個expression包裹,即變成一個大的expression。
3.source()
透過`source`指令,來載入一個撰寫R指令的文件,並且執行文件中的expressions。
4. objects()
object可以是一個變數,也可以是一連串的數字,文字,甚至是函數,以及 更複雜的東西。
使用 objects() 、ls()來列出目前存在的object
5.rm() : 刪除存在之物件

RBasic-02-Data-Structure-Vectors

1.R 的object結構是針對資料分析所設計的。所以最簡單 的object,就是一連串的數字。在R 中,大部份的運算都是向量式的。舉例來說,加法`+`在R 就是向量式。 結果的第一個值,就是輸入的兩個向量的第一個值的相加。

1.1向量式運算:
+-*/ 、log、exp、sin、cos、tan、sqrt
1.2非向量式運算 : 
max()、min()、range():回傳向量的範圍(最大到最小)
sum():加總、length():回傳個數、mean()樣本平均數、var()樣本變異數、sd()樣本標準差、sort()回傳與原向量相同長度的向量,但值由小排到大。
NaN (not a number)
NA (not available)
Inf (無限)
可以利用`is.na`來判斷一個向量裡面有沒有NA,雖然我們理解NA和NaN的不同,但是`is.na`會把兩者都看成TRUE。

2. : 運算子,可提供指定數字的序列,如產生1到10,1:10。在R中的優先處理順序高於+-*/。與seq()函數功能相同,如seq(1,10)。seq(to = 起點,from = 終點, by = 如何間隔, length.out = 產出個數)
不想要序列,僅想要重複值可使用rep(值, times = 重複次數,each = 每個重複次數)

3.邏輯值  TRUE(T)、FALSE(F) ,注意T、F非保留字,可自行更改。
類似可用於建立邏輯向量的「條件」有:大於`>`、大於等於`>=`、
小於`<`、小於等於`<=`、相等`==`和不相等`!=`。
「交集」`&`和「聯集」`|`

4.字串
有時候,我們需要處理文字類型的object。這些object常常用於指定繪圖的標題、或是處理一些類別形變數,如:國籍、行政區等等。 這樣的資料,在R之中是透過單引號`'`或雙引號`"`來建立的。 這類的資料,常常被人稱為:「字串」。
`x`而不用雙引號包覆它,R 會把這個`x`當成變數名稱,輸入一個包含雙引號的字串,可使用單引號`'`來包覆雙引號。
paste():將字串接成一個字串,是向量化的函數
paste0():將字串接成一個字串(無空格)

5.指定資料位址
5.1 使用vector搜尋 x[c(1,3)]
5.2 邏輯搜尋 x[x >5]
5.3 消去法 x[-2] 除了第二個值以外的
5.4 使用names()為所有值取名,x[c("值的名字)]
HW:
`7e9`是R 的科學符號,代表`7 * 10^9`

RBasic-03-Data-Structure-Object

1.`mode`和`length`
在R 中,我們操作的所有變數,都是一種R 物件(Object)。這些向量物件有兩個很重要的屬性:`mode`和`length`。`mode`代表這個向量的值型態,總共有:`logical`、`integer`、`numeric`、`complex`、`character`和`raw`。`length`代表這個向量的值的個數。

2. list
R 也可以建立一種叫做`list`的向量,這是「R 物件」的向量。換句話說,每一個值 都是R物件,都有自己的`mode`、`length`等屬性。我們會在一些複雜的統計模型中,見到這樣的資料型態。
`g[1]`和`g[[1]]`的差異。使用`g[1]`時,R取出向量的第一個元素,並且維持list的結構,
使用`g[[1]]`時,R會打破list的結構,再取出向量的第一個元素,所以`g[[1]]`的 型態會是存放在list裡面的R物件的型態。
list向量最有用的地方,在於它可以裝不同型態的值。

3.attributes:  "names"和"class"
所有的R 物件,都有「屬性」(attributes)。我們可以用`attributes`這個函數來印出一個R物件的屬性。 請同學試試看:`attributes(g)`
在R 中,我們可以用`attr(g, "names")`來取得名字是"names"的屬性。請同學試試看。 names():查詢names屬性、class(): 查詢class屬性。


RBasic-04-Factors


Factor是一個向量物件,用途是儲存「類別」的資料,有這樣的資料格式,我們可以輕易把資料集依照類別分組。
Factor() : 轉為Factor向量,Factor向量中的levels屬性代表向量中允許出現的類別。 要取出這些類別,可使用levels()。
在Factor向量中指派沒在levels裡面的類別,會出現NA。
進一步觀察factor向量的結構。請輸入 str()。Factor向量本質上只是整數向量加上levels。這樣設計的原因是儲存整數比儲存文字更省空間。

其實「類別」的資料有兩種。分為「無順序」與「有順序」的,轉為有順序的factor向量。做法是在factor函數中,把ordered設為TRUE。
並且把levels順序以向量方式傳入,level要由小到大填入。

此章節小結
1.Factor向量用來儲存類別的資料。level屬性限制能在向量中出現的類別種類。
2.Factor本質上是整數向量,只是帶有levels。
3.Factor可以是無順序或有順序的,可用在Factor函數中使用ordered=TRUE讓Factor變成有序。