關卡 1
這堂課程要跟各位同學介紹list和data.frame這兩個很重要的資料結構。
關卡 2
R 的list是非常泛用的物件,同學在前面的課程有簡單操作過R 裡面的迴歸模型,而這些迴歸模型的底層架構,就是用list所建立的。
關卡 3
list的本質,其實就是一個「R 物件的向量」,這裡要特別強調「向量」的概念,因為list是有順序性的。
關卡 4
請同學建立一個list,x <- list(iris = iris, cars = cars, n = 2)
這裡iris = iris
的意思是說,第一個元素的名字是"iris"
,而值會是變數iris
的值。 而cars = cars
表示第二個元素的名字是"cars"
,值則是變數cars
的值。以此類推。
x <- list(iris = iris, cars = cars, n = 2)
關卡 5
在建立的過程中,因為iris在前面,所以是第一個元素(component),而cars跟在iris後面,所以 是第二個component。我們可以利用兩個中括號:[[]]
來取出component。請同學試試看:x[[3]]
x[[3]]
關卡 6
請檢查一下x[[3]]
的型態。
mode(x[[3]])
關卡 7
可以看到x[[3]]
的型態是numeric,這是因為x <- list(iris = iris, cars = cars, n = 2)
, 所以mode(x[[3]])
的結果等同於mode(2)
,也就是numeric。 同理,mode(x[[1]])
和mode(x[[2]])
的結果則是x 的第一個值和第二個值的型態。
關卡 8
因為list是個向量,所以可以使用我們過去學過的[]
。 如果我們運用如:x[3]
的指令,從x 中選出只有包含第三個元素的向量,得到的輸出會和x
一樣是一個list向量。 簡言之,mode(x[1])
、mode(x[2])
和mode(x[3])
的結果都會是list,和mode(x[[3]])
是numeric是不同的。請同學試試看mode(x[3])
mode(x[3])
關卡 9
輸出的型態是否仍為list,就是[[]]
和[]
主要的不同。
關卡 10
也由於list是一種向量,所以先前學過的函數,如length
之類,都是可以在list上使用的。
關卡 11
請各位同學猜猜看,length(x)
的結果會是多少呢?
3
關卡 12
list的元素除了用位置做選取之外(如:x[[3]]
),也可以用名字做選取。 在我們建立list的時候,使用指令如下:x <- list(iris = iris, cars = cars, n = 2)
, 這代表第一個元素的名字是"iris"
,第二個是"cars"
,第三個是"n"
。 而和我們使用x[[3]]
的方式類似,我們也可以使用x[["n"]]
來選擇第三個,也就是名字是"n"
的元素。請同學試試看。
x[["n"]]
關卡 13
除了[[]]
之外,也可以使用$
來透過名字取出list的值。 舉例來說,x$n
就會取出x
中名字為"n"
的值。 請同學試試看。
x$n
關卡 14
在windows系統中,如果名字是中文時,使用$
的語法可能會出錯。一個比較保險的寫法是: x$中文名稱
。 這裡的 `符號的按鍵,在美式鍵盤中位於1的左方,這個符號唸作:Grave accent,是R 在console中的跳脫字元。 以特殊符號為名稱的變數可以透過兩邊包覆Grave accent來在console中進行存取。
關卡 15
接著,我們要介紹一個在R 中很有名的物件。這個物件的設計,完全滿足了近代對結構化資料分析的需求。
關卡 16
包含最近火紅的Apache Spark,以及Python的pandas都有受到這個物件的影響。這個物件就是R 的data.frame。
關卡 17
由於傳統的matrix和array 有同質性的限制(所有的元素都要同樣的型態),所以在資料分析上並不方便。 因為我們分析的資料,通常並不會全部都用相同的型態。 在結構化的資料中,通常資料是以表格的形式,而各欄位會有自己的型態,例如是:數值型態、類別型態等等。
關卡 18
R 的data.frame就是要表現出二維表格特性的物件。以下我們要介紹data.frame這個物件。
關卡 19
首先,data.frame是一種list。因為表格的各欄是型態不一的向量,所以我們需要用list來裝不同型態的向量。
關卡 20
第二,因為表格的資料是結構化的,所以data.frame存放的值會有格式上的限制。 具體來說,data.frame的各個元素必須是以下幾種類型之一:數值(numeric)、字串(character)、布林(logical)、類別(factor)、數值矩陣(numeric matrix)、 list或data.frame。
關卡 21
最重要的是,因為data.frame代表的是二維表格,所以每一個值的長度須一致(若為矩陣或data.frame,則是列(row)的數量需一致)。 上述的特性可以在整理資料時提供很大的幫助。
關卡 22
請問下列哪一個list物件,符合data.frame的要素?如果不確定的話,可以看Hint了解原因。
list(a = 1:3, b = matrix(1:6, nrow = 3, ncol = 2))
關卡 23
data.frame的操作也是非常重要的。
關卡 24
在R 之中,可以使用data.frame
函數來建立一個data.frame。 請同學現在試試看利用data.frame(class = "NTU", id = 1:10,scores = matrix(c(80:99),nrow=10,ncol=2 ) )
建立一個data.frame,並且把這個物件存到變數a
a <- data.frame(class = "NTU", id = 1:10,scores = matrix(c(80:99),nrow=10,ncol=2 ) )
關卡 25
所有list的操作,都可用在data.frame上。 請問同學,下面哪一個語法「不能」選取a
的第一欄?
a[[“id”]]
關卡 26
除了list的語法之外,在data.frame上也可以使用和matrix一樣的語法。
關卡 27
舉例來說,nrow(a)
可以列出a 所包含的列數、ncol(a)
可以列出a 所包含的欄數、dim(a)
則可以一次列出兩者。 上述特性都和matrix一樣。
關卡 28
資料的選取的方式也是一樣的。我們可以用a[,1]
選取第一欄。請同學試試看。
a[,1]
關卡 29
根據螢幕上的輸出,請問同學a[,1]
的類別是什麼呢?
factor
關卡 30
同理,我們也可以用a[1,2]
來取出第1 列、第2 欄的資料。 請同學試試看。
a[1,2]
關卡 31
colnames(a)
則可以取出a 的欄位名稱。請同學試試看。名稱也可以用於接下來的資料選取中。
colnames(a)
關卡 32
資料選取時,欄位的方向也可以用名字代替。 舉例來說,a[2,"id"]
可以選到第二列第二欄,因為a[2,]
代表第二列,而a[,"id"]
會選到名稱為"id"
的第二欄。 兩者的交集,就是第2 列第2 欄。請同學試試看。
a[2,"id"]
關卡 33
中括號[]
也可以一次選取多列多欄。 舉例來說,a[1:2,"id"]
可以一次選取a$id
底下第1個到第2個的值。 請問同學,下面哪一種語法「不能」得到一樣的結果?
a[1:2][“id”]
關卡 34
另一個用法是:a[1:2,1:2]
,可以選許出前兩列的前兩欄。請同學試試看。
a[1:2,1:2]
關卡 35
請問同學,能不能用class
查看a[1:2,1:2]
的型態呢?
class(a[1:2,1:2])
關卡 36
同學是否注意到,在輸入a[1:2,"id"]
的時候,R 會輸出一個向量,但是輸入a[1:2,1:2]
的時候R 反而會給一個data.frame呢? 其實這樣不一致的行為,在未來若要進行更複雜的資料整理時,會帶來困擾的。
關卡 37
其實[]
中括號這個函數,有一個參數叫做:drop
,而且預設為TRUE
。 當我們使用[]
取得結果的時候,如果有一個方向可以縮減維度(例如只有一個欄位的表格),R 就會自動把表格的結構破壞,回傳一個向量。 請同學試試看:a[1:2, "id", drop = FALSE]
a[1:2, "id", drop = FALSE]
關卡 38
從R 顯示在console的輸出結果,同學會發現這是一個data.frame。 在R 中,console會根據不同的class
而用不同的方式呈現輸出結果。
關卡 39
上述的內容就是我們對於list和data.frame的介紹。 data.frame是處理資料和進行進階演算法時非常實用結構。 所以請同學務必要熟悉不同data.frame的操作,才能有系統地整理資料,並且在資料上運行其他的演算法。
關卡 40
接著,請同學依照這個課程所學到的技巧,做一個簡單的練習。 請同學在完成之後存檔,並輸入submit()
來檢查結果是否符合預期。 如果同學在檔案中看到亂碼,請使用Rstudio 左上角的File -> Reopen With Encoding… -> 選取:UTF-8
#' 這裡我們使用CO2這個資料集請同學做練習
data(CO2)
#' 請問CO2 有多少列?
answer1 <- nrow(CO2)
#' 請問CO2 有多少行(column)?
answer2 <- ncol(CO2)
#' 請問CO2 的各行的名稱為何?
answer3 <- colnames(CO2)
#' 請問uptake這欄的平均值為多少?
answer4 <- mean(CO2$uptake)
#' CO2 共有很多很多列(answer1)
#' 請從CO2 中挑出一些列,滿足以下的條件:
#' 這些列的uptake直,超過全部CO2的uptake值
#' (`mean(CO2$uptake)`)
#'
#' 你可以先取出uptake的向量、接著拿該向量和平均值做比較、把結果的logical vector丟到`[]`的第一個參數
answer5 <- CO2[CO2$uptake > answer4,]
#' 請問Type有多少種類別?
answer6 <- length(levels(CO2$Type))
#' 請問當Type的類別為Quebec時,uptake的平均值為多少?
answer7 <- mean(CO2[CO2$Type == "Quebec","uptake"])
#' 請問當Type的類別為Mississippi時,uptake的平均值為多少?
answer8 <- mean(CO2[CO2$Type == "Mississippi","uptake"])
#' 我們可以利用`model.matrix`來建立一個矩陣。舉例來說:
#' `model.matrix(~ Type + Treatment + conc, CO2)`可以
#' 建立一個基於Type、Treatment和conc的矩陣。
X <- model.matrix(~ Type + Treatment + conc, CO2)
#' 請取出uptake的值放入y 之中
y <- CO2$uptake
#' 請利用<https://en.wikipedia.org/wiki/Ordinary_least_squares#Estimation>的公式,利用迴歸的演算法,
#' 找出beta.hat讓 X %*% beta.hat 很靠近 y
#' ps. class(beta.hat) 應該為matrix
#' dim(beta.hat) 應該為 c(4, 1)
#' rownames(beta.hat) 應該為 c("(Intercept)","TypeMississippi","Treatmentchilled","conc")
beta.hat <- solve(t(X) %*% X, t(X) %*% y)
#' 請計算X %*% beta.hat 和 y 的correlation(提示:用函數`cor`)
answer11 <- cor(X %*% beta.hat, y)
#' answer11 的平方,就是迴歸分析時常提到的:R-squared。
#' 很多分析師會用這個數據來判斷這個模型好不好。
#' 在R 裡面,跑迴歸分析,可以簡單用`lm`這個函數:
g <- lm(uptake ~ Type + Treatment + conc, CO2)
#' g 這個物件就會包含我們剛剛算過得答案
#' g$coef就會是beta.hat
#' g$fitted.value就會是X %*% beta.hat
#' summary(g)則會顯示各個參數的t 檢定,以及整個模型的R-squared
g.s <- summary(g)
#' mode(g.s)顯示它是一個list。
#' 請找出一個名字,answer12,讓g[[answer12]]就是R-squared
#' 你可以參考help(summary.lm)裡面的說明。
answer12 <- "r.squared"