操作向量

Doug: Remember, there’s no “I” in team. Chandler: Yes, but there’s two in martini, so everybody back to my office!

Friends

經過認識向量的簡介,我們得知在 R 語言的世界中的基本資料單位並不是多數程式語言的純量(scalar),而是以長度為 1 的向量(vector)作為基本資料單位。向量有許多特性值得留意,像是單一類型、可以判斷和轉換類型以及可以子集操作等。

向量是單一類型

向量只能被宣告為單一類型,舉例來說,如果我們將整數向量與數值向量合併起來,R 語言會自動將整數向量轉換為數值向量(因為整數包含於浮點數),最終將自動得到一個數值向量。

lucky_int <- 7L
lucky_num <- 24
lucky_numbers <- c(lucky_int, lucky_num)
class(lucky_int)
class(lucky_num)
lucky_numbers
class(lucky_numbers[1])
class(lucky_numbers[2])
1
2
3
4
5
6
7
8
## > lucky_int <- 7L
## > lucky_num <- 24
## > lucky_numbers <- c(lucky_int, lucky_num)
## > class(lucky_int)
## [1] "integer"
## > class(lucky_num)
## [1] "numeric"
## > lucky_numbers
## [1]  7 24
## > class(lucky_numbers[1])
## [1] "numeric"
## > class(lucky_numbers[2])
## [1] "numeric"
1
2
3
4
5
6
7
8
9
10
11
12
13

如果我們將邏輯值向量跟整數向量合併,R 語言會自動將邏輯值向量轉換為整數向量(因為邏輯值的 TRUE1LFALSE0L),最終將自動得到一個數值向量。


lucky_int <- 7L
logicals <- c(TRUE, FALSE)
lucky_integers <- c(lucky_int, logicals)
class(lucky_int)
class(logicals)
lucky_integers
class(lucky_integers[1])
class(lucky_integers[2])
class(lucky_integers[3])
1
2
3
4
5
6
7
8
9
10
## > lucky_int <- 7L
## > logicals <- c(TRUE, FALSE)
## > lucky_integers <- c(lucky_int, logicals)
## > class(lucky_int)
## [1] "integer"
## > class(logicals)
## [1] "logical"
## > lucky_integers
## [1] 7 1 0
## > class(lucky_integers[1])
## [1] "integer"
## > class(lucky_integers[2])
## [1] "integer"
## > class(lucky_integers[3])
## [1] "integer"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

假如是將邏輯值向量、整數向量、數值向量以及文字向量合併,R 語言會自動轉換為文字向量(任何的資料類型只要放入成對的單雙引號中都是文字)。

lucky_int <- 7L
lucky_num <- 24
logicals <- c(TRUE, FALSE)
char <- "Hello R"
mixed_vector <- c(lucky_int, lucky_num, logicals, char)
class(lucky_int)
class(lucky_num)
class(logicals)
class(char)
class(mixed_vector)
class(mixed_vector[1])
class(mixed_vector[2])
class(mixed_vector[3])
class(mixed_vector[4])
class(mixed_vector[5])
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
## > lucky_int <- 7L
## > lucky_num <- 24
## > logicals <- c(TRUE, FALSE)
## > char <- "Hello R"
## > mixed_vector <- c(lucky_int, lucky_num, logicals, char)
## > class(lucky_int)
## [1] "integer"
## > class(lucky_num)
## [1] "numeric"
## > class(logicals)
## [1] "logical"
## > class(char)
## [1] "character"
## > class(mixed_vector)
## [1] "character"
## > class(mixed_vector[1])
## [1] "character"
## > class(mixed_vector[2])
## [1] "character"
## > class(mixed_vector[3])
## [1] "character"
## > class(mixed_vector[4])
## [1] "character"
## > class(mixed_vector[5])
## [1] "character"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

向量可以判斷、轉換類型

