Các hàm trong lập trình R với ví dụ

Hàm trong R là gì?

A chức năng, trong môi trường lập trình, là một tập hợp các hướng dẫn. Một lập trình viên xây dựng một hàm để tránh lặp đi lặp lại nhiệm vụ tương tự, hoặc giảm sự phức tạp.

Một chức năng nên được

  • được viết để thực hiện một nhiệm vụ cụ thể
  • có thể hoặc không bao gồm các đối số
  • chứa một cơ thể
  • có thể hoặc không thể trả về một hoặc nhiều giá trị.

Cách tiếp cận chung đối với hàm là sử dụng phần đối số làm đầu vào, nuôi thân hình một phần và cuối cùng trả lại một đầu ra. Cú pháp của một hàm như sau:

function (arglist)  {
  #Function body
}

R các chức năng tích hợp quan trọng

Có rất nhiều hàm dựng sẵn trong R. R khớp các tham số đầu vào của bạn với các đối số hàm của nó, theo giá trị hoặc theo vị trí, sau đó thực thi phần thân hàm. Đối số của hàm có thể có giá trị mặc định: nếu bạn không chỉ định các đối số này, R sẽ lấy giá trị mặc định.
Chú thích:
Có thể xem mã nguồn của một hàm bằng cách chạy tên của chính hàm đó trong bảng điều khiển.

R Các chức năng tích hợp quan trọng

Chúng ta sẽ thấy ba nhóm chức năng hoạt động

  • Chức năng chung
  • hàm toán học
  • Hàm thống kê

Chức năng chung

Chúng ta đã quen thuộc với các hàm chung như cbind(), rbind(),range(),sort(),order(). Mỗi hàm này có một nhiệm vụ cụ thể, lấy đối số để trả về đầu ra. Sau đây là các hàm quan trọng mà người ta phải biết-

hàm khác biệt ()

Nếu bạn làm việc trên chuỗi thời gian, bạn cần phải dừng chuỗi bằng cách lấy giá trị độ trễ. Một quá trình đứng yên cho phép giá trị trung bình, phương sai và tự tương quan không đổi theo thời gian. Điều này chủ yếu cải thiện khả năng dự đoán của chuỗi thời gian. Việc này có thể được thực hiện dễ dàng bằng hàm diff(). Chúng ta có thể xây dựng dữ liệu chuỗi thời gian ngẫu nhiên theo xu hướng và sau đó sử dụng hàm diff() để cố định chuỗi. Hàm diff() chấp nhận một đối số, một vectơ và trả về sai phân có độ trễ và lặp phù hợp.

Chú thích: Chúng ta thường cần tạo dữ liệu ngẫu nhiên, nhưng để học và so sánh, chúng ta muốn các số giống hệt nhau trên các máy. Để đảm bảo tất cả chúng ta tạo ra cùng một dữ liệu, chúng ta sử dụng hàm set.seed() với các giá trị tùy ý là 123. Hàm set.seed() được tạo thông qua quá trình tạo số giả ngẫu nhiên giúp mọi máy tính hiện đại có cùng một chuỗi số. Nếu chúng ta không sử dụng hàm set.seed(), tất cả chúng ta sẽ có chuỗi số khác nhau.

set.seed(123)
## Create the data
x = rnorm(1000)
ts <- cumsum(x)
## Stationary the serie
diff_ts <- diff(ts)
par(mfrow=c(1,2))
## Plot the series
plot(ts, type='l')
plot(diff(ts), type='l')

Hàm Diff()

hàm chiều dài()

Trong nhiều trường hợp, chúng ta muốn biết chiều dài của một vectơ để tính toán hoặc được sử dụng trong vòng lặp for. Hàm length() đếm số hàng trong vectơ x. Các mã sau đây nhập tập dữ liệu cars và trả về số hàng.

Chú thích: length() trả về số phần tử trong một vectơ. Nếu hàm được truyền vào ma trận hoặc khung dữ liệu thì số cột sẽ được trả về.

