Lập trình với R: Functions

Function

Function

Functions là một trong những thành phần cơ bản của ngôn ngữ R. Chúng là những mẫu code nhỏ có thể sử dụng lại nhiều lần và được xem như các đối tượng khác trong R. Ở các bài viết trước, chắc hẳn chúng ta cũng đã sử dụng qua nhiều hàm dựng sẵn (built-in function). Một function bao gồm tên hàm và đi kèm theo là các đối số (parameters).

Chúng ta hãy thử một vài hàm cơ bản cho vui. Hàm Sys.Date() trả về thông tin thời gian và ngày hiện tại của hệ thống.

Sys.Date()
[1] "2015-07-14"

Hầu hết các hàm trong R đều trả về một giá trị. Giống như hàm Sys.Date() sẽ trả về một giá trị dựa trên hệ thống hiện tại. Trong khi đó, cũng có những hàm biến đổi dữ liệu đầu vào và trả về kết quả tính toán trên dữ liệu đó. Ví dụ hàm mean() sẽ lấy numeric vector đầu vào, và trả về giá trị trung bình của các phần tử trong vector đó. Đầu vào của hàm thường được gọi là đối số (arguments/parameters). Đưa đối số vào một hàm còn gọi là truyền đối số vào hàm đó. Đối số bạn muốn truyền vào hàm được đặt trong dấu ngoặc đơn. Ta xem hàm mean dưới đây nhận vào đối số là vector c(2, 4, 5) và trả về giá trị trung bình của vector đó.

mean(c(2, 4, 5))
[1] 3.666667

Ví dụ tiếp theo sẽ hướng dẫn bạn viết một hàm đơn giản boring_fuction. Hàm này nhận đối số đầu vào là biến x và trả ra kết quả cũng chính là biến x này.

# định nghĩa hàm boring_fucntion
boring_function <- function(x) {
   x
}
# kiểm tra hàm boring_function
boring_function('My first function!')
[1] "My first function!"

Xin chúc mừng, bạn đã viết được một hàm đầu tiên. Khi viết các hàm, bạn sẽ hiểu rõ hơn cách mà R hoạt động. Như John Chambers, người sáng chế ra R có nói "To understand computations in R, two slogans are helpful: 1: Everything that exists is an object. 2. Everything that happens is a function call."

Nếu bạn muốn xem source code của bất kỳ hàm nào, chỉ cần nhập tên của hàm đó và nhấn Enter.

boring_function
function(x) {
x
}

Tiếp theo ta sẽ thử viết hàm có các đối số mặc định. Bạn có thể gán giá trị mặc định cho các đối số đầu vào của mình.

remainder <- function(num, divisor = 2) {
num %% divisor
}

# kiểm tra hàm remainder
remainder(5)
[1] 1

Qua ví dụ trên, ta thấy mặc dù chúng ta không truyền cho hàm remainder đối số thứ hai là divisor nhưng do mặc định divisor là 2 nên ta vẫn lấy được kết quả trả về 1. Ngoài ra, bạn còn có thể chỉ định tường minh tên của các đối số cho hàm. Do bạn đã đặt tên cho các đối số đầu vào nên thứ tự của các đối số không còn quan trọng nữa nếu bạn nhập tên của đối số:

remainder(11, 5)
[1] 1
remainder(divisor = 11, num = 5)
[1] 5
remainder(4, div = 2)
[1] 0

Như các bạn có thể thấy, có một sự khác biệt rõ ràng giữa remainder(11, 5) và remainder(divisor = 11, num = 5). Hơn nữa, R còn cho phép chúng ta nhập một phần tên của đối số. Ví dụ, bạn chỉ nhập "div = 2", R tự động hiểu "div" ở đây là viết tắt của "divisor".

Lưu ý rằng bạn nên viết code sao cho dễ hiểu. Việc thay đổi thứ tự các đối số đầu vào bằng tên của chúng hay viết một phần tên của các đối số có thể gây nhầm lẫn, do đó chúng ta sử dụng đặc tính này của R một cách cẩn thận.

Ta đã nói nhiều về đối số, vậy nếu bạn muốn liệt kê tất cả các đối số thì sao? Dưới đây bạn có thể sử dụng hàm args() để xem các đối số của hàm remainder().

args(remainder)
function (num, divisor = 2)
NULL