R 語言針對向量類型的判斷除了使用 class() 函數能夠直截了當地告訴我們答案以外,也能夠使用一系列 is.向量類型() 函數回傳邏輯值向量,用 TRUEFALSE 將判斷的結果回傳;而變數類型的轉換則是透過一系列 as.向量類型() 函數進行轉換。

判斷向量類型

除了判斷日期向量與日期時間向量要使用的是 inherits() 函數,其他變數類型都可以使用 is.向量類型() 系列函數判斷。

  • is.numeric():判斷物件是否為數值向量類型
  • is.integer():判斷物件是否為整數向量類型
  • is.character():判斷物件是否為文字向量類型
  • is.logical():判斷物件是否為邏輯值向量類型
  • inherits(x, what = "Date"):判斷物件是否為日期向量類型
  • inherits(x, what = "POSIXct"):判斷物件是否為日期時間向量類型
# is.numeric()
is.numeric(87)
is.numeric("87")

# is.integer()
is.integer(87L)
is.integer(87)

# is.character()
is.character("TRUE")
is.character(TRUE)

# is.logical()
is.logical(FALSE)
is.logical("FALSE")

# inherits()
inherits(Sys.Date(), what = "Date") # Sys.Date() 是日期類型
inherits("1970-01-01", what = "Date") # "1970-01-01" 是文字類型
inherits(Sys.time(), what = "POSIXct") # Sys.time() 是時間類型
inherits("1970-01-01 00:00:00", what = "POSIXct") # "1970-01-01 00:00:00" 是文字類型
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
## > # is.numeric()
## > is.numeric(87)
## [1] TRUE
## > is.numeric("87")
## [1] FALSE
## > 
## > # is.integer()
## > is.integer(87L)
## [1] TRUE
## > is.integer(87)
## [1] FALSE
## > 
## > # is.character()
## > is.character("TRUE")
## [1] TRUE
## > is.character(TRUE)
## [1] FALSE
## > 
## > # is.logical()
## > is.logical(FALSE)
## [1] TRUE
## > is.logical("FALSE")
## [1] FALSE
## > 
## > # inherits()
## > inherits(Sys.Date(), what = "Date") # Sys.Date() 是日期類型
## [1] TRUE
## > inherits("1970-01-01", what = "Date") # "1970-01-01" 是文字類型
## [1] FALSE
## > inherits(Sys.time(), what = "POSIXct") # Sys.time() 是時間類型
## [1] TRUE
## > inherits("1970-01-01 00:00:00", what = "POSIXct") # "1970-01-01 00:00:00" 是文字類型
## [1] FALSE
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

轉換向量類型

使用 as.向量類型() 系列函數轉換。

  • as.numeric():轉換物件為數值向量類型
  • as.integer():轉換物件為整數向量類型
  • as.character():轉換物件為文字向量類型
  • as.logical():轉換物件為邏輯值向量類型
  • as.Date():轉換物件為日期向量類型
  • as.POSIXct():轉換物件為日期時間向量類型

使用 as.numeric() 函數轉換物件為數值向量,我們可以輸入整數向量、邏輯值向量、日期向量或日期時間向量讓 R 語言轉換成數值向量。

as.numeric(87L)
as.numeric(TRUE)
as.numeric(FALSE)
as.numeric(Sys.Date())
as.numeric(Sys.time())
1
2
3
4
5
## > as.numeric(87L)
## [1] 87
## > as.numeric(TRUE)
## [1] 1
## > as.numeric(FALSE)
## [1] 0
## > as.numeric(Sys.Date())
## [1] 17849
## > as.numeric(Sys.time())
## [1] 1542191349
1
2
3
4
5
6
7
8
9
10

使用 as.integer() 函數轉換物件為整數向量,我們可以輸入沒有小數位數的數值向量、邏輯值向量、日期向量或日期時間向量讓 R 語言轉換成整數向量。

