第 6 章 Vectors

6.1 參考資料

RDS, chapter 20

6.2 Two types of vectors

R裡的Vectors有兩大類:

  1. Atomic vectors: 向量內的每個元素有相同的type, 均為numeric,均為character,均為logical等等,可使用的type有logical, integer, double, character, complex, and raw.
  • 使用c( )將元素包起來。
  1. Lists: 向量內的每個元素不需要有相同type,每個元素可以是不同長度的向量。
  • 使用list( )將元素包起來。

Atomic vector範例

a<-c(1:3)
typeof(a)
a

c(1:3)或只寫1:3會產生c(1,2,3)`的數值向量,因此a有3個元素,每個都是數值,其值分別是1,2,3。

每個元素我們可以用name=value的型式對它命名:

aWithNames <- c(
  a1=1,
  a2=2,
  a3=3
)
typeof(a)
aWithNames

List範例

b1<-list("a","b",c(1:10))
typeof(b1)

b1有三個元素:

  • 第一個:“a”

  • 第二個:“b”

  • 第三個:c(1,2,3,…,10) (由1:10產生的1至10的數值向量)

使用name=value命名及定義內容值:

b2<-list(
  第一個="a",
  第二個="b",
  第三個=c(1:10))
b1
b2

6.3 Recursive objects

list元素可以是list,所以它的架構可以不停留在一個層次而可不斷加深,稱之為Recursive object,例如:

studentRecord <-
  list(
    學號="410073058",
    姓名="王小明",
    性別="男",
    學年平均成績=list(
      一年級=88,
      二年級=90.3,
      三年級=92,
      四年級=95
    )
  )

studentRecord

6.4 Object extraction

有時我們只想取出vector裡的某個元素,以下面的list vector為例:

plasticContainer <- list(
  greenBox=c("paper","scissor"),     # location 1
  redBox=c(1,3,2.5),               # location 2
  blueBox=c(TRUE,FALSE,TRUE,TRUE)    # location 3
)

它有三個元素:greenBox, redBox, blueBox;各別在位置順序是1,2,3。

另外:

  • greenBox: 有二個沒命名的元素

  • redBox: 有三個沒命名的元素

  • blueBox: 有四個沒命名的元素

以下面的成績單物件為例:

成績單 <- c(
  個經=90,
  總經=77,
  統計=88
)

它是什麼樣的vector? 各別元素是什麼?位置為?

6.4.1 [[.]] extraction

[[.]]用來取出所要的「一個」元素:

  • 若元素有命名,.可用"元素名稱"

  • 否則,也可以用元素位置數字

取出greenBox這個元素:

plasticContainer[["greenBox"]] 
plasticContainer[[1]]

greenBox包含兩個元素:paper, scissor。如果上面要取出paper,要怎麼延伸拿取?

該元素沒命名,只能用數字。

方法一:

x <- plasticContainer[["greenBox"]] 
x[[1]]
方法二:

所有extraction操作均可直接串接。

plasticContainer[["greenBox"]][[1]]

請取出前面成績單物件的個經元素。

針對studentRecord物件:

  1. 請取出姓名元素。

  2. 請取出三年級學年平均成績

6.4.2 [.] extraction

[.]用來取出所要的「一群」元素:

  • 若元素有命名,.可用c("元素名稱1","元素名稱2",...)

  • 否則,也可以用元素位置數字, 如c(2,4)代表第2及第4個元素。

同時取出greenBox及redBox兩個元素:

plasticContainer[c("greenBox","redBox")] 
plasticContainer[c(1,2)]

要留意[.]所取出的物群會以母層vector結構保存。以plasticContainer[c(1,2)]為例,取出的物群來自一個為list vector結構的母層,所以它也會是個list vector,也就是說它相當於以下的list vector:

list(
  greenBox=c("paper","scissor"),
  redBox=c(1,3,2.5)
)

對照一下源頭母層的定義會更清楚:

plasticContainer <- list(
  greenBox=c("paper","scissor"),
  redBox=c(1,3,2.5),  
  blueBox=c(TRUE,FALSE,TRUE,TRUE) 
)

[.]是用來取出一群元素,當然一群的個數也可以是一個,然而以[.][[.]]一個元素的結果會有一些不同。以下兩者取出來的結果其class為什麼?

extract1 <- plasticContainer[c("greenBox")]

extract2 <- plasticContainer[[c("greenBox")]]

請各自由extract1及extract2取出“paper”元素值。

另一個[.] extraction可以接受的是使用logical vector來對應「個別」元素要(TRUE)/不要(FALSE)取出來;由於是對應「個別」元素,所以logical vector長度要和物件內元素個數一樣。

length(plasticContainer)
plasticContainer[c(T,F,T)]
成績單
成績單[c(FALSE,TRUE,TRUE)]

若確定只要取「一個」元素,建議用[[.]];後續程式寫作比較不會出現錯誤。

6.4.3 $. extraction

$.:

  • 只能用在list vector,且

  • 只能取「一個」元素,其中

  • .一定為「元素名稱」。

以下兩者相同:

plasticContainer$greenBox
plasticContainer[["greenBox"]]

6.4.4 範例:Github commit記錄

這個範例必需先安裝httr, stringr套件

your_github_username <- "tpemartin"
your_practice_reponame <- "107-2-inclass-practice"
library(httr)
library(stringr)
str_replace_all(
  "https://api.github.com/repos/:owner/:repo/commits",
  c(
    ":owner"=your_github_username,
    ":repo"=your_practice_reponame
    )
  ) -> commitCheckStatement
commitCheck <- content(GET(commitCheckStatement))

commitCheck是個list vector,裡面每個元素(沒命名)各自代表一次commit紀錄。請取出第4個commit紀錄的commit時間(為UTC time),並轉成台灣時間。

有一種date time格式如“2019-04-10T14:38:45Z”,它是ISO8601標準下的一種寫法,其中Z表示此格式為UTC時間——許多國際性的公司如Google, GitHub等都是用ISO8601格式在記錄日期時間。

6.4.5 範例:Plotly

請先安裝plotly

install.packages("plotly")

下載繪圖成品(源自:https://plot.ly/~neda/4070

download.file("https://github.com/tpemartin/github-data/blob/master/plotly_4070_neda.Rda?raw=true",destfile = "plotly_4070_neda.Rda")
load("plotly_4070_neda.Rda")
library(plotly)
plotly_4070_neda
plotly_4070_neda$x$layout$shapes[[1]]$opacity<-0.8
plotly_4070_neda

6.4.6 範例:str_split

第三屆經濟播客競賽人氣投票結果在以下的favoriteTwo物件裡

library(readr)
filmVotingData <- read_csv("https://raw.githubusercontent.com/tpemartin/github-data/master/podcastcompetition3.csv")
str_replace(filmVotingData$請選擇你最喜歡的影片二部,", by"," by") -> favoriteTwo
birthday <- filmVotingData$`出生西元年月日(驗證本人用)`
timeStamp <- filmVotingData$Timestamp
  • favoriteTwo的每個元素是一位同學選出的兩部片片名,中間用逗號空一格分隔,即,

  • birthday是出生日期。

  • timeStamp是交作業時間

library(stringr)
str_split(favoriteTwo,", ") -> favoriteTwoList # 將選擇的兩片split成兩個元素
unlist(favoriteTwoList) -> allVotes # 將list堆疊成atomic vector
table(allVotes) # 計算每個類別的次數
  • birthday只能有8位元,str_length()可計算每個元素的位元長度。請產生一個logical vector稱為logiCorrect,TRUE表示剛好8位元。

  • 只留下birthday輸入正確的人,請統計各別片名支持人數。

  • 若只留下凌晨1點(含)到早上5點(含)的投票人,他們的出生年份統計為何。