1 課程目標

本週上課將介紹R的資料型態與資料結構,也就是R可以讀取並進行運算的對象,例如我們用 c() 來表示數字、文字的集合:

A<-c("台北市","新北市", "桃園市", "台中市","台南市","高雄市")
print(A)
## [1] "台北市" "新北市" "桃園市" "台中市" "台南市" "高雄市"
B<-c(0,1,2,3,4,5,6,7,8,9)
print(B)
##  [1] 0 1 2 3 4 5 6 7 8 9

A是文字而B是數字的集合,另外還有邏輯以及日期等常用的資料型態。
R資料結構可分為一維、二維、多維:

2 資料型態

2.1 數值(numeric)

數值可分為數值(numeric)或者是整數(integer)。任意數例如:

x<-c(2, 4, 6, 8); x
## [1] 2 4 6 8
class(x)
## [1] "numeric"

class()函數告訴我們該資料型態或者是結構的屬性。

可以用科學符號表示比較大的數字:

y=c(1.1e+06); y
## [1] 1100000
class(y)
## [1] "numeric"

整數則為:

u<-as.integer(c(4)); class(u)
## [1] "integer"

整數是數值的子集合,因為整數的最大值是2147483647,遠小於數值的最大值。在一般運算或是統計上幾乎沒有差異,唯一的差別在於整數的儲存佔用空間比較小。如果某一個變數當作識別碼,可以考慮用整數。
請輸入

is.numeric(100)
is.integer(100)

乍看之下100應該是整數,但是其實是數值。

2.2 字串(character)

請輸入

state.abb
class(state.abb)

文字對於資料使用者而言相對於數值容易理解,但是用途比較受限,無法進行數學運算,但是在資料視覺化時相當有用,例如:

df<-data.frame(state.abb, pop=state.x77[,2])
library(lattice)
dotplot(state.abb ~ pop, data=df)

state.x77是矩陣,所以取出這個矩陣中的人口此一欄位,然後與state.abb結合成一個資料框,再以dotplot指令畫成點狀圖。

數字也可以當成文字,例如:

char1<-c("1","2","Word"); char1
## [1] "1"    "2"    "Word"
char2<-c(1, 2, "文字"); char2
## [1] "1"    "2"    "文字"

數字都被視為字串,無法進行數學運算。字串無法用as.numeric轉換為數字,但是可以用語法進行轉換(請見因素一節)。

請嘗試

quakes
class(row.names(quakes))

以及

state.x77
class(row.names(state.x77))

2.3 邏輯(logic)

資料可以是真(True)或是偽(False)的邏輯,對於篩選資料特別有用。例如我們先建立一筆資料以及邏輯:

a<-c(0:9); a
##  [1] 0 1 2 3 4 5 6 7 8 9
ok<-a>5; ok
##  [1] FALSE FALSE FALSE FALSE FALSE FALSE  TRUE  TRUE  TRUE  TRUE

然後用這個邏輯篩選資料:

a[ok]
## [1] 6 7 8 9

請嘗試

head(Duncan)
ok<-Duncan$income>50  
Duncan$income[ok]

請問篩選後的變數剩下幾個觀察值? 附帶介紹一個指令length(),用途為顯示向量的長度。

2.4 日期(date)

請輸入 Sys.Date()

as.Date()可以將字串轉變為日期資料

v<-c("2/27/2018", "6/26/2018", "12/31/2018"); class(v)
## [1] "character"
v.date<-as.Date(v, format='%m/%d/%Y'); class(v.date)
## Warning in strptime(x, format, tz = "GMT"): unknown timezone 'zone/tz/
## 2018c.1.0/zoneinfo/Asia/Taipei'
## [1] "Date"

或者是

v<-c("", "6/26/2018", "12/31/2018")
as.Date(v, format='%m/%d/%Y')
## [1] NA           "2018-06-26" "2018-12-31"

format()則轉換屬性為日期的資料為不同格式,例如:

today <- Sys.Date()
format(today, format='%m/%d/%Y')
## [1] "03/06/2018"

2.4.1 日期的差距

請輸入