dt <- cars
## number columns
length(dt)

Đầu ra:

## [1] 1
## number rows
length(dt[,1])

Đầu ra:

## [1] 50

Các hàm toán học

R có một mảng các hàm toán học.

Operator Mô tả
abs (x) Lấy giá trị tuyệt đối của x
log (x, base = y) Lấy logarit của x với cơ số y; nếu cơ số không được chỉ định, trả về lôgarit tự nhiên
exp (x) Trả về cấp số nhân của x
sqrt (x) Trả về căn bậc hai của x
giai thừa(x) Trả về giai thừa của x (x!)
# sequence of number from 44 to 55 both including incremented by 1
x_vector <- seq(45,55, by = 1)
#logarithm
log(x_vector)

Đầu ra:

##  [1] 3.806662 3.828641 3.850148 3.871201 3.891820 3.912023 3.931826
##  [8] 3.951244 3.970292 3.988984 4.007333
#exponential
exp(x_vector)
#squared root
sqrt(x_vector)

Đầu ra:

##  [1] 6.708204 6.782330 6.855655 6.928203 7.000000 7.071068 7.141428
##  [8] 7.211103 7.280110 7.348469 7.416198
#factorial
factorial(x_vector)

Đầu ra:

##  [1] 1.196222e+56 5.502622e+57 2.586232e+59 1.241392e+61 6.082819e+62
##  [6] 3.041409e+64 1.551119e+66 8.065818e+67 4.274883e+69 2.308437e+71
## [11] 1.269640e+73

Chức năng thống kê

Cài đặt tiêu chuẩn R chứa nhiều chức năng thống kê. Trong hướng dẫn này, chúng ta sẽ xem xét ngắn gọn chức năng quan trọng nhất..

Các hàm thống kê cơ bản

Operator Mô tả
nghĩa là (x) Giá trị trung bình của x
trung vị(x) Trung vị của x
var(x) Phương sai của x
sd(x) Độ lệch chuẩn của x
tỷ lệ (x) Điểm chuẩn (z-score) của x
lượng tử(x) Tứ phân vị của x
tóm tắt(x) Tóm tắt về x: trung bình, tối thiểu, tối đa, v.v.
speed <- dt$speed
speed
# Mean speed of cars dataset
mean(speed)

Đầu ra:

## [1] 15.4
# Median speed of cars dataset
median(speed)

Đầu ra:

## [1] 15
# Variance speed of cars dataset
var(speed)

Đầu ra:

## [1] 27.95918
# Standard deviation speed of cars dataset
sd(speed)

Đầu ra:

## [1] 5.287644
# Standardize vector speed of cars dataset		
head(scale(speed), 5)

Đầu ra:

##           [,1]
## [1,] -2.155969
## [2,] -2.155969
## [3,] -1.588609
## [4,] -1.588609
## [5,] -1.399489
# Quantile speed of cars dataset
quantile(speed)

Đầu ra:

##   0%  25%  50%  75% 100%
##    4   12   15   19   25
# Summary speed of cars dataset
summary(speed)

Đầu ra:

##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max.
##     4.0    12.0    15.0    15.4    19.0    25.0

Cho đến thời điểm này, chúng ta đã học được rất nhiều hàm dựng sẵn của R.

Chú thích: Hãy cẩn thận với lớp đối số, tức là số, Boolean hoặc chuỗi. Chẳng hạn, nếu chúng ta cần truyền một giá trị chuỗi, chúng ta cần đặt chuỗi đó trong dấu ngoặc kép: “ABC” .

Viết hàm trong R

Trong một số trường hợp, chúng ta cần viết hàm của riêng mình vì chúng ta phải hoàn thành một nhiệm vụ cụ thể và không có hàm nào tồn tại sẵn. Một hàm do người dùng định nghĩa bao gồm một tên, đối sốthân hình.

function.name <- function(arguments) 
{
    computations on the arguments	
    some other code
}		

