“Học cho rộng, hỏi cho kỹ, nghĩ cho cẩn thận, phân biệt cho rõ, làm cho hết sức.”
Khổng Tử

Một vài giá trị đặc biệt

Khi một số quá lớn mà R không thể hiện thị thì nó được coi là vô cùng (infinite). Giá trị vô cùng trong R được ký hiệu là Inf và nó được xem là số không phải chuỗi ký tự.

a <- Inf
a
## [1] Inf
b <- c(3401, Inf, 3.1, -555, Inf, 43)
b
## [1] 3401.0    Inf    3.1 -555.0    Inf   43.0
a <- 90000^100
a
## [1] Inf
b <- c(-42,565,-Inf,-Inf,Inf,-45632.3)
b
## [1]    -42.0    565.0     -Inf     -Inf      Inf -45632.3

Chúng ta có thể thực hiện phép toán với Inf.

Inf*-9
## [1] -Inf
Inf+1
## [1] Inf
4*-Inf
## [1] -Inf
-45.2-Inf
## [1] -Inf
Inf-45.2
## [1] Inf
Inf+Inf
## [1] Inf
Inf/23
## [1] Inf
-59/Inf
## [1] 0
-59/-Inf
## [1] 0
-59/0
## [1] -Inf
59/0
## [1] Inf
Inf/0
## [1] Inf

Chúng ta có thể dùng hàm is.infinite()is.finite() để kiểm tra dữ liệu có chứa giá trị vô cùng hay không.

b
## [1]    -42.0    565.0     -Inf     -Inf      Inf -45632.3
is.infinite(b)
## [1] FALSE FALSE  TRUE  TRUE  TRUE FALSE
is.finite(b)
## [1]  TRUE  TRUE FALSE FALSE FALSE  TRUE

Một vài trường hợp tính toán với Inf dẫn đến kết quả không xác định. Lúc đó R sẽ hiển thị NaN (Not a Number).

-Inf+Inf
## [1] NaN
Inf/Inf
## [1] NaN
0/0
## [1] NaN
NaN+1
## [1] NaN
2+6*(4-4)/0
## [1] NaN
3.5^(-Inf/Inf)
## [1] NaN

Để kiểm tra dữ liệu có chứa NaN hay không chúng ta dùng hàm is.nan().

a <- c(NaN,54.3,-2,NaN,90094.123,-Inf,55)
is.nan(a)
## [1]  TRUE FALSE FALSE  TRUE FALSE FALSE FALSE
!is.nan(a)
## [1] FALSE  TRUE  TRUE FALSE  TRUE  TRUE  TRUE
a[-(which(is.nan(a)|is.infinite(a)))]
## [1]    54.30    -2.00 90094.12    55.00

Bài tập 6.1.

  1. Tạo vectơ: vec <- c(13563,-14156,-14319,16981,12921,11979,9568,8833,-12968, 8133). Sau đó hãy thực hiện:
    1. Trích các phần tử của vec mà mũ \(75\) không phải là vô cùng (Inf).
    2. Trích các phần tử của vec mà mũ \(75\) không phải là âm vô cùng (-Inf).
  2. Tạo và đặt tên ma trận \(3\times 4\) sau là mat. \[\begin{equation*} \left[\begin{array}{cccc} 77875.40 & 27551.45 & 23764.30 & -36478.88 \\ -35466.25 & -73333.85 & 36599.69 & -70585.69 \\ -39803.81 & 55976.34 & 76694.82 & 47032.00 \end{array}\right] \end{equation*}\] Sau đó hãy thực hiện:
    1. Xác định chỉ số dòng cột của phần tử của mat mà mũ 65 và chia cho InfNaN.
    2. Xuất các phần tử của mat không phải NaN sau khi mũ 67 và cộng Inf.
    3. Xác định các phần tử của mat có giá trị âm vô cùng hoặc hữu hạn khi mũ 67.

Các tập dữ liệu trong thống kê thường chứa giá trị khuyết (missing value). Trong R giá trị khuyết thường được ký hiệu là NA (Not Available).