xi<-"1953-06-15" #Xi's birthday
tsai<-"1956-08-31" #Tsai's birthday

我們可以加以轉換,計算兩個日期之間的差距:

as.Date(c(xi,tsai), origin="1904-01-01")
## [1] "1953-06-15" "1956-08-31"
difftime(tsai, xi)
## Time difference of 1173 days

在這個例子中,origin指令可設定也可不設定。但是計算某一個數字代表的日期時必須要有起始日:

as.Date(1100, origin="2018-08-01")
## [1] "2021-08-05"

日期的資料必須完整,R無法從年份知道完整日期,進而計算時間差距:

library(car)
head(USPop)
##   year population
## 1 1790   3.929214
## 2 1800   5.308483
## 3 1810   7.239881
## 4 1820   9.638453
## 5 1830  12.860702
## 6 1840  17.063353
USPop$year<-as.Date(USPop$year, format='%Y', origin="1904-01-01")
USPop$year
##  [1] "1909-01-29" "1909-02-08" "1909-02-18" "1909-02-28" "1909-03-10"
##  [6] "1909-03-20" "1909-03-30" "1909-04-09" "1909-04-19" "1909-04-29"
## [11] "1909-05-09" "1909-05-19" "1909-05-29" "1909-06-08" "1909-06-18"
## [16] "1909-06-28" "1909-07-08" "1909-07-18" "1909-07-28" "1909-08-07"
## [21] "1909-08-17" "1909-08-27"
difftime(USPop$year[2], USPop$year[1])
## Time difference of 10 days

2.4.2 日期的格式

日期的格式如下:

符號 意義 例子
%d 01-31
%a 星期幾的縮寫 Mon
%A 星期幾 Monday
%m 月份(數字) 01-12
%b 月份的縮寫 Jan
%B 月份的完整寫法 January
%y 兩位數年份 18
%Y 年份 2018

format()這個函數可以轉換已經是日期格式的資料。

Today<-Sys.Date(); Today
## [1] "2018-03-06"
to_day<-format(Today, format='%Y-%b-%d'); to_day
## [1] "2018- 3-06"

3 資料結構

3.1 一維

3.1.1 向量(vector)

向量是最常見的資料結構,可以寫成:

example<-c(0,1,2,3,4)
print(example)
## [1] 0 1 2 3 4

或者是

c(2,4,6,8)->A

英文字母的向量:

c(letters)
##  [1] "a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l" "m" "n" "o" "p" "q"
## [18] "r" "s" "t" "u" "v" "w" "x" "y" "z"
c(LETTERS)
##  [1] "A" "B" "C" "D" "E" "F" "G" "H" "I" "J" "K" "L" "M" "N" "O" "P" "Q"
## [18] "R" "S" "T" "U" "V" "W" "X" "Y" "Z"

可以在向量內進行數學運算:

j<-c(2*2,2*9, 10-2); j
## [1]  4 18  8

向量可以加、減、乘、除其他數字:

R<-c(100, 200, 300); R/5; sqrt(R)
## [1] 20 40 60
## [1] 10.00000 14.14214 17.32051

請嘗試

c(A, R)

3.1.2 因素(factor)

有些資料具有類別,例如性別、是或否、地區等等。Verzani (p.10) 的例子:

x=c("Yes","No","No","Yes","Yes"); x
## [1] "Yes" "No"  "No"  "Yes" "Yes"
factor(x)
## [1] Yes No  No  Yes Yes
## Levels: No Yes
table(x)
## x
##  No Yes 
##   2   3

在這個例子中,x是字串資料,而factor()這個函數把x轉換為因素
常用的指令是table(),用途為統計向量的分佈。
因素在許多分析之中讓人容易理解,例如在交叉分析時:

library(car)
table(Chile$sex, Chile$vote)
##    
##       A   N   U   Y
##   F 104 363 362 480
##   M  83 526 226 388

有字串比較容易理解。

Chile$ncode<-as.numeric(Chile$sex) 
table(Chile$ncode, Chile$vote)
##    
##       A   N   U   Y
##   1 104 363 362 480
##   2  83 526 226 388