Chú thích: Một cách tốt là đặt tên cho hàm do người dùng xác định khác với hàm có sẵn. Nó tránh nhầm lẫn.

Một hàm đối số

Trong đoạn mã tiếp theo, chúng ta xác định một hàm bình phương đơn giản. Hàm chấp nhận một giá trị và trả về bình phương của giá trị đó.

square_function<- function(n) 
{
  # compute the square of integer `n`
  n^2
}  
# calling the function and passing value 4
square_function(4)

Giải thích mã

  • Hàm này được đặt tên là Square_function; nó có thể được gọi là bất cứ điều gì chúng ta muốn.
  • Nó nhận được một đối số “n”. Chúng tôi không chỉ định loại biến để người dùng có thể truyền số nguyên, vectơ hoặc ma trận
  • Hàm lấy đầu vào “n” và trả về bình phương của đầu vào. Khi bạn sử dụng xong hàm, chúng ta có thể xóa nó bằng hàm rm().

# sau khi bạn tạo hàm

rm(square_function)
square_function

Trên bảng điều khiển, chúng ta có thể thấy thông báo lỗi :Error: object 'square_function' not Found cho biết hàm này không tồn tại.

Phạm vi môi trường

Trong R, môi trường là một bộ sưu tập của các đối tượng như hàm, biến, khung dữ liệu, v.v.

R mở một môi trường mỗi khi Rstudio được nhắc.

Môi trường cấp cao nhất hiện có là môi trường toàn cầu, được gọi là R_GlobalEnv. Và chúng tôi có môi trường địa phương.

Chúng ta có thể liệt kê nội dung của môi trường hiện tại.

ls(environment())

Đầu ra

## [1] "diff_ts"         "dt"              "speed"           "square_function"
## [5] "ts"              "x"               "x_vector"

Bạn có thể thấy tất cả các biến và hàm được tạo trong R_GlobalEnv.

Danh sách trên sẽ khác nhau tùy theo mã lịch sử bạn thực thi trong R Studio.

Lưu ý rằng n, đối số của hàm Square_function là không phải trong môi trường toàn cầu này.

A mới môi trường được tạo ra cho từng chức năng. Trong ví dụ trên, hàm Square_function() tạo một môi trường mới bên trong môi trường toàn cục.

Để làm rõ sự khác biệt giữa toàn cầumôi trường địa phương, chúng ta hãy nghiên cứu ví dụ sau

Hàm này lấy giá trị x làm đối số và thêm nó vào y để xác định bên ngoài và bên trong hàm

Phạm vi môi trường

Hàm f trả về kết quả đầu ra là 15. Điều này là do y được xác định trong môi trường toàn cục. Bất kỳ biến nào được xác định trong môi trường toàn cục đều có thể được sử dụng cục bộ. Biến y có giá trị 10 trong tất cả các lệnh gọi hàm và có thể truy cập được bất cứ lúc nào.

Hãy xem điều gì sẽ xảy ra nếu biến y được xác định bên trong hàm.

Chúng ta cần bỏ `y` trước khi chạy mã này bằng rm r

Phạm vi môi trường

Kết quả cũng là 15 khi chúng ta gọi f(5) nhưng trả về lỗi khi chúng ta cố in giá trị y. Biến y không có trong môi trường toàn cầu.

Cuối cùng, R sử dụng định nghĩa biến mới nhất để truyền vào bên trong thân hàm. Hãy xem xét ví dụ sau:

Phạm vi môi trường

R bỏ qua các giá trị y được xác định bên ngoài hàm vì chúng ta đã tạo biến ay bên trong thân hàm một cách rõ ràng.

Hàm đa đối số

Chúng ta có thể viết một hàm có nhiều hơn một đối số. Hãy xem xét hàm được gọi là “thời gian”. Đây là một hàm đơn giản nhân hai biến.

times <- function(x,y) {
  x*y
	}
times(2,4)

Đầu ra:

## [1] 8

Khi nào chúng ta nên viết hàm?

