R là ngôn ngữ lai tạp giữa lập trình và thống kê ứng dụng, do đó để thành thạo sử dụng ngôn ngữ này chúng ta cần có một chút kiến thức về lập trình, sử dụng vòng lặp và điều quan trọng đó là hiểu được cấu trúc dữ liệu và kiểu dữ liệu chúng ta sẽ làm việc và xử lý trong R. Do đó qua nội dung này, chúng ta có thể hiểu và làm quen với một số câu lệnh, vòng lặp lập trình trong R
Kiểu dữ liệu trong R
Kiểu số và kiểu ký tự
Chúng ta thường gặp nhất là hai dạng kiểu dữ liệu là số và kiểu dữ liệu là chữ (hay còn gọi là ký tự, xâu ký tự). Ví dụ như sau
<- 1
x <- "1"
y mode(x)
## [1] "numeric"
mode(y)
## [1] "character"
sqrt(x)
## [1] 1
#sqrt(y)
Hàm mode cho chúng ta biết kiểu dữ liệu mà biến số lưu là gì. Nếu lấy căn bậc hai bằng hàm sqrt() chương trình sẽ báo lỗi vì không có căn bậc hai của kiểu ký tự. Sở dĩ chúng ta phải phân biệt kiểu số và ký tự vì ứng với mỗi kiểu này sẽ có những hàm xử lý dữ liệu khác nhau đi kèm với chúng. Để chuyển một kiểu ký tự về số sử dụng hàm as.numeric().
as.numeric(y) -> y1
mode(y1)
## [1] "numeric"
Kiểu logic
Đôi khi trong các trường hợp chúng ta sẽ gặp các phép toán hoặc kết quả liên quan đến giá trị đúng/sai. Đây gọi là kiểu dữ liệu Boolean (BOOL), kiểu logic.
<- 3
a <- 4
b <- a > b
d mode(d)
## [1] "logical"
Kiểu dữ liệu có cấu trúc trong R
Véc tơ
Giả sử ta muốn thực hiện sản xuất hàng loạt: Nếu ta bắt gặp bài toán phải tính diện tích của năm hình chữ nhật với chiều rộng 10, 20, 30, 40, 50 cm và chiều dài 15, 25, 35, 45, 55 cm. Dĩ nhiên với các thao tác bằng tay chúng ta có thể thực hiện phép tính nhân để tính diện tích của 5 hình này một cách liên tục, tuy nhiên nếu là 50 hình chữ nhật thì sao nhỉ? Khi đó chúng ta sẽ sử dụng một kiểu dữ liệu có cấu trúc để lưu dữ liệu, đó là véc tơ. Véc tơ là kiểu dữ liệu cơ bản trong R, trong đó tất cả các thành phần của 1 véc tơ đều có chung một kiểu cấu trúc dữ liệu (int,char,float….). Để tạo một vector, có thể dùng hàm c() - concatenate để nối các phần tử của vector:
<- c("r", "hello", "stat", "software")
s1 s1
## [1] "r" "hello" "stat" "software"
<- c(1, 2, 3, 4, 5)
s2 s2
## [1] 1 2 3 4 5
Nếu nhu cầu của chúng ta là tạo một vector gồm các số liền kề, R cung cấp toán tử : rất hữu ích.
<- 1:5
s3 s3
## [1] 1 2 3 4 5
<- 5.4:9
num num
## [1] 5.4 6.4 7.4 8.4
Ngoài ra bạn có thể tạo một chuổi liên tiếp với “bước nhảy” tùy ý với hàm seq(…)
seq(from=1, to=5, by=0.5) -> ct1
ct1
## [1] 1.0 1.5 2.0 2.5 3.0 3.5 4.0 4.5 5.0
# Viết gọn hơn
seq(1,5,0.5)
## [1] 1.0 1.5 2.0 2.5 3.0 3.5 4.0 4.5 5.0
seq(1,7, length.out = 3) # Tao ra tu 1 den 7 voi kich thuoc la 3 so
## [1] 1 4 7
Để xem độ dài của 1 véc tơ chúng ta sử dụng lệnh length()
<- c(1:5)
m length(m)
## [1] 5
Để trích ra một phần tử của vector chúng ta có thể dùng toán tử [], chúng ta có thể trích duy nhất một phần tử hoặc một vector phần tử theo thứ tự:
<- c(0,1,2,3,9,8,7,4,5,6)
x # Lấy ra phần tử thứ 4
4] x[
## [1] 3
# Lấy phần từ 2 3 4 5
2:5] x[
## [1] 1 2 3 9
# Lấy vector phần tử 1 3 5
c(1,3,5)] x[
## [1] 0 2 9
Sửa phần tử trong vector: vector trong R chúng ta có thể gán lại giá trị phần tử trong vector như sau: `
5] <- 256
x[ x
## [1] 0 1 2 3 256 8 7 4 5 6
c(1,5,7)] <- c(-3,-2,-1)
x[ x
## [1] -3 1 2 3 -2 8 -1 4 5 6
Toán tử vector hóa: vector trong R cung cấp nhiều toán tử hữu ích giữa hai vector, trong nhiều trường hợp để tăng hiệu năng tính toán thì chúng ta nên dùng những toán tử này, vì chúng được tối ưu bởi các thư viện đại số ở bên dưới khá kĩ.
<- c(1,2,3)
u <- c(2,3,1)
v > v u
## [1] FALSE FALSE TRUE
# Thực hiện cộng với một scalar:
+ 10 u
## [1] 11 12 13
# Làm tròn số:
<- c(3.4, 4.5, 5.6, 10.1)
g round(g)
## [1] 3 4 6 10
Quay lại với nội dung liên quan đến tính diện tích của 10 hình chữ nhật. Chúng ta có thể sử dụng 2 véc tơ để lưu giá trị của chiều rộng và dài
= c(10,20,30,40,50)
dai = c(15,25,35,45,55)
rong = dai * rong
S S
## [1] 150 500 1050 1800 2750
Mảng (Array)
Các cấu trúc kết gộp như vậy được gọi là mảng, trong trường hợp này là mảng một chiều, vector. Tương tự, ta cũng có thể làm việc với một bảng vuông (hai chiều) hoặc nhiều chiều hơn các số, gọi là ma trận. Nếu bạn lo ngại thuật ngữ đó thì có thể gọi nó là: bảng số.
= array(1, c(3,3))
A = array(2, c(3,3))
B = A + B
M A
## [,1] [,2] [,3]
## [1,] 1 1 1
## [2,] 1 1 1
## [3,] 1 1 1
B
## [,1] [,2] [,3]
## [1,] 2 2 2
## [2,] 2 2 2
## [3,] 2 2 2
M
## [,1] [,2] [,3]
## [1,] 3 3 3
## [2,] 3 3 3
## [3,] 3 3 3
Data Frame
Có thể xem data frame là dạng dữ liệu thuộc loại em ruột của ma trận. Với ma trận, tất cả các phần tử phải thuộc cùng một loại nguyên tố, tức là ma trận có thể chứa các ô là numeric, logical hoặc character chứ không thể vừa kiểu này vừa kiểu kia. Điều này bất tiện, chẳng hạn khi ta muốn lưu dữ liệu mà cột thứ nhất là giới tính học sinh (character) cột thứ hai là điểm số (numeric). Data frame cho phép ta làm việc này, chẳng hạn:
= c("m","f","m");
sex = c(7,9,8);
score = data.frame(sex,score);
M rownames(M) = c("Nam","Anh","Man")
M
## sex score
## Nam m 7
## Anh f 9
## Man m 8
write.table(M, file = "record.txt")
Các toán tử số học trong R
Cú pháp của các toán tử trong R rất giống với các ngôn ngữ lập trình khác. Sau đây là danh sách toán tử cùng với giải thích ý nghĩa của chúng. Bảng sau định nghĩa các toán tử số học khác nhau:
= c("+","-","*","/","** or ^","%%","%/%")
Operators = c("Addition","Subtraction","Multiplication","Division","Exponentiation","Modulus","Integer Quotient")
Explanations =data.frame(Operators,Explanations)
Syntax ::kable(Syntax) knitr
Operators | Explanations |
---|---|
+ | Addition |
- | Subtraction |
* | Multiplication |
/ | Division |
** or ^ | Exponentiation |
%% | Modulus |
%/% | Integer Quotient |
Tiếp theo sẽ là vế các toán tử logic.
= c("==","<",">","<=",">=")
Operators = c("Expact equal to","Less than","Greater than","Less than or equal to","Greater than or equal to")
Explanations = data.frame(Operators,Explanations)
Syntax ::kable(Syntax) knitr
Operators | Explanations |
---|---|
== | Expact equal to |
< | Less than |
> | Greater than |
<= | Less than or equal to |
>= | Greater than or equal to |
Cấu trúc điều khiển trong R
Cấu trúc rẽ nhánh If
if(điều kiện){ nội dung }
= 20
x if(x > 5){
print(x)
}
## [1] 20
Cấu trúc rẽ nhánh If-Esle
if(điều kiện){ nội dung khi điều kiện đúng }else{ nội dung khi điều kiện sai }
= 5
x if(x %% 2 != 0)
{print(paste0(x,": la so le"))
else{
}print(paste0(x," : là so chan"))
}
## [1] "5: la so le"
Hàm Ifelse
ifelse(điều kiện,nội dung khi điều kiện đúng, nội dung khi điều kiện sai)
= 1:5
x ifelse(x %% 2,paste0(x," : la so le"),paste0(x," : la so chan"))
## [1] "1 : la so le" "2 : la so chan" "3 : la so le" "4 : la so chan"
## [5] "5 : la so le"
Cấu trúc lặp for
for ( x trong 1 trình tự nào đó){ nội dung cần lặp }
= c("Tran","Quang","Quy","ICTU")
x for(i in seq(x))
{print(x[i])
}
## [1] "Tran"
## [1] "Quang"
## [1] "Quy"
## [1] "ICTU"
Sử dụng vòng lặp viết ma trận cỡ 3*3 và tính tổng tất cả các phần tử của ma trận đó.
= matrix(1:9,nrow = 3,ncol = 3)
mat = 0
sum for(i in seq(nrow(mat))){
for (j in seq(ncol(mat))) {
= sum + mat[i,j]
sum print(sum)
} }
## [1] 1
## [1] 5
## [1] 12
## [1] 14
## [1] 19
## [1] 27
## [1] 30
## [1] 36
## [1] 45
Ví dụ: Dùng vòng lặp for, viết chương trình kiểm tra một số nhập từ bàn phím có phải là số nguyên tố hay không?
= 5
x = 1
ngto for(i in 2:sqrt(x)){
if(x %% i ==0){
= 0
ngto
}
}if(ngto == 1){
print(paste0(x,": la so nguyen to"))
else{
}print(paste0(x,": khong la so nguyen to"))
}
## [1] "5: la so nguyen to"
Cấu trúc lặp vô hạn While
while(điều kiện){ nội dung khi điều kiện đúng (lặp vô hạn) }
= 1
i while(i<10){
print(i)
= i + 1
i }
## [1] 1
## [1] 2
## [1] 3
## [1] 4
## [1] 5
## [1] 6
## [1] 7
## [1] 8
## [1] 9
Một số dạng lặp khác
# lặp kết hợp với break
for( i in 1:30){
if(i < 8){
print(paste0("Gia tri hien tai la :",i))
else{
}print(paste0("Gia tri hien tai la :",i," va dung vong lap"))
break
} }
## [1] "Gia tri hien tai la :1"
## [1] "Gia tri hien tai la :2"
## [1] "Gia tri hien tai la :3"
## [1] "Gia tri hien tai la :4"
## [1] "Gia tri hien tai la :5"
## [1] "Gia tri hien tai la :6"
## [1] "Gia tri hien tai la :7"
## [1] "Gia tri hien tai la :8 va dung vong lap"
# Lặp kết hợp với next
for(i in 1:10){
if(i %% 2){
print(paste0(i,": la so le"))
else{
}next
} }
## [1] "1: la so le"
## [1] "3: la so le"
## [1] "5: la so le"
## [1] "7: la so le"
## [1] "9: la so le"
Cấu trúc lặp Repeat
repeat { nội dung cần lặp đi lặp lại với 1 điều kiện rõ ràng bao gồm nội dung thoát khỏi vòng lặp }
= 1
i repeat
{= i^2
square =i+1
i if(square < 36){
print(paste0(square,": nho hon 36. Va van con dang trong vong lap"))
else{
}print(paste0(square," :lon hon hoac bang 36 . Va thoat khoi vong lap"))
break
} }
## [1] "1: nho hon 36. Va van con dang trong vong lap"
## [1] "4: nho hon 36. Va van con dang trong vong lap"
## [1] "9: nho hon 36. Va van con dang trong vong lap"
## [1] "16: nho hon 36. Va van con dang trong vong lap"
## [1] "25: nho hon 36. Va van con dang trong vong lap"
## [1] "36 :lon hon hoac bang 36 . Va thoat khoi vong lap"
Họ hàm apply()
= c("apply","lapply","sapply","mapply","tapply","rapply")
Function = c("dataframe or matrix or array",
Input_data_type "vecto,list,variables in dataframe or matrix",
"vector,list,variables in dataframe or matrix",
"vector,list,variables in dataframe or matrix",
"ragged array",
"vector,list,variables")
= c("Vecto,matrix,array,list","list",
Output_data_type "matrix,vecto,list",
"matrix,vecto,list",
"array","list")
= data.frame(Function,Input_data_type,Output_data_type)
df ::kable(df) knitr
Function | Input_data_type | Output_data_type |
---|---|---|
apply | dataframe or matrix or array | Vecto,matrix,array,list |
lapply | vecto,list,variables in dataframe or matrix | list |
sapply | vector,list,variables in dataframe or matrix | matrix,vecto,list |
mapply | vector,list,variables in dataframe or matrix | matrix,vecto,list |
tapply | ragged array | array |
rapply | vector,list,variables | list |
Hàm apply()
Đầu vào của hàm này có thể là một dataframe, một ma trận hoặc một mảng, đầu ra sau khi áp dụng các phương thức tính toán có thể là dataframe, một ma trận hoặc một mảng.
= cbind(x1 = 7,x2 = c(7:1,2:5))
x =apply(x, 2,sum) # Tham số thứ 2 nếu là 2 dành cho cột, là 1 thì là dòng
col.sums = apply(x,1,sum) row.sums
Hàm lapply()
Sử dụng cho một list, đầu vào có thể là véc tơ, một list trong dataframe, đầu ra là một list kết quả
= list(x1 =7:1,x2 = c(7:1,2:5))
x3 lapply(x3,mean)
## $x1
## [1] 4
##
## $x2
## [1] 3.818182
Hàm sapply()
Giống như hàm lapply, tuy nhiên có thể xây dựng hàm con trực tiếp
= 1:10
V_in = sapply(V_in,function(x) x^2)
V_out V_out
## [1] 1 4 9 16 25 36 49 64 81 100
Hàm mapply()
Đầu vào và ra giống như lapply() và sapply()
mapply(rep,1:6,6:1)
## [[1]]
## [1] 1 1 1 1 1 1
##
## [[2]]
## [1] 2 2 2 2 2
##
## [[3]]
## [1] 3 3 3 3
##
## [[4]]
## [1] 4 4 4
##
## [[5]]
## [1] 5 5
##
## [[6]]
## [1] 6