chac <- c("character", "a", NA, "with", "string", NA)
chac
## [1] "character" "a"         NA          "with"      "string"    NA
fac <- factor(c("blue", NA, NA, "blue", "green", "blue", NA, "red", "red", NA, "green"))
fac
##  [1] blue  <NA>  <NA>  blue  green blue  <NA>  red   red   <NA>  green
## Levels: blue green red
mat <- matrix(c(1:3, NA, 5, 6, NA, 8, NA), nrow = 3, ncol = 3)
mat 
##      [,1] [,2] [,3]
## [1,]    1   NA   NA
## [2,]    2    5    8
## [3,]    3    6   NA

Để kiểm tra dữ liệu có chứa NA chúng ta dùng hàm is.na().

vec <- c(NA, 5.89, Inf, NA, 9.43, -2.35, NaN, 2.10, -8.53, -7.58, NA, -4.58, 2.01, NaN)
vec
##  [1]    NA  5.89   Inf    NA  9.43 -2.35   NaN  2.10 -8.53 -7.58    NA -4.58
## [13]  2.01   NaN
is.na(vec)
##  [1]  TRUE FALSE FALSE  TRUE FALSE FALSE  TRUE FALSE FALSE FALSE  TRUE FALSE
## [13] FALSE  TRUE

Lưu ý: hàm is.na() xem NaN như là NA. Do đó để phân biệt NaN chúng ta phải dùng hàm is.nan().

which(is.nan(vec))
## [1]  7 14
which(is.na(vec)&!is.nan(vec))
## [1]  1  4 11

Để loại bỏ giá trị khuyết khỏi tập dữ liệu chúng ta dùng hàm na.omit(). Lưu ý rằng NaN cũng được loại bỏ.

na.omit(vec)
## [1]  5.89   Inf  9.43 -2.35  2.10 -8.53 -7.58 -4.58  2.01
## attr(,"na.action")
## [1]  1  4  7 11 14
## attr(,"class")
## [1] "omit"

Các phép toán trên NA cho kết quả là NA.

3 + 2.1*NA - 4
## [1] NA
3*c(1, 2, NA, NA, NaN, 6)
## [1]   3   6  NA  NA NaN  18
NA > 76
## [1] NA
76 > NaN
## [1] NA

Giá trị đặc biệt cuối cùng là giá trị rỗng NULL.

a <- NULL
a
## NULL
c(2, 4, NA, 8)
## [1]  2  4 NA  8
c(2, 4, NULL, 8)
## [1] 2 4 8
c(NA, NA, NA)
## [1] NA NA NA
c(NULL, NULL, NULL)
## NULL

Ở đây chúng ta tạo ra đối tượng rỗng chỉ để minh họa. Thực chất việc tạo ra một đối tượng rỗng là vô nghĩa. NULL thường xuất hiện trong định nghĩa hàm trong R, trong đó một số đối số nào đó của hàm có thể nhận giá trị NULL. NULL cũng thường xuất hiện như một kết quả rỗng của một số thao tác nào đó.

seq(from = 1, to = 10, by = ((to - from)/(length.out - 1)), length.out = NULL, along.with = NULL, ...)
lst <- list(a1 = 3, a2 = c(10, 11))
lst$a2
## [1] 10 11
lst$a3
## NULL

Để kiểm tra một đối tượng có phải là NULL hay không chúng ta dùng hàm is.null().

chac <- c("string1", "string2", "string3")
is.null(chac)
## [1] FALSE
nul <- c(NULL, NULL, NULL)
is.null(nul)
## [1] TRUE

Một điều thú vị là các phép toán trên NULL dẫn đến kết quả rỗng.

NULL + 53
## numeric(0)
53 <= NULL
## logical(0)
NaN - NULL + NA/Inf
## numeric(0)

Bài tập 6.2.

  1. Cho vectơ vec <- c(4.3, 2.2, NULL, 2.4, NaN, 3.3, 3.1, NULL, 3.4, NA). Phát biểu nào sau đây là đúng.
    1. Độ dài của vec là 8
    2. Lệnh which(is.na(vec)) sẽ không cho kết quả là 4 và 8.
    3. Lệnh is.null(vec) sẽ cho chỉ số vị trí của hai giá trị NULL trong vec.
    4. Lệnh is.na(vec[8])+4/NULL sẽ không cho kết quả NA.
  2. Tạo và đặt tên list chứa vectơ c(7, 7, NA, 3, NA, 1, 1, 5, NA). Sau đó hãy thực hiện các điều sau:
    1. Đặt tên thành phần của list đó là alpha.
    2. Xác minh rằng list không có thành phần tên là beta.
    3. Thêm vào list thành phần tên beta là vectơ chỉ số vị trí NA của alpha.