Nhà khoa học dữ liệu cần thực hiện nhiều nhiệm vụ lặp đi lặp lại. Hầu hết thời gian, chúng tôi sao chép và dán các đoạn mã lặp đi lặp lại. Ví dụ: nên chuẩn hóa một biến trước khi chúng tôi chạy một học máy thuật toán. Công thức chuẩn hóa một biến là:

Công thức chuẩn hóa một biến

Chúng ta đã biết cách sử dụng hàm min() và max() trong R. Chúng ta sử dụng thư viện tibble để tạo khung dữ liệu. Tibble cho đến nay là chức năng thuận tiện nhất để tạo tập dữ liệu từ đầu.

library(tibble)
# Create a data frame
data_frame <- tibble(  
  c1 = rnorm(50, 5, 1.5), 
  c2 = rnorm(50, 5, 1.5),    
  c3 = rnorm(50, 5, 1.5),    
)

Chúng ta sẽ tiến hành theo hai bước để tính hàm được mô tả ở trên. Trong bước đầu tiên, chúng ta sẽ tạo một biến có tên c1_norm để thay đổi tỷ lệ của c1. Ở bước hai, chúng ta chỉ cần sao chép và dán mã của c1_norm và thay đổi bằng c2 và c3.

Chi tiết hàm với cột c1:

Người đề cử: : data_frame$c1 -min(data_frame$c1))

Mẫu số: max(data_frame$c1)-min(data_frame$c1))

Do đó, chúng ta có thể chia chúng để lấy giá trị chuẩn hóa của cột c1:

(data_frame$c1 -min(data_frame$c1))/(max(data_frame$c1)-min(data_frame$c1))

Chúng ta có thể tạo c1_norm, c2_norm và c3_norm:

Create c1_norm: rescaling of c1		
data_frame$c1_norm <- (data_frame$c1 -min(data_frame$c1))/(max(data_frame$c1)-min(data_frame$c1))
# show the first five values
head(data_frame$c1_norm, 5)

Đầu ra:

## [1] 0.3400113 0.4198788 0.8524394 0.4925860 0.5067991

Nó hoạt động. Chúng ta có thể sao chép và dán

data_frame$c1_norm <- (data_frame$c1 -min(data_frame$c1))/(max(data_frame$c1)-min(data_frame$c1))

sau đó thay đổi c1_norm thành c2_norm và c1 thành c2. Chúng ta làm tương tự để tạo c3_norm

data_frame$c2_norm <- (data_frame$c2 - min(data_frame$c2))/(max(data_frame$c2)-min(data_frame$c2))
data_frame$c3_norm <- (data_frame$c3 - min(data_frame$c3))/(max(data_frame$c3)-min(data_frame$c3))

Chúng tôi đã thay đổi tỷ lệ một cách hoàn hảo các biến c1, c2 và c3.

Tuy nhiên, phương pháp này dễ mắc sai lầm. Chúng ta có thể sao chép và quên thay đổi tên cột sau khi dán. Do đó, cách tốt nhất là viết một hàm mỗi khi bạn cần dán cùng một mã nhiều hơn hai lần. Chúng ta có thể sắp xếp lại mã thành một công thức và gọi nó bất cứ khi nào cần. Để viết hàm của riêng mình, chúng ta cần cung cấp:

  • Tên: bình thường hóa
  • số lượng đối số: Chúng ta chỉ cần một đối số, đó là cột chúng ta sử dụng trong tính toán của mình.
  • Phần thân: đây đơn giản là công thức mà chúng tôi muốn trả về.

Chúng ta sẽ tiến hành từng bước để tạo hàm chuẩn hóa.

Bước 1) Chúng tôi tạo ra người đề cử, đó là . Trong R, chúng ta có thể lưu trữ bộ đề cử trong một biến như thế này:

nominator <- x-min(x)

Bước 2) Chúng tôi tính toán mẫu số: . Chúng ta có thể sao chép ý tưởng của bước 1 và lưu trữ tính toán vào một biến:

