8 精簡的變數型別
8.1 暸解不同的變數型別
| 變數型別 | 變數型別英文 | 範例 |
|---|---|---|
| 數值 | numeric | 2 |
| 整數 | integer | 2L |
| 邏輯值 | logical | TRUE |
| 文字 | character | “Learning R the easy way” |
| 日期 | Date | Sys.Date() |
| 時間 | POSIXct POSIXt | Sys.time() |
我們不需要自己去猜測,可以使用一個函數 class() 讓 R 語言告訴我們輸入的變數是什麼型別,就像在 RStudio 的左下角命令列(Console)輸入這些程式,詢問 R 語言它們的型別為何?
class(2)## [1] "numeric"
class(2L)## [1] "integer"
class(TRUE)## [1] "logical"
class("Learning R the easy way")## [1] "character"
class(Sys.Date())## [1] "Date"
class(Sys.time())## [1] "POSIXct" "POSIXt"
如果您對 class() 這個函數感到好奇,可以在命令列輸入 ?class 或者 help(class),這兩個指令都會在右下角打開文件。即便您對 class() 不甚感興趣,知道如何使用 ? 或 help() 進行查詢也相當有幫助。

8.2 數值
不論我們輸入的數字帶有小數位數或不帶有小數位數,R 語言預設儲存為數值(numeric)。
my_num <- 2.33
class(my_num)## [1] "numeric"
my_num <- 2.0
class(my_num)## [1] "numeric"
my_num <- 2
class(my_num)## [1] "numeric"
8.3 整數
當我們輸入一個整數並加入 L,R 語言就會儲存為整數(integer)。如果整數帶有不必要的小數位數,R 語言會回傳警示訊息但依舊會儲存為整數;但若在帶有小數位數的數字後加上 L 則 R 語言回傳警示訊息,並且忽略 L 儲存為數值。
my_int <- 2L
class(my_int)## [1] "integer"
my_int <- 2.0L
class(my_int)## [1] "integer"
my_int <- 2.33L
class(my_int)## [1] "numeric"
8.4 邏輯值
當我們進行判斷條件或者篩選的時候就會需要使用邏輯值(logical),邏輯值只有 TRUE 與 FALSE 這兩個值,或者可以簡寫為 T 與 F。
class(TRUE)## [1] "logical"
class(FALSE)## [1] "logical"
class(T)## [1] "logical"
class(F)## [1] "logical"
這裡要提醒您一個觀念,R 語言對大小寫是敏感的(case-sensitive),像是 TRUE 會被 R 語言識別為邏輯值,但是 True 與 true 則不會喔!
class(TRUE)## [1] "logical"
class(True)## Error in eval(expr, envir, enclos): object 'True' not found
class(true)## Error in eval(expr, envir, enclos): object 'true' not found
除了直接輸入邏輯值,我們也可以透過判斷條件得到邏輯值的輸出:
8 > 7 # 判斷 8 是否大於 7## [1] TRUE
8 < 7 # 判斷 8 是否小於 7## [1] FALSE
8 >= 7 # 判斷 8 是否大於等於 7## [1] TRUE
8 <= 7 # 判斷 8 是否小於等於 7## [1] FALSE
8 == 7 # 判斷 8 是否等於 7## [1] FALSE
8 != 7 # 判斷 8 是否不等於 7## [1] TRUE
7 %in% c(8, 7) # 判斷 7 是否包含於一個 c(8, 7) 的向量之中## [1] TRUE
我們稍微停頓一下,因為這裡有兩個新觀念需要您花點時間吸收:
c(8, 7)是一種叫做向量的資料結構,我們會在之後的章節細談- 常用的判斷運算子有:
| 判斷運算子 | 作用 |
|---|---|
== |
等於 |
> |
大於 |
< |
小於 |
>= |
大於等於 |
<= |
小於等於 |
!= |
不等於 |
%in% |
包含於 |
8.5 文字
在 R 語言中我們可以使用單引號(’)或雙引號(“)來建立文字(character),我的習慣是使用雙引號(”),所以在本書中的範例都會使用 " 來建立文字。
first_name <- 'Tony'
first_name## [1] "Tony"
class(first_name)## [1] "character"
8.5.1 日期
在 R 語言中被定義為日期(Date)的變數外觀看起來跟文字沒有什麼差別,但是我們一但將它們放入 class() 函數中檢驗,就會發現它並不是文字,我們接下來要使用的 Sys.Date() 是一個不需要任何輸入就會輸出電腦系統日期的函數。
sys_date <- Sys.Date() # 系統日期
sys_date # 看起來跟文字相同## [1] "2018-05-12"
class(sys_date)## [1] "Date"
而這兩個變數類型最大的分野,就在於日期是可以被轉換為整數,而文字是不行的:
sys_date <- Sys.Date()
sys_date_char <- as.character(sys_date) # 創造一個文字類型
as.integer(sys_date)## [1] 17663
as.integer(sys_date_char)## Warning: NAs introduced by coercion
## [1] NA
這裡我們使用的 as.character() 與 as.integer() 函數是 R 語言中用來進行變數類型轉換的函數,我們可以清楚文字類型的系統日期在轉換整數時失敗,以致於產生一個遺失值(Not Available,NA)。
那麼日期類型的系統日期轉換的整數是有什麼根據嗎?答案是有的,R 語言預設以西元 1970 年 1 月 1 日作為 0,在這一天以後的每天都 +1 來記錄,而這一天以前的每天都 -1 來記錄。
date_of_origin <- as.Date("1970-01-01")
as.integer(date_of_origin)## [1] 0
as.integer(date_of_origin + 1)## [1] 1
as.integer(date_of_origin - 1)## [1] -1
date_of_origin## [1] "1970-01-01"
date_of_origin + 1## [1] "1970-01-02"
date_of_origin - 1## [1] "1969-12-31"
也因為這樣的特性,日期類型可以進行四則運算,而文字類型不行:
sys_date <- Sys.Date()
sys_date_char <- as.character(sys_date) # 創造一個文字類型
sys_date - 1 # 昨天的日期## [1] "2018-05-11"
sys_date_char - 1## Error in sys_date_char - 1: non-numeric argument to binary operator
8.6 時間
在 R 語言中被定義為時間(POSIXct POSIXt)的變數外觀看起來跟文字同樣也沒有什麼差別,但是我們一但將它們放入 class() 函數中檢驗,就會發現它並不是文字,我們接下來要使用的 Sys.time() 是一個不需要任何輸入就會輸出電腦系統時間的函數。
sys_time <- Sys.time() # 系統時間
sys_time # 看起來跟文字相同## [1] "2018-05-12 01:37:53 UTC"
class(sys_time)## [1] "POSIXct" "POSIXt"
與日期相似,時間亦是可以被轉換為整數的:
sys_time <- Sys.time()
as.integer(sys_time)## [1] 1526089073
與日期相似,R 語言預設以西元 1970 年 1 月 1 日格林威治標準時間(Greenwich Mean Time,GMT)00 時 00 分 00 秒作為 0,在這個時間點以後的每秒都 +1 來記錄,這個時間點以前的每秒都 -1 來記錄。
time_of_origin <- as.POSIXct("1970-01-01 00:00:00", tz = "GMT")
as.integer(time_of_origin)## [1] 0
as.integer(time_of_origin + 1)## [1] 1
as.integer(time_of_origin - 1)## [1] -1
time_of_origin## [1] "1970-01-01 GMT"
time_of_origin + 1## [1] "1970-01-01 00:00:01 GMT"
time_of_origin - 1## [1] "1969-12-31 23:59:59 GMT"
我們這裡所使用的參數 tz = "GMT" 是指定時區,假如您的電腦和我一樣時區是設在中原標準時間(Chungyuan Standard Time,CST),早格林威治標準時間八個小時(GMT + 8),則基準時間會是西元 1970 年 1 月 1 日 08 時 00 分 00 秒。
time_of_origin_cst <- as.POSIXct("1970-01-01 08:00:00")
as.integer(time_of_origin_cst)## [1] 28800
8.7 數學運算
對數值,整數與邏輯值進行數學運算,常用的數學運算子有七種:
| 數學運算子 | 作用 |
|---|---|
+ |
加 |
- |
減 |
* |
乘 |
/ |
除 |
^ 或 ** |
次方 |
%/% |
回傳商數 |
%% |
回傳餘數 |
我們先進行僅有數值的運算:
first_num <- 8
second_num <- 7
first_num + second_num## [1] 15
first_num - second_num## [1] 1
first_num * second_num## [1] 56
first_num / second_num## [1] 1.142857
first_num^second_num## [1] 2097152
first_num**second_num## [1] 2097152
first_num %% second_num## [1] 1
first_num %/% second_num## [1] 1
接著我們進行僅有整數的運算:
first_int <- 8L
second_int <- 7L
ans <- first_int * second_int
ans## [1] 56
class(ans)## [1] "integer"
ans <- first_int / second_int
ans## [1] 1.142857
class(ans)## [1] "numeric"
相乘之後仍然是整數的變數型別,注意相除之後 R 語言自動幫我們把答案轉換成了適當型別,我們時不時都可以觀察到 R 語言的彈性:
my_num <- 8
my_int <- 7L
ans <- my_num + my_int
class(ans)## [1] "numeric"
最後我們把邏輯值也放進來做四則運算,看看會發生什麼事情:
my_num <- 8
my_int <- 7L
my_logi <- TRUE
ans <- my_num + my_int + my_logi
ans## [1] 16
class(ans)## [1] "numeric"
my_logi <- FALSE
ans <- my_num + my_int + my_logi
ans## [1] 15
class(ans)## [1] "numeric"
為什麼 TRUE 和 FALSE 納入四則運算沒有任何問題呢?原來在 R 語言中,TRUE 跟 1 或者 1L 是相等的;FALSE 跟 0 或者 0L 是相等的。
my_num <- 0
my_int <- 0L
my_logi <- FALSE
my_num == my_logi## [1] TRUE
my_int == my_logi## [1] TRUE
my_num <- 1
my_int <- 1L
my_logi <- TRUE
my_num == my_logi## [1] TRUE
my_int == my_logi## [1] TRUE
8.8 變數型別的判斷與轉換
R 語言針對變數型別的判斷除了使用 class() 函數直截了當告訴我們答案以外,也能夠使用一系列 is.型別名稱() 的函數回傳邏輯值,用 TRUE 或者 FALSE 回傳判斷的結果;而變數型別的轉換則是透過一系列 as.型別名稱() 的函數進行轉換。
8.8.1 變數型別的判斷
除了判斷日期與時間變數型別要使用的是 inherits() 函數,其他都可以使用 is.型別名稱()這樣形式的函數判斷。
| 函數 | 範例 |
|---|---|
is.numeric() |
is.numeric(7.7) |
is.integer() |
is.integer(7L) |
is.logical() |
is.logical(FALSE) |
is.character() |
is.character("Learn R the easy way") |
inherits(x, what = "Date") |
inherits(Sys.Date(), what = "Date") |
inherits(x, what = "POSIXct") |
inherits(Sys.time(), what = "POSIXct") |
8.8.1.1 判斷是否為數值
使用 is.numeric() 函數請 R 語言判斷這個變數是不是數值。
is.numeric(8.7)## [1] TRUE
is.numeric("8.7")## [1] FALSE
8.8.1.2 判斷是否為整數
使用 is.integer() 函數請 R 語言判斷這個變數是不是整數。
is.integer(7L)## [1] TRUE
is.integer(7)## [1] FALSE
8.8.1.3 判斷是否為邏輯值
使用 is.logical() 函數請 R 語言判斷這個變數是不是邏輯值。
is.logical(FALSE)## [1] TRUE
is.logical("FALSE")## [1] FALSE
8.8.1.4 判斷是否為文字
使用 is.character() 函數請 R 語言判斷這個變數是不是文字。
is.character("TRUE")## [1] TRUE
is.character(TRUE)## [1] FALSE
8.8.1.5 判斷是否為日期
使用 inherit(x, what = "Date") 函數請 R 語言判斷這個變數 x 是不是日期,Sys.Date() 是一個 Date 的型別,因此 inherit(Sys.Date(), what = "Date") 函數會回傳 TRUE;而 "1970-01-01" 是一個 Character 的型別,inherit("1970-01-01", what = "Date") 函數會回傳 FALSE。
inherits(Sys.Date(), what = "Date") # Sys.Date() 是日期型別## [1] TRUE
inherits("1970-01-01", what = "Date") # "1970-01-01" 是文字型別## [1] FALSE
8.8.1.6 判斷是否為時間
使用 inherit(x, what = "POSIXct") 函數請 R 語言判斷這個變數 x 是不是時間,Sys.time() 是一個 POSIXct 的型別,因此 inherit(Sys.time(), what = "POSIXct") 函數會回傳 TRUE;而 "1970-01-01 00:00:00" 是一個 Character 的型別,inherit("1970-01-01 00:00:00", what = "POSIXct") 函數會回傳 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
8.8.2 變數型別的轉換
使用 as.型別名稱() 這樣形式的函數進行轉換。
| 函數 | 範例 |
|---|---|
as.numeric() |
as.numeric(7L) |
as.integer() |
as.integer(7) |
as.logical() |
as.logical("TRUE") |
as.character() |
as.character(Sys.Date()) |
as.Date() |
as.Date("1970-01-01") |
as.POSIXct() |
as.POSIXct("1970-01-01 00:00:00", tz = "GMT") |
8.8.2.1 轉換成數值
使用 as.numeric() 函數轉換變數為數值型別,我們可以輸入整數、邏輯值、日期或時間讓 R 語言轉換成數值。
as.numeric(7L)## [1] 7
as.numeric(TRUE)## [1] 1
as.numeric(FALSE)## [1] 0
as.numeric(Sys.Date())## [1] 17663
as.numeric(Sys.time())## [1] 1526089073
8.8.2.2 轉換成整數
使用 as.integer() 函數轉換變數為數值型別,我們可以輸入沒有小數位數的數值、邏輯值、日期或時間讓 R 語言轉換成整數。
as.integer(7)## [1] 7
as.integer(TRUE)## [1] 1
as.integer(FALSE)## [1] 0
as.integer(Sys.Date())## [1] 17663
as.integer(Sys.time())## [1] 1526089073
8.8.2.3 轉換成邏輯值
使用 as.logical() 函數轉換變數為邏輯值型別,輸入數值或整數型別的 0 會轉換成為 FALSE,其他的數字則一律轉換為 TRUE。
as.logical(0)## [1] FALSE
as.logical(0L)## [1] FALSE
as.logical(1L)## [1] TRUE
as.logical(-1.3)## [1] TRUE
as.logical(87)## [1] TRUE
輸入文字型別的 "TRUE"、"True" 或 "true" 則會轉換成為 TRUE,反之亦同。
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
8.8.2.4 轉換成文字
使用 as.character() 函數轉換變數為文字型別,我們可以輸入任意的變數型別讓 R 語言轉換成文字。
as.character(8.7)## [1] "8.7"
as.character(87L)## [1] "87"
as.character(TRUE)## [1] "TRUE"
as.character(Sys.Date())## [1] "2018-05-12"
as.character(Sys.time())## [1] "2018-05-12 01:37:53"
8.8.2.5 轉換成日期
使用 as.Date() 函數轉換變數為日期型別,我們可以輸入文字讓 R 語言轉換成日期。as.Date() 函數預設可以識別 %Y-%m-%d 或 %Y/%m/%d 這兩種格式。
as.Date("1970-01-01")## [1] "1970-01-01"
as.Date("1970/01/01")## [1] "1970-01-01"
如果是其他的格式,必須要加入 format 參數告知日期被記錄的文字格式為何,函數才能順利轉換,例如文字不是預設的格式,而是將月與日的資訊寫在年份的前面,沒有以 format 參數指定就會轉換成錯誤的日期:
as.Date("01-01-1970") # 轉換錯誤## [1] "1-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"
不同符號所代表的格式整理在下表:
| 符號 | 格式 | 範例 |
|---|---|---|
| %d | 日 | 01 |
| %a | 禮拜幾的縮寫 | Mon |
| %A | 禮拜幾 | Monday |
| %m | 月 | 01 |
| %b | 月名稱的縮寫 | Jan |
| %B | 月名稱 | January |
| %y | 兩位數的年 | 70 |
| %Y | 四位數的年 | 1970 |
想查詢更多的格式,可以在 R Console 輸入 ?strptime。
8.8.2.6 轉換成時間
使用 as.POSIXct() 函數轉換變數為時間型別,我們可以輸入文字讓 R 語言轉換成時間。如果沒有指定參數 tz =會預設使用電腦的時區。
as.POSIXct("1970-01-01 00:00:00")## [1] "1970-01-01 UTC"
as.POSIXct("1970-01-01 00:00:00", tz = "GMT")## [1] "1970-01-01 GMT"