Ngoài các đối số là các kiểu dữ liệu, ta còn có thể truyền vào đối số là một hàm. Ví dụ hàm evaluate sau:

evaluate <- function(func, dat){
func(dat)
}

# tính tổng của chuỗi số dựa vào hàm evaluate()
evaluate(sum, c(2, 4, 6))
[1] 12

# tính trung vị của chuỗi số dựa vào hàm evaluate()
evaluate(median, c(7, 40, 9))
[1] 9

# phép làm tròn xuống dựa vào hàm evaluate()
evaluate(floor, 11.1)
[1] 11

# định nghĩa hàm inline cộng dồn giá trị hiện tại lên 1
evaluate(function(x){x+1}, 6)
[1] 7

Ý tưởng truyền vào một hàm làm đối số cho hàm khác là một khái niệm quan trọng trong lập trình. Có thể bạn sẽ ngạc nhiên khi biết rằng bạn có thể làm như vậy mà không cần chỉ định trước tên hàm dùng để tính toán. Các hàm không cần được đặt tên trước này được gọi là anonymous functions.

Hàm dưới đây sẽ lấy danh sách các từ loại (Part of speech) từ đối số được biểu diễn bởi "…". Sau đó, ta sẽ truy xuất từng đối số dựa vào tên của các từ loại truyền vào và xuất ra câu có nghĩa. Toán tử "…" này cho phép truyền vào vô hạn các đối số.

mad_libs <- function(…){
# Do your argument unpacking here!
args <- list(…)
place <- args[["place"]]
adjective <- args[["adjective"]]
noun <- args[["noun"]]

paste("News from", place, "today where", adjective, "students took to the streets in protest of the new", noun, "being installed on campus.")
}

mad_libs(adjective = "interesting", place = "University", noun = "library")
[1] "News from University today where interesting students took to the streets in protest of the new library being installed on campus."

Có lẽ chúng ta đã quen thuộc với các phép toán cộng, trừ, nhân, chia trên số thực trong R. Để làm được như vậy ta dùng các toán tử +, -, *, /. Các toán tử này được gọi là các toán tử hai ngôi bởi vì chúng nhận vào hai đối số, đối số bên trái và đối số bên phải. Trong R, chúng ta có thể định nghĩa cho mình các toán tử hai ngôi riêng. Bạn hãy tham khảo đoạn code bên dưới:

"%mult_add_one%" <- function(left, right){ # Remember to add arguments!
left * right + 1
}
4 %mult_add_one% 5
[1] 21

Hàm trên đơn giản lấy vào hai đối số left và right nhân với nhau sau đó cộng thêm một cho kết quả nhân ban đầu để có kết quả cuối cùng là 21 cho hai số 4 và 5.

Chúng ta đã kết thúc bài học hôm nay. Chúc các bạn có thể viết được những hàm hữu ích cho dự án của mình.

Nguồn tham khảo: http://swirlstats.com/

Advertisements

2 thoughts on “Lập trình với R: Functions

  1. Chào bạn, mình đang tìm hiểu R thì tình cờ đọc được blog của bạn. Cám ơn bạn rất nhiều vì đã chia sẻ kiến thức hay cho tất cả các bạn ham học hỏi. Phần này có 1 chỗ mình mình ra kết quả hơi khác bạn đó là chỗ bạn ví dụ cho các trường hợp thay đổi vị trí đối số, giá trị đối số của hàm remainder(11, 5). Chỗ này kết quả mình nghĩ là 1 nhưng kết quả của bạn là 5
    ——————-
    remainder(11, 5)
    [1] 5
    remainder(divisor = 11, num = 5)
    [1] 5
    remainder(4, div = 2)
    [1] 0
    ——————-
    Cái đầu tiên mình nghĩ kết quả là 1.
    Mong nhận được reply của bạn.

    Số lượt thích

Trả lời

Mời bạn điền thông tin vào ô dưới đây hoặc kích vào một biểu tượng để đăng nhập:

WordPress.com Logo

Bạn đang bình luận bằng tài khoản WordPress.com Đăng xuất / Thay đổi )

Twitter picture

Bạn đang bình luận bằng tài khoản Twitter Đăng xuất / Thay đổi )

Facebook photo

Bạn đang bình luận bằng tài khoản Facebook Đăng xuất / Thay đổi )

Google+ photo

Bạn đang bình luận bằng tài khoản Google+ Đăng xuất / Thay đổi )

Connecting to %s