或者是繪圖:

library(lattice)
plot(Chile$sex, Chile$vote, xlab="Sex", ylab="Vote")

3.1.2.1 因素轉換

如果想要轉換因素為數值,例如:

library(car)
data(Chile)
class(Chile$region)
## [1] "factor"

直接以as.numeric( )轉換變數:

class(Chile$region)
## [1] "factor"
table(Chile$region)
## 
##   C   M   N   S  SA 
## 600 100 322 718 960
y<-as.numeric(Chile$region)
table(y)
## y
##   1   2   3   4   5 
## 600 100 322 718 960

也可以寫語法先轉換為字串:

Chile$gender[Chile$sex=="F"]<-"Female"
Chile$gender[Chile$sex=="M"]<-"Male"
table(Chile$gender)
## 
## Female   Male 
##   1379   1321

如果是字串,可以進行交叉分析,但是無法畫箱形圖

#plot(Chile$gender, Chile$vote, xlab="Sex", ylab="Vote")

然後再轉換為因素:

Chile$gender<-factor(Chile$gender)
plot(Chile$gender, Chile$vote, xlab="Sex", ylab="Vote")

請嘗試練習AMSsurveycitizen等類別變數的轉換。

3.1.2.2 因素的順序

請輸入 x<-c(“花蓮縣”,“臺北市”,“屏東縣”,“臺南市”,“高雄市”);x; table(x)

x的排列方式為“花蓮縣”,“臺北市”,“屏東縣”,“臺南市”,“高雄市”,而分布的排列方式也是如此。
如果希望按照由北到南再到東排列觀察值,可以加上level指令 xf<-factor(x, levels=c(“臺北市”, “臺南市”,“高雄市”,“屏東縣”,“花蓮縣”)); xf
table(xf)

請練習把Chile裡面的region變數的類別重新排序,然後執行

table(Chile$sex,Chile$regionorder)

附帶一提,factor()這個函數裡面有ordered的邏輯選項,不過只要指定levels,有無ordered為真並不影響。但是ordered()這個函數會得到一個已經排序的因素,例如:

od<-ordered(1:20); class(od)
## [1] "ordered" "factor"

3.2 二維

3.2.1 矩陣 (matrix)

數學的矩陣與R類似,例如我們需要一個3*3的矩陣可寫成:

m<-matrix(c(1:9), nrow=3, ncol=3); m
##      [,1] [,2] [,3]
## [1,]    1    4    7
## [2,]    2    5    8
## [3,]    3    6    9
n<-matrix(c(1:6), nrow=3, ncol=2)

兩個矩陣相乘可寫成:

m<-matrix(c(1:9), nrow=3, ncol=3); n<-matrix(c(1:6), nrow=3, ncol=2); m%*%n
##      [,1] [,2]
## [1,]   30   66
## [2,]   36   81
## [3,]   42   96

矩陣的乘法需要第一個矩陣的行(column)等於第二個矩陣的列(row)。
矩陣的對角向量為:

diag(m)
## [1] 1 5 9

轉置矩陣為:

t(m)
##      [,1] [,2] [,3]
## [1,]    1    2    3
## [2,]    4    5    6
## [3,]    7    8    9

如果要替代或者是選取部分的矩陣資料,矩陣的讀法是先列再行,例如要選取m矩陣的第二列第三行的資料,並且命它為0:

m[2,3]; m[2,3]<-0
## [1] 8

請嘗試(1)轉置n矩陣(2)輸入以下指令:n<-matrix(c(1:6), nrow=3, ncol=2, byrow=T)

矩陣的列與行命名方式為用dimnames的指令分別對列與行指定名稱,例如:

n<-matrix(c(1:6), nrow=3, ncol=2, dimnames = list(c("a","b","c"),c("A","B"))); n
##   A B
## a 1 4
## b 2 5
## c 3 6

3.2.2 資料框 (data frame)

資料框是向量組合起來成為一個類似矩陣的資料,然後指定變數名稱。例如:

R1<-c(170, 175, 166, 172, 165, 157, 167, 167, 
        156, 160)
