本週上課將介紹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
的資料型態以及運算。
介紹R
的資料型態之前,先來認識R
的函數。 函數類似一個黑盒子,把變數或者是資料放進去這個黑盒子,根據函數中的設定,回傳計算的結果。例如,我們想知道一個變數的平均值,R
的平均值函數為:
?mean
mean(x, trim = 0, na.rm = FALSE)
x
為變數,trim
表示設定要去除多少百分比的變數中的資料。例如有一個變數型態為:
x<-c(100000, 10000000, c(1:10)); x
## [1] 1e+05 1e+07 1e+00 2e+00 3e+00 4e+00 5e+00 6e+00 7e+00 8e+00 9e+00
## [12] 1e+01
可以看到這個變數有一些極端值,我們可以用trim=0.2去掉 \(0.2 \times 12=2.4\),等於從這一串數字前後拿掉2個數字。以下比較有無設定傳回的結果:
x<-c(100000, 10000000, c(1:10))
sort(x)
## [1] 1e+00 2e+00 3e+00 4e+00 5e+00 6e+00 7e+00 8e+00 9e+00 1e+01 1e+05
## [12] 1e+07
mean(x)
## [1] 841671.2
mean(x, trim=0.2)
## [1] 6.5
mean(sort(x)[3:10])
## [1] 6.5
當trim=0.2,x剩下第3到第10個資料,也就是x[3:10]。記得用sort()排序x,再取出正確的資料。
我們可以順便認識數字用科學符號表示的方式。e+01代表兩位數,e+05代表6位數。
Rousselet的部落格進一步介紹為何要去掉極端值。
大部份時候我們執行函數時,不會用到所有的設定,但是越了解每一個函數的設定的意義,越能發揮函數的功能。
數值可分為數值(numeric)或者是整數(integer)。任意數例如:
X<-c(2, 4, 6, 8); X
## [1] 2 4 6 8
class(X)
## [1] "numeric"
str(X)
## num [1:4] 2 4 6 8
class()函數告訴我們該資料型態或者是結構的屬性。
可以用科學符號表示比較大的數字:
y=c(1.1e+06); y
## [1] 1100000
class(y)
## [1] "numeric"
整數則為:
u<-as.integer(c(4)); class(u)
## [1] "integer"
整數是數值的子集合,因為整數的最大值是2147483647,遠小於數值的最大值。在一般運算或是統計上幾乎沒有差異,唯一的差別在於整數的儲存佔用空間比較小,而一般數值其實帶有小數點,只是沒有顯示,稱為浮點運算。由於電腦使用二進位制的運算,由一個有效數字加上冪數來表示,以這種表示法表示的數值,稱為浮點數。利用浮點進行運算,稱為浮點計算,也就是所有渉及小數的運算。。
請輸入
乍看之下100應該是整數,但是其實是數值。 又例如:
a<-c(7, 8.5, 9); class(a)
## [1] "numeric"
b<-as.integer(a); b
## [1] 7 8 9
as.integer()傳回整數。 變數如果與另一個變數對應條件時,R
會顯示變數性質與對應結果:
h<-c(100, 200, 500)
ok<-h>300
b[ok]
## [1] 9
ok<-h>1000
b[ok]
## integer(0)
變數可以是字串,例如受訪者的性別、學生的姓名、國家名稱等等。
請輸入
文字對於資料使用者而言相對於數值容易理解,但是用途比較受限,無法進行數學運算,但是在資料視覺化時相當有用,例如:
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這筆資料的列名稱看起來是數字,卻被視為字串。
以及
字串經常會被誤認為因素(factor),具有類別,例如1,000個受訪者中可能有500多個男或是女,因此R
視為因素變數而非字串。 例如,我們到政府開放資料網站下載一筆資料:
library(foreign); library(tidyverse)
dat<-read.csv("opendata106N0101.csv", header=T, fileEncoding = 'UTF-8')
as.tibble(dat)
## # A tibble: 375 x 4
## code 年底人口數 土地面積 人口密度
## <fct> <fct> <dbl> <fct>
## 1 新北市板橋區 551480 23.1 23835
## 2 新北市三重區 387484 16.3 23747
## 3 新北市中和區 413590 20.1 20532
## 4 新北市永和區 222585 5.71 38956
## 5 新北市新莊區 416524 19.7 21102
## 6 新北市新店區 302089 120. 2513
## 7 新北市樹林區 184149 33.1 5559
## 8 新北市鶯歌區 86593 21.1 4099
## 9 新北市三峽區 114926 191. 600
## 10 新北市淡水區 169597 70.7 2400
## # ... with 365 more rows
可以看出許多變數被視為因素。 加上stringsAsFactors = F避免把字串當做因素:
dat<-read.csv("opendata106N0101.csv", header=T, stringsAsFactors = F)
nrow(dat) #check how many rows; n=375
## [1] 375
dat <- dat[-c(369:375),] #delete the rows of small islands and notes
dat<-as.tibble(dat); head(dat, n=3)
## # A tibble: 3 x 4
## code 年底人口數 土地面積 人口密度
## <chr> <chr> <dbl> <chr>
## 1 新北市板橋區 551480 23.1 23835
## 2 新北市三重區 387484 16.3 23747
## 3 新北市中和區 413590 20.1 20532
可以看到,新的資料中,變數code被認為是是字串,但是年底人口數、人口密度也被認為是字串。 我們創造一個新的數字變數來取代字串變數:
dat <- dat %>% mutate(popu=as.numeric(年底人口數))
str(dat)
## Classes 'tbl_df', 'tbl' and 'data.frame': 368 obs. of 5 variables:
## $ code : chr "新北市板橋區" "新北市三重區" "新北市中和區" "新北市永和區" ...
## $ 年底人口數: chr "551480" "387484" "413590" "222585" ...
## $ 土地面積 : num 23.14 16.32 20.14 5.71 19.74 ...
## $ 人口密度 : chr "23835" "23747" "20532" "38956" ...
## $ popu : num 551480 387484 413590 222585 416524 ...
str()函數可以顯示資料中的變數性質。
另一個方式為讀取時故意不讀第一列為欄位的標題,這樣所有欄位會被視為字串:
df<-read.csv("opendata106N0101.csv", header=F, stringsAsFactors = F)
colnames(df) <-df[1,]
df <- df[-c(1, 370:376),] #delete the first row and the rows of notes
df<-df%>% mutate(popu=as.numeric(年底人口數))
head(df, n=3)
## code 年底人口數 土地面積 人口密度 popu
## 1 新北市板橋區 551480 23.1373 23835 551480
## 2 新北市三重區 387484 16.317 23747 387484
## 3 新北市中和區 413590 20.144 20532 413590
str(df)
## 'data.frame': 368 obs. of 5 variables:
## $ code : chr "新北市板橋區" "新北市三重區" "新北市中和區" "新北市永和區" ...
## $ 年底人口數: chr "551480" "387484" "413590" "222585" ...
## $ 土地面積 : chr "23.1373" "16.317" "20.144" "5.7138" ...
## $ 人口密度 : chr "23835" "23747" "20532" "38956" ...
## $ popu : num 551480 387484 413590 222585 416524 ...
min(df$popu) #check if data has no missing value
## [1] 685
第三個方式為利用data.table
這個套件,以及transform()的功能,直接轉換某一個變數的屬性,但是不創造新的變數:
library(data.table)
##
## Attaching package: 'data.table'
## The following objects are masked from 'package:dplyr':
##
## between, first, last
## The following object is masked from 'package:purrr':
##
## transpose
DT <- read.csv("opendata106N0101.csv", header=F, stringsAsFactors = F)
colnames(DT) <-DT[1,]
nrow(DT) #check how many rows; n=376
## [1] 376
DT <- DT[-c(1, 370:376),] #delete the first row and the rows of notes
DT <- data.table(DT)
DT <- DT %>% transform(年底人口數=as.numeric(年底人口數))
head(DT, n=3)
## code 年底人口數 土地面積 人口密度
## 1: 新北市板橋區 551480 23.1373 23835
## 2: 新北市三重區 387484 16.317 23747
## 3: 新北市中和區 413590 20.144 20532
str(DT)
## Classes 'data.table' and 'data.frame': 368 obs. of 4 variables:
## $ code : chr "新北市板橋區" "新北市三重區" "新北市中和區" "新北市永和區" ...
## $ 年底人口數: num 551480 387484 413590 222585 416524 ...
## $ 土地面積 : chr "23.1373" "16.317" "20.144" "5.7138" ...
## $ 人口密度 : chr "23835" "23747" "20532" "38956" ...
## - attr(*, ".internal.selfref")=<externalptr>
min(DT$年底人口數) #check if data has no missing value
## [1] 685
請注意上述三組語法之中,我們去掉東沙群島、南沙群島的資料,以及一些資料的說明。
有些資料具有類別,例如性別、是或否、地區等等。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轉換為因素,有No, Yes兩類別。 常用的指令是table(),用途為統計向量的分佈。
因素在許多分析之中讓人容易理解,例如在交叉分析時:
library(car)
## Loading required package: carData
##
## Attaching package: 'car'
## The following object is masked from 'package:dplyr':
##
## recode
## The following object is masked from 'package:purrr':
##
## some
table(Chile$sex, Chile$vote)
##
## A N U Y
## F 104 363 362 480
## M 83 526 226 388
不論是字串或者是因素,比較容易讓人理解交叉分析的結果。例如我們的資料用數字代表地區:
Chile$ncode<-as.numeric(Chile$region)
table(Chile$ncode, Chile$vote)
##
## A N U Y
## 1 44 210 141 174
## 2 2 18 23 38
## 3 30 102 46 135
## 4 42 214 148 275
## 5 69 345 230 246
或者是繪圖:
library(lattice)
plot(Chile$sex, Chile$vote, xlab="Sex", ylab="Vote")
有時候我們需要把因素轉換成數值,例如教育程度從國小、國中、…轉換成1到6的尺度。或者性別從男、女轉換成0與1。可用as.numeric()函數:
gender<-as.numeric(Chile$sex)
table(Chile$sex); table(gender)
##
## F M
## 1379 1321
## gender
## 1 2
## 1379 1321
可以看到R
按照類別的字母順序轉換類別為數字。 如果進一步要轉換數字就容易了:
sex <- c()
sex[gender==2]<-0
sex[gender==1]<-1
table(sex)
## sex
## 0 1
## 1321 1379
也可以寫語法直接轉換因素為需要的數字:
ngender<-c()
ngender[Chile$sex=='F']<-1
ngender[Chile$sex=='M']<-0
table(ngender)
## ngender
## 0 1
## 1321 1379
或是把因素轉換為字串:
Chile$gender[Chile$sex=="F"]<-"Female"
Chile$gender[Chile$sex=="M"]<-"Male"
class(Chile$gender)
## [1] "character"
table(Chile$gender)
##
## Female Male
## 1379 1321
如果是字串,可以進行交叉分析,但是無法畫圖
table(Chile$gender, Chile$vote)
plot(Chile$gender, Chile$vote, xlab="Sex", ylab="Vote")
需要注意字串無法轉換為數字,因為R
無法判斷哪一個字串應該被給予哪一個數字。
as.numeric(Chile$gender)
請嘗試練習AMSsurvey
的citizen
等類別變數的轉換。 如果要避免讀取資料時把字串認定為因素,可以加上一個設定stringsAsFactors=FALSE
library(data.table)
X = data.table(A=sample(3, 6, TRUE),
B=sample(letters[1:3], 6, TRUE),
C=sample(6), stringsAsFactors=FALSE)
X
## A B C
## 1: 2 c 1
## 2: 2 a 4
## 3: 1 a 5
## 4: 2 a 3
## 5: 2 b 6
## 6: 1 b 2
## Warning in (function (..., .x = ..1, .y = ..2, . = ..1) : 強制變更過程中產
## 生了 NA
## # A tibble: 6 x 4
## name birth height weight
## <chr> <dbl> <dbl> <dbl>
## 1 Wang NA 111 8.5
## 2 Lin NA 113 10.6
## 3 Yang NA 106 7.5
## 4 Huang NA 114 9.6
## 5 Cheng NA 102 9.4
## 6 Chao NA 114 10.5
請輸入 - 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"
資料可以是真(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(),用途為顯示向量的長度。
有時候我們的資料裡面有遺漏值NA。可以用邏輯加上is.na()函數,剔除這些遺漏值。
H<-data.table(Age=c("40-49","30-39","40-49","20-29","20-29","60-69","60-69","30-39","60-69","30-39"), Vote=c("Ding", NA, "Ko", "Ko", "Ko", NA, "Ko", "Yao","Ding","Ko"), Income=c(NA,NA, "900-1200K", "600-900K", NA, "2000-3000K", NA, "600-900K", "2000-3000K", "900-1200K")); H
## Age Vote Income
## 1: 40-49 Ding <NA>
## 2: 30-39 <NA> <NA>
## 3: 40-49 Ko 900-1200K
## 4: 20-29 Ko 600-900K
## 5: 20-29 Ko <NA>
## 6: 60-69 <NA> 2000-3000K
## 7: 60-69 Ko <NA>
## 8: 30-39 Yao 600-900K
## 9: 60-69 Ding 2000-3000K
## 10: 30-39 Ko 900-1200K
ok <- !is.na(H$Vote)
table(H$Age[ok], H$Vote[ok])
##
## Ding Ko Yao
## 20-29 0 2 0
## 30-39 0 1 1
## 40-49 1 1 0
## 60-69 1 1 0
請嘗試用以上的技巧顯示收入與投票之間的關係。
##
## Ding Ko Yao
## 2000-3000K 1 0 0
## 600-900K 0 1 1
## 900-1200K 0 2 0
請輸入 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)
## [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/08/2019"
日期的格式如下:
符號 | 意義 | 例子 |
---|---|---|
%d | 日 | 01-31 |
%a | 星期幾的縮寫 | Mon |
%A | 星期幾 | Monday |
%m | 月份(數字) | 01-12 |
%b | 月份的縮寫 | Jan |
%B | 月份的完整寫法 | January |
%y | 兩位數年份 | 18 |
%Y | 年份 | 2018 |
format()
這個函數可以轉換已經是日期格式的資料。
Today<-Sys.Date(); Today
## [1] "2019-03-08"
to_day<-format(Today, format='%Y-%b-%d'); to_day
## [1] "2019- 3-08"
請輸入
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"
介紹完資料型態之後,接下來介紹資料結構。
向量是最常見的資料結構,可以寫成:
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"
有時候我們為向量中的元素加上名稱,方便繪圖,例如有兩個向量分別表示某位投資者的資金配置以及2016到2019的現金數量:
shares <- c(150, 40, 65)
names(shares) <- c('Finance','Techonolgy','Cash')
shares
## Finance Techonolgy Cash
## 150 40 65
class(shares)
## [1] "numeric"
cash<-c(100, 120, 80, 65)
names(cash) <- c(2016, 2017, 2018, 2019)
par(mfrow=c(1,2), bg='lightgreen',mai=c(0.4,0.3,0.1,0.3))
pie(shares); barplot(cash, cex.axis = 0.8)
可以在向量內進行數學運算,例如:
j<-c(2*2, 2*9, 10-2, 3^3); j
## [1] 4 18 8 27
向量可以加、減、乘、除其他數字:
R<-c(100, 200, 300); R/5; sqrt(R)
## [1] 20 40 60
## [1] 10.00000 14.14214 17.32051
一個向量可以合併另一個向量:
c(j, R)
## [1] 4 18 8 27 100 200 300
或者是一個向量包含其他向量:
Y<-c(j, c(9:5), R[c(1,2)]); Y
## [1] 4 18 8 27 9 8 7 6 5 100 200
因為R
的向量可以連結,我們可以增加資料的數量。 用減號可以去除向量中的元素,例如:
Y[-c(8:12)]
## [1] 4 18 8 27 9 8 7
R
的資料結構之一是矩陣,例如:
data("VADeaths"); VADeaths
## Rural Male Rural Female Urban Male Urban Female
## 50-54 11.7 8.7 15.4 8.4
## 55-59 18.1 11.7 24.3 13.6
## 60-64 26.9 20.3 37.0 19.3
## 65-69 41.0 30.9 54.6 35.1
## 70-74 66.0 54.3 71.1 50.0
class(VADeaths)
## [1] "matrix"
數學的矩陣與R
的矩陣類似。矩陣的讀法是先列再行。例如我們需要一個\(3\times 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
再寫一個\(3\times 2\)
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,
stringsAsFactors = FALSE)
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
資料框的每一行必須有相同的長度,每一列也必須要有同樣數目的數字、文字等。 如果沒有特別指定資料框,R
會當做矩陣。例如:
H<-cbind(LETTERS[1:6], seq(10,60, 10))
class(H)
## [1] "matrix"
因為矩陣無法設定stringAsFactor=F,所以資料框比較好用。
有幾個資料框與矩陣的相關指令:
有關rownames的更多說明,請參考這個部落格 。
例如我們想知道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等工作表讀取而來,被賦予流水號,但是並不是第一行,真正的第一行應該有欄位的名稱。有的資料框則用字串當做列的名稱:
library(ISLR)
head(College, n=3)
## Private Apps Accept Enroll Top10perc
## Abilene Christian University Yes 1660 1232 721 23
## Adelphi University Yes 2186 1924 512 16
## Adrian College Yes 1428 1097 336 22
## Top25perc F.Undergrad P.Undergrad Outstate
## Abilene Christian University 52 2885 537 7440
## Adelphi University 29 2683 1227 12280
## Adrian College 50 1036 99 11250
## Room.Board Books Personal PhD Terminal
## Abilene Christian University 3300 450 2200 70 78
## Adelphi University 6450 750 1500 29 30
## Adrian College 3750 400 1165 53 66
## S.F.Ratio perc.alumni Expend Grad.Rate
## Abilene Christian University 18.1 12 7041 60
## Adelphi University 12.2 16 10527 56
## Adrian College 12.9 30 8735 54
rownames 可以幫助我們刪掉不需要的資料。例如我們有一筆美國各州的資料:
head(state.x77, n=5)
## Population Income Illiteracy Life Exp Murder HS Grad Frost
## Alabama 3615 3624 2.1 69.05 15.1 41.3 20
## Alaska 365 6315 1.5 69.31 11.3 66.7 152
## Arizona 2212 4530 1.8 70.55 7.8 58.1 15
## Arkansas 2110 3378 1.9 70.66 10.1 39.9 65
## California 21198 5114 1.1 71.71 10.3 62.6 20
## Area
## Alabama 50708
## Alaska 566432
## Arizona 113417
## Arkansas 51945
## California 156361
我們想刪掉Alabama, Alaska, Arkansas三個州的資料,先成立一個矩陣:
names.to.delete<-c('Alabama', 'Alaska', 'Arkansas')
再用which(rownames(data) %in% vector)傳回所要選出的列:
rows.to.delete<-which(rownames(state.x77) %in% names.to.delete)
最後用data[-c(), ]刪掉所選的列:
newstate <- state.x77[-c(rows.to.delete),]
head(newstate, n=5)
## Population Income Illiteracy Life Exp Murder HS Grad Frost
## Arizona 2212 4530 1.8 70.55 7.8 58.1 15
## California 21198 5114 1.1 71.71 10.3 62.6 20
## Colorado 2541 4884 0.7 72.06 6.8 63.9 166
## Connecticut 3100 5348 1.1 72.48 3.1 56.0 139
## Delaware 579 4809 0.9 70.06 6.2 54.6 103
## Area
## Arizona 113417
## California 156361
## Colorado 103766
## Connecticut 4862
## Delaware 1982
更進一步的篩選資料方法將會在後面課程介紹。
陣列容納一個以上的矩陣,只有一個矩陣的陣列相當於矩陣:
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, H, c(xi,tsai)); 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]
## [1,] "A" "10"
## [2,] "B" "20"
## [3,] "C" "30"
## [4,] "D" "40"
## [5,] "E" "50"
## [6,] "F" "60"
##
## [[3]]
## [1] "1953-06-15" "1956-08-31"
又例如我們在一個列表中,創造兩個資料框並給定名稱:
list(A=data.frame(x=c(1:5),y=c(101:105)),
B=data.frame(v1=rep(NA,6)))
## $A
## x y
## 1 1 101
## 2 2 102
## 3 3 103
## 4 4 104
## 5 5 105
##
## $B
## v1
## 1 NA
## 2 NA
## 3 NA
## 4 NA
## 5 NA
## 6 NA
如果要取出列表中的某一個部分資料,可以寫成:
listA[[3]]
## [1] "1953-06-15" "1956-08-31"
列表的優點是儲存尚未格式化的資料,但是資料相當龐大,矩陣與陣列的資料分散為一個個元素,不容易取出,如果事先命名,就比較容易了解哪些元素來自於什麼資料。例如:
listB<-list(data=R123, vec=m, char=c(tsai, xi));
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
如果列表中的變數有同樣的長度,可以用setDT()轉換列表為data.table。例如:
X = list(1:5, letters[1:5], c('Y','Y','N','Y','N'), c("2/27/2018", "6/26/2018", "12/31/2018","1/20/2019","4/8/2019")); X
## [[1]]
## [1] 1 2 3 4 5
##
## [[2]]
## [1] "a" "b" "c" "d" "e"
##
## [[3]]
## [1] "Y" "Y" "N" "Y" "N"
##
## [[4]]
## [1] "2/27/2018" "6/26/2018" "12/31/2018" "1/20/2019" "4/8/2019"
X.dt<-setDT(X); X.dt
## V1 V2 V3 V4
## 1: 1 a Y 2/27/2018
## 2: 2 b Y 6/26/2018
## 3: 3 c N 12/31/2018
## 4: 4 d Y 1/20/2019
## 5: 5 e N 4/8/2019
請嘗試把`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
可以看到這筆資料有四個變數:艙等、性別、年齡、是否存活。 因為有四個陣列,所以我們取出其中一個表格時需要給定兩個條件,如果設定三個條件,就是一個向量,如果設定四個就是一個元素。 例如我們想知道沒有生還的兒童搭的艙等與性別,也就是第一個表格,可以這樣輸入:
T1<-Titanic[, , 1, 1]
class(T1); T1
## [1] "table"
## Sex
## Class Male Female
## 1st 0 0
## 2nd 0 0
## 3rd 35 17
## Crew 0 0
顯示沒有生還的兒童都是搭三等艙,男童為女童一倍。如果我們想知道艙等與生還的關係,可以先試著呈現:
Titanic[, 1, 1,]
## Survived
## Class No Yes
## 1st 0 5
## 2nd 0 11
## 3rd 35 13
## Crew 0 0
Titanic[, 1, 2,]
## Survived
## Class No Yes
## 1st 118 57
## 2nd 154 14
## 3rd 387 75
## Crew 670 192
Titanic[, 2, 1,]
## Survived
## Class No Yes
## 1st 0 1
## 2nd 0 13
## 3rd 17 14
## Crew 0 0
Titanic[, 2, 2,]
## Survived
## Class No Yes
## 1st 4 140
## 2nd 13 80
## 3rd 89 76
## Crew 3 20
資料表(data.table)是資料框的延伸,可以直接在資料中計算特定的列或是行。例如:
library(data.table)
DT = data.table(a = 1:3, b = c(10,20,30))
DT
## a b
## 1: 1 10
## 2: 2 20
## 3: 3 30
DT[1:3, sum(a)]
## [1] 6
DT[1:2, mean(b)]
## [1] 15
在創造一個資料表之後,先計算a變數的總和,然後算b變數前兩個值的平均。 也可以直接繪圖,例如我們先建立一個常態分佈的變數,然後畫出機率密度圖:
DT <-data.table(x=rnorm(1000, 0, 1))
DT[, plot(density(x), type='l', xlab='x', ylab='', lwd=3, col='lightblue')]
## NULL
資料表的功能非常多,相較於資料框來得複雜,不過這門課程主要用資料框來處理資料。對於資料表有興趣的同學可以參考該套件的網站。
資料框在各種資料結構之中,是最常被用到的。如果要把資料提出,最好把各種資料結構轉成資料框。例如我們想知道一筆資料的變數性質:
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的資料有幾筆?
請嘗試建立一個包含流水號序號、一個數字變數、一個類別變數的資料框或資料表。
請創造一個對角向量為{1,1,1}的矩陣
請用data.table計算Titanic男性與女性生還的人數。
請問faithful這筆資料有多少個觀察值?
請建立三個\(3\times 2\)的陣列
請把Arrests資料裡面的employed變數改成0, 1
請用三種格式表示今天的日期
請計算英文有幾個字母。
請寫一段語法把今天的氣溫轉換成華氏
請問在您寫作業的這一天,今年已經過了幾天?