Kiểu, lớp và ép kiểu dữ liệu

Để biết các thông tin bổ sung về một đối tượng trong R chúng ta dùng hàm attribute() và một thông tin cụ thể nào đó chúng ta dùng hàm attr().

x <- 1:5
attributes(x)
## NULL
mymat <- matrix(data = 1:9, nrow = 3, ncol = 3)
attributes(mymat)
## $dim
## [1] 3 3
attr(mymat, which = "dim")
## [1] 3 3
dim(mymat)
## [1] 3 3
mymat2 <- matrix(data = 1:9, nrow = 3, ncol = 3, dimnames = list(c("A", "B", "C"), c("D", "E", "F")))
mymat2
##   D E F
## A 1 4 7
## B 2 5 8
## C 3 6 9
attributes(mymat2)
## $dim
## [1] 3 3
## 
## $dimnames
## $dimnames[[1]]
## [1] "A" "B" "C"
## 
## $dimnames[[2]]
## [1] "D" "E" "F"
dimnames(mymat2)
## [[1]]
## [1] "A" "B" "C"
## 
## [[2]]
## [1] "D" "E" "F"
dimnames(mymat)
## NULL
dimnames(mymat) <- list(c("A", "B", "C"), c("D", "E", "F"))
mymat
##   D E F
## A 1 4 7
## B 2 5 8
## C 3 6 9

Lớp của đối tượng là một trong những thuộc tính hữu ích nhất để mô tả một đối tượng trong R. Hàm class() được dùng để kiểm tra lớp của đối tượng. Nếu đối tượng là vectơ thì hàm class() cho kết quả là kiểu giá trị của dữ liệu.

num.vec1 <- 1:4
class(num.vec1)
## [1] "integer"
num.vec2 <- seq(from = 1, to = 4, length = 6)
class(num.vec2)
## [1] "numeric"
char.vec <- c("a", "few", "strings", "here")
class(char.vec)
## [1] "character"
logic.vec <- c(T, F, F, F, T, F, T, T)
class(logic.vec)
## [1] "logical"
fac.vec <- factor(c("Blue", "Blue", "Green", "Red", "Green", "Yellow"))
class(fac.vec)
## [1] "factor"
num.mat1 <- matrix(data = num.vec1, nrow = 2, ncol = 2)
class(num.mat1)
## [1] "matrix" "array"
ordfac.vec <- factor(c("Small","Large","Large","Regular",
"Small"),levels=c("Small","Regular","Large"),ordered=TRUE)
class(ordfac.vec)
## [1] "ordered" "factor"

Khi chúng ta biết đối tượng là một factor thì chúng ta có thể vẽ biểu đồ thể hiện phân phối của biến định tính bằng hàm plot() rất dễ dàng.

plot(ordfac.vec)

Để kiểm tra xem một đối tượng thuộc một lớp hay kiểu dữ liệu nào đó, chúng ta có thể dùng hàm is-dot và nó sẽ trả về giá trị TRUE hoặc FALSE.

num.vec1 <- 1:4
num.vec1
## [1] 1 2 3 4
is.integer(num.vec1)
## [1] TRUE
is.numeric(num.vec1)
## [1] TRUE
is.matrix(num.vec1)
## [1] FALSE
is.data.frame(num.vec1)
## [1] FALSE
is.vector(num.vec1)
## [1] TRUE
is.logical(num.vec1)
## [1] FALSE

Chúng ta có thể thay đổi kiểu dữ liệu hoặc lớp của một đối tượng bằng cách dùng hàm as-dot.