as.integer(87)
as.integer(TRUE)
as.integer(FALSE)
as.integer(Sys.Date())
as.integer(Sys.time())
1
2
3
4
5
## > as.integer(87)
## [1] 87
## > as.integer(TRUE)
## [1] 1
## > as.integer(FALSE)
## [1] 0
## > as.integer(Sys.Date())
## [1] 17849
## > as.integer(Sys.time())
## [1] 1542191612
1
2
3
4
5
6
7
8
9
10

使用 as.logical() 函數轉換物件為邏輯值向量,輸入數值或整數類型的 0 會轉換成為 FALSE,其他數字則一律轉換為 TRUE

as.logical(0)
as.logical(0L)
as.logical(1L)
as.logical(-8.7)
as.logical(87)
1
2
3
4
5
## > as.logical(0)
## [1] FALSE
## > as.logical(0L)
## [1] FALSE
## > as.logical(1L)
## [1] TRUE
## > as.logical(-8.7)
## [1] TRUE
## > as.logical(87)
## [1] TRUE
1
2
3
4
5
6
7
8
9
10

輸入文字向量的 "TRUE""True""true" 會轉換為 TRUE 邏輯值向量,反之輸入文字向量的 "FALSE""False""false" 會轉換為 FALSE 邏輯值向量。

as.logical("TRUE")
as.logical("True")
as.logical("true")
as.logical("FALSE")
as.logical("False")
as.logical("false")
1
2
3
4
5
6
## > as.logical("TRUE")
## [1] TRUE
## > as.logical("True")
## [1] TRUE
## > as.logical("true")
## [1] TRUE
## > as.logical("FALSE")
## [1] FALSE
## > as.logical("False")
## [1] FALSE
## > as.logical("false")
## [1] FALSE
1
2
3
4
5
6
7
8
9
10
11
12

使用 as.character() 函數轉換物件為文字向量,我們可以輸入任意向量類型讓 R 語言將其轉換成文字向量。

as.character(8.7)
as.character(87L)
as.character(TRUE)
as.character(FALSE)
as.character(Sys.Date())
as.character(Sys.time())
1
2
3
4
5
6
## > as.character(8.7)
## [1] "8.7"
## > as.character(87L)
## [1] "87"
## > as.character(TRUE)
## [1] "TRUE"
## > as.character(FALSE)
## [1] "FALSE"
## > as.character(Sys.Date())
## [1] "2018-11-14"
## > as.character(Sys.time())
## [1] "2018-11-14 18:45:34"
1
2
3
4
5
6
7
8
9
10
11
12

使用 as.Date() 函數轉換物件為日期向量,我們可以輸入文字向量讓 R 語言轉換成日期向量。 as.Date() 函數預設可以識別 %Y-%m-%d%Y/%m/%d 這兩種格式。

as.Date("1970-01-01")
as.Date("1970/01/01")
1
2
## > as.Date("1970-01-01")
## [1] "1970-01-01"
## > as.Date("1970/01/01")
## [1] "1970-01-01"
1
2
3
4

如果是其他的格式,必須要加入 format 參數告知日期被記錄的文字向量格式為何,函數才能順利轉換,假如文字向量不是預設格式,而是將月與日的資訊寫在年份的前面,若沒有以 format 參數指定就會轉換成錯誤的日期向量:

as.Date("01-01-1970") # 轉換錯誤
as.Date("01-01-1970", format = "%m-%d-%Y") # 轉換正確
as.Date("01/01/70") # 不是預設格式,轉換失敗
as.Date("01/01/70", format = "%m/%d/%y") # 轉換正確
1
2
3
4
## > as.Date("01-01-1970") # 轉換錯誤
## [1] "0001-01-19"
## > as.Date("01-01-1970", format = "%m-%d-%Y") # 轉換正確
## [1] "1970-01-01"
## > as.Date("01/01/70") # 不是預設格式,轉換失敗
## Error in charToDate(x) : 
##   character string is not in a standard unambiguous format
## > as.Date("01/01/70", format = "%m/%d/%y") # 轉換正確
## [1] "1970-01-01"
1
2
3
4
5
6
7
8
9