R2<-c("F","M","M","M","F","F","F","F","M","F")
R3<-R1/10 + 42
R123<-data.frame(height=R1,gender=R2,weight=R3); R123
##    height gender weight
## 1     170      F   59.0
## 2     175      M   59.5
## 3     166      M   58.6
## 4     172      M   59.2
## 5     165      F   58.5
## 6     157      F   57.7
## 7     167      F   58.7
## 8     167      F   58.7
## 9     156      M   57.6
## 10    160      F   58.0

資料框的每一行必須有相同的長度,每一列也必須要有同樣數目的數字、文字等。 有幾個資料框的相關指令:

  • nrow():顯示列的數量
  • ncol():顯示行的數量
  • dim():同時顯示行列的數量
  • head():顯示前6列

例如我們想知道AMSsurvey有幾個觀察值:

nrow(AMSsurvey)
## [1] 24

如果想要改變欄位名稱,可以這麼做:

colnames(R123)<-c("v1","v2","v3"); R123
##     v1 v2   v3
## 1  170  F 59.0
## 2  175  M 59.5
## 3  166  M 58.6
## 4  172  M 59.2
## 5  165  F 58.5
## 6  157  F 57.7
## 7  167  F 58.7
## 8  167  F 58.7
## 9  156  M 57.6
## 10 160  F 58.0

有的資料框的最左邊是流水號,有的資料框沒有,前者可能是因為從csv等工作表讀取而來,被賦予流水號,但是並不是第一行,真正的第一行應該有欄位的名稱。

3.3 多維

3.3.1 陣列 (array)

陣列容納一個以上的矩陣,只有一個矩陣的陣列相當於矩陣:

Array1 <- array(1:12, dim = c(2, 6, 1)); Array1
## , , 1
## 
##      [,1] [,2] [,3] [,4] [,5] [,6]
## [1,]    1    3    5    7    9   11
## [2,]    2    4    6    8   10   12

而有多個矩陣的陣列如:

Array2 <- array(1:12, dim = c(2, 3, 2)); Array2
## , , 1
## 
##      [,1] [,2] [,3]
## [1,]    1    3    5
## [2,]    2    4    6
## 
## , , 2
## 
##      [,1] [,2] [,3]
## [1,]    7    9   11
## [2,]    8   10   12

陣列的優點是同時容納一個以上的矩陣,如果只需要某一個矩陣,可以這樣取出:

A12<-Array2[,,2]; A12
##      [,1] [,2] [,3]
## [1,]    7    9   11
## [2,]    8   10   12

3.3.2 列表 (list)

列表的特性為資料的長度、結構沒有限制,例如:

listA<-c(dataframe=R123, matrix=m, vector=char1, array=Array2); listA
## $dataframe.v1
##  [1] 170 175 166 172 165 157 167 167 156 160
## 
## $dataframe.v2
##  [1] F M M M F F F F M F
## Levels: F M
## 
## $dataframe.v3
##  [1] 59.0 59.5 58.6 59.2 58.5 57.7 58.7 58.7 57.6 58.0
## 
## $matrix1
## [1] 1
## 
## $matrix2
## [1] 2
## 
## $matrix3
## [1] 3
## 
## $matrix4
## [1] 4
## 
## $matrix5
## [1] 5
## 
## $matrix6
## [1] 6
## 
## $matrix7
## [1] 7
## 
## $matrix8
## [1] 0
## 
## $matrix9
## [1] 9
## 
## $vector1
## [1] "1"
## 
## $vector2
## [1] "2"
## 
## $vector3
## [1] "Word"
## 
## $array1
## [1] 1
## 
## $array2
## [1] 2
## 
## $array3
## [1] 3
## 
## $array4
## [1] 4
## 
## $array5
## [1] 5
## 
## $array6
## [1] 6
## 
## $array7
## [1] 7
## 
## $array8
## [1] 8
## 
## $array9
## [1] 9
## 
## $array10
## [1] 10
## 
## $array11
## [1] 11
## 
## $array12
## [1] 12

