本週上課將介紹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
資料結構可分為一維、二維、多維:
R
的資料型態以及運算。數值可分為數值(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應該是整數,但是其實是數值。
請輸入
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))
資料可以是真(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(),用途為顯示向量的長度。
請輸入 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/13/2018"
請輸入
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"
計算兩個人的年齡差距為例:
birthday <- c("xi"="1953-06-15", "tsai"="1956-08-31")
birthday_date <- as.Date(birthday, format='%Y-%m-%d')
difftime(birthday_date[2], birthday_date[1])
## Time difference of 1173 days
日期的格式如下:
符號 | 意義 | 例子 |
---|---|---|
%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-13"
to_day<-format(Today, format='%Y-%b-%d'); to_day
## [1] "2018- 3-13"
向量是最常見的資料結構,可以寫成:
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)
有些資料具有類別,例如性別、是或否、地區等等。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")
如果想要轉換因素為數值,例如:
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")
請嘗試練習AMSsurvey
的citizen
等類別變數的轉換。
請輸入 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"
數學的矩陣與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
資料框是向量組合起來成為一個類似矩陣的資料,然後指定變數名稱。例如:
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
資料框的每一行必須有相同的長度,每一列也必須要有同樣數目的數字、文字等。 有幾個資料框的相關指令:
例如我們想知道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等工作表讀取而來,被賦予流水號,但是並不是第一行,真正的第一行應該有欄位的名稱。
資料框可以結合數值、邏輯、字串等等資料。
陣列容納一個以上的矩陣,只有一個矩陣的陣列相當於矩陣:
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
列表的特性為資料的長度、結構沒有限制,例如:
listA<-list(R123, m, birthday); listA
## [[1]]
## 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
##
## [[2]]
## [,1] [,2] [,3]
## [1,] 1 4 7
## [2,] 2 5 0
## [3,] 3 6 9
##
## [[3]]
## xi tsai
## "1953-06-15" "1956-08-31"
listA[[3]]
## xi tsai
## "1953-06-15" "1956-08-31"
列表的優點是儲存尚未格式化的資料,但是資料相當龐大,矩陣與陣列的資料分散為一個個元素,不容易取出,如果事先命名,就比較容易了解哪些元素來自於什麼資料。例如:
listB<-list(data=R123, vec=m, char=birthday);
listB[["data"]]
## 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
請嘗試把`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')`結合成為一個列表。
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
資料框在各種資料結構之中,是最常被用到的。如果要把資料提出,最好把各種資料結構轉成資料框。例如:
g<-Titanic[ , , 2, 2]; class(g)
## [1] "table"
請輸入
g$Class
會發生錯誤。改為:
g<-data.frame(g)
請輸入 g$Class
因為向量具有方位的性質,所以數字具有先後順序,與另一個有同樣數目的向量相加減乘除時,將會依照順序進行運算。我們以一個純量 (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
進位的指令有:
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
orange
資料,把Tree變數換成A, B, C, D, E,然後顯示每一個類型的數量。請用weekdays()
指令顯示今天上課日期是星期二。
請問在mtcars
資料裡面,mpg高於或等於21的資料有幾筆?
請嘗試取出Titanic
這個列表的四個表格
請計算英文有幾個字母。
請寫一段語法把今天的氣溫轉換成華氏
請創造一個對角向量為{1,1,1}的矩陣
請問在您寫作業的這一天,今年已經過了幾天?