使用 as.POSIXct() 函數轉換物件為日期時間向量,我們可以輸入文字向量讓 R 語言轉換成日期時間向量。如果沒有指定參數 tz 會預設使用電腦的時區。

as.POSIXct("1970-01-01 00:00:00")
as.POSIXct("1970-01-01 00:00:00", tz = "GMT")
1
2
## > as.POSIXct("1970-01-01 00:00:00")
## [1] "1970-01-01 CST"
## > as.POSIXct("1970-01-01 00:00:00", tz = "GMT")
## [1] "1970-01-01 GMT"
1
2
3
4

常用的文字對應日期時間格式(strptime)有:

  • %a:縮寫的星期幾,從 Sun 至 Sat
  • %A:全稱的星期幾,從 Sunday 至 Saturday
  • %b:縮寫的月份,從 Jan 至 Dec
  • %B:全稱的月份,從 January 至 December
  • %d:月份中的第幾天,從 01 至 31
  • %m:以兩位數字表示的月份,從 01 至 12
  • %Y:以四位數字表示的西元年份,從 0 至 9999
  • %H:以兩位數字表示的小時,從 00 至 23
  • %M:以兩位數字表示的分鐘,從 00 至 59
  • %S:以兩位數字表示的秒數,從 00 至 61

如何操作向量

對於長度超過 1 的向量我們亦能將其視作一種類似陣列(array)的資料結構,用來將多筆相關的資料對應於一個物件名稱,假使 R 語言允許這樣化零為整的創建,必然也能夠讓我們進行化整為零的子集(subsetting),有關於子集的操作技巧,又可細分為:

  • 索引(indexing)
  • 切割(slicing)
  • 邏輯篩選(logical filtering)

索引

我們可以利用 c() 函數創建一些文字向量與數值向量,就像將四季的名稱宣告為一個長度為 4 的文字向量,好比將 4 個長度為 1 的文字向量再放置於有四個格子的抽屜中;將喜歡的數字宣告為一個長度為 5 的數值向量,好比將 5 個長度為 1 的數值向量再放置於有五個格子的抽屜中。使用 R 語言內建函數 length() 函數能夠得知向量的資料個數(長度)。

four_seasons <- c("spring", "summer", "autumn", "winter")
lucky_numbers <- c(7, 13, 24, 34, 87)
four_seasons
length(four_seasons)
lucky_numbers
length(lucky_numbers)
1
2
3
4
5
6
## > four_seasons <- c("spring", "summer", "autumn", "winter")
## > lucky_numbers <- c(7, 13, 24, 34, 87)
## > four_seasons
## [1] "spring" "summer" "autumn" "winter"
## > length(four_seasons)
## [1] 4
## > lucky_numbers
## [1]  7 13 24 34 87
## > length(lucky_numbers)
## [1] 5
1
2
3
4
5
6
7
8
9
10

向量像是有格子的抽屜,每個格子上面都有一個索引值,方便 R 語言搜尋放在裡頭的資料,這個索引值從左邊由 1 起始計算。假如我們最喜歡的季節是秋天,可以使用 four_seasons[3] 選出秋天。

four_seasons <- c("spring", "summer", "autumn", "winter")
msg <- sprintf("My favorite season is %s.", four_seasons[3])
msg
1
2
3
## > four_seasons <- c("spring", "summer", "autumn", "winter")
## > msg <- sprintf("My favorite season is %s.", four_seasons[3])
## > msg
## [1] "My favorite season is autumn."
1
2
3
4

或者我們認為夏天太熱、冬天太冷,不要放在喜歡的季節中,可以使用負面表列的索引方式 four_seasons[c(-2, -4)]

four_seasons <- c("spring", "summer", "autumn", "winter")
favorite_seasons <- four_seasons[c(-2, -4)]
favorite_seasons
1
2
3
## > four_seasons <- c("spring", "summer", "autumn", "winter")
## > favorite_seasons <- four_seasons[c(-2, -4)]
## > favorite_seasons
## [1] "spring" "autumn"
1
2
3
4