as.numeric(c(T, F, F, T))
## [1] 1 0 0 1
as.character(c(34, 52))
## [1] "34" "52"
as.character(c(T, F, F, T))
## [1] "TRUE"  "FALSE" "FALSE" "TRUE"
as.numeric("Hello friends")
## Warning: NAs introduced by coercion
## [1] NA
as.logical(c("1", "0", "1", "0", "0"))
## [1] NA NA NA NA NA
as.logical(as.numeric(c("1", "0", "1", "0", "0")))
## [1]  TRUE FALSE  TRUE FALSE FALSE
mymat <- matrix(data = 1:4, nrow = 2, ncol = 2)
as.vector(mymat)
## [1] 1 2 3 4
myarr <- array(data = c(8, 1, 9, 5, 5, 1, 3, 4, 3, 9, 8, 8), dim = c(2, 3, 2))
as.matrix(myarr)
##       [,1]
##  [1,]    8
##  [2,]    1
##  [3,]    9
##  [4,]    5
##  [5,]    5
##  [6,]    1
##  [7,]    3
##  [8,]    4
##  [9,]    3
## [10,]    9
## [11,]    8
## [12,]    8
as.vector(myarr)
##  [1] 8 1 9 5 5 1 3 4 3 9 8 8
mylst <- list(var1 = mymat, var2 = c(T, F, T), var3 = factor(c(2, 3, 4, 4, 2)))
as.data.frame(mylst)
## Error in (function (..., row.names = NULL, check.rows = FALSE, check.names = TRUE, : arguments imply differing number of rows: 2, 3, 5
mylst1 <- list(var1 = c(3, 4, 5, 1), var2 = c(T, F, T, T), var3 = factor(c(4, 4, 2, 1)))
as.data.frame(mylst1)
##   var1  var2 var3
## 1    3  TRUE    4
## 2    4 FALSE    4
## 3    5  TRUE    2
## 4    1  TRUE    1

Hàm is-dotas-dot có thể được dùng trong trường hợp tạo hàm như sau:

autoplot <- function(x) {
  if (is.numeric(x)==TRUE)
    hist(x)
  else if (is.character(x)==TRUE)
    plot(as.factor(x))
  else plot(x)
}
x <- c(5,4,6,5,4,3,6,5,4,6,5,5,7)
autoplot(x)

autoplot(ordfac.vec)

Bài tập 6.3.

  1. Xác định lớp của các đối tượng sau:
    1. myarr <- array(data = 1:36, dim =c(3, 3, 4))
    2. myvec <- as.vector(myarr)
    3. mychar <- as.character(myvec)
    4. myfac <- as.factor(mychar)
    5. myvec_plus <- myvec + c(-0.1,0.1)
  2. Hãy tính is.numeric() + is.integer() cho từng đối tượng ở câu (a). Sau đó hãy tập hợp các kết quả lại thành một factor. So sánh factor vừa tạo và as.numeric() của chính nó.
  3. Đổi ma trận
     [,1] [,2] [,3] [,4]
[1,]    2    5    8   11
[2,]    3    6    9   12
[3,]    4    7   10   13

thành vectơ

 [1] "2"  "5"  "8"  "11" "3"  "6"  "9"  "12" "4"  "7"  "10" "13"
  1. Tạo và đặt tên cho ma trận: \[\begin{equation*} \left[\begin{array}{lll} 34 & 0 & 1 \\ 23 & 1 & 2 \\ 33 & 1 & 1 \\ 42 & 0 & 1 \\ 41 & 0 & 2 \end{array}\right] \end{equation*}\] Sau đó hãy thực hiện các yêu cầu sau:
    1. Đổi ma trận vừa tạo thành data frame.
    2. Đổi cột thứ 2 của data frame thành giá trị logic.
    3. Đổi cột thứ 3 của data frame thành factor.

Tóm tắt

Hàm/Toán tử Ý nghĩa
Inf, -Inf Giá trị vô cùng
is.infinite() Kiểm tra phần tử vô cùng
is.finite() Kiểm tra phần tử hữu hạn
NaN Giá trị không xác định
is.nan() Kiểm tra NaN
NA Giá trị khuyết
is.na() Kiểm tra NA
na.omit() Xóa tất cả NANaN
NULL Giá trị rỗng
is.null() Kiểm tra NULL
attributes() Xuất thông tin bổ sung
attr() Xuất một thông tin bổ sung cụ thể
dimnames() Xuất tên dòng và cột
class() Xác định lớp của đối tượng
is._ Kiểm tra đối tượng thuộc lớp nào đó
as._ Thay đổi lớp của đối tượng

Tài liệu tham khảo

Davies, Tilman M. 2016. The Book of R: A First Course in Programming and Statistics. No Starch Press.