列表的優點是儲存尚未格式化的資料,但是資料相當龐大,矩陣與陣列的資料分散為一個個元素,不容易取出,如果事先命名,就比較容易了解哪些元素來自於什麼資料。例如:

listA$dataframe.v1
##  [1] 170 175 166 172 165 157 167 167 156 160

請嘗試把c('a','b','c')c(1,2,3,4)以及c('2018-01-01', '2018-04-04', '2018-04-05', '2018-06-18', '2018-10-10')結合成為一個列表。

3.3.3 表格 (table)

Titanic這筆資料為表格的型態,同時也是四個陣列,

class(Titanic); Titanic
## [1] "table"
## , , Age = Child, Survived = No
## 
##       Sex
## Class  Male Female
##   1st     0      0
##   2nd     0      0
##   3rd    35     17
##   Crew    0      0
## 
## , , Age = Adult, Survived = No
## 
##       Sex
## Class  Male Female
##   1st   118      4
##   2nd   154     13
##   3rd   387     89
##   Crew  670      3
## 
## , , Age = Child, Survived = Yes
## 
##       Sex
## Class  Male Female
##   1st     5      1
##   2nd    11     13
##   3rd    13     14
##   Crew    0      0
## 
## , , Age = Adult, Survived = Yes
## 
##       Sex
## Class  Male Female
##   1st    57    140
##   2nd    14     80
##   3rd    75     76
##   Crew  192     20
Titanic[, , 1, 1]; Titanic[ , , 2, 2]
##       Sex
## Class  Male Female
##   1st     0      0
##   2nd     0      0
##   3rd    35     17
##   Crew    0      0
##       Sex
## Class  Male Female
##   1st    57    140
##   2nd    14     80
##   3rd    75     76
##   Crew  192     20

3.4 小結

資料框在各種資料結構之中,是最常被用到的。如果要把資料提出,最好把各種資料結構轉成資料框。例如:

g<-Titanic[ , , 2, 2]; class(g)
## [1] "table"

請輸入

g$Class

會發生錯誤。改為:

g<-data.frame(g)

請輸入 g$Class

4 基本運算

4.1 向量的運算

因為向量具有方位的性質,所以數字具有先後順序,與另一個有同樣數目的向量相加減乘除時,將會依照順序進行運算。我們以一個純量 (scalar) Sca 為例:

X<-c(10,20,30,40,50,60); Sca<-10
X+Sca
## [1] 20 30 40 50 60 70

如果是乘或是除,就是每個元素同時乘或除某個數:

X/Sca
## [1] 1 2 3 4 5 6

如果是乘或是除另一個矩陣向量,就是兩個向量對應的每個元素進行乘或除:

Y<-c(5,10,6,8,25,6)
X/Y; X*Y
## [1]  2  2  5  5  2 10
## [1]   50  200  180  320 1250  360

也可以運算平方與開根號:

a<-c(2,3,4); b<-a^2; print(b)
## [1]  4  9 16
c<-sqrt(b); print(c)
## [1] 2 3 4

4.2 進位

進位的指令有:

  • round:四捨五入
  • floor:強制捨去
  • ceiling:強制進位
a1<-c(2.54, 3.111, 10.999)
round(a1, digits=2)
## [1]  2.54  3.11 11.00
floor(a1)
## [1]  2  3 10
ceiling(a1)
## [1]  3  4 11

5 作業

  1. 請問 \(\text{log}(\frac{14}{5})=\)?
  2. 請問 \(1\times 2\times 3\times , \dots ,\times 8=\)?
  3. 使用orange資料,把Tree變數換成A, B, C, D, E,然後顯示每一個類型的數量。
  4. 請用weekdays()指令顯示今天上課日期是星期二。

  5. 請問在mtcars資料裡面,mpg高於或等於21的資料有幾筆?

  6. 請嘗試取出Titanic這個列表的四個表格

  7. 請計算英文有幾個字母。

  8. 請寫一段語法把今天的氣溫轉換成華氏

  9. 請創造一個對角向量為{1,1,1}的矩陣

  10. 請問在您寫作業的這一天,今年已經過了幾天?