切割

一如索引,可以在中括號輸入一組數值向量指定要切割出來的部分向量內容為何,可以使用 c() 函數、seq() 函數或 : 符號建立,通常使用 : 符號。延續長度為 4 紀錄季節名稱的文字向量,可以使用 four_seasons[1:3] 選出春天、夏天與秋天;亦可以使用 four_seasons[2:4] 選出夏天、秋天與冬天。

four_seasons <- c("spring", "summer", "autumn", "winter")
four_seasons[1:3]
four_seasons[2:4]
1
2
3
## > four_seasons <- c("spring", "summer", "autumn", "winter")
## > four_seasons[1:3]
## [1] "spring" "summer" "autumn"
## > four_seasons[2:4]
## [1] "summer" "autumn" "winter"
1
2
3
4
5

值得注意的是,如果需要切割一個長度不固定向量中的倒數 N 筆資料,應當養成以 length() 函數標註最後一個索引位置的良好習慣,而非將索引值以固定數字代入。

four_seasons <- c("spring", "summer", "autumn", "winter")
# This is better than four_seasons[2:4]
four_seasons[2:length(four_seasons)]
1
2
3
## > four_seasons <- c("spring", "summer", "autumn", "winter")
## > # This is better than four_seasons[2:4]
## > four_seasons[2:length(four_seasons)]
## [1] "summer" "autumn" "winter"
1
2
3
4

邏輯篩選

除了直接使用資料在向量中的索引值,以索引或切割方式選出子集,亦可以對向量應用判斷條件,進而產生邏輯值向量然後對原向量進行篩選,保留判斷結果為 TRUE 的資料。

four_seasons <- c("spring", "summer", "autumn", "winter")
favorite_season <- four_seasons == "autumn"
favorite_season
four_seasons[favorite_season]
1
2
3
4
## > four_seasons <- c("spring", "summer", "autumn", "winter")
## > favorite_season <- four_seasons == "autumn"
## > favorite_season
## [1] FALSE FALSE  TRUE FALSE
## > four_seasons[favorite_season]
## [1] "autumn"
1
2
3
4
5
6

如果不只一個條件,我們可以使用 & 以及 | 這兩個符號連結判斷條件,其中 & 唸作 AND 將判斷條件取交集、 | 唸作 OR 將判斷條件取聯集。

four_seasons <- c("spring", "summer", "autumn", "winter")
favorite_seasons <- four_seasons == "spring" | four_seasons == "autumn" # 喜歡春天或秋天
favorite_seasons
four_seasons[favorite_seasons]
1
2
3
4
## > four_seasons <- c("spring", "summer", "autumn", "winter")
## > favorite_seasons <- four_seasons == "spring" | four_seasons == "autumn" # 喜歡春天或秋天
## > favorite_seasons
## [1]  TRUE FALSE  TRUE FALSE
## > four_seasons[favorite_seasons]
## [1] "spring" "autumn"
1
2
3
4
5
6

小結

在這個小節中我們簡介 R 語言中的向量是單一類型、如何判斷和轉換向量類型以及使用索引、切割與邏輯值篩選對向量進行子集操作。

練習

  • 我們有一個文字向量 weekdays 是一週的星期一到星期五,請您將最喜歡的週五(Happy Friday)從這個向量中用索引值選出來並且指派給 favorite_day
weekdays <- c("Monday", "Tuesday", "Wednesday", "Thursday", "Friday")
favorite_day <- weekdays[___]
favorite_day
1
2
3
  • 同樣的文字向量,請您利用判斷運算子將最藍的週一(Blue Monday)從這個向量中剔除後將剩餘的日子指派給 without_monday
weekdays <- c("Monday", "Tuesday", "Wednesday", "Thursday", "Friday")
not_blue_monday <- weekdays != "Monday"
without_monday <- weekdays[___]
without_monday
1
2
3
4

延伸閱讀