denominator <- max(x)-min(x)

Bước 3) Chúng tôi thực hiện phép chia giữa đề cử và mẫu số.

normalize <- nominator/denominator

Bước 4) Để trả về giá trị cho hàm gọi, chúng ta cần chuyển normalize bên trong return() để lấy đầu ra của hàm.

return(normalize)

Bước 5) Chúng ta đã sẵn sàng sử dụng hàm này bằng cách gói mọi thứ vào trong dấu ngoặc.

normalize <- function(x){
  # step 1: create the nominator
  nominator <- x-min(x)
  # step 2: create the denominator
  denominator <- max(x)-min(x)
  # step 3: divide nominator by denominator
  normalize <- nominator/denominator
  # return the value
  return(normalize)
}

Hãy kiểm tra hàm của chúng tôi với biến c1:

normalize(data_frame$c1)

Nó hoạt động hoàn hảo. Chúng tôi đã tạo ra chức năng đầu tiên của mình.

Chức năng là cách toàn diện hơn để thực hiện một nhiệm vụ lặp đi lặp lại. Chúng ta có thể sử dụng công thức chuẩn hóa trên các cột khác nhau, như dưới đây:

data_frame$c1_norm_function <- normalize (data_frame$c1)
data_frame$c2_norm_function <- normalize	(data_frame$c2)
data_frame$c3_norm_function <- normalize	(data_frame$c3)

Mặc dù ví dụ này đơn giản nhưng chúng ta có thể suy ra sức mạnh của một công thức. Đoạn code trên dễ đọc hơn và đặc biệt tránh mắc lỗi khi dán code.

Hàm có điều kiện

Đôi khi, chúng ta cần đưa các điều kiện vào một hàm để cho phép mã trả về các kết quả đầu ra khác nhau.

Trong các tác vụ của Machine Learning, chúng ta cần phân chia tập dữ liệu thành tập huấn luyện và tập kiểm tra. Tập huấn luyện cho phép thuật toán học từ dữ liệu. Để kiểm tra hiệu suất của mô hình, chúng ta có thể sử dụng bộ kiểm tra để trả về thước đo hiệu suất. R không có chức năng tạo hai tập dữ liệu. Chúng ta có thể viết hàm riêng của mình để làm điều đó. Hàm của chúng ta có hai đối số và được gọi là Split_data(). Ý tưởng đằng sau rất đơn giản, chúng tôi nhân độ dài của tập dữ liệu (tức là số lượng quan sát) với 0.8. Ví dụ: nếu chúng ta muốn chia tập dữ liệu theo tỷ lệ 80/20 và tập dữ liệu của chúng ta chứa 100 hàng thì hàm của chúng ta sẽ nhân 0.8*100 = 80. 80 hàng sẽ được chọn để trở thành dữ liệu huấn luyện của chúng ta.

Chúng tôi sẽ sử dụng tập dữ liệu chất lượng không khí để kiểm tra chức năng do người dùng xác định. Bộ dữ liệu chất lượng không khí có 153 hàng. Chúng ta có thể thấy nó với đoạn mã dưới đây:

nrow(airquality)

Đầu ra:

## [1] 153

Chúng ta sẽ tiến hành như sau:

split_data <- function(df, train = TRUE)
Arguments:
-df: Define the dataset
-train: Specify if the function returns the train set or test set. By default, set to TRUE

Hàm của chúng tôi có hai đối số. Đối số train là tham số Boolean. Nếu được đặt thành TRUE, hàm của chúng tôi sẽ tạo tập dữ liệu train, nếu không, nó sẽ tạo tập dữ liệu thử nghiệm.

Chúng ta có thể tiến hành giống như chúng ta đã làm với hàm normalise(). Chúng ta viết mã như thể đó chỉ là mã một lần và sau đó gói mọi thứ có điều kiện vào phần nội dung để tạo hàm.

Bước 1:

Chúng ta cần tính toán độ dài của tập dữ liệu. Việc này được thực hiện bằng hàm nrow(). Nrow trả về tổng số hàng trong tập dữ liệu. Chúng tôi gọi độ dài thay đổi.

length<- nrow(airquality)
length

Đầu ra:

## [1] 153

Bước 2:

Chúng tôi nhân chiều dài với 0.8. Nó sẽ trả về số hàng để chọn. Nó phải là 153*0.8 = 122.4

total_row <- length*0.8
total_row

Đầu ra:

## [1] 122.4

Chúng tôi muốn chọn 122 hàng trong số 153 hàng trong bộ dữ liệu chất lượng không khí. Chúng tôi tạo một danh sách chứa các giá trị từ 1 đến Total_row. Chúng tôi lưu trữ kết quả trong biến được gọi là chia

split <- 1:total_row
split[1:5]

Đầu ra:

## [1] 1 2 3 4 5

tách chọn 122 hàng đầu tiên từ tập dữ liệu. Ví dụ: chúng ta có thể thấy rằng biến phân chia của chúng ta tập hợp các giá trị 1, 2, 3, 4, 5, v.v. Các giá trị này sẽ là chỉ mục khi chúng ta chọn các hàng để trả về.

Bước 3:

Chúng ta cần chọn các hàng trong tập dữ liệu chất lượng không khí dựa trên các giá trị được lưu trữ trong biến phân tách. Điều này được thực hiện như thế này:

train_df <- airquality[split, ] 
head(train_df)

Đầu ra:

##[1]    Ozone Solar.R Wind Temp Month Day
##[2]  51    13     137 10.3   76     6  20
##[3]  15    18      65 13.2   58     5  15
##[4]  64    32     236  9.2   81     7   3
##[5]  27    NA      NA  8.0   57     5  27
##[6]  58    NA      47 10.3   73     6  27
##[7]  44    23     148  8.0   82     6  13

Bước 4:

Chúng ta có thể tạo tập dữ liệu thử nghiệm bằng cách sử dụng các hàng còn lại, 123:153. Điều này được thực hiện bằng cách sử dụng – trước phần chia.

test_df <- airquality[-split, ] 
head(test_df)

Đầu ra:

##[1] Ozone Solar.R Wind Temp Month Day
##[2]  123    85     188  6.3   94     8  31
##[3]  124    96     167  6.9   91     9   1
##[4]  125    78     197  5.1   92     9   2
##[5]  126    73     183  2.8   93     9   3
##[6]  127    91     189  4.6   93     9   4
##[7]  128    47      95  7.4   87     9   5

Bước 5:

Chúng ta có thể tạo điều kiện bên trong thân hàm. Hãy nhớ rằng, chúng ta có một chuỗi đối số có giá trị Boolean được đặt thành TRUE theo mặc định để trả về tập hợp tàu. Để tạo điều kiện, chúng ta sử dụng cú pháp if:

  if (train ==TRUE){ 
    train_df <- airquality[split, ] 
      return(train)		
  } else {
    test_df <- airquality[-split, ] 
      return(test)		
  }

Thế là xong, chúng ta có thể viết hàm. Chúng tôi chỉ cần thay đổi chất lượng không khí thành df vì chúng tôi muốn thử chức năng của mình với bất kỳ khung dữ liệu, không chỉ chất lượng không khí:

split_data <- function(df, train = TRUE){
  length<- nrow(df)
  total_row <- length *0.8
  split <- 1:total_row
  if (train ==TRUE){ 
    train_df <- df[split, ] 
      return(train_df)		
  } else {
    test_df <- df[-split, ] 
      return(test_df)		
  }
}

Hãy thử chức năng của chúng tôi trên tập dữ liệu chất lượng không khí. chúng ta nên có một bộ tàu với 122 hàng và một bộ thử nghiệm với 31 hàng.

train <- split_data(airquality, train = TRUE)
dim(train)

Đầu ra:

## [1] 122   6
test <- split_data(airquality, train = FALSE)
dim(test)

Đầu ra:

